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