1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29960aa7cSTomi Valkeinen /*
39960aa7cSTomi Valkeinen * Copyright (C) 2009 Nokia Corporation
46505d75cSTomi Valkeinen * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
59960aa7cSTomi Valkeinen *
69960aa7cSTomi Valkeinen * VENC settings from TI's DSS driver
79960aa7cSTomi Valkeinen */
89960aa7cSTomi Valkeinen
99960aa7cSTomi Valkeinen #define DSS_SUBSYS_NAME "VENC"
109960aa7cSTomi Valkeinen
119960aa7cSTomi Valkeinen #include <linux/kernel.h>
129960aa7cSTomi Valkeinen #include <linux/module.h>
139960aa7cSTomi Valkeinen #include <linux/clk.h>
149960aa7cSTomi Valkeinen #include <linux/err.h>
159960aa7cSTomi Valkeinen #include <linux/io.h>
169960aa7cSTomi Valkeinen #include <linux/completion.h>
179960aa7cSTomi Valkeinen #include <linux/delay.h>
189960aa7cSTomi Valkeinen #include <linux/string.h>
199960aa7cSTomi Valkeinen #include <linux/seq_file.h>
209960aa7cSTomi Valkeinen #include <linux/platform_device.h>
219960aa7cSTomi Valkeinen #include <linux/regulator/consumer.h>
229960aa7cSTomi Valkeinen #include <linux/pm_runtime.h>
239960aa7cSTomi Valkeinen #include <linux/of.h>
2409bffa6eSRob Herring #include <linux/of_graph.h>
259960aa7cSTomi Valkeinen #include <linux/component.h>
2634dfb85fSLaurent Pinchart #include <linux/sys_soc.h>
279960aa7cSTomi Valkeinen
282f004792SLaurent Pinchart #include <drm/drm_bridge.h>
292f004792SLaurent Pinchart
3032043da7SPeter Ujfalusi #include "omapdss.h"
319960aa7cSTomi Valkeinen #include "dss.h"
329960aa7cSTomi Valkeinen
339960aa7cSTomi Valkeinen /* Venc registers */
349960aa7cSTomi Valkeinen #define VENC_REV_ID 0x00
359960aa7cSTomi Valkeinen #define VENC_STATUS 0x04
369960aa7cSTomi Valkeinen #define VENC_F_CONTROL 0x08
379960aa7cSTomi Valkeinen #define VENC_VIDOUT_CTRL 0x10
389960aa7cSTomi Valkeinen #define VENC_SYNC_CTRL 0x14
399960aa7cSTomi Valkeinen #define VENC_LLEN 0x1C
409960aa7cSTomi Valkeinen #define VENC_FLENS 0x20
419960aa7cSTomi Valkeinen #define VENC_HFLTR_CTRL 0x24
429960aa7cSTomi Valkeinen #define VENC_CC_CARR_WSS_CARR 0x28
439960aa7cSTomi Valkeinen #define VENC_C_PHASE 0x2C
449960aa7cSTomi Valkeinen #define VENC_GAIN_U 0x30
459960aa7cSTomi Valkeinen #define VENC_GAIN_V 0x34
469960aa7cSTomi Valkeinen #define VENC_GAIN_Y 0x38
479960aa7cSTomi Valkeinen #define VENC_BLACK_LEVEL 0x3C
489960aa7cSTomi Valkeinen #define VENC_BLANK_LEVEL 0x40
499960aa7cSTomi Valkeinen #define VENC_X_COLOR 0x44
509960aa7cSTomi Valkeinen #define VENC_M_CONTROL 0x48
519960aa7cSTomi Valkeinen #define VENC_BSTAMP_WSS_DATA 0x4C
529960aa7cSTomi Valkeinen #define VENC_S_CARR 0x50
539960aa7cSTomi Valkeinen #define VENC_LINE21 0x54
549960aa7cSTomi Valkeinen #define VENC_LN_SEL 0x58
559960aa7cSTomi Valkeinen #define VENC_L21__WC_CTL 0x5C
569960aa7cSTomi Valkeinen #define VENC_HTRIGGER_VTRIGGER 0x60
579960aa7cSTomi Valkeinen #define VENC_SAVID__EAVID 0x64
589960aa7cSTomi Valkeinen #define VENC_FLEN__FAL 0x68
599960aa7cSTomi Valkeinen #define VENC_LAL__PHASE_RESET 0x6C
609960aa7cSTomi Valkeinen #define VENC_HS_INT_START_STOP_X 0x70
619960aa7cSTomi Valkeinen #define VENC_HS_EXT_START_STOP_X 0x74
629960aa7cSTomi Valkeinen #define VENC_VS_INT_START_X 0x78
639960aa7cSTomi Valkeinen #define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C
649960aa7cSTomi Valkeinen #define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x80
659960aa7cSTomi Valkeinen #define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x84
669960aa7cSTomi Valkeinen #define VENC_VS_EXT_STOP_Y 0x88
679960aa7cSTomi Valkeinen #define VENC_AVID_START_STOP_X 0x90
689960aa7cSTomi Valkeinen #define VENC_AVID_START_STOP_Y 0x94
699960aa7cSTomi Valkeinen #define VENC_FID_INT_START_X__FID_INT_START_Y 0xA0
709960aa7cSTomi Valkeinen #define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA4
719960aa7cSTomi Valkeinen #define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA8
729960aa7cSTomi Valkeinen #define VENC_TVDETGP_INT_START_STOP_X 0xB0
739960aa7cSTomi Valkeinen #define VENC_TVDETGP_INT_START_STOP_Y 0xB4
749960aa7cSTomi Valkeinen #define VENC_GEN_CTRL 0xB8
759960aa7cSTomi Valkeinen #define VENC_OUTPUT_CONTROL 0xC4
769960aa7cSTomi Valkeinen #define VENC_OUTPUT_TEST 0xC8
779960aa7cSTomi Valkeinen #define VENC_DAC_B__DAC_C 0xC8
789960aa7cSTomi Valkeinen
799960aa7cSTomi Valkeinen struct venc_config {
809960aa7cSTomi Valkeinen u32 f_control;
819960aa7cSTomi Valkeinen u32 vidout_ctrl;
829960aa7cSTomi Valkeinen u32 sync_ctrl;
839960aa7cSTomi Valkeinen u32 llen;
849960aa7cSTomi Valkeinen u32 flens;
859960aa7cSTomi Valkeinen u32 hfltr_ctrl;
869960aa7cSTomi Valkeinen u32 cc_carr_wss_carr;
879960aa7cSTomi Valkeinen u32 c_phase;
889960aa7cSTomi Valkeinen u32 gain_u;
899960aa7cSTomi Valkeinen u32 gain_v;
909960aa7cSTomi Valkeinen u32 gain_y;
919960aa7cSTomi Valkeinen u32 black_level;
929960aa7cSTomi Valkeinen u32 blank_level;
939960aa7cSTomi Valkeinen u32 x_color;
949960aa7cSTomi Valkeinen u32 m_control;
959960aa7cSTomi Valkeinen u32 bstamp_wss_data;
969960aa7cSTomi Valkeinen u32 s_carr;
979960aa7cSTomi Valkeinen u32 line21;
989960aa7cSTomi Valkeinen u32 ln_sel;
999960aa7cSTomi Valkeinen u32 l21__wc_ctl;
1009960aa7cSTomi Valkeinen u32 htrigger_vtrigger;
1019960aa7cSTomi Valkeinen u32 savid__eavid;
1029960aa7cSTomi Valkeinen u32 flen__fal;
1039960aa7cSTomi Valkeinen u32 lal__phase_reset;
1049960aa7cSTomi Valkeinen u32 hs_int_start_stop_x;
1059960aa7cSTomi Valkeinen u32 hs_ext_start_stop_x;
1069960aa7cSTomi Valkeinen u32 vs_int_start_x;
1079960aa7cSTomi Valkeinen u32 vs_int_stop_x__vs_int_start_y;
1089960aa7cSTomi Valkeinen u32 vs_int_stop_y__vs_ext_start_x;
1099960aa7cSTomi Valkeinen u32 vs_ext_stop_x__vs_ext_start_y;
1109960aa7cSTomi Valkeinen u32 vs_ext_stop_y;
1119960aa7cSTomi Valkeinen u32 avid_start_stop_x;
1129960aa7cSTomi Valkeinen u32 avid_start_stop_y;
1139960aa7cSTomi Valkeinen u32 fid_int_start_x__fid_int_start_y;
1149960aa7cSTomi Valkeinen u32 fid_int_offset_y__fid_ext_start_x;
1159960aa7cSTomi Valkeinen u32 fid_ext_start_y__fid_ext_offset_y;
1169960aa7cSTomi Valkeinen u32 tvdetgp_int_start_stop_x;
1179960aa7cSTomi Valkeinen u32 tvdetgp_int_start_stop_y;
1189960aa7cSTomi Valkeinen u32 gen_ctrl;
1199960aa7cSTomi Valkeinen };
1209960aa7cSTomi Valkeinen
1219960aa7cSTomi Valkeinen /* from TRM */
1229960aa7cSTomi Valkeinen static const struct venc_config venc_config_pal_trm = {
1239960aa7cSTomi Valkeinen .f_control = 0,
1249960aa7cSTomi Valkeinen .vidout_ctrl = 1,
1259960aa7cSTomi Valkeinen .sync_ctrl = 0x40,
1269960aa7cSTomi Valkeinen .llen = 0x35F, /* 863 */
1279960aa7cSTomi Valkeinen .flens = 0x270, /* 624 */
1289960aa7cSTomi Valkeinen .hfltr_ctrl = 0,
1299960aa7cSTomi Valkeinen .cc_carr_wss_carr = 0x2F7225ED,
1309960aa7cSTomi Valkeinen .c_phase = 0,
1319960aa7cSTomi Valkeinen .gain_u = 0x111,
1329960aa7cSTomi Valkeinen .gain_v = 0x181,
1339960aa7cSTomi Valkeinen .gain_y = 0x140,
1349960aa7cSTomi Valkeinen .black_level = 0x3B,
1359960aa7cSTomi Valkeinen .blank_level = 0x3B,
1369960aa7cSTomi Valkeinen .x_color = 0x7,
1379960aa7cSTomi Valkeinen .m_control = 0x2,
1389960aa7cSTomi Valkeinen .bstamp_wss_data = 0x3F,
1399960aa7cSTomi Valkeinen .s_carr = 0x2A098ACB,
1409960aa7cSTomi Valkeinen .line21 = 0,
1419960aa7cSTomi Valkeinen .ln_sel = 0x01290015,
1429960aa7cSTomi Valkeinen .l21__wc_ctl = 0x0000F603,
1439960aa7cSTomi Valkeinen .htrigger_vtrigger = 0,
1449960aa7cSTomi Valkeinen
1459960aa7cSTomi Valkeinen .savid__eavid = 0x06A70108,
1469960aa7cSTomi Valkeinen .flen__fal = 0x00180270,
1479960aa7cSTomi Valkeinen .lal__phase_reset = 0x00040135,
1489960aa7cSTomi Valkeinen .hs_int_start_stop_x = 0x00880358,
1499960aa7cSTomi Valkeinen .hs_ext_start_stop_x = 0x000F035F,
1509960aa7cSTomi Valkeinen .vs_int_start_x = 0x01A70000,
1519960aa7cSTomi Valkeinen .vs_int_stop_x__vs_int_start_y = 0x000001A7,
1529960aa7cSTomi Valkeinen .vs_int_stop_y__vs_ext_start_x = 0x01AF0000,
1539960aa7cSTomi Valkeinen .vs_ext_stop_x__vs_ext_start_y = 0x000101AF,
1549960aa7cSTomi Valkeinen .vs_ext_stop_y = 0x00000025,
1559960aa7cSTomi Valkeinen .avid_start_stop_x = 0x03530083,
1569960aa7cSTomi Valkeinen .avid_start_stop_y = 0x026C002E,
1579960aa7cSTomi Valkeinen .fid_int_start_x__fid_int_start_y = 0x0001008A,
1589960aa7cSTomi Valkeinen .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
1599960aa7cSTomi Valkeinen .fid_ext_start_y__fid_ext_offset_y = 0x01380001,
1609960aa7cSTomi Valkeinen
1619960aa7cSTomi Valkeinen .tvdetgp_int_start_stop_x = 0x00140001,
1629960aa7cSTomi Valkeinen .tvdetgp_int_start_stop_y = 0x00010001,
1639960aa7cSTomi Valkeinen .gen_ctrl = 0x00FF0000,
1649960aa7cSTomi Valkeinen };
1659960aa7cSTomi Valkeinen
1669960aa7cSTomi Valkeinen /* from TRM */
1679960aa7cSTomi Valkeinen static const struct venc_config venc_config_ntsc_trm = {
1689960aa7cSTomi Valkeinen .f_control = 0,
1699960aa7cSTomi Valkeinen .vidout_ctrl = 1,
1709960aa7cSTomi Valkeinen .sync_ctrl = 0x8040,
1719960aa7cSTomi Valkeinen .llen = 0x359,
1729960aa7cSTomi Valkeinen .flens = 0x20C,
1739960aa7cSTomi Valkeinen .hfltr_ctrl = 0,
1749960aa7cSTomi Valkeinen .cc_carr_wss_carr = 0x043F2631,
1759960aa7cSTomi Valkeinen .c_phase = 0,
1769960aa7cSTomi Valkeinen .gain_u = 0x102,
1779960aa7cSTomi Valkeinen .gain_v = 0x16C,
1789960aa7cSTomi Valkeinen .gain_y = 0x12F,
1799960aa7cSTomi Valkeinen .black_level = 0x43,
1809960aa7cSTomi Valkeinen .blank_level = 0x38,
1819960aa7cSTomi Valkeinen .x_color = 0x7,
1829960aa7cSTomi Valkeinen .m_control = 0x1,
1839960aa7cSTomi Valkeinen .bstamp_wss_data = 0x38,
1849960aa7cSTomi Valkeinen .s_carr = 0x21F07C1F,
1859960aa7cSTomi Valkeinen .line21 = 0,
1869960aa7cSTomi Valkeinen .ln_sel = 0x01310011,
1879960aa7cSTomi Valkeinen .l21__wc_ctl = 0x0000F003,
1889960aa7cSTomi Valkeinen .htrigger_vtrigger = 0,
1899960aa7cSTomi Valkeinen
1909960aa7cSTomi Valkeinen .savid__eavid = 0x069300F4,
1919960aa7cSTomi Valkeinen .flen__fal = 0x0016020C,
1929960aa7cSTomi Valkeinen .lal__phase_reset = 0x00060107,
1939960aa7cSTomi Valkeinen .hs_int_start_stop_x = 0x008E0350,
1949960aa7cSTomi Valkeinen .hs_ext_start_stop_x = 0x000F0359,
1959960aa7cSTomi Valkeinen .vs_int_start_x = 0x01A00000,
1969960aa7cSTomi Valkeinen .vs_int_stop_x__vs_int_start_y = 0x020701A0,
1979960aa7cSTomi Valkeinen .vs_int_stop_y__vs_ext_start_x = 0x01AC0024,
1989960aa7cSTomi Valkeinen .vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,
1999960aa7cSTomi Valkeinen .vs_ext_stop_y = 0x00000006,
2009960aa7cSTomi Valkeinen .avid_start_stop_x = 0x03480078,
2019960aa7cSTomi Valkeinen .avid_start_stop_y = 0x02060024,
2029960aa7cSTomi Valkeinen .fid_int_start_x__fid_int_start_y = 0x0001008A,
2039960aa7cSTomi Valkeinen .fid_int_offset_y__fid_ext_start_x = 0x01AC0106,
2049960aa7cSTomi Valkeinen .fid_ext_start_y__fid_ext_offset_y = 0x01060006,
2059960aa7cSTomi Valkeinen
2069960aa7cSTomi Valkeinen .tvdetgp_int_start_stop_x = 0x00140001,
2079960aa7cSTomi Valkeinen .tvdetgp_int_start_stop_y = 0x00010001,
2089960aa7cSTomi Valkeinen .gen_ctrl = 0x00F90000,
2099960aa7cSTomi Valkeinen };
2109960aa7cSTomi Valkeinen
211beea6214STomi Valkeinen enum venc_videomode {
212beea6214STomi Valkeinen VENC_MODE_UNKNOWN,
213beea6214STomi Valkeinen VENC_MODE_PAL,
214beea6214STomi Valkeinen VENC_MODE_NTSC,
215beea6214STomi Valkeinen };
216beea6214STomi Valkeinen
217b08644a2SLaurent Pinchart static const struct drm_display_mode omap_dss_pal_mode = {
218b08644a2SLaurent Pinchart .hdisplay = 720,
219b08644a2SLaurent Pinchart .hsync_start = 732,
220b08644a2SLaurent Pinchart .hsync_end = 796,
221b08644a2SLaurent Pinchart .htotal = 864,
222b08644a2SLaurent Pinchart .vdisplay = 574,
223b08644a2SLaurent Pinchart .vsync_start = 579,
224b08644a2SLaurent Pinchart .vsync_end = 584,
225b08644a2SLaurent Pinchart .vtotal = 625,
226b08644a2SLaurent Pinchart .clock = 13500,
2279960aa7cSTomi Valkeinen
228b08644a2SLaurent Pinchart .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |
229b08644a2SLaurent Pinchart DRM_MODE_FLAG_NVSYNC,
2309960aa7cSTomi Valkeinen };
2319960aa7cSTomi Valkeinen
232b08644a2SLaurent Pinchart static const struct drm_display_mode omap_dss_ntsc_mode = {
233b08644a2SLaurent Pinchart .hdisplay = 720,
234b08644a2SLaurent Pinchart .hsync_start = 736,
235b08644a2SLaurent Pinchart .hsync_end = 800,
236b08644a2SLaurent Pinchart .htotal = 858,
237b08644a2SLaurent Pinchart .vdisplay = 482,
238b08644a2SLaurent Pinchart .vsync_start = 488,
239b08644a2SLaurent Pinchart .vsync_end = 494,
240b08644a2SLaurent Pinchart .vtotal = 525,
241b08644a2SLaurent Pinchart .clock = 13500,
2429960aa7cSTomi Valkeinen
243b08644a2SLaurent Pinchart .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |
244b08644a2SLaurent Pinchart DRM_MODE_FLAG_NVSYNC,
2459960aa7cSTomi Valkeinen };
2469960aa7cSTomi Valkeinen
247663ac57bSLaurent Pinchart struct venc_device {
2489960aa7cSTomi Valkeinen struct platform_device *pdev;
2499960aa7cSTomi Valkeinen void __iomem *base;
2509960aa7cSTomi Valkeinen struct regulator *vdda_dac_reg;
2511ef904e1SLaurent Pinchart struct dss_device *dss;
2529960aa7cSTomi Valkeinen
253f33656e1SLaurent Pinchart struct dss_debugfs_entry *debugfs;
254f33656e1SLaurent Pinchart
2559960aa7cSTomi Valkeinen struct clk *tv_dac_clk;
2569960aa7cSTomi Valkeinen
257d60dfabaSLaurent Pinchart const struct venc_config *config;
2589960aa7cSTomi Valkeinen enum omap_dss_venc_type type;
2599960aa7cSTomi Valkeinen bool invert_polarity;
26034dfb85fSLaurent Pinchart bool requires_tv_dac_clk;
2619960aa7cSTomi Valkeinen
2629960aa7cSTomi Valkeinen struct omap_dss_device output;
2632f004792SLaurent Pinchart struct drm_bridge bridge;
264663ac57bSLaurent Pinchart };
2659960aa7cSTomi Valkeinen
2662f004792SLaurent Pinchart #define drm_bridge_to_venc(b) container_of(b, struct venc_device, bridge)
267663ac57bSLaurent Pinchart
venc_write_reg(struct venc_device * venc,int idx,u32 val)268663ac57bSLaurent Pinchart static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val)
2699960aa7cSTomi Valkeinen {
270663ac57bSLaurent Pinchart __raw_writel(val, venc->base + idx);
2719960aa7cSTomi Valkeinen }
2729960aa7cSTomi Valkeinen
venc_read_reg(struct venc_device * venc,int idx)273663ac57bSLaurent Pinchart static inline u32 venc_read_reg(struct venc_device *venc, int idx)
2749960aa7cSTomi Valkeinen {
275663ac57bSLaurent Pinchart u32 l = __raw_readl(venc->base + idx);
2769960aa7cSTomi Valkeinen return l;
2779960aa7cSTomi Valkeinen }
2789960aa7cSTomi Valkeinen
venc_write_config(struct venc_device * venc,const struct venc_config * config)279663ac57bSLaurent Pinchart static void venc_write_config(struct venc_device *venc,
280663ac57bSLaurent Pinchart const struct venc_config *config)
2819960aa7cSTomi Valkeinen {
2829960aa7cSTomi Valkeinen DSSDBG("write venc conf\n");
2839960aa7cSTomi Valkeinen
284663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_LLEN, config->llen);
285663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_FLENS, config->flens);
286663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
287663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_C_PHASE, config->c_phase);
288663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_GAIN_U, config->gain_u);
289663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_GAIN_V, config->gain_v);
290663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_GAIN_Y, config->gain_y);
291663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_BLACK_LEVEL, config->black_level);
292663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_BLANK_LEVEL, config->blank_level);
293663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_M_CONTROL, config->m_control);
294d79bd6b4SLaurent Pinchart venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data);
295663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_S_CARR, config->s_carr);
296663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_L21__WC_CTL, config->l21__wc_ctl);
297663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_SAVID__EAVID, config->savid__eavid);
298663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_FLEN__FAL, config->flen__fal);
299663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_LAL__PHASE_RESET, config->lal__phase_reset);
300663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_HS_INT_START_STOP_X,
301663ac57bSLaurent Pinchart config->hs_int_start_stop_x);
302663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_HS_EXT_START_STOP_X,
303663ac57bSLaurent Pinchart config->hs_ext_start_stop_x);
304663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_VS_INT_START_X, config->vs_int_start_x);
305663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y,
3069960aa7cSTomi Valkeinen config->vs_int_stop_x__vs_int_start_y);
307663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X,
3089960aa7cSTomi Valkeinen config->vs_int_stop_y__vs_ext_start_x);
309663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
3109960aa7cSTomi Valkeinen config->vs_ext_stop_x__vs_ext_start_y);
311663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
312663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_AVID_START_STOP_X, config->avid_start_stop_x);
313663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
314663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_FID_INT_START_X__FID_INT_START_Y,
3159960aa7cSTomi Valkeinen config->fid_int_start_x__fid_int_start_y);
316663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
3179960aa7cSTomi Valkeinen config->fid_int_offset_y__fid_ext_start_x);
318663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
3199960aa7cSTomi Valkeinen config->fid_ext_start_y__fid_ext_offset_y);
3209960aa7cSTomi Valkeinen
321663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_DAC_B__DAC_C,
322663ac57bSLaurent Pinchart venc_read_reg(venc, VENC_DAC_B__DAC_C));
323663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_VIDOUT_CTRL, config->vidout_ctrl);
324663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_HFLTR_CTRL, config->hfltr_ctrl);
325663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_X_COLOR, config->x_color);
326663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_LINE21, config->line21);
327663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_LN_SEL, config->ln_sel);
328663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
329663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_X,
3309960aa7cSTomi Valkeinen config->tvdetgp_int_start_stop_x);
331663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_Y,
3329960aa7cSTomi Valkeinen config->tvdetgp_int_start_stop_y);
333663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_GEN_CTRL, config->gen_ctrl);
334663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_F_CONTROL, config->f_control);
335663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_SYNC_CTRL, config->sync_ctrl);
3369960aa7cSTomi Valkeinen }
3379960aa7cSTomi Valkeinen
venc_reset(struct venc_device * venc)338663ac57bSLaurent Pinchart static void venc_reset(struct venc_device *venc)
3399960aa7cSTomi Valkeinen {
3409960aa7cSTomi Valkeinen int t = 1000;
3419960aa7cSTomi Valkeinen
342663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_F_CONTROL, 1<<8);
343663ac57bSLaurent Pinchart while (venc_read_reg(venc, VENC_F_CONTROL) & (1<<8)) {
3449960aa7cSTomi Valkeinen if (--t == 0) {
3459960aa7cSTomi Valkeinen DSSERR("Failed to reset venc\n");
3469960aa7cSTomi Valkeinen return;
3479960aa7cSTomi Valkeinen }
3489960aa7cSTomi Valkeinen }
3499960aa7cSTomi Valkeinen
3509960aa7cSTomi Valkeinen #ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
3519960aa7cSTomi Valkeinen /* the magical sleep that makes things work */
3529960aa7cSTomi Valkeinen /* XXX more info? What bug this circumvents? */
3539960aa7cSTomi Valkeinen msleep(20);
3549960aa7cSTomi Valkeinen #endif
3559960aa7cSTomi Valkeinen }
3569960aa7cSTomi Valkeinen
venc_runtime_get(struct venc_device * venc)357663ac57bSLaurent Pinchart static int venc_runtime_get(struct venc_device *venc)
3589960aa7cSTomi Valkeinen {
3599960aa7cSTomi Valkeinen int r;
3609960aa7cSTomi Valkeinen
3619960aa7cSTomi Valkeinen DSSDBG("venc_runtime_get\n");
3629960aa7cSTomi Valkeinen
363663ac57bSLaurent Pinchart r = pm_runtime_get_sync(&venc->pdev->dev);
364a5d704d3SDinghao Liu if (WARN_ON(r < 0)) {
365a5d704d3SDinghao Liu pm_runtime_put_noidle(&venc->pdev->dev);
366a5d704d3SDinghao Liu return r;
367a5d704d3SDinghao Liu }
368a5d704d3SDinghao Liu return 0;
3699960aa7cSTomi Valkeinen }
3709960aa7cSTomi Valkeinen
venc_runtime_put(struct venc_device * venc)371663ac57bSLaurent Pinchart static void venc_runtime_put(struct venc_device *venc)
3729960aa7cSTomi Valkeinen {
3739960aa7cSTomi Valkeinen int r;
3749960aa7cSTomi Valkeinen
3759960aa7cSTomi Valkeinen DSSDBG("venc_runtime_put\n");
3769960aa7cSTomi Valkeinen
377663ac57bSLaurent Pinchart r = pm_runtime_put_sync(&venc->pdev->dev);
3789960aa7cSTomi Valkeinen WARN_ON(r < 0 && r != -ENOSYS);
3799960aa7cSTomi Valkeinen }
3809960aa7cSTomi Valkeinen
venc_power_on(struct venc_device * venc)381663ac57bSLaurent Pinchart static int venc_power_on(struct venc_device *venc)
3829960aa7cSTomi Valkeinen {
3839960aa7cSTomi Valkeinen u32 l;
3849960aa7cSTomi Valkeinen int r;
3859960aa7cSTomi Valkeinen
386663ac57bSLaurent Pinchart r = venc_runtime_get(venc);
3879960aa7cSTomi Valkeinen if (r)
3889960aa7cSTomi Valkeinen goto err0;
3899960aa7cSTomi Valkeinen
390663ac57bSLaurent Pinchart venc_reset(venc);
391d60dfabaSLaurent Pinchart venc_write_config(venc, venc->config);
3929960aa7cSTomi Valkeinen
393663ac57bSLaurent Pinchart dss_set_venc_output(venc->dss, venc->type);
394663ac57bSLaurent Pinchart dss_set_dac_pwrdn_bgz(venc->dss, 1);
3959960aa7cSTomi Valkeinen
3969960aa7cSTomi Valkeinen l = 0;
3979960aa7cSTomi Valkeinen
398663ac57bSLaurent Pinchart if (venc->type == OMAP_DSS_VENC_TYPE_COMPOSITE)
3999960aa7cSTomi Valkeinen l |= 1 << 1;
4009960aa7cSTomi Valkeinen else /* S-Video */
4019960aa7cSTomi Valkeinen l |= (1 << 0) | (1 << 2);
4029960aa7cSTomi Valkeinen
403663ac57bSLaurent Pinchart if (venc->invert_polarity == false)
4049960aa7cSTomi Valkeinen l |= 1 << 3;
4059960aa7cSTomi Valkeinen
406663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_OUTPUT_CONTROL, l);
4079960aa7cSTomi Valkeinen
408663ac57bSLaurent Pinchart r = regulator_enable(venc->vdda_dac_reg);
4099960aa7cSTomi Valkeinen if (r)
4109960aa7cSTomi Valkeinen goto err1;
4119960aa7cSTomi Valkeinen
412663ac57bSLaurent Pinchart r = dss_mgr_enable(&venc->output);
4139960aa7cSTomi Valkeinen if (r)
4149960aa7cSTomi Valkeinen goto err2;
4159960aa7cSTomi Valkeinen
4169960aa7cSTomi Valkeinen return 0;
4179960aa7cSTomi Valkeinen
4189960aa7cSTomi Valkeinen err2:
419663ac57bSLaurent Pinchart regulator_disable(venc->vdda_dac_reg);
4209960aa7cSTomi Valkeinen err1:
421663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0);
422663ac57bSLaurent Pinchart dss_set_dac_pwrdn_bgz(venc->dss, 0);
4239960aa7cSTomi Valkeinen
424663ac57bSLaurent Pinchart venc_runtime_put(venc);
4259960aa7cSTomi Valkeinen err0:
4269960aa7cSTomi Valkeinen return r;
4279960aa7cSTomi Valkeinen }
4289960aa7cSTomi Valkeinen
venc_power_off(struct venc_device * venc)429663ac57bSLaurent Pinchart static void venc_power_off(struct venc_device *venc)
4309960aa7cSTomi Valkeinen {
431663ac57bSLaurent Pinchart venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0);
432663ac57bSLaurent Pinchart dss_set_dac_pwrdn_bgz(venc->dss, 0);
4339960aa7cSTomi Valkeinen
434663ac57bSLaurent Pinchart dss_mgr_disable(&venc->output);
4359960aa7cSTomi Valkeinen
436663ac57bSLaurent Pinchart regulator_disable(venc->vdda_dac_reg);
4379960aa7cSTomi Valkeinen
438663ac57bSLaurent Pinchart venc_runtime_put(venc);
4399960aa7cSTomi Valkeinen }
4409960aa7cSTomi Valkeinen
venc_get_videomode(const struct drm_display_mode * mode)44141322aa6SLaurent Pinchart static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode)
442d60dfabaSLaurent Pinchart {
44341322aa6SLaurent Pinchart if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
444d60dfabaSLaurent Pinchart return VENC_MODE_UNKNOWN;
445d60dfabaSLaurent Pinchart
446b08644a2SLaurent Pinchart if (mode->clock == omap_dss_pal_mode.clock &&
447b08644a2SLaurent Pinchart mode->hdisplay == omap_dss_pal_mode.hdisplay &&
448b08644a2SLaurent Pinchart mode->vdisplay == omap_dss_pal_mode.vdisplay)
449d60dfabaSLaurent Pinchart return VENC_MODE_PAL;
450d60dfabaSLaurent Pinchart
451b08644a2SLaurent Pinchart if (mode->clock == omap_dss_ntsc_mode.clock &&
452b08644a2SLaurent Pinchart mode->hdisplay == omap_dss_ntsc_mode.hdisplay &&
453b08644a2SLaurent Pinchart mode->vdisplay == omap_dss_ntsc_mode.vdisplay)
454d60dfabaSLaurent Pinchart return VENC_MODE_NTSC;
455d60dfabaSLaurent Pinchart
456d60dfabaSLaurent Pinchart return VENC_MODE_UNKNOWN;
457d60dfabaSLaurent Pinchart }
458d60dfabaSLaurent Pinchart
venc_dump_regs(struct seq_file * s,void * p)459f33656e1SLaurent Pinchart static int venc_dump_regs(struct seq_file *s, void *p)
4609960aa7cSTomi Valkeinen {
461663ac57bSLaurent Pinchart struct venc_device *venc = s->private;
4629960aa7cSTomi Valkeinen
463663ac57bSLaurent Pinchart #define DUMPREG(venc, r) \
464663ac57bSLaurent Pinchart seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(venc, r))
465663ac57bSLaurent Pinchart
466663ac57bSLaurent Pinchart if (venc_runtime_get(venc))
467f33656e1SLaurent Pinchart return 0;
4689960aa7cSTomi Valkeinen
469663ac57bSLaurent Pinchart DUMPREG(venc, VENC_F_CONTROL);
470663ac57bSLaurent Pinchart DUMPREG(venc, VENC_VIDOUT_CTRL);
471663ac57bSLaurent Pinchart DUMPREG(venc, VENC_SYNC_CTRL);
472663ac57bSLaurent Pinchart DUMPREG(venc, VENC_LLEN);
473663ac57bSLaurent Pinchart DUMPREG(venc, VENC_FLENS);
474663ac57bSLaurent Pinchart DUMPREG(venc, VENC_HFLTR_CTRL);
475663ac57bSLaurent Pinchart DUMPREG(venc, VENC_CC_CARR_WSS_CARR);
476663ac57bSLaurent Pinchart DUMPREG(venc, VENC_C_PHASE);
477663ac57bSLaurent Pinchart DUMPREG(venc, VENC_GAIN_U);
478663ac57bSLaurent Pinchart DUMPREG(venc, VENC_GAIN_V);
479663ac57bSLaurent Pinchart DUMPREG(venc, VENC_GAIN_Y);
480663ac57bSLaurent Pinchart DUMPREG(venc, VENC_BLACK_LEVEL);
481663ac57bSLaurent Pinchart DUMPREG(venc, VENC_BLANK_LEVEL);
482663ac57bSLaurent Pinchart DUMPREG(venc, VENC_X_COLOR);
483663ac57bSLaurent Pinchart DUMPREG(venc, VENC_M_CONTROL);
484663ac57bSLaurent Pinchart DUMPREG(venc, VENC_BSTAMP_WSS_DATA);
485663ac57bSLaurent Pinchart DUMPREG(venc, VENC_S_CARR);
486663ac57bSLaurent Pinchart DUMPREG(venc, VENC_LINE21);
487663ac57bSLaurent Pinchart DUMPREG(venc, VENC_LN_SEL);
488663ac57bSLaurent Pinchart DUMPREG(venc, VENC_L21__WC_CTL);
489663ac57bSLaurent Pinchart DUMPREG(venc, VENC_HTRIGGER_VTRIGGER);
490663ac57bSLaurent Pinchart DUMPREG(venc, VENC_SAVID__EAVID);
491663ac57bSLaurent Pinchart DUMPREG(venc, VENC_FLEN__FAL);
492663ac57bSLaurent Pinchart DUMPREG(venc, VENC_LAL__PHASE_RESET);
493663ac57bSLaurent Pinchart DUMPREG(venc, VENC_HS_INT_START_STOP_X);
494663ac57bSLaurent Pinchart DUMPREG(venc, VENC_HS_EXT_START_STOP_X);
495663ac57bSLaurent Pinchart DUMPREG(venc, VENC_VS_INT_START_X);
496663ac57bSLaurent Pinchart DUMPREG(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y);
497663ac57bSLaurent Pinchart DUMPREG(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X);
498663ac57bSLaurent Pinchart DUMPREG(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
499663ac57bSLaurent Pinchart DUMPREG(venc, VENC_VS_EXT_STOP_Y);
500663ac57bSLaurent Pinchart DUMPREG(venc, VENC_AVID_START_STOP_X);
501663ac57bSLaurent Pinchart DUMPREG(venc, VENC_AVID_START_STOP_Y);
502663ac57bSLaurent Pinchart DUMPREG(venc, VENC_FID_INT_START_X__FID_INT_START_Y);
503663ac57bSLaurent Pinchart DUMPREG(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
504663ac57bSLaurent Pinchart DUMPREG(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
505663ac57bSLaurent Pinchart DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_X);
506663ac57bSLaurent Pinchart DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_Y);
507663ac57bSLaurent Pinchart DUMPREG(venc, VENC_GEN_CTRL);
508663ac57bSLaurent Pinchart DUMPREG(venc, VENC_OUTPUT_CONTROL);
509663ac57bSLaurent Pinchart DUMPREG(venc, VENC_OUTPUT_TEST);
5109960aa7cSTomi Valkeinen
511663ac57bSLaurent Pinchart venc_runtime_put(venc);
5129960aa7cSTomi Valkeinen
5139960aa7cSTomi Valkeinen #undef DUMPREG
514f33656e1SLaurent Pinchart return 0;
5159960aa7cSTomi Valkeinen }
5169960aa7cSTomi Valkeinen
venc_get_clocks(struct venc_device * venc)517663ac57bSLaurent Pinchart static int venc_get_clocks(struct venc_device *venc)
5189960aa7cSTomi Valkeinen {
5199960aa7cSTomi Valkeinen struct clk *clk;
5209960aa7cSTomi Valkeinen
521663ac57bSLaurent Pinchart if (venc->requires_tv_dac_clk) {
522663ac57bSLaurent Pinchart clk = devm_clk_get(&venc->pdev->dev, "tv_dac_clk");
5239960aa7cSTomi Valkeinen if (IS_ERR(clk)) {
5249960aa7cSTomi Valkeinen DSSERR("can't get tv_dac_clk\n");
5259960aa7cSTomi Valkeinen return PTR_ERR(clk);
5269960aa7cSTomi Valkeinen }
5279960aa7cSTomi Valkeinen } else {
5289960aa7cSTomi Valkeinen clk = NULL;
5299960aa7cSTomi Valkeinen }
5309960aa7cSTomi Valkeinen
531663ac57bSLaurent Pinchart venc->tv_dac_clk = clk;
5329960aa7cSTomi Valkeinen
5339960aa7cSTomi Valkeinen return 0;
5349960aa7cSTomi Valkeinen }
5359960aa7cSTomi Valkeinen
536c8719326SLaurent Pinchart /* -----------------------------------------------------------------------------
5372f004792SLaurent Pinchart * DRM Bridge Operations
5382f004792SLaurent Pinchart */
5392f004792SLaurent Pinchart
venc_bridge_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)5402f004792SLaurent Pinchart static int venc_bridge_attach(struct drm_bridge *bridge,
5412f004792SLaurent Pinchart enum drm_bridge_attach_flags flags)
5422f004792SLaurent Pinchart {
5432f004792SLaurent Pinchart struct venc_device *venc = drm_bridge_to_venc(bridge);
5442f004792SLaurent Pinchart
545e7e67d9aSLaurent Pinchart if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
546e7e67d9aSLaurent Pinchart return -EINVAL;
5472f004792SLaurent Pinchart
5482f004792SLaurent Pinchart return drm_bridge_attach(bridge->encoder, venc->output.next_bridge,
5492f004792SLaurent Pinchart bridge, flags);
5502f004792SLaurent Pinchart }
5512f004792SLaurent Pinchart
5522f004792SLaurent Pinchart static enum drm_mode_status
venc_bridge_mode_valid(struct drm_bridge * bridge,const struct drm_display_info * info,const struct drm_display_mode * mode)5532f004792SLaurent Pinchart venc_bridge_mode_valid(struct drm_bridge *bridge,
55412c683e1SLaurent Pinchart const struct drm_display_info *info,
5552f004792SLaurent Pinchart const struct drm_display_mode *mode)
5562f004792SLaurent Pinchart {
5572f004792SLaurent Pinchart switch (venc_get_videomode(mode)) {
5582f004792SLaurent Pinchart case VENC_MODE_PAL:
5592f004792SLaurent Pinchart case VENC_MODE_NTSC:
5602f004792SLaurent Pinchart return MODE_OK;
5612f004792SLaurent Pinchart
5622f004792SLaurent Pinchart default:
5632f004792SLaurent Pinchart return MODE_BAD;
5642f004792SLaurent Pinchart }
5652f004792SLaurent Pinchart }
5662f004792SLaurent Pinchart
venc_bridge_mode_fixup(struct drm_bridge * bridge,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)5672f004792SLaurent Pinchart static bool venc_bridge_mode_fixup(struct drm_bridge *bridge,
5682f004792SLaurent Pinchart const struct drm_display_mode *mode,
5692f004792SLaurent Pinchart struct drm_display_mode *adjusted_mode)
5702f004792SLaurent Pinchart {
5712f004792SLaurent Pinchart const struct drm_display_mode *venc_mode;
5722f004792SLaurent Pinchart
5732f004792SLaurent Pinchart switch (venc_get_videomode(adjusted_mode)) {
5742f004792SLaurent Pinchart case VENC_MODE_PAL:
5752f004792SLaurent Pinchart venc_mode = &omap_dss_pal_mode;
5762f004792SLaurent Pinchart break;
5772f004792SLaurent Pinchart
5782f004792SLaurent Pinchart case VENC_MODE_NTSC:
5792f004792SLaurent Pinchart venc_mode = &omap_dss_ntsc_mode;
5802f004792SLaurent Pinchart break;
5812f004792SLaurent Pinchart
5822f004792SLaurent Pinchart default:
5832f004792SLaurent Pinchart return false;
5842f004792SLaurent Pinchart }
5852f004792SLaurent Pinchart
5862f004792SLaurent Pinchart drm_mode_copy(adjusted_mode, venc_mode);
5872f004792SLaurent Pinchart drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
5882f004792SLaurent Pinchart drm_mode_set_name(adjusted_mode);
5892f004792SLaurent Pinchart
5902f004792SLaurent Pinchart return true;
5912f004792SLaurent Pinchart }
5922f004792SLaurent Pinchart
venc_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)5932f004792SLaurent Pinchart static void venc_bridge_mode_set(struct drm_bridge *bridge,
5942f004792SLaurent Pinchart const struct drm_display_mode *mode,
5952f004792SLaurent Pinchart const struct drm_display_mode *adjusted_mode)
5962f004792SLaurent Pinchart {
5972f004792SLaurent Pinchart struct venc_device *venc = drm_bridge_to_venc(bridge);
5982f004792SLaurent Pinchart enum venc_videomode venc_mode = venc_get_videomode(adjusted_mode);
5992f004792SLaurent Pinchart
6002f004792SLaurent Pinchart switch (venc_mode) {
6012f004792SLaurent Pinchart default:
6022f004792SLaurent Pinchart WARN_ON_ONCE(1);
603df561f66SGustavo A. R. Silva fallthrough;
6042f004792SLaurent Pinchart case VENC_MODE_PAL:
6052f004792SLaurent Pinchart venc->config = &venc_config_pal_trm;
6062f004792SLaurent Pinchart break;
6072f004792SLaurent Pinchart
6082f004792SLaurent Pinchart case VENC_MODE_NTSC:
6092f004792SLaurent Pinchart venc->config = &venc_config_ntsc_trm;
6102f004792SLaurent Pinchart break;
6112f004792SLaurent Pinchart }
6122f004792SLaurent Pinchart
6132f004792SLaurent Pinchart dispc_set_tv_pclk(venc->dss->dispc, 13500000);
6142f004792SLaurent Pinchart }
6152f004792SLaurent Pinchart
venc_bridge_enable(struct drm_bridge * bridge)6162f004792SLaurent Pinchart static void venc_bridge_enable(struct drm_bridge *bridge)
6172f004792SLaurent Pinchart {
6182f004792SLaurent Pinchart struct venc_device *venc = drm_bridge_to_venc(bridge);
6192f004792SLaurent Pinchart
6202f004792SLaurent Pinchart venc_power_on(venc);
6212f004792SLaurent Pinchart }
6222f004792SLaurent Pinchart
venc_bridge_disable(struct drm_bridge * bridge)6232f004792SLaurent Pinchart static void venc_bridge_disable(struct drm_bridge *bridge)
6242f004792SLaurent Pinchart {
6252f004792SLaurent Pinchart struct venc_device *venc = drm_bridge_to_venc(bridge);
6262f004792SLaurent Pinchart
6272f004792SLaurent Pinchart venc_power_off(venc);
6282f004792SLaurent Pinchart }
6292f004792SLaurent Pinchart
venc_bridge_get_modes(struct drm_bridge * bridge,struct drm_connector * connector)6302f004792SLaurent Pinchart static int venc_bridge_get_modes(struct drm_bridge *bridge,
6312f004792SLaurent Pinchart struct drm_connector *connector)
6322f004792SLaurent Pinchart {
6332f004792SLaurent Pinchart static const struct drm_display_mode *modes[] = {
6342f004792SLaurent Pinchart &omap_dss_pal_mode,
6352f004792SLaurent Pinchart &omap_dss_ntsc_mode,
6362f004792SLaurent Pinchart };
6372f004792SLaurent Pinchart unsigned int i;
6382f004792SLaurent Pinchart
6392f004792SLaurent Pinchart for (i = 0; i < ARRAY_SIZE(modes); ++i) {
6402f004792SLaurent Pinchart struct drm_display_mode *mode;
6412f004792SLaurent Pinchart
6422f004792SLaurent Pinchart mode = drm_mode_duplicate(connector->dev, modes[i]);
6432f004792SLaurent Pinchart if (!mode)
6442f004792SLaurent Pinchart return i;
6452f004792SLaurent Pinchart
6462f004792SLaurent Pinchart mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
6472f004792SLaurent Pinchart drm_mode_set_name(mode);
6482f004792SLaurent Pinchart drm_mode_probed_add(connector, mode);
6492f004792SLaurent Pinchart }
6502f004792SLaurent Pinchart
6512f004792SLaurent Pinchart return ARRAY_SIZE(modes);
6522f004792SLaurent Pinchart }
6532f004792SLaurent Pinchart
6542f004792SLaurent Pinchart static const struct drm_bridge_funcs venc_bridge_funcs = {
6552f004792SLaurent Pinchart .attach = venc_bridge_attach,
6562f004792SLaurent Pinchart .mode_valid = venc_bridge_mode_valid,
6572f004792SLaurent Pinchart .mode_fixup = venc_bridge_mode_fixup,
6582f004792SLaurent Pinchart .mode_set = venc_bridge_mode_set,
6592f004792SLaurent Pinchart .enable = venc_bridge_enable,
6602f004792SLaurent Pinchart .disable = venc_bridge_disable,
6612f004792SLaurent Pinchart .get_modes = venc_bridge_get_modes,
6622f004792SLaurent Pinchart };
6632f004792SLaurent Pinchart
venc_bridge_init(struct venc_device * venc)6642f004792SLaurent Pinchart static void venc_bridge_init(struct venc_device *venc)
6652f004792SLaurent Pinchart {
6662f004792SLaurent Pinchart venc->bridge.funcs = &venc_bridge_funcs;
6672f004792SLaurent Pinchart venc->bridge.of_node = venc->pdev->dev.of_node;
6682f004792SLaurent Pinchart venc->bridge.ops = DRM_BRIDGE_OP_MODES;
6692f004792SLaurent Pinchart venc->bridge.type = DRM_MODE_CONNECTOR_SVIDEO;
6702f004792SLaurent Pinchart venc->bridge.interlace_allowed = true;
6712f004792SLaurent Pinchart
6722f004792SLaurent Pinchart drm_bridge_add(&venc->bridge);
6732f004792SLaurent Pinchart }
6742f004792SLaurent Pinchart
venc_bridge_cleanup(struct venc_device * venc)6752f004792SLaurent Pinchart static void venc_bridge_cleanup(struct venc_device *venc)
6762f004792SLaurent Pinchart {
6772f004792SLaurent Pinchart drm_bridge_remove(&venc->bridge);
6782f004792SLaurent Pinchart }
6792f004792SLaurent Pinchart
6802f004792SLaurent Pinchart /* -----------------------------------------------------------------------------
681c8719326SLaurent Pinchart * Component Bind & Unbind
682c8719326SLaurent Pinchart */
683c8719326SLaurent Pinchart
venc_bind(struct device * dev,struct device * master,void * data)684c8719326SLaurent Pinchart static int venc_bind(struct device *dev, struct device *master, void *data)
685c8719326SLaurent Pinchart {
686c8719326SLaurent Pinchart struct dss_device *dss = dss_get_device(master);
687c8719326SLaurent Pinchart struct venc_device *venc = dev_get_drvdata(dev);
688c8719326SLaurent Pinchart u8 rev_id;
689c8719326SLaurent Pinchart int r;
690c8719326SLaurent Pinchart
691c8719326SLaurent Pinchart venc->dss = dss;
692c8719326SLaurent Pinchart
693c8719326SLaurent Pinchart r = venc_runtime_get(venc);
694c8719326SLaurent Pinchart if (r)
695c8719326SLaurent Pinchart return r;
696c8719326SLaurent Pinchart
697c8719326SLaurent Pinchart rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff);
698c8719326SLaurent Pinchart dev_dbg(dev, "OMAP VENC rev %d\n", rev_id);
699c8719326SLaurent Pinchart
700c8719326SLaurent Pinchart venc_runtime_put(venc);
701c8719326SLaurent Pinchart
702c8719326SLaurent Pinchart venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs,
703c8719326SLaurent Pinchart venc);
704c8719326SLaurent Pinchart
705c8719326SLaurent Pinchart return 0;
706c8719326SLaurent Pinchart }
707c8719326SLaurent Pinchart
venc_unbind(struct device * dev,struct device * master,void * data)708c8719326SLaurent Pinchart static void venc_unbind(struct device *dev, struct device *master, void *data)
709c8719326SLaurent Pinchart {
710c8719326SLaurent Pinchart struct venc_device *venc = dev_get_drvdata(dev);
711c8719326SLaurent Pinchart
712c8719326SLaurent Pinchart dss_debugfs_remove_file(venc->debugfs);
713c8719326SLaurent Pinchart }
714c8719326SLaurent Pinchart
715c8719326SLaurent Pinchart static const struct component_ops venc_component_ops = {
716c8719326SLaurent Pinchart .bind = venc_bind,
717c8719326SLaurent Pinchart .unbind = venc_unbind,
718c8719326SLaurent Pinchart };
719c8719326SLaurent Pinchart
720c8719326SLaurent Pinchart /* -----------------------------------------------------------------------------
721c8719326SLaurent Pinchart * Probe & Remove, Suspend & Resume
722c8719326SLaurent Pinchart */
723c8719326SLaurent Pinchart
venc_init_output(struct venc_device * venc)72427d62452SLaurent Pinchart static int venc_init_output(struct venc_device *venc)
7259960aa7cSTomi Valkeinen {
726663ac57bSLaurent Pinchart struct omap_dss_device *out = &venc->output;
72771316556SLaurent Pinchart int r;
7289960aa7cSTomi Valkeinen
7292f004792SLaurent Pinchart venc_bridge_init(venc);
7302f004792SLaurent Pinchart
731663ac57bSLaurent Pinchart out->dev = &venc->pdev->dev;
7329960aa7cSTomi Valkeinen out->id = OMAP_DSS_OUTPUT_VENC;
7330dbfc396SLaurent Pinchart out->type = OMAP_DISPLAY_TYPE_VENC;
7349960aa7cSTomi Valkeinen out->name = "venc.0";
7359960aa7cSTomi Valkeinen out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
736c83fefd7SLaurent Pinchart out->of_port = 0;
7379960aa7cSTomi Valkeinen
7382f004792SLaurent Pinchart r = omapdss_device_init_output(out, &venc->bridge);
7392f004792SLaurent Pinchart if (r < 0) {
7402f004792SLaurent Pinchart venc_bridge_cleanup(venc);
74171316556SLaurent Pinchart return r;
7422f004792SLaurent Pinchart }
74371316556SLaurent Pinchart
744de57e9dbSLaurent Pinchart omapdss_device_register(out);
74527d62452SLaurent Pinchart
74627d62452SLaurent Pinchart return 0;
7479960aa7cSTomi Valkeinen }
7489960aa7cSTomi Valkeinen
venc_uninit_output(struct venc_device * venc)749663ac57bSLaurent Pinchart static void venc_uninit_output(struct venc_device *venc)
7509960aa7cSTomi Valkeinen {
751de57e9dbSLaurent Pinchart omapdss_device_unregister(&venc->output);
752d17eb453SLaurent Pinchart omapdss_device_cleanup_output(&venc->output);
7532f004792SLaurent Pinchart
7542f004792SLaurent Pinchart venc_bridge_cleanup(venc);
7559960aa7cSTomi Valkeinen }
7569960aa7cSTomi Valkeinen
venc_probe_of(struct venc_device * venc)757663ac57bSLaurent Pinchart static int venc_probe_of(struct venc_device *venc)
7589960aa7cSTomi Valkeinen {
759663ac57bSLaurent Pinchart struct device_node *node = venc->pdev->dev.of_node;
7609960aa7cSTomi Valkeinen struct device_node *ep;
7619960aa7cSTomi Valkeinen u32 channels;
7629960aa7cSTomi Valkeinen int r;
7639960aa7cSTomi Valkeinen
76409bffa6eSRob Herring ep = of_graph_get_endpoint_by_regs(node, 0, 0);
7659960aa7cSTomi Valkeinen if (!ep)
7669960aa7cSTomi Valkeinen return 0;
7679960aa7cSTomi Valkeinen
768663ac57bSLaurent Pinchart venc->invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");
7699960aa7cSTomi Valkeinen
7709960aa7cSTomi Valkeinen r = of_property_read_u32(ep, "ti,channels", &channels);
7719960aa7cSTomi Valkeinen if (r) {
772663ac57bSLaurent Pinchart dev_err(&venc->pdev->dev,
7739960aa7cSTomi Valkeinen "failed to read property 'ti,channels': %d\n", r);
7749960aa7cSTomi Valkeinen goto err;
7759960aa7cSTomi Valkeinen }
7769960aa7cSTomi Valkeinen
7779960aa7cSTomi Valkeinen switch (channels) {
7789960aa7cSTomi Valkeinen case 1:
779663ac57bSLaurent Pinchart venc->type = OMAP_DSS_VENC_TYPE_COMPOSITE;
7809960aa7cSTomi Valkeinen break;
7819960aa7cSTomi Valkeinen case 2:
782663ac57bSLaurent Pinchart venc->type = OMAP_DSS_VENC_TYPE_SVIDEO;
7839960aa7cSTomi Valkeinen break;
7849960aa7cSTomi Valkeinen default:
785227c6d10SColin Ian King dev_err(&venc->pdev->dev, "bad channel property '%d'\n",
786663ac57bSLaurent Pinchart channels);
7879960aa7cSTomi Valkeinen r = -EINVAL;
7889960aa7cSTomi Valkeinen goto err;
7899960aa7cSTomi Valkeinen }
7909960aa7cSTomi Valkeinen
7919960aa7cSTomi Valkeinen of_node_put(ep);
7929960aa7cSTomi Valkeinen
7939960aa7cSTomi Valkeinen return 0;
79418cbe723SLaurent Pinchart
7959960aa7cSTomi Valkeinen err:
7969960aa7cSTomi Valkeinen of_node_put(ep);
79718cbe723SLaurent Pinchart return r;
7989960aa7cSTomi Valkeinen }
7999960aa7cSTomi Valkeinen
80034dfb85fSLaurent Pinchart static const struct soc_device_attribute venc_soc_devices[] = {
80134dfb85fSLaurent Pinchart { .machine = "OMAP3[45]*" },
80234dfb85fSLaurent Pinchart { .machine = "AM35*" },
80334dfb85fSLaurent Pinchart { /* sentinel */ }
80434dfb85fSLaurent Pinchart };
80534dfb85fSLaurent Pinchart
venc_probe(struct platform_device * pdev)806c8719326SLaurent Pinchart static int venc_probe(struct platform_device *pdev)
8079960aa7cSTomi Valkeinen {
808663ac57bSLaurent Pinchart struct venc_device *venc;
8099960aa7cSTomi Valkeinen int r;
8109960aa7cSTomi Valkeinen
811663ac57bSLaurent Pinchart venc = kzalloc(sizeof(*venc), GFP_KERNEL);
812663ac57bSLaurent Pinchart if (!venc)
813663ac57bSLaurent Pinchart return -ENOMEM;
814663ac57bSLaurent Pinchart
815663ac57bSLaurent Pinchart venc->pdev = pdev;
816c8719326SLaurent Pinchart
817c8719326SLaurent Pinchart platform_set_drvdata(pdev, venc);
8189960aa7cSTomi Valkeinen
81934dfb85fSLaurent Pinchart /* The OMAP34xx, OMAP35xx and AM35xx VENC require the TV DAC clock. */
82034dfb85fSLaurent Pinchart if (soc_device_match(venc_soc_devices))
821663ac57bSLaurent Pinchart venc->requires_tv_dac_clk = true;
82234dfb85fSLaurent Pinchart
823d60dfabaSLaurent Pinchart venc->config = &venc_config_pal_trm;
8249960aa7cSTomi Valkeinen
825ed8414abSCai Huoqing venc->base = devm_platform_ioremap_resource(pdev, 0);
826663ac57bSLaurent Pinchart if (IS_ERR(venc->base)) {
827663ac57bSLaurent Pinchart r = PTR_ERR(venc->base);
828663ac57bSLaurent Pinchart goto err_free;
829663ac57bSLaurent Pinchart }
8309960aa7cSTomi Valkeinen
8318a36357aSLaurent Pinchart venc->vdda_dac_reg = devm_regulator_get(&pdev->dev, "vdda");
8328a36357aSLaurent Pinchart if (IS_ERR(venc->vdda_dac_reg)) {
8338a36357aSLaurent Pinchart r = PTR_ERR(venc->vdda_dac_reg);
8348a36357aSLaurent Pinchart if (r != -EPROBE_DEFER)
8358a36357aSLaurent Pinchart DSSERR("can't get VDDA_DAC regulator\n");
8368a36357aSLaurent Pinchart goto err_free;
8378a36357aSLaurent Pinchart }
8388a36357aSLaurent Pinchart
839663ac57bSLaurent Pinchart r = venc_get_clocks(venc);
8409960aa7cSTomi Valkeinen if (r)
841663ac57bSLaurent Pinchart goto err_free;
8429960aa7cSTomi Valkeinen
843663ac57bSLaurent Pinchart r = venc_probe_of(venc);
844c8719326SLaurent Pinchart if (r)
845c8719326SLaurent Pinchart goto err_free;
8469960aa7cSTomi Valkeinen
847c8719326SLaurent Pinchart pm_runtime_enable(&pdev->dev);
8489960aa7cSTomi Valkeinen
84927d62452SLaurent Pinchart r = venc_init_output(venc);
85027d62452SLaurent Pinchart if (r)
85127d62452SLaurent Pinchart goto err_pm_disable;
8529960aa7cSTomi Valkeinen
853c8719326SLaurent Pinchart r = component_add(&pdev->dev, &venc_component_ops);
854c8719326SLaurent Pinchart if (r)
855c8719326SLaurent Pinchart goto err_uninit_output;
856c8719326SLaurent Pinchart
8579960aa7cSTomi Valkeinen return 0;
8589960aa7cSTomi Valkeinen
859c8719326SLaurent Pinchart err_uninit_output:
860c8719326SLaurent Pinchart venc_uninit_output(venc);
86127d62452SLaurent Pinchart err_pm_disable:
8629960aa7cSTomi Valkeinen pm_runtime_disable(&pdev->dev);
863663ac57bSLaurent Pinchart err_free:
864663ac57bSLaurent Pinchart kfree(venc);
8659960aa7cSTomi Valkeinen return r;
8669960aa7cSTomi Valkeinen }
8679960aa7cSTomi Valkeinen
venc_remove(struct platform_device * pdev)868*c2807ecbSUwe Kleine-König static void venc_remove(struct platform_device *pdev)
8699960aa7cSTomi Valkeinen {
870c8719326SLaurent Pinchart struct venc_device *venc = platform_get_drvdata(pdev);
8719960aa7cSTomi Valkeinen
872c8719326SLaurent Pinchart component_del(&pdev->dev, &venc_component_ops);
873f33656e1SLaurent Pinchart
874663ac57bSLaurent Pinchart venc_uninit_output(venc);
8759960aa7cSTomi Valkeinen
876c8719326SLaurent Pinchart pm_runtime_disable(&pdev->dev);
877663ac57bSLaurent Pinchart
878663ac57bSLaurent Pinchart kfree(venc);
8799960aa7cSTomi Valkeinen }
8809960aa7cSTomi Valkeinen
venc_runtime_suspend(struct device * dev)881d6c75c29SArnd Bergmann static __maybe_unused int venc_runtime_suspend(struct device *dev)
8829960aa7cSTomi Valkeinen {
883663ac57bSLaurent Pinchart struct venc_device *venc = dev_get_drvdata(dev);
8849960aa7cSTomi Valkeinen
885663ac57bSLaurent Pinchart if (venc->tv_dac_clk)
886663ac57bSLaurent Pinchart clk_disable_unprepare(venc->tv_dac_clk);
887663ac57bSLaurent Pinchart
8889960aa7cSTomi Valkeinen return 0;
8899960aa7cSTomi Valkeinen }
8909960aa7cSTomi Valkeinen
venc_runtime_resume(struct device * dev)891d6c75c29SArnd Bergmann static __maybe_unused int venc_runtime_resume(struct device *dev)
8929960aa7cSTomi Valkeinen {
893663ac57bSLaurent Pinchart struct venc_device *venc = dev_get_drvdata(dev);
8949960aa7cSTomi Valkeinen
895663ac57bSLaurent Pinchart if (venc->tv_dac_clk)
896663ac57bSLaurent Pinchart clk_prepare_enable(venc->tv_dac_clk);
8979960aa7cSTomi Valkeinen
8989960aa7cSTomi Valkeinen return 0;
8999960aa7cSTomi Valkeinen }
9009960aa7cSTomi Valkeinen
9019960aa7cSTomi Valkeinen static const struct dev_pm_ops venc_pm_ops = {
902b92f7ea5SCai Huoqing SET_RUNTIME_PM_OPS(venc_runtime_suspend, venc_runtime_resume, NULL)
903ecfdedd7STomi Valkeinen SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
9049960aa7cSTomi Valkeinen };
9059960aa7cSTomi Valkeinen
9069960aa7cSTomi Valkeinen static const struct of_device_id venc_of_match[] = {
9079960aa7cSTomi Valkeinen { .compatible = "ti,omap2-venc", },
9089960aa7cSTomi Valkeinen { .compatible = "ti,omap3-venc", },
9099960aa7cSTomi Valkeinen { .compatible = "ti,omap4-venc", },
9109960aa7cSTomi Valkeinen {},
9119960aa7cSTomi Valkeinen };
9129960aa7cSTomi Valkeinen
913d66c36a3SAndrew F. Davis struct platform_driver omap_venchw_driver = {
9149960aa7cSTomi Valkeinen .probe = venc_probe,
915*c2807ecbSUwe Kleine-König .remove_new = venc_remove,
9169960aa7cSTomi Valkeinen .driver = {
9179960aa7cSTomi Valkeinen .name = "omapdss_venc",
9189960aa7cSTomi Valkeinen .pm = &venc_pm_ops,
9199960aa7cSTomi Valkeinen .of_match_table = venc_of_match,
9209960aa7cSTomi Valkeinen .suppress_bind_attrs = true,
9219960aa7cSTomi Valkeinen },
9229960aa7cSTomi Valkeinen };
923