1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f76ee892STomi Valkeinen /*
3f76ee892STomi Valkeinen  * linux/drivers/video/omap2/dss/venc.c
4f76ee892STomi Valkeinen  *
5f76ee892STomi Valkeinen  * Copyright (C) 2009 Nokia Corporation
6f76ee892STomi Valkeinen  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7f76ee892STomi Valkeinen  *
8f76ee892STomi Valkeinen  * VENC settings from TI's DSS driver
9f76ee892STomi Valkeinen  */
10f76ee892STomi Valkeinen 
11f76ee892STomi Valkeinen #define DSS_SUBSYS_NAME "VENC"
12f76ee892STomi Valkeinen 
13f76ee892STomi Valkeinen #include <linux/kernel.h>
14f76ee892STomi Valkeinen #include <linux/module.h>
15f76ee892STomi Valkeinen #include <linux/clk.h>
16f76ee892STomi Valkeinen #include <linux/err.h>
17f76ee892STomi Valkeinen #include <linux/io.h>
18f76ee892STomi Valkeinen #include <linux/mutex.h>
19f76ee892STomi Valkeinen #include <linux/completion.h>
20f76ee892STomi Valkeinen #include <linux/delay.h>
21f76ee892STomi Valkeinen #include <linux/string.h>
22f76ee892STomi Valkeinen #include <linux/seq_file.h>
23f76ee892STomi Valkeinen #include <linux/platform_device.h>
24f76ee892STomi Valkeinen #include <linux/regulator/consumer.h>
25f76ee892STomi Valkeinen #include <linux/pm_runtime.h>
26f76ee892STomi Valkeinen #include <linux/of.h>
27f76ee892STomi Valkeinen #include <linux/component.h>
28f76ee892STomi Valkeinen 
2962d9e44eSPeter Ujfalusi #include <video/omapfb_dss.h>
30f76ee892STomi Valkeinen 
31f76ee892STomi Valkeinen #include "dss.h"
32f76ee892STomi Valkeinen #include "dss_features.h"
33f76ee892STomi Valkeinen 
34f76ee892STomi Valkeinen /* Venc registers */
35f76ee892STomi Valkeinen #define VENC_REV_ID				0x00
36f76ee892STomi Valkeinen #define VENC_STATUS				0x04
37f76ee892STomi Valkeinen #define VENC_F_CONTROL				0x08
38f76ee892STomi Valkeinen #define VENC_VIDOUT_CTRL			0x10
39f76ee892STomi Valkeinen #define VENC_SYNC_CTRL				0x14
40f76ee892STomi Valkeinen #define VENC_LLEN				0x1C
41f76ee892STomi Valkeinen #define VENC_FLENS				0x20
42f76ee892STomi Valkeinen #define VENC_HFLTR_CTRL				0x24
43f76ee892STomi Valkeinen #define VENC_CC_CARR_WSS_CARR			0x28
44f76ee892STomi Valkeinen #define VENC_C_PHASE				0x2C
45f76ee892STomi Valkeinen #define VENC_GAIN_U				0x30
46f76ee892STomi Valkeinen #define VENC_GAIN_V				0x34
47f76ee892STomi Valkeinen #define VENC_GAIN_Y				0x38
48f76ee892STomi Valkeinen #define VENC_BLACK_LEVEL			0x3C
49f76ee892STomi Valkeinen #define VENC_BLANK_LEVEL			0x40
50f76ee892STomi Valkeinen #define VENC_X_COLOR				0x44
51f76ee892STomi Valkeinen #define VENC_M_CONTROL				0x48
52f76ee892STomi Valkeinen #define VENC_BSTAMP_WSS_DATA			0x4C
53f76ee892STomi Valkeinen #define VENC_S_CARR				0x50
54f76ee892STomi Valkeinen #define VENC_LINE21				0x54
55f76ee892STomi Valkeinen #define VENC_LN_SEL				0x58
56f76ee892STomi Valkeinen #define VENC_L21__WC_CTL			0x5C
57f76ee892STomi Valkeinen #define VENC_HTRIGGER_VTRIGGER			0x60
58f76ee892STomi Valkeinen #define VENC_SAVID__EAVID			0x64
59f76ee892STomi Valkeinen #define VENC_FLEN__FAL				0x68
60f76ee892STomi Valkeinen #define VENC_LAL__PHASE_RESET			0x6C
61f76ee892STomi Valkeinen #define VENC_HS_INT_START_STOP_X		0x70
62f76ee892STomi Valkeinen #define VENC_HS_EXT_START_STOP_X		0x74
63f76ee892STomi Valkeinen #define VENC_VS_INT_START_X			0x78
64f76ee892STomi Valkeinen #define VENC_VS_INT_STOP_X__VS_INT_START_Y	0x7C
65f76ee892STomi Valkeinen #define VENC_VS_INT_STOP_Y__VS_EXT_START_X	0x80
66f76ee892STomi Valkeinen #define VENC_VS_EXT_STOP_X__VS_EXT_START_Y	0x84
67f76ee892STomi Valkeinen #define VENC_VS_EXT_STOP_Y			0x88
68f76ee892STomi Valkeinen #define VENC_AVID_START_STOP_X			0x90
69f76ee892STomi Valkeinen #define VENC_AVID_START_STOP_Y			0x94
70f76ee892STomi Valkeinen #define VENC_FID_INT_START_X__FID_INT_START_Y	0xA0
71f76ee892STomi Valkeinen #define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X	0xA4
72f76ee892STomi Valkeinen #define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y	0xA8
73f76ee892STomi Valkeinen #define VENC_TVDETGP_INT_START_STOP_X		0xB0
74f76ee892STomi Valkeinen #define VENC_TVDETGP_INT_START_STOP_Y		0xB4
75f76ee892STomi Valkeinen #define VENC_GEN_CTRL				0xB8
76f76ee892STomi Valkeinen #define VENC_OUTPUT_CONTROL			0xC4
77f76ee892STomi Valkeinen #define VENC_OUTPUT_TEST			0xC8
78f76ee892STomi Valkeinen #define VENC_DAC_B__DAC_C			0xC8
79f76ee892STomi Valkeinen 
80f76ee892STomi Valkeinen struct venc_config {
81f76ee892STomi Valkeinen 	u32 f_control;
82f76ee892STomi Valkeinen 	u32 vidout_ctrl;
83f76ee892STomi Valkeinen 	u32 sync_ctrl;
84f76ee892STomi Valkeinen 	u32 llen;
85f76ee892STomi Valkeinen 	u32 flens;
86f76ee892STomi Valkeinen 	u32 hfltr_ctrl;
87f76ee892STomi Valkeinen 	u32 cc_carr_wss_carr;
88f76ee892STomi Valkeinen 	u32 c_phase;
89f76ee892STomi Valkeinen 	u32 gain_u;
90f76ee892STomi Valkeinen 	u32 gain_v;
91f76ee892STomi Valkeinen 	u32 gain_y;
92f76ee892STomi Valkeinen 	u32 black_level;
93f76ee892STomi Valkeinen 	u32 blank_level;
94f76ee892STomi Valkeinen 	u32 x_color;
95f76ee892STomi Valkeinen 	u32 m_control;
96f76ee892STomi Valkeinen 	u32 bstamp_wss_data;
97f76ee892STomi Valkeinen 	u32 s_carr;
98f76ee892STomi Valkeinen 	u32 line21;
99f76ee892STomi Valkeinen 	u32 ln_sel;
100f76ee892STomi Valkeinen 	u32 l21__wc_ctl;
101f76ee892STomi Valkeinen 	u32 htrigger_vtrigger;
102f76ee892STomi Valkeinen 	u32 savid__eavid;
103f76ee892STomi Valkeinen 	u32 flen__fal;
104f76ee892STomi Valkeinen 	u32 lal__phase_reset;
105f76ee892STomi Valkeinen 	u32 hs_int_start_stop_x;
106f76ee892STomi Valkeinen 	u32 hs_ext_start_stop_x;
107f76ee892STomi Valkeinen 	u32 vs_int_start_x;
108f76ee892STomi Valkeinen 	u32 vs_int_stop_x__vs_int_start_y;
109f76ee892STomi Valkeinen 	u32 vs_int_stop_y__vs_ext_start_x;
110f76ee892STomi Valkeinen 	u32 vs_ext_stop_x__vs_ext_start_y;
111f76ee892STomi Valkeinen 	u32 vs_ext_stop_y;
112f76ee892STomi Valkeinen 	u32 avid_start_stop_x;
113f76ee892STomi Valkeinen 	u32 avid_start_stop_y;
114f76ee892STomi Valkeinen 	u32 fid_int_start_x__fid_int_start_y;
115f76ee892STomi Valkeinen 	u32 fid_int_offset_y__fid_ext_start_x;
116f76ee892STomi Valkeinen 	u32 fid_ext_start_y__fid_ext_offset_y;
117f76ee892STomi Valkeinen 	u32 tvdetgp_int_start_stop_x;
118f76ee892STomi Valkeinen 	u32 tvdetgp_int_start_stop_y;
119f76ee892STomi Valkeinen 	u32 gen_ctrl;
120f76ee892STomi Valkeinen };
121f76ee892STomi Valkeinen 
122f76ee892STomi Valkeinen /* from TRM */
123f76ee892STomi Valkeinen static const struct venc_config venc_config_pal_trm = {
124f76ee892STomi Valkeinen 	.f_control				= 0,
125f76ee892STomi Valkeinen 	.vidout_ctrl				= 1,
126f76ee892STomi Valkeinen 	.sync_ctrl				= 0x40,
127f76ee892STomi Valkeinen 	.llen					= 0x35F, /* 863 */
128f76ee892STomi Valkeinen 	.flens					= 0x270, /* 624 */
129f76ee892STomi Valkeinen 	.hfltr_ctrl				= 0,
130f76ee892STomi Valkeinen 	.cc_carr_wss_carr			= 0x2F7225ED,
131f76ee892STomi Valkeinen 	.c_phase				= 0,
132f76ee892STomi Valkeinen 	.gain_u					= 0x111,
133f76ee892STomi Valkeinen 	.gain_v					= 0x181,
134f76ee892STomi Valkeinen 	.gain_y					= 0x140,
135f76ee892STomi Valkeinen 	.black_level				= 0x3B,
136f76ee892STomi Valkeinen 	.blank_level				= 0x3B,
137f76ee892STomi Valkeinen 	.x_color				= 0x7,
138f76ee892STomi Valkeinen 	.m_control				= 0x2,
139f76ee892STomi Valkeinen 	.bstamp_wss_data			= 0x3F,
140f76ee892STomi Valkeinen 	.s_carr					= 0x2A098ACB,
141f76ee892STomi Valkeinen 	.line21					= 0,
142f76ee892STomi Valkeinen 	.ln_sel					= 0x01290015,
143f76ee892STomi Valkeinen 	.l21__wc_ctl				= 0x0000F603,
144f76ee892STomi Valkeinen 	.htrigger_vtrigger			= 0,
145f76ee892STomi Valkeinen 
146f76ee892STomi Valkeinen 	.savid__eavid				= 0x06A70108,
147f76ee892STomi Valkeinen 	.flen__fal				= 0x00180270,
148f76ee892STomi Valkeinen 	.lal__phase_reset			= 0x00040135,
149f76ee892STomi Valkeinen 	.hs_int_start_stop_x			= 0x00880358,
150f76ee892STomi Valkeinen 	.hs_ext_start_stop_x			= 0x000F035F,
151f76ee892STomi Valkeinen 	.vs_int_start_x				= 0x01A70000,
152f76ee892STomi Valkeinen 	.vs_int_stop_x__vs_int_start_y		= 0x000001A7,
153f76ee892STomi Valkeinen 	.vs_int_stop_y__vs_ext_start_x		= 0x01AF0000,
154f76ee892STomi Valkeinen 	.vs_ext_stop_x__vs_ext_start_y		= 0x000101AF,
155f76ee892STomi Valkeinen 	.vs_ext_stop_y				= 0x00000025,
156f76ee892STomi Valkeinen 	.avid_start_stop_x			= 0x03530083,
157f76ee892STomi Valkeinen 	.avid_start_stop_y			= 0x026C002E,
158f76ee892STomi Valkeinen 	.fid_int_start_x__fid_int_start_y	= 0x0001008A,
159f76ee892STomi Valkeinen 	.fid_int_offset_y__fid_ext_start_x	= 0x002E0138,
160f76ee892STomi Valkeinen 	.fid_ext_start_y__fid_ext_offset_y	= 0x01380001,
161f76ee892STomi Valkeinen 
162f76ee892STomi Valkeinen 	.tvdetgp_int_start_stop_x		= 0x00140001,
163f76ee892STomi Valkeinen 	.tvdetgp_int_start_stop_y		= 0x00010001,
164f76ee892STomi Valkeinen 	.gen_ctrl				= 0x00FF0000,
165f76ee892STomi Valkeinen };
166f76ee892STomi Valkeinen 
167f76ee892STomi Valkeinen /* from TRM */
168f76ee892STomi Valkeinen static const struct venc_config venc_config_ntsc_trm = {
169f76ee892STomi Valkeinen 	.f_control				= 0,
170f76ee892STomi Valkeinen 	.vidout_ctrl				= 1,
171f76ee892STomi Valkeinen 	.sync_ctrl				= 0x8040,
172f76ee892STomi Valkeinen 	.llen					= 0x359,
173f76ee892STomi Valkeinen 	.flens					= 0x20C,
174f76ee892STomi Valkeinen 	.hfltr_ctrl				= 0,
175f76ee892STomi Valkeinen 	.cc_carr_wss_carr			= 0x043F2631,
176f76ee892STomi Valkeinen 	.c_phase				= 0,
177f76ee892STomi Valkeinen 	.gain_u					= 0x102,
178f76ee892STomi Valkeinen 	.gain_v					= 0x16C,
179f76ee892STomi Valkeinen 	.gain_y					= 0x12F,
180f76ee892STomi Valkeinen 	.black_level				= 0x43,
181f76ee892STomi Valkeinen 	.blank_level				= 0x38,
182f76ee892STomi Valkeinen 	.x_color				= 0x7,
183f76ee892STomi Valkeinen 	.m_control				= 0x1,
184f76ee892STomi Valkeinen 	.bstamp_wss_data			= 0x38,
185f76ee892STomi Valkeinen 	.s_carr					= 0x21F07C1F,
186f76ee892STomi Valkeinen 	.line21					= 0,
187f76ee892STomi Valkeinen 	.ln_sel					= 0x01310011,
188f76ee892STomi Valkeinen 	.l21__wc_ctl				= 0x0000F003,
189f76ee892STomi Valkeinen 	.htrigger_vtrigger			= 0,
190f76ee892STomi Valkeinen 
191f76ee892STomi Valkeinen 	.savid__eavid				= 0x069300F4,
192f76ee892STomi Valkeinen 	.flen__fal				= 0x0016020C,
193f76ee892STomi Valkeinen 	.lal__phase_reset			= 0x00060107,
194f76ee892STomi Valkeinen 	.hs_int_start_stop_x			= 0x008E0350,
195f76ee892STomi Valkeinen 	.hs_ext_start_stop_x			= 0x000F0359,
196f76ee892STomi Valkeinen 	.vs_int_start_x				= 0x01A00000,
197f76ee892STomi Valkeinen 	.vs_int_stop_x__vs_int_start_y		= 0x020701A0,
198f76ee892STomi Valkeinen 	.vs_int_stop_y__vs_ext_start_x		= 0x01AC0024,
199f76ee892STomi Valkeinen 	.vs_ext_stop_x__vs_ext_start_y		= 0x020D01AC,
200f76ee892STomi Valkeinen 	.vs_ext_stop_y				= 0x00000006,
201f76ee892STomi Valkeinen 	.avid_start_stop_x			= 0x03480078,
202f76ee892STomi Valkeinen 	.avid_start_stop_y			= 0x02060024,
203f76ee892STomi Valkeinen 	.fid_int_start_x__fid_int_start_y	= 0x0001008A,
204f76ee892STomi Valkeinen 	.fid_int_offset_y__fid_ext_start_x	= 0x01AC0106,
205f76ee892STomi Valkeinen 	.fid_ext_start_y__fid_ext_offset_y	= 0x01060006,
206f76ee892STomi Valkeinen 
207f76ee892STomi Valkeinen 	.tvdetgp_int_start_stop_x		= 0x00140001,
208f76ee892STomi Valkeinen 	.tvdetgp_int_start_stop_y		= 0x00010001,
209f76ee892STomi Valkeinen 	.gen_ctrl				= 0x00F90000,
210f76ee892STomi Valkeinen };
211f76ee892STomi Valkeinen 
212f76ee892STomi Valkeinen const struct omap_video_timings omap_dss_pal_timings = {
213f76ee892STomi Valkeinen 	.x_res		= 720,
214f76ee892STomi Valkeinen 	.y_res		= 574,
215f76ee892STomi Valkeinen 	.pixelclock	= 13500000,
216f76ee892STomi Valkeinen 	.hsw		= 64,
217f76ee892STomi Valkeinen 	.hfp		= 12,
218f76ee892STomi Valkeinen 	.hbp		= 68,
219f76ee892STomi Valkeinen 	.vsw		= 5,
220f76ee892STomi Valkeinen 	.vfp		= 5,
221f76ee892STomi Valkeinen 	.vbp		= 41,
222f76ee892STomi Valkeinen 
223f76ee892STomi Valkeinen 	.interlace	= true,
224f76ee892STomi Valkeinen };
225f76ee892STomi Valkeinen EXPORT_SYMBOL(omap_dss_pal_timings);
226f76ee892STomi Valkeinen 
227f76ee892STomi Valkeinen const struct omap_video_timings omap_dss_ntsc_timings = {
228f76ee892STomi Valkeinen 	.x_res		= 720,
229f76ee892STomi Valkeinen 	.y_res		= 482,
230f76ee892STomi Valkeinen 	.pixelclock	= 13500000,
231f76ee892STomi Valkeinen 	.hsw		= 64,
232f76ee892STomi Valkeinen 	.hfp		= 16,
233f76ee892STomi Valkeinen 	.hbp		= 58,
234f76ee892STomi Valkeinen 	.vsw		= 6,
235f76ee892STomi Valkeinen 	.vfp		= 6,
236f76ee892STomi Valkeinen 	.vbp		= 31,
237f76ee892STomi Valkeinen 
238f76ee892STomi Valkeinen 	.interlace	= true,
239f76ee892STomi Valkeinen };
240f76ee892STomi Valkeinen EXPORT_SYMBOL(omap_dss_ntsc_timings);
241f76ee892STomi Valkeinen 
242f76ee892STomi Valkeinen static struct {
243f76ee892STomi Valkeinen 	struct platform_device *pdev;
244f76ee892STomi Valkeinen 	void __iomem *base;
245f76ee892STomi Valkeinen 	struct mutex venc_lock;
246f76ee892STomi Valkeinen 	u32 wss_data;
247f76ee892STomi Valkeinen 	struct regulator *vdda_dac_reg;
248f76ee892STomi Valkeinen 
249f76ee892STomi Valkeinen 	struct clk	*tv_dac_clk;
250f76ee892STomi Valkeinen 
251f76ee892STomi Valkeinen 	struct omap_video_timings timings;
252f76ee892STomi Valkeinen 	enum omap_dss_venc_type type;
253f76ee892STomi Valkeinen 	bool invert_polarity;
254f76ee892STomi Valkeinen 
255f76ee892STomi Valkeinen 	struct omap_dss_device output;
256f76ee892STomi Valkeinen } venc;
257f76ee892STomi Valkeinen 
venc_write_reg(int idx,u32 val)258f76ee892STomi Valkeinen static inline void venc_write_reg(int idx, u32 val)
259f76ee892STomi Valkeinen {
260f76ee892STomi Valkeinen 	__raw_writel(val, venc.base + idx);
261f76ee892STomi Valkeinen }
262f76ee892STomi Valkeinen 
venc_read_reg(int idx)263f76ee892STomi Valkeinen static inline u32 venc_read_reg(int idx)
264f76ee892STomi Valkeinen {
265f76ee892STomi Valkeinen 	u32 l = __raw_readl(venc.base + idx);
266f76ee892STomi Valkeinen 	return l;
267f76ee892STomi Valkeinen }
268f76ee892STomi Valkeinen 
venc_write_config(const struct venc_config * config)269f76ee892STomi Valkeinen static void venc_write_config(const struct venc_config *config)
270f76ee892STomi Valkeinen {
271f76ee892STomi Valkeinen 	DSSDBG("write venc conf\n");
272f76ee892STomi Valkeinen 
273f76ee892STomi Valkeinen 	venc_write_reg(VENC_LLEN, config->llen);
274f76ee892STomi Valkeinen 	venc_write_reg(VENC_FLENS, config->flens);
275f76ee892STomi Valkeinen 	venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
276f76ee892STomi Valkeinen 	venc_write_reg(VENC_C_PHASE, config->c_phase);
277f76ee892STomi Valkeinen 	venc_write_reg(VENC_GAIN_U, config->gain_u);
278f76ee892STomi Valkeinen 	venc_write_reg(VENC_GAIN_V, config->gain_v);
279f76ee892STomi Valkeinen 	venc_write_reg(VENC_GAIN_Y, config->gain_y);
280f76ee892STomi Valkeinen 	venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
281f76ee892STomi Valkeinen 	venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
282f76ee892STomi Valkeinen 	venc_write_reg(VENC_M_CONTROL, config->m_control);
283f76ee892STomi Valkeinen 	venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
284f76ee892STomi Valkeinen 			venc.wss_data);
285f76ee892STomi Valkeinen 	venc_write_reg(VENC_S_CARR, config->s_carr);
286f76ee892STomi Valkeinen 	venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
287f76ee892STomi Valkeinen 	venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
288f76ee892STomi Valkeinen 	venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
289f76ee892STomi Valkeinen 	venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
290f76ee892STomi Valkeinen 	venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
291f76ee892STomi Valkeinen 	venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
292f76ee892STomi Valkeinen 	venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
293f76ee892STomi Valkeinen 	venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
294f76ee892STomi Valkeinen 		       config->vs_int_stop_x__vs_int_start_y);
295f76ee892STomi Valkeinen 	venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
296f76ee892STomi Valkeinen 		       config->vs_int_stop_y__vs_ext_start_x);
297f76ee892STomi Valkeinen 	venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
298f76ee892STomi Valkeinen 		       config->vs_ext_stop_x__vs_ext_start_y);
299f76ee892STomi Valkeinen 	venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
300f76ee892STomi Valkeinen 	venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
301f76ee892STomi Valkeinen 	venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
302f76ee892STomi Valkeinen 	venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
303f76ee892STomi Valkeinen 		       config->fid_int_start_x__fid_int_start_y);
304f76ee892STomi Valkeinen 	venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
305f76ee892STomi Valkeinen 		       config->fid_int_offset_y__fid_ext_start_x);
306f76ee892STomi Valkeinen 	venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
307f76ee892STomi Valkeinen 		       config->fid_ext_start_y__fid_ext_offset_y);
308f76ee892STomi Valkeinen 
309f76ee892STomi Valkeinen 	venc_write_reg(VENC_DAC_B__DAC_C,  venc_read_reg(VENC_DAC_B__DAC_C));
310f76ee892STomi Valkeinen 	venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
311f76ee892STomi Valkeinen 	venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
312f76ee892STomi Valkeinen 	venc_write_reg(VENC_X_COLOR, config->x_color);
313f76ee892STomi Valkeinen 	venc_write_reg(VENC_LINE21, config->line21);
314f76ee892STomi Valkeinen 	venc_write_reg(VENC_LN_SEL, config->ln_sel);
315f76ee892STomi Valkeinen 	venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
316f76ee892STomi Valkeinen 	venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
317f76ee892STomi Valkeinen 		       config->tvdetgp_int_start_stop_x);
318f76ee892STomi Valkeinen 	venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
319f76ee892STomi Valkeinen 		       config->tvdetgp_int_start_stop_y);
320f76ee892STomi Valkeinen 	venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
321f76ee892STomi Valkeinen 	venc_write_reg(VENC_F_CONTROL, config->f_control);
322f76ee892STomi Valkeinen 	venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
323f76ee892STomi Valkeinen }
324f76ee892STomi Valkeinen 
venc_reset(void)325f76ee892STomi Valkeinen static void venc_reset(void)
326f76ee892STomi Valkeinen {
327f76ee892STomi Valkeinen 	int t = 1000;
328f76ee892STomi Valkeinen 
329f76ee892STomi Valkeinen 	venc_write_reg(VENC_F_CONTROL, 1<<8);
330f76ee892STomi Valkeinen 	while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
331f76ee892STomi Valkeinen 		if (--t == 0) {
332f76ee892STomi Valkeinen 			DSSERR("Failed to reset venc\n");
333f76ee892STomi Valkeinen 			return;
334f76ee892STomi Valkeinen 		}
335f76ee892STomi Valkeinen 	}
336f76ee892STomi Valkeinen 
33735b522cfSTomi Valkeinen #ifdef CONFIG_FB_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
338f76ee892STomi Valkeinen 	/* the magical sleep that makes things work */
339f76ee892STomi Valkeinen 	/* XXX more info? What bug this circumvents? */
340f76ee892STomi Valkeinen 	msleep(20);
341f76ee892STomi Valkeinen #endif
342f76ee892STomi Valkeinen }
343f76ee892STomi Valkeinen 
venc_runtime_get(void)344f76ee892STomi Valkeinen static int venc_runtime_get(void)
345f76ee892STomi Valkeinen {
346f76ee892STomi Valkeinen 	int r;
347f76ee892STomi Valkeinen 
348f76ee892STomi Valkeinen 	DSSDBG("venc_runtime_get\n");
349f76ee892STomi Valkeinen 
350b0e07060SZhang Qilong 	r = pm_runtime_resume_and_get(&venc.pdev->dev);
351b0e07060SZhang Qilong 	if (WARN_ON(r < 0))
35278c2ce9bSAditya Pakki 		return r;
35378c2ce9bSAditya Pakki 	return 0;
354f76ee892STomi Valkeinen }
355f76ee892STomi Valkeinen 
venc_runtime_put(void)356f76ee892STomi Valkeinen static void venc_runtime_put(void)
357f76ee892STomi Valkeinen {
358f76ee892STomi Valkeinen 	int r;
359f76ee892STomi Valkeinen 
360f76ee892STomi Valkeinen 	DSSDBG("venc_runtime_put\n");
361f76ee892STomi Valkeinen 
362f76ee892STomi Valkeinen 	r = pm_runtime_put_sync(&venc.pdev->dev);
363f76ee892STomi Valkeinen 	WARN_ON(r < 0 && r != -ENOSYS);
364f76ee892STomi Valkeinen }
365f76ee892STomi Valkeinen 
venc_timings_to_config(struct omap_video_timings * timings)366f76ee892STomi Valkeinen static const struct venc_config *venc_timings_to_config(
367f76ee892STomi Valkeinen 		struct omap_video_timings *timings)
368f76ee892STomi Valkeinen {
369f76ee892STomi Valkeinen 	if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
370f76ee892STomi Valkeinen 		return &venc_config_pal_trm;
371f76ee892STomi Valkeinen 
372f76ee892STomi Valkeinen 	if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
373f76ee892STomi Valkeinen 		return &venc_config_ntsc_trm;
374f76ee892STomi Valkeinen 
375f76ee892STomi Valkeinen 	BUG();
376f76ee892STomi Valkeinen 	return NULL;
377f76ee892STomi Valkeinen }
378f76ee892STomi Valkeinen 
venc_power_on(struct omap_dss_device * dssdev)379f76ee892STomi Valkeinen static int venc_power_on(struct omap_dss_device *dssdev)
380f76ee892STomi Valkeinen {
381f76ee892STomi Valkeinen 	struct omap_overlay_manager *mgr = venc.output.manager;
382f76ee892STomi Valkeinen 	u32 l;
383f76ee892STomi Valkeinen 	int r;
384f76ee892STomi Valkeinen 
385f76ee892STomi Valkeinen 	r = venc_runtime_get();
386f76ee892STomi Valkeinen 	if (r)
387f76ee892STomi Valkeinen 		goto err0;
388f76ee892STomi Valkeinen 
389f76ee892STomi Valkeinen 	venc_reset();
390f76ee892STomi Valkeinen 	venc_write_config(venc_timings_to_config(&venc.timings));
391f76ee892STomi Valkeinen 
392f76ee892STomi Valkeinen 	dss_set_venc_output(venc.type);
393f76ee892STomi Valkeinen 	dss_set_dac_pwrdn_bgz(1);
394f76ee892STomi Valkeinen 
395f76ee892STomi Valkeinen 	l = 0;
396f76ee892STomi Valkeinen 
397f76ee892STomi Valkeinen 	if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
398f76ee892STomi Valkeinen 		l |= 1 << 1;
399f76ee892STomi Valkeinen 	else /* S-Video */
400f76ee892STomi Valkeinen 		l |= (1 << 0) | (1 << 2);
401f76ee892STomi Valkeinen 
402f76ee892STomi Valkeinen 	if (venc.invert_polarity == false)
403f76ee892STomi Valkeinen 		l |= 1 << 3;
404f76ee892STomi Valkeinen 
405f76ee892STomi Valkeinen 	venc_write_reg(VENC_OUTPUT_CONTROL, l);
406f76ee892STomi Valkeinen 
407f76ee892STomi Valkeinen 	dss_mgr_set_timings(mgr, &venc.timings);
408f76ee892STomi Valkeinen 
409f76ee892STomi Valkeinen 	r = regulator_enable(venc.vdda_dac_reg);
410f76ee892STomi Valkeinen 	if (r)
411f76ee892STomi Valkeinen 		goto err1;
412f76ee892STomi Valkeinen 
413f76ee892STomi Valkeinen 	r = dss_mgr_enable(mgr);
414f76ee892STomi Valkeinen 	if (r)
415f76ee892STomi Valkeinen 		goto err2;
416f76ee892STomi Valkeinen 
417f76ee892STomi Valkeinen 	return 0;
418f76ee892STomi Valkeinen 
419f76ee892STomi Valkeinen err2:
420f76ee892STomi Valkeinen 	regulator_disable(venc.vdda_dac_reg);
421f76ee892STomi Valkeinen err1:
422f76ee892STomi Valkeinen 	venc_write_reg(VENC_OUTPUT_CONTROL, 0);
423f76ee892STomi Valkeinen 	dss_set_dac_pwrdn_bgz(0);
424f76ee892STomi Valkeinen 
425f76ee892STomi Valkeinen 	venc_runtime_put();
426f76ee892STomi Valkeinen err0:
427f76ee892STomi Valkeinen 	return r;
428f76ee892STomi Valkeinen }
429f76ee892STomi Valkeinen 
venc_power_off(struct omap_dss_device * dssdev)430f76ee892STomi Valkeinen static void venc_power_off(struct omap_dss_device *dssdev)
431f76ee892STomi Valkeinen {
432f76ee892STomi Valkeinen 	struct omap_overlay_manager *mgr = venc.output.manager;
433f76ee892STomi Valkeinen 
434f76ee892STomi Valkeinen 	venc_write_reg(VENC_OUTPUT_CONTROL, 0);
435f76ee892STomi Valkeinen 	dss_set_dac_pwrdn_bgz(0);
436f76ee892STomi Valkeinen 
437f76ee892STomi Valkeinen 	dss_mgr_disable(mgr);
438f76ee892STomi Valkeinen 
439f76ee892STomi Valkeinen 	regulator_disable(venc.vdda_dac_reg);
440f76ee892STomi Valkeinen 
441f76ee892STomi Valkeinen 	venc_runtime_put();
442f76ee892STomi Valkeinen }
443f76ee892STomi Valkeinen 
venc_display_enable(struct omap_dss_device * dssdev)444f76ee892STomi Valkeinen static int venc_display_enable(struct omap_dss_device *dssdev)
445f76ee892STomi Valkeinen {
446f76ee892STomi Valkeinen 	struct omap_dss_device *out = &venc.output;
447f76ee892STomi Valkeinen 	int r;
448f76ee892STomi Valkeinen 
449f76ee892STomi Valkeinen 	DSSDBG("venc_display_enable\n");
450f76ee892STomi Valkeinen 
451f76ee892STomi Valkeinen 	mutex_lock(&venc.venc_lock);
452f76ee892STomi Valkeinen 
453f76ee892STomi Valkeinen 	if (out->manager == NULL) {
454f76ee892STomi Valkeinen 		DSSERR("Failed to enable display: no output/manager\n");
455f76ee892STomi Valkeinen 		r = -ENODEV;
456f76ee892STomi Valkeinen 		goto err0;
457f76ee892STomi Valkeinen 	}
458f76ee892STomi Valkeinen 
459f76ee892STomi Valkeinen 	r = venc_power_on(dssdev);
460f76ee892STomi Valkeinen 	if (r)
461f76ee892STomi Valkeinen 		goto err0;
462f76ee892STomi Valkeinen 
463f76ee892STomi Valkeinen 	venc.wss_data = 0;
464f76ee892STomi Valkeinen 
465f76ee892STomi Valkeinen 	mutex_unlock(&venc.venc_lock);
466f76ee892STomi Valkeinen 
467f76ee892STomi Valkeinen 	return 0;
468f76ee892STomi Valkeinen err0:
469f76ee892STomi Valkeinen 	mutex_unlock(&venc.venc_lock);
470f76ee892STomi Valkeinen 	return r;
471f76ee892STomi Valkeinen }
472f76ee892STomi Valkeinen 
venc_display_disable(struct omap_dss_device * dssdev)473f76ee892STomi Valkeinen static void venc_display_disable(struct omap_dss_device *dssdev)
474f76ee892STomi Valkeinen {
475f76ee892STomi Valkeinen 	DSSDBG("venc_display_disable\n");
476f76ee892STomi Valkeinen 
477f76ee892STomi Valkeinen 	mutex_lock(&venc.venc_lock);
478f76ee892STomi Valkeinen 
479f76ee892STomi Valkeinen 	venc_power_off(dssdev);
480f76ee892STomi Valkeinen 
481f76ee892STomi Valkeinen 	mutex_unlock(&venc.venc_lock);
482f76ee892STomi Valkeinen }
483f76ee892STomi Valkeinen 
venc_set_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)484f76ee892STomi Valkeinen static void venc_set_timings(struct omap_dss_device *dssdev,
485f76ee892STomi Valkeinen 		struct omap_video_timings *timings)
486f76ee892STomi Valkeinen {
487f76ee892STomi Valkeinen 	DSSDBG("venc_set_timings\n");
488f76ee892STomi Valkeinen 
489f76ee892STomi Valkeinen 	mutex_lock(&venc.venc_lock);
490f76ee892STomi Valkeinen 
491f76ee892STomi Valkeinen 	/* Reset WSS data when the TV standard changes. */
492f76ee892STomi Valkeinen 	if (memcmp(&venc.timings, timings, sizeof(*timings)))
493f76ee892STomi Valkeinen 		venc.wss_data = 0;
494f76ee892STomi Valkeinen 
495f76ee892STomi Valkeinen 	venc.timings = *timings;
496f76ee892STomi Valkeinen 
497f76ee892STomi Valkeinen 	dispc_set_tv_pclk(13500000);
498f76ee892STomi Valkeinen 
499f76ee892STomi Valkeinen 	mutex_unlock(&venc.venc_lock);
500f76ee892STomi Valkeinen }
501f76ee892STomi Valkeinen 
venc_check_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)502f76ee892STomi Valkeinen static int venc_check_timings(struct omap_dss_device *dssdev,
503f76ee892STomi Valkeinen 		struct omap_video_timings *timings)
504f76ee892STomi Valkeinen {
505f76ee892STomi Valkeinen 	DSSDBG("venc_check_timings\n");
506f76ee892STomi Valkeinen 
507f76ee892STomi Valkeinen 	if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
508f76ee892STomi Valkeinen 		return 0;
509f76ee892STomi Valkeinen 
510f76ee892STomi Valkeinen 	if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
511f76ee892STomi Valkeinen 		return 0;
512f76ee892STomi Valkeinen 
513f76ee892STomi Valkeinen 	return -EINVAL;
514f76ee892STomi Valkeinen }
515f76ee892STomi Valkeinen 
venc_get_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)516f76ee892STomi Valkeinen static void venc_get_timings(struct omap_dss_device *dssdev,
517f76ee892STomi Valkeinen 		struct omap_video_timings *timings)
518f76ee892STomi Valkeinen {
519f76ee892STomi Valkeinen 	mutex_lock(&venc.venc_lock);
520f76ee892STomi Valkeinen 
521f76ee892STomi Valkeinen 	*timings = venc.timings;
522f76ee892STomi Valkeinen 
523f76ee892STomi Valkeinen 	mutex_unlock(&venc.venc_lock);
524f76ee892STomi Valkeinen }
525f76ee892STomi Valkeinen 
venc_get_wss(struct omap_dss_device * dssdev)526f76ee892STomi Valkeinen static u32 venc_get_wss(struct omap_dss_device *dssdev)
527f76ee892STomi Valkeinen {
528f76ee892STomi Valkeinen 	/* Invert due to VENC_L21_WC_CTL:INV=1 */
529f76ee892STomi Valkeinen 	return (venc.wss_data >> 8) ^ 0xfffff;
530f76ee892STomi Valkeinen }
531f76ee892STomi Valkeinen 
venc_set_wss(struct omap_dss_device * dssdev,u32 wss)532f76ee892STomi Valkeinen static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
533f76ee892STomi Valkeinen {
534f76ee892STomi Valkeinen 	const struct venc_config *config;
535f76ee892STomi Valkeinen 	int r;
536f76ee892STomi Valkeinen 
537f76ee892STomi Valkeinen 	DSSDBG("venc_set_wss\n");
538f76ee892STomi Valkeinen 
539f76ee892STomi Valkeinen 	mutex_lock(&venc.venc_lock);
540f76ee892STomi Valkeinen 
541f76ee892STomi Valkeinen 	config = venc_timings_to_config(&venc.timings);
542f76ee892STomi Valkeinen 
543f76ee892STomi Valkeinen 	/* Invert due to VENC_L21_WC_CTL:INV=1 */
544f76ee892STomi Valkeinen 	venc.wss_data = (wss ^ 0xfffff) << 8;
545f76ee892STomi Valkeinen 
546f76ee892STomi Valkeinen 	r = venc_runtime_get();
547f76ee892STomi Valkeinen 	if (r)
548f76ee892STomi Valkeinen 		goto err;
549f76ee892STomi Valkeinen 
550f76ee892STomi Valkeinen 	venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
551f76ee892STomi Valkeinen 			venc.wss_data);
552f76ee892STomi Valkeinen 
553f76ee892STomi Valkeinen 	venc_runtime_put();
554f76ee892STomi Valkeinen 
555f76ee892STomi Valkeinen err:
556f76ee892STomi Valkeinen 	mutex_unlock(&venc.venc_lock);
557f76ee892STomi Valkeinen 
558f76ee892STomi Valkeinen 	return r;
559f76ee892STomi Valkeinen }
560f76ee892STomi Valkeinen 
venc_set_type(struct omap_dss_device * dssdev,enum omap_dss_venc_type type)561f76ee892STomi Valkeinen static void venc_set_type(struct omap_dss_device *dssdev,
562f76ee892STomi Valkeinen 		enum omap_dss_venc_type type)
563f76ee892STomi Valkeinen {
564f76ee892STomi Valkeinen 	mutex_lock(&venc.venc_lock);
565f76ee892STomi Valkeinen 
566f76ee892STomi Valkeinen 	venc.type = type;
567f76ee892STomi Valkeinen 
568f76ee892STomi Valkeinen 	mutex_unlock(&venc.venc_lock);
569f76ee892STomi Valkeinen }
570f76ee892STomi Valkeinen 
venc_invert_vid_out_polarity(struct omap_dss_device * dssdev,bool invert_polarity)571f76ee892STomi Valkeinen static void venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
572f76ee892STomi Valkeinen 		bool invert_polarity)
573f76ee892STomi Valkeinen {
574f76ee892STomi Valkeinen 	mutex_lock(&venc.venc_lock);
575f76ee892STomi Valkeinen 
576f76ee892STomi Valkeinen 	venc.invert_polarity = invert_polarity;
577f76ee892STomi Valkeinen 
578f76ee892STomi Valkeinen 	mutex_unlock(&venc.venc_lock);
579f76ee892STomi Valkeinen }
580f76ee892STomi Valkeinen 
venc_init_regulator(void)581f76ee892STomi Valkeinen static int venc_init_regulator(void)
582f76ee892STomi Valkeinen {
583f76ee892STomi Valkeinen 	struct regulator *vdda_dac;
584f76ee892STomi Valkeinen 
585f76ee892STomi Valkeinen 	if (venc.vdda_dac_reg != NULL)
586f76ee892STomi Valkeinen 		return 0;
587f76ee892STomi Valkeinen 
588f76ee892STomi Valkeinen 	if (venc.pdev->dev.of_node)
589f76ee892STomi Valkeinen 		vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda");
590f76ee892STomi Valkeinen 	else
591f76ee892STomi Valkeinen 		vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac");
592f76ee892STomi Valkeinen 
593f76ee892STomi Valkeinen 	if (IS_ERR(vdda_dac)) {
594f76ee892STomi Valkeinen 		if (PTR_ERR(vdda_dac) != -EPROBE_DEFER)
595f76ee892STomi Valkeinen 			DSSERR("can't get VDDA_DAC regulator\n");
596f76ee892STomi Valkeinen 		return PTR_ERR(vdda_dac);
597f76ee892STomi Valkeinen 	}
598f76ee892STomi Valkeinen 
599f76ee892STomi Valkeinen 	venc.vdda_dac_reg = vdda_dac;
600f76ee892STomi Valkeinen 
601f76ee892STomi Valkeinen 	return 0;
602f76ee892STomi Valkeinen }
603f76ee892STomi Valkeinen 
venc_dump_regs(struct seq_file * s)604f76ee892STomi Valkeinen static void venc_dump_regs(struct seq_file *s)
605f76ee892STomi Valkeinen {
606f76ee892STomi Valkeinen #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
607f76ee892STomi Valkeinen 
608f76ee892STomi Valkeinen 	if (venc_runtime_get())
609f76ee892STomi Valkeinen 		return;
610f76ee892STomi Valkeinen 
611f76ee892STomi Valkeinen 	DUMPREG(VENC_F_CONTROL);
612f76ee892STomi Valkeinen 	DUMPREG(VENC_VIDOUT_CTRL);
613f76ee892STomi Valkeinen 	DUMPREG(VENC_SYNC_CTRL);
614f76ee892STomi Valkeinen 	DUMPREG(VENC_LLEN);
615f76ee892STomi Valkeinen 	DUMPREG(VENC_FLENS);
616f76ee892STomi Valkeinen 	DUMPREG(VENC_HFLTR_CTRL);
617f76ee892STomi Valkeinen 	DUMPREG(VENC_CC_CARR_WSS_CARR);
618f76ee892STomi Valkeinen 	DUMPREG(VENC_C_PHASE);
619f76ee892STomi Valkeinen 	DUMPREG(VENC_GAIN_U);
620f76ee892STomi Valkeinen 	DUMPREG(VENC_GAIN_V);
621f76ee892STomi Valkeinen 	DUMPREG(VENC_GAIN_Y);
622f76ee892STomi Valkeinen 	DUMPREG(VENC_BLACK_LEVEL);
623f76ee892STomi Valkeinen 	DUMPREG(VENC_BLANK_LEVEL);
624f76ee892STomi Valkeinen 	DUMPREG(VENC_X_COLOR);
625f76ee892STomi Valkeinen 	DUMPREG(VENC_M_CONTROL);
626f76ee892STomi Valkeinen 	DUMPREG(VENC_BSTAMP_WSS_DATA);
627f76ee892STomi Valkeinen 	DUMPREG(VENC_S_CARR);
628f76ee892STomi Valkeinen 	DUMPREG(VENC_LINE21);
629f76ee892STomi Valkeinen 	DUMPREG(VENC_LN_SEL);
630f76ee892STomi Valkeinen 	DUMPREG(VENC_L21__WC_CTL);
631f76ee892STomi Valkeinen 	DUMPREG(VENC_HTRIGGER_VTRIGGER);
632f76ee892STomi Valkeinen 	DUMPREG(VENC_SAVID__EAVID);
633f76ee892STomi Valkeinen 	DUMPREG(VENC_FLEN__FAL);
634f76ee892STomi Valkeinen 	DUMPREG(VENC_LAL__PHASE_RESET);
635f76ee892STomi Valkeinen 	DUMPREG(VENC_HS_INT_START_STOP_X);
636f76ee892STomi Valkeinen 	DUMPREG(VENC_HS_EXT_START_STOP_X);
637f76ee892STomi Valkeinen 	DUMPREG(VENC_VS_INT_START_X);
638f76ee892STomi Valkeinen 	DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
639f76ee892STomi Valkeinen 	DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
640f76ee892STomi Valkeinen 	DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
641f76ee892STomi Valkeinen 	DUMPREG(VENC_VS_EXT_STOP_Y);
642f76ee892STomi Valkeinen 	DUMPREG(VENC_AVID_START_STOP_X);
643f76ee892STomi Valkeinen 	DUMPREG(VENC_AVID_START_STOP_Y);
644f76ee892STomi Valkeinen 	DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
645f76ee892STomi Valkeinen 	DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
646f76ee892STomi Valkeinen 	DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
647f76ee892STomi Valkeinen 	DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
648f76ee892STomi Valkeinen 	DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
649f76ee892STomi Valkeinen 	DUMPREG(VENC_GEN_CTRL);
650f76ee892STomi Valkeinen 	DUMPREG(VENC_OUTPUT_CONTROL);
651f76ee892STomi Valkeinen 	DUMPREG(VENC_OUTPUT_TEST);
652f76ee892STomi Valkeinen 
653f76ee892STomi Valkeinen 	venc_runtime_put();
654f76ee892STomi Valkeinen 
655f76ee892STomi Valkeinen #undef DUMPREG
656f76ee892STomi Valkeinen }
657f76ee892STomi Valkeinen 
venc_get_clocks(struct platform_device * pdev)658f76ee892STomi Valkeinen static int venc_get_clocks(struct platform_device *pdev)
659f76ee892STomi Valkeinen {
660f76ee892STomi Valkeinen 	struct clk *clk;
661f76ee892STomi Valkeinen 
662f76ee892STomi Valkeinen 	if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
663f76ee892STomi Valkeinen 		clk = devm_clk_get(&pdev->dev, "tv_dac_clk");
664f76ee892STomi Valkeinen 		if (IS_ERR(clk)) {
665f76ee892STomi Valkeinen 			DSSERR("can't get tv_dac_clk\n");
666f76ee892STomi Valkeinen 			return PTR_ERR(clk);
667f76ee892STomi Valkeinen 		}
668f76ee892STomi Valkeinen 	} else {
669f76ee892STomi Valkeinen 		clk = NULL;
670f76ee892STomi Valkeinen 	}
671f76ee892STomi Valkeinen 
672f76ee892STomi Valkeinen 	venc.tv_dac_clk = clk;
673f76ee892STomi Valkeinen 
674f76ee892STomi Valkeinen 	return 0;
675f76ee892STomi Valkeinen }
676f76ee892STomi Valkeinen 
venc_connect(struct omap_dss_device * dssdev,struct omap_dss_device * dst)677f76ee892STomi Valkeinen static int venc_connect(struct omap_dss_device *dssdev,
678f76ee892STomi Valkeinen 		struct omap_dss_device *dst)
679f76ee892STomi Valkeinen {
680f76ee892STomi Valkeinen 	struct omap_overlay_manager *mgr;
681f76ee892STomi Valkeinen 	int r;
682f76ee892STomi Valkeinen 
683f76ee892STomi Valkeinen 	r = venc_init_regulator();
684f76ee892STomi Valkeinen 	if (r)
685f76ee892STomi Valkeinen 		return r;
686f76ee892STomi Valkeinen 
687f76ee892STomi Valkeinen 	mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
688f76ee892STomi Valkeinen 	if (!mgr)
689f76ee892STomi Valkeinen 		return -ENODEV;
690f76ee892STomi Valkeinen 
691f76ee892STomi Valkeinen 	r = dss_mgr_connect(mgr, dssdev);
692f76ee892STomi Valkeinen 	if (r)
693f76ee892STomi Valkeinen 		return r;
694f76ee892STomi Valkeinen 
695f76ee892STomi Valkeinen 	r = omapdss_output_set_device(dssdev, dst);
696f76ee892STomi Valkeinen 	if (r) {
697f76ee892STomi Valkeinen 		DSSERR("failed to connect output to new device: %s\n",
698f76ee892STomi Valkeinen 				dst->name);
699f76ee892STomi Valkeinen 		dss_mgr_disconnect(mgr, dssdev);
700f76ee892STomi Valkeinen 		return r;
701f76ee892STomi Valkeinen 	}
702f76ee892STomi Valkeinen 
703f76ee892STomi Valkeinen 	return 0;
704f76ee892STomi Valkeinen }
705f76ee892STomi Valkeinen 
venc_disconnect(struct omap_dss_device * dssdev,struct omap_dss_device * dst)706f76ee892STomi Valkeinen static void venc_disconnect(struct omap_dss_device *dssdev,
707f76ee892STomi Valkeinen 		struct omap_dss_device *dst)
708f76ee892STomi Valkeinen {
709f76ee892STomi Valkeinen 	WARN_ON(dst != dssdev->dst);
710f76ee892STomi Valkeinen 
711f76ee892STomi Valkeinen 	if (dst != dssdev->dst)
712f76ee892STomi Valkeinen 		return;
713f76ee892STomi Valkeinen 
714f76ee892STomi Valkeinen 	omapdss_output_unset_device(dssdev);
715f76ee892STomi Valkeinen 
716f76ee892STomi Valkeinen 	if (dssdev->manager)
717f76ee892STomi Valkeinen 		dss_mgr_disconnect(dssdev->manager, dssdev);
718f76ee892STomi Valkeinen }
719f76ee892STomi Valkeinen 
720f76ee892STomi Valkeinen static const struct omapdss_atv_ops venc_ops = {
721f76ee892STomi Valkeinen 	.connect = venc_connect,
722f76ee892STomi Valkeinen 	.disconnect = venc_disconnect,
723f76ee892STomi Valkeinen 
724f76ee892STomi Valkeinen 	.enable = venc_display_enable,
725f76ee892STomi Valkeinen 	.disable = venc_display_disable,
726f76ee892STomi Valkeinen 
727f76ee892STomi Valkeinen 	.check_timings = venc_check_timings,
728f76ee892STomi Valkeinen 	.set_timings = venc_set_timings,
729f76ee892STomi Valkeinen 	.get_timings = venc_get_timings,
730f76ee892STomi Valkeinen 
731f76ee892STomi Valkeinen 	.set_type = venc_set_type,
732f76ee892STomi Valkeinen 	.invert_vid_out_polarity = venc_invert_vid_out_polarity,
733f76ee892STomi Valkeinen 
734f76ee892STomi Valkeinen 	.set_wss = venc_set_wss,
735f76ee892STomi Valkeinen 	.get_wss = venc_get_wss,
736f76ee892STomi Valkeinen };
737f76ee892STomi Valkeinen 
venc_init_output(struct platform_device * pdev)738f76ee892STomi Valkeinen static void venc_init_output(struct platform_device *pdev)
739f76ee892STomi Valkeinen {
740f76ee892STomi Valkeinen 	struct omap_dss_device *out = &venc.output;
741f76ee892STomi Valkeinen 
742f76ee892STomi Valkeinen 	out->dev = &pdev->dev;
743f76ee892STomi Valkeinen 	out->id = OMAP_DSS_OUTPUT_VENC;
744f76ee892STomi Valkeinen 	out->output_type = OMAP_DISPLAY_TYPE_VENC;
745f76ee892STomi Valkeinen 	out->name = "venc.0";
746f76ee892STomi Valkeinen 	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
747f76ee892STomi Valkeinen 	out->ops.atv = &venc_ops;
748f76ee892STomi Valkeinen 	out->owner = THIS_MODULE;
749f76ee892STomi Valkeinen 
750f76ee892STomi Valkeinen 	omapdss_register_output(out);
751f76ee892STomi Valkeinen }
752f76ee892STomi Valkeinen 
venc_uninit_output(struct platform_device * pdev)753f76ee892STomi Valkeinen static void venc_uninit_output(struct platform_device *pdev)
754f76ee892STomi Valkeinen {
755f76ee892STomi Valkeinen 	struct omap_dss_device *out = &venc.output;
756f76ee892STomi Valkeinen 
757f76ee892STomi Valkeinen 	omapdss_unregister_output(out);
758f76ee892STomi Valkeinen }
759f76ee892STomi Valkeinen 
venc_probe_of(struct platform_device * pdev)760f76ee892STomi Valkeinen static int venc_probe_of(struct platform_device *pdev)
761f76ee892STomi Valkeinen {
762f76ee892STomi Valkeinen 	struct device_node *node = pdev->dev.of_node;
763f76ee892STomi Valkeinen 	struct device_node *ep;
764f76ee892STomi Valkeinen 	u32 channels;
765f76ee892STomi Valkeinen 	int r;
766f76ee892STomi Valkeinen 
767f76ee892STomi Valkeinen 	ep = omapdss_of_get_first_endpoint(node);
768f76ee892STomi Valkeinen 	if (!ep)
769f76ee892STomi Valkeinen 		return 0;
770f76ee892STomi Valkeinen 
771f76ee892STomi Valkeinen 	venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");
772f76ee892STomi Valkeinen 
773f76ee892STomi Valkeinen 	r = of_property_read_u32(ep, "ti,channels", &channels);
774f76ee892STomi Valkeinen 	if (r) {
775f76ee892STomi Valkeinen 		dev_err(&pdev->dev,
776f76ee892STomi Valkeinen 			"failed to read property 'ti,channels': %d\n", r);
777f76ee892STomi Valkeinen 		goto err;
778f76ee892STomi Valkeinen 	}
779f76ee892STomi Valkeinen 
780f76ee892STomi Valkeinen 	switch (channels) {
781f76ee892STomi Valkeinen 	case 1:
782f76ee892STomi Valkeinen 		venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
783f76ee892STomi Valkeinen 		break;
784f76ee892STomi Valkeinen 	case 2:
785f76ee892STomi Valkeinen 		venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
786f76ee892STomi Valkeinen 		break;
787f76ee892STomi Valkeinen 	default:
788fe2ab107SColin Ian King 		dev_err(&pdev->dev, "bad channel property '%d'\n", channels);
789f76ee892STomi Valkeinen 		r = -EINVAL;
790f76ee892STomi Valkeinen 		goto err;
791f76ee892STomi Valkeinen 	}
792f76ee892STomi Valkeinen 
793f76ee892STomi Valkeinen 	of_node_put(ep);
794f76ee892STomi Valkeinen 
795f76ee892STomi Valkeinen 	return 0;
796f76ee892STomi Valkeinen err:
797f76ee892STomi Valkeinen 	of_node_put(ep);
798f76ee892STomi Valkeinen 
799f76ee892STomi Valkeinen 	return 0;
800f76ee892STomi Valkeinen }
801f76ee892STomi Valkeinen 
802f76ee892STomi Valkeinen /* VENC HW IP initialisation */
venc_bind(struct device * dev,struct device * master,void * data)803f76ee892STomi Valkeinen static int venc_bind(struct device *dev, struct device *master, void *data)
804f76ee892STomi Valkeinen {
805f76ee892STomi Valkeinen 	struct platform_device *pdev = to_platform_device(dev);
806f76ee892STomi Valkeinen 	u8 rev_id;
807f76ee892STomi Valkeinen 	struct resource *venc_mem;
808f76ee892STomi Valkeinen 	int r;
809f76ee892STomi Valkeinen 
810f76ee892STomi Valkeinen 	venc.pdev = pdev;
811f76ee892STomi Valkeinen 
812f76ee892STomi Valkeinen 	mutex_init(&venc.venc_lock);
813f76ee892STomi Valkeinen 
814f76ee892STomi Valkeinen 	venc.wss_data = 0;
815f76ee892STomi Valkeinen 
816f76ee892STomi Valkeinen 	venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
817f76ee892STomi Valkeinen 	if (!venc_mem) {
818f76ee892STomi Valkeinen 		DSSERR("can't get IORESOURCE_MEM VENC\n");
819f76ee892STomi Valkeinen 		return -EINVAL;
820f76ee892STomi Valkeinen 	}
821f76ee892STomi Valkeinen 
822f76ee892STomi Valkeinen 	venc.base = devm_ioremap(&pdev->dev, venc_mem->start,
823f76ee892STomi Valkeinen 				 resource_size(venc_mem));
824f76ee892STomi Valkeinen 	if (!venc.base) {
825f76ee892STomi Valkeinen 		DSSERR("can't ioremap VENC\n");
826f76ee892STomi Valkeinen 		return -ENOMEM;
827f76ee892STomi Valkeinen 	}
828f76ee892STomi Valkeinen 
829f76ee892STomi Valkeinen 	r = venc_get_clocks(pdev);
830f76ee892STomi Valkeinen 	if (r)
831f76ee892STomi Valkeinen 		return r;
832f76ee892STomi Valkeinen 
833f76ee892STomi Valkeinen 	pm_runtime_enable(&pdev->dev);
834f76ee892STomi Valkeinen 
835f76ee892STomi Valkeinen 	r = venc_runtime_get();
836f76ee892STomi Valkeinen 	if (r)
837f76ee892STomi Valkeinen 		goto err_runtime_get;
838f76ee892STomi Valkeinen 
839f76ee892STomi Valkeinen 	rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
840f76ee892STomi Valkeinen 	dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
841f76ee892STomi Valkeinen 
842f76ee892STomi Valkeinen 	venc_runtime_put();
843f76ee892STomi Valkeinen 
844f76ee892STomi Valkeinen 	if (pdev->dev.of_node) {
845f76ee892STomi Valkeinen 		r = venc_probe_of(pdev);
846f76ee892STomi Valkeinen 		if (r) {
847f76ee892STomi Valkeinen 			DSSERR("Invalid DT data\n");
848f76ee892STomi Valkeinen 			goto err_probe_of;
849f76ee892STomi Valkeinen 		}
850f76ee892STomi Valkeinen 	}
851f76ee892STomi Valkeinen 
852f76ee892STomi Valkeinen 	dss_debugfs_create_file("venc", venc_dump_regs);
853f76ee892STomi Valkeinen 
854f76ee892STomi Valkeinen 	venc_init_output(pdev);
855f76ee892STomi Valkeinen 
856f76ee892STomi Valkeinen 	return 0;
857f76ee892STomi Valkeinen 
858f76ee892STomi Valkeinen err_probe_of:
859f76ee892STomi Valkeinen err_runtime_get:
860f76ee892STomi Valkeinen 	pm_runtime_disable(&pdev->dev);
861f76ee892STomi Valkeinen 	return r;
862f76ee892STomi Valkeinen }
863f76ee892STomi Valkeinen 
venc_unbind(struct device * dev,struct device * master,void * data)864f76ee892STomi Valkeinen static void venc_unbind(struct device *dev, struct device *master, void *data)
865f76ee892STomi Valkeinen {
866f76ee892STomi Valkeinen 	struct platform_device *pdev = to_platform_device(dev);
867f76ee892STomi Valkeinen 
868f76ee892STomi Valkeinen 	venc_uninit_output(pdev);
869f76ee892STomi Valkeinen 
870f76ee892STomi Valkeinen 	pm_runtime_disable(&pdev->dev);
871f76ee892STomi Valkeinen }
872f76ee892STomi Valkeinen 
873f76ee892STomi Valkeinen static const struct component_ops venc_component_ops = {
874f76ee892STomi Valkeinen 	.bind	= venc_bind,
875f76ee892STomi Valkeinen 	.unbind	= venc_unbind,
876f76ee892STomi Valkeinen };
877f76ee892STomi Valkeinen 
venc_probe(struct platform_device * pdev)878f76ee892STomi Valkeinen static int venc_probe(struct platform_device *pdev)
879f76ee892STomi Valkeinen {
880f76ee892STomi Valkeinen 	return component_add(&pdev->dev, &venc_component_ops);
881f76ee892STomi Valkeinen }
882f76ee892STomi Valkeinen 
venc_remove(struct platform_device * pdev)883*dc6b77baSUwe Kleine-König static void venc_remove(struct platform_device *pdev)
884f76ee892STomi Valkeinen {
885f76ee892STomi Valkeinen 	component_del(&pdev->dev, &venc_component_ops);
886f76ee892STomi Valkeinen }
887f76ee892STomi Valkeinen 
venc_runtime_suspend(struct device * dev)888f76ee892STomi Valkeinen static int venc_runtime_suspend(struct device *dev)
889f76ee892STomi Valkeinen {
890f76ee892STomi Valkeinen 	clk_disable_unprepare(venc.tv_dac_clk);
891f76ee892STomi Valkeinen 
892f76ee892STomi Valkeinen 	dispc_runtime_put();
893f76ee892STomi Valkeinen 
894f76ee892STomi Valkeinen 	return 0;
895f76ee892STomi Valkeinen }
896f76ee892STomi Valkeinen 
venc_runtime_resume(struct device * dev)897f76ee892STomi Valkeinen static int venc_runtime_resume(struct device *dev)
898f76ee892STomi Valkeinen {
899f76ee892STomi Valkeinen 	int r;
900f76ee892STomi Valkeinen 
901f76ee892STomi Valkeinen 	r = dispc_runtime_get();
902f76ee892STomi Valkeinen 	if (r < 0)
903f76ee892STomi Valkeinen 		return r;
904f76ee892STomi Valkeinen 
905f76ee892STomi Valkeinen 	clk_prepare_enable(venc.tv_dac_clk);
906f76ee892STomi Valkeinen 
907f76ee892STomi Valkeinen 	return 0;
908f76ee892STomi Valkeinen }
909f76ee892STomi Valkeinen 
910f76ee892STomi Valkeinen static const struct dev_pm_ops venc_pm_ops = {
911f76ee892STomi Valkeinen 	.runtime_suspend = venc_runtime_suspend,
912f76ee892STomi Valkeinen 	.runtime_resume = venc_runtime_resume,
913f76ee892STomi Valkeinen };
914f76ee892STomi Valkeinen 
915f76ee892STomi Valkeinen static const struct of_device_id venc_of_match[] = {
916f76ee892STomi Valkeinen 	{ .compatible = "ti,omap2-venc", },
917f76ee892STomi Valkeinen 	{ .compatible = "ti,omap3-venc", },
918f76ee892STomi Valkeinen 	{ .compatible = "ti,omap4-venc", },
919f76ee892STomi Valkeinen 	{},
920f76ee892STomi Valkeinen };
921f76ee892STomi Valkeinen 
922f76ee892STomi Valkeinen static struct platform_driver omap_venchw_driver = {
923f76ee892STomi Valkeinen 	.probe		= venc_probe,
924*dc6b77baSUwe Kleine-König 	.remove_new	= venc_remove,
925f76ee892STomi Valkeinen 	.driver         = {
926f76ee892STomi Valkeinen 		.name   = "omapdss_venc",
927f76ee892STomi Valkeinen 		.pm	= &venc_pm_ops,
928f76ee892STomi Valkeinen 		.of_match_table = venc_of_match,
929f76ee892STomi Valkeinen 		.suppress_bind_attrs = true,
930f76ee892STomi Valkeinen 	},
931f76ee892STomi Valkeinen };
932f76ee892STomi Valkeinen 
venc_init_platform_driver(void)933f76ee892STomi Valkeinen int __init venc_init_platform_driver(void)
934f76ee892STomi Valkeinen {
935f76ee892STomi Valkeinen 	return platform_driver_register(&omap_venchw_driver);
936f76ee892STomi Valkeinen }
937f76ee892STomi Valkeinen 
venc_uninit_platform_driver(void)938f76ee892STomi Valkeinen void venc_uninit_platform_driver(void)
939f76ee892STomi Valkeinen {
940f76ee892STomi Valkeinen 	platform_driver_unregister(&omap_venchw_driver);
941f76ee892STomi Valkeinen }
942