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