xref: /openbmc/linux/drivers/gpu/drm/omapdrm/dss/venc.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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