cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

venc.c (21805B)


      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	clk_disable_unprepare(venc.tv_dac_clk);
    894
    895	dispc_runtime_put();
    896
    897	return 0;
    898}
    899
    900static int venc_runtime_resume(struct device *dev)
    901{
    902	int r;
    903
    904	r = dispc_runtime_get();
    905	if (r < 0)
    906		return r;
    907
    908	clk_prepare_enable(venc.tv_dac_clk);
    909
    910	return 0;
    911}
    912
    913static const struct dev_pm_ops venc_pm_ops = {
    914	.runtime_suspend = venc_runtime_suspend,
    915	.runtime_resume = venc_runtime_resume,
    916};
    917
    918static const struct of_device_id venc_of_match[] = {
    919	{ .compatible = "ti,omap2-venc", },
    920	{ .compatible = "ti,omap3-venc", },
    921	{ .compatible = "ti,omap4-venc", },
    922	{},
    923};
    924
    925static struct platform_driver omap_venchw_driver = {
    926	.probe		= venc_probe,
    927	.remove		= venc_remove,
    928	.driver         = {
    929		.name   = "omapdss_venc",
    930		.pm	= &venc_pm_ops,
    931		.of_match_table = venc_of_match,
    932		.suppress_bind_attrs = true,
    933	},
    934};
    935
    936int __init venc_init_platform_driver(void)
    937{
    938	return platform_driver_register(&omap_venchw_driver);
    939}
    940
    941void venc_uninit_platform_driver(void)
    942{
    943	platform_driver_unregister(&omap_venchw_driver);
    944}