162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/drivers/video/omap2/dss/venc.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation
662306a36Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * VENC settings from TI's DSS driver
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define DSS_SUBSYS_NAME "VENC"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/clk.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/io.h>
1862306a36Sopenharmony_ci#include <linux/mutex.h>
1962306a36Sopenharmony_ci#include <linux/completion.h>
2062306a36Sopenharmony_ci#include <linux/delay.h>
2162306a36Sopenharmony_ci#include <linux/string.h>
2262306a36Sopenharmony_ci#include <linux/seq_file.h>
2362306a36Sopenharmony_ci#include <linux/platform_device.h>
2462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2562306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2662306a36Sopenharmony_ci#include <linux/of.h>
2762306a36Sopenharmony_ci#include <linux/component.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <video/omapfb_dss.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include "dss.h"
3262306a36Sopenharmony_ci#include "dss_features.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Venc registers */
3562306a36Sopenharmony_ci#define VENC_REV_ID				0x00
3662306a36Sopenharmony_ci#define VENC_STATUS				0x04
3762306a36Sopenharmony_ci#define VENC_F_CONTROL				0x08
3862306a36Sopenharmony_ci#define VENC_VIDOUT_CTRL			0x10
3962306a36Sopenharmony_ci#define VENC_SYNC_CTRL				0x14
4062306a36Sopenharmony_ci#define VENC_LLEN				0x1C
4162306a36Sopenharmony_ci#define VENC_FLENS				0x20
4262306a36Sopenharmony_ci#define VENC_HFLTR_CTRL				0x24
4362306a36Sopenharmony_ci#define VENC_CC_CARR_WSS_CARR			0x28
4462306a36Sopenharmony_ci#define VENC_C_PHASE				0x2C
4562306a36Sopenharmony_ci#define VENC_GAIN_U				0x30
4662306a36Sopenharmony_ci#define VENC_GAIN_V				0x34
4762306a36Sopenharmony_ci#define VENC_GAIN_Y				0x38
4862306a36Sopenharmony_ci#define VENC_BLACK_LEVEL			0x3C
4962306a36Sopenharmony_ci#define VENC_BLANK_LEVEL			0x40
5062306a36Sopenharmony_ci#define VENC_X_COLOR				0x44
5162306a36Sopenharmony_ci#define VENC_M_CONTROL				0x48
5262306a36Sopenharmony_ci#define VENC_BSTAMP_WSS_DATA			0x4C
5362306a36Sopenharmony_ci#define VENC_S_CARR				0x50
5462306a36Sopenharmony_ci#define VENC_LINE21				0x54
5562306a36Sopenharmony_ci#define VENC_LN_SEL				0x58
5662306a36Sopenharmony_ci#define VENC_L21__WC_CTL			0x5C
5762306a36Sopenharmony_ci#define VENC_HTRIGGER_VTRIGGER			0x60
5862306a36Sopenharmony_ci#define VENC_SAVID__EAVID			0x64
5962306a36Sopenharmony_ci#define VENC_FLEN__FAL				0x68
6062306a36Sopenharmony_ci#define VENC_LAL__PHASE_RESET			0x6C
6162306a36Sopenharmony_ci#define VENC_HS_INT_START_STOP_X		0x70
6262306a36Sopenharmony_ci#define VENC_HS_EXT_START_STOP_X		0x74
6362306a36Sopenharmony_ci#define VENC_VS_INT_START_X			0x78
6462306a36Sopenharmony_ci#define VENC_VS_INT_STOP_X__VS_INT_START_Y	0x7C
6562306a36Sopenharmony_ci#define VENC_VS_INT_STOP_Y__VS_EXT_START_X	0x80
6662306a36Sopenharmony_ci#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y	0x84
6762306a36Sopenharmony_ci#define VENC_VS_EXT_STOP_Y			0x88
6862306a36Sopenharmony_ci#define VENC_AVID_START_STOP_X			0x90
6962306a36Sopenharmony_ci#define VENC_AVID_START_STOP_Y			0x94
7062306a36Sopenharmony_ci#define VENC_FID_INT_START_X__FID_INT_START_Y	0xA0
7162306a36Sopenharmony_ci#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X	0xA4
7262306a36Sopenharmony_ci#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y	0xA8
7362306a36Sopenharmony_ci#define VENC_TVDETGP_INT_START_STOP_X		0xB0
7462306a36Sopenharmony_ci#define VENC_TVDETGP_INT_START_STOP_Y		0xB4
7562306a36Sopenharmony_ci#define VENC_GEN_CTRL				0xB8
7662306a36Sopenharmony_ci#define VENC_OUTPUT_CONTROL			0xC4
7762306a36Sopenharmony_ci#define VENC_OUTPUT_TEST			0xC8
7862306a36Sopenharmony_ci#define VENC_DAC_B__DAC_C			0xC8
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct venc_config {
8162306a36Sopenharmony_ci	u32 f_control;
8262306a36Sopenharmony_ci	u32 vidout_ctrl;
8362306a36Sopenharmony_ci	u32 sync_ctrl;
8462306a36Sopenharmony_ci	u32 llen;
8562306a36Sopenharmony_ci	u32 flens;
8662306a36Sopenharmony_ci	u32 hfltr_ctrl;
8762306a36Sopenharmony_ci	u32 cc_carr_wss_carr;
8862306a36Sopenharmony_ci	u32 c_phase;
8962306a36Sopenharmony_ci	u32 gain_u;
9062306a36Sopenharmony_ci	u32 gain_v;
9162306a36Sopenharmony_ci	u32 gain_y;
9262306a36Sopenharmony_ci	u32 black_level;
9362306a36Sopenharmony_ci	u32 blank_level;
9462306a36Sopenharmony_ci	u32 x_color;
9562306a36Sopenharmony_ci	u32 m_control;
9662306a36Sopenharmony_ci	u32 bstamp_wss_data;
9762306a36Sopenharmony_ci	u32 s_carr;
9862306a36Sopenharmony_ci	u32 line21;
9962306a36Sopenharmony_ci	u32 ln_sel;
10062306a36Sopenharmony_ci	u32 l21__wc_ctl;
10162306a36Sopenharmony_ci	u32 htrigger_vtrigger;
10262306a36Sopenharmony_ci	u32 savid__eavid;
10362306a36Sopenharmony_ci	u32 flen__fal;
10462306a36Sopenharmony_ci	u32 lal__phase_reset;
10562306a36Sopenharmony_ci	u32 hs_int_start_stop_x;
10662306a36Sopenharmony_ci	u32 hs_ext_start_stop_x;
10762306a36Sopenharmony_ci	u32 vs_int_start_x;
10862306a36Sopenharmony_ci	u32 vs_int_stop_x__vs_int_start_y;
10962306a36Sopenharmony_ci	u32 vs_int_stop_y__vs_ext_start_x;
11062306a36Sopenharmony_ci	u32 vs_ext_stop_x__vs_ext_start_y;
11162306a36Sopenharmony_ci	u32 vs_ext_stop_y;
11262306a36Sopenharmony_ci	u32 avid_start_stop_x;
11362306a36Sopenharmony_ci	u32 avid_start_stop_y;
11462306a36Sopenharmony_ci	u32 fid_int_start_x__fid_int_start_y;
11562306a36Sopenharmony_ci	u32 fid_int_offset_y__fid_ext_start_x;
11662306a36Sopenharmony_ci	u32 fid_ext_start_y__fid_ext_offset_y;
11762306a36Sopenharmony_ci	u32 tvdetgp_int_start_stop_x;
11862306a36Sopenharmony_ci	u32 tvdetgp_int_start_stop_y;
11962306a36Sopenharmony_ci	u32 gen_ctrl;
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* from TRM */
12362306a36Sopenharmony_cistatic const struct venc_config venc_config_pal_trm = {
12462306a36Sopenharmony_ci	.f_control				= 0,
12562306a36Sopenharmony_ci	.vidout_ctrl				= 1,
12662306a36Sopenharmony_ci	.sync_ctrl				= 0x40,
12762306a36Sopenharmony_ci	.llen					= 0x35F, /* 863 */
12862306a36Sopenharmony_ci	.flens					= 0x270, /* 624 */
12962306a36Sopenharmony_ci	.hfltr_ctrl				= 0,
13062306a36Sopenharmony_ci	.cc_carr_wss_carr			= 0x2F7225ED,
13162306a36Sopenharmony_ci	.c_phase				= 0,
13262306a36Sopenharmony_ci	.gain_u					= 0x111,
13362306a36Sopenharmony_ci	.gain_v					= 0x181,
13462306a36Sopenharmony_ci	.gain_y					= 0x140,
13562306a36Sopenharmony_ci	.black_level				= 0x3B,
13662306a36Sopenharmony_ci	.blank_level				= 0x3B,
13762306a36Sopenharmony_ci	.x_color				= 0x7,
13862306a36Sopenharmony_ci	.m_control				= 0x2,
13962306a36Sopenharmony_ci	.bstamp_wss_data			= 0x3F,
14062306a36Sopenharmony_ci	.s_carr					= 0x2A098ACB,
14162306a36Sopenharmony_ci	.line21					= 0,
14262306a36Sopenharmony_ci	.ln_sel					= 0x01290015,
14362306a36Sopenharmony_ci	.l21__wc_ctl				= 0x0000F603,
14462306a36Sopenharmony_ci	.htrigger_vtrigger			= 0,
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	.savid__eavid				= 0x06A70108,
14762306a36Sopenharmony_ci	.flen__fal				= 0x00180270,
14862306a36Sopenharmony_ci	.lal__phase_reset			= 0x00040135,
14962306a36Sopenharmony_ci	.hs_int_start_stop_x			= 0x00880358,
15062306a36Sopenharmony_ci	.hs_ext_start_stop_x			= 0x000F035F,
15162306a36Sopenharmony_ci	.vs_int_start_x				= 0x01A70000,
15262306a36Sopenharmony_ci	.vs_int_stop_x__vs_int_start_y		= 0x000001A7,
15362306a36Sopenharmony_ci	.vs_int_stop_y__vs_ext_start_x		= 0x01AF0000,
15462306a36Sopenharmony_ci	.vs_ext_stop_x__vs_ext_start_y		= 0x000101AF,
15562306a36Sopenharmony_ci	.vs_ext_stop_y				= 0x00000025,
15662306a36Sopenharmony_ci	.avid_start_stop_x			= 0x03530083,
15762306a36Sopenharmony_ci	.avid_start_stop_y			= 0x026C002E,
15862306a36Sopenharmony_ci	.fid_int_start_x__fid_int_start_y	= 0x0001008A,
15962306a36Sopenharmony_ci	.fid_int_offset_y__fid_ext_start_x	= 0x002E0138,
16062306a36Sopenharmony_ci	.fid_ext_start_y__fid_ext_offset_y	= 0x01380001,
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	.tvdetgp_int_start_stop_x		= 0x00140001,
16362306a36Sopenharmony_ci	.tvdetgp_int_start_stop_y		= 0x00010001,
16462306a36Sopenharmony_ci	.gen_ctrl				= 0x00FF0000,
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/* from TRM */
16862306a36Sopenharmony_cistatic const struct venc_config venc_config_ntsc_trm = {
16962306a36Sopenharmony_ci	.f_control				= 0,
17062306a36Sopenharmony_ci	.vidout_ctrl				= 1,
17162306a36Sopenharmony_ci	.sync_ctrl				= 0x8040,
17262306a36Sopenharmony_ci	.llen					= 0x359,
17362306a36Sopenharmony_ci	.flens					= 0x20C,
17462306a36Sopenharmony_ci	.hfltr_ctrl				= 0,
17562306a36Sopenharmony_ci	.cc_carr_wss_carr			= 0x043F2631,
17662306a36Sopenharmony_ci	.c_phase				= 0,
17762306a36Sopenharmony_ci	.gain_u					= 0x102,
17862306a36Sopenharmony_ci	.gain_v					= 0x16C,
17962306a36Sopenharmony_ci	.gain_y					= 0x12F,
18062306a36Sopenharmony_ci	.black_level				= 0x43,
18162306a36Sopenharmony_ci	.blank_level				= 0x38,
18262306a36Sopenharmony_ci	.x_color				= 0x7,
18362306a36Sopenharmony_ci	.m_control				= 0x1,
18462306a36Sopenharmony_ci	.bstamp_wss_data			= 0x38,
18562306a36Sopenharmony_ci	.s_carr					= 0x21F07C1F,
18662306a36Sopenharmony_ci	.line21					= 0,
18762306a36Sopenharmony_ci	.ln_sel					= 0x01310011,
18862306a36Sopenharmony_ci	.l21__wc_ctl				= 0x0000F003,
18962306a36Sopenharmony_ci	.htrigger_vtrigger			= 0,
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	.savid__eavid				= 0x069300F4,
19262306a36Sopenharmony_ci	.flen__fal				= 0x0016020C,
19362306a36Sopenharmony_ci	.lal__phase_reset			= 0x00060107,
19462306a36Sopenharmony_ci	.hs_int_start_stop_x			= 0x008E0350,
19562306a36Sopenharmony_ci	.hs_ext_start_stop_x			= 0x000F0359,
19662306a36Sopenharmony_ci	.vs_int_start_x				= 0x01A00000,
19762306a36Sopenharmony_ci	.vs_int_stop_x__vs_int_start_y		= 0x020701A0,
19862306a36Sopenharmony_ci	.vs_int_stop_y__vs_ext_start_x		= 0x01AC0024,
19962306a36Sopenharmony_ci	.vs_ext_stop_x__vs_ext_start_y		= 0x020D01AC,
20062306a36Sopenharmony_ci	.vs_ext_stop_y				= 0x00000006,
20162306a36Sopenharmony_ci	.avid_start_stop_x			= 0x03480078,
20262306a36Sopenharmony_ci	.avid_start_stop_y			= 0x02060024,
20362306a36Sopenharmony_ci	.fid_int_start_x__fid_int_start_y	= 0x0001008A,
20462306a36Sopenharmony_ci	.fid_int_offset_y__fid_ext_start_x	= 0x01AC0106,
20562306a36Sopenharmony_ci	.fid_ext_start_y__fid_ext_offset_y	= 0x01060006,
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	.tvdetgp_int_start_stop_x		= 0x00140001,
20862306a36Sopenharmony_ci	.tvdetgp_int_start_stop_y		= 0x00010001,
20962306a36Sopenharmony_ci	.gen_ctrl				= 0x00F90000,
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ciconst struct omap_video_timings omap_dss_pal_timings = {
21362306a36Sopenharmony_ci	.x_res		= 720,
21462306a36Sopenharmony_ci	.y_res		= 574,
21562306a36Sopenharmony_ci	.pixelclock	= 13500000,
21662306a36Sopenharmony_ci	.hsw		= 64,
21762306a36Sopenharmony_ci	.hfp		= 12,
21862306a36Sopenharmony_ci	.hbp		= 68,
21962306a36Sopenharmony_ci	.vsw		= 5,
22062306a36Sopenharmony_ci	.vfp		= 5,
22162306a36Sopenharmony_ci	.vbp		= 41,
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	.interlace	= true,
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ciEXPORT_SYMBOL(omap_dss_pal_timings);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ciconst struct omap_video_timings omap_dss_ntsc_timings = {
22862306a36Sopenharmony_ci	.x_res		= 720,
22962306a36Sopenharmony_ci	.y_res		= 482,
23062306a36Sopenharmony_ci	.pixelclock	= 13500000,
23162306a36Sopenharmony_ci	.hsw		= 64,
23262306a36Sopenharmony_ci	.hfp		= 16,
23362306a36Sopenharmony_ci	.hbp		= 58,
23462306a36Sopenharmony_ci	.vsw		= 6,
23562306a36Sopenharmony_ci	.vfp		= 6,
23662306a36Sopenharmony_ci	.vbp		= 31,
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	.interlace	= true,
23962306a36Sopenharmony_ci};
24062306a36Sopenharmony_ciEXPORT_SYMBOL(omap_dss_ntsc_timings);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic struct {
24362306a36Sopenharmony_ci	struct platform_device *pdev;
24462306a36Sopenharmony_ci	void __iomem *base;
24562306a36Sopenharmony_ci	struct mutex venc_lock;
24662306a36Sopenharmony_ci	u32 wss_data;
24762306a36Sopenharmony_ci	struct regulator *vdda_dac_reg;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	struct clk	*tv_dac_clk;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	struct omap_video_timings timings;
25262306a36Sopenharmony_ci	enum omap_dss_venc_type type;
25362306a36Sopenharmony_ci	bool invert_polarity;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	struct omap_dss_device output;
25662306a36Sopenharmony_ci} venc;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic inline void venc_write_reg(int idx, u32 val)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	__raw_writel(val, venc.base + idx);
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic inline u32 venc_read_reg(int idx)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	u32 l = __raw_readl(venc.base + idx);
26662306a36Sopenharmony_ci	return l;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic void venc_write_config(const struct venc_config *config)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	DSSDBG("write venc conf\n");
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	venc_write_reg(VENC_LLEN, config->llen);
27462306a36Sopenharmony_ci	venc_write_reg(VENC_FLENS, config->flens);
27562306a36Sopenharmony_ci	venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
27662306a36Sopenharmony_ci	venc_write_reg(VENC_C_PHASE, config->c_phase);
27762306a36Sopenharmony_ci	venc_write_reg(VENC_GAIN_U, config->gain_u);
27862306a36Sopenharmony_ci	venc_write_reg(VENC_GAIN_V, config->gain_v);
27962306a36Sopenharmony_ci	venc_write_reg(VENC_GAIN_Y, config->gain_y);
28062306a36Sopenharmony_ci	venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
28162306a36Sopenharmony_ci	venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
28262306a36Sopenharmony_ci	venc_write_reg(VENC_M_CONTROL, config->m_control);
28362306a36Sopenharmony_ci	venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
28462306a36Sopenharmony_ci			venc.wss_data);
28562306a36Sopenharmony_ci	venc_write_reg(VENC_S_CARR, config->s_carr);
28662306a36Sopenharmony_ci	venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
28762306a36Sopenharmony_ci	venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
28862306a36Sopenharmony_ci	venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
28962306a36Sopenharmony_ci	venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
29062306a36Sopenharmony_ci	venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
29162306a36Sopenharmony_ci	venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
29262306a36Sopenharmony_ci	venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
29362306a36Sopenharmony_ci	venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
29462306a36Sopenharmony_ci		       config->vs_int_stop_x__vs_int_start_y);
29562306a36Sopenharmony_ci	venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
29662306a36Sopenharmony_ci		       config->vs_int_stop_y__vs_ext_start_x);
29762306a36Sopenharmony_ci	venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
29862306a36Sopenharmony_ci		       config->vs_ext_stop_x__vs_ext_start_y);
29962306a36Sopenharmony_ci	venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
30062306a36Sopenharmony_ci	venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
30162306a36Sopenharmony_ci	venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
30262306a36Sopenharmony_ci	venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
30362306a36Sopenharmony_ci		       config->fid_int_start_x__fid_int_start_y);
30462306a36Sopenharmony_ci	venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
30562306a36Sopenharmony_ci		       config->fid_int_offset_y__fid_ext_start_x);
30662306a36Sopenharmony_ci	venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
30762306a36Sopenharmony_ci		       config->fid_ext_start_y__fid_ext_offset_y);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	venc_write_reg(VENC_DAC_B__DAC_C,  venc_read_reg(VENC_DAC_B__DAC_C));
31062306a36Sopenharmony_ci	venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
31162306a36Sopenharmony_ci	venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
31262306a36Sopenharmony_ci	venc_write_reg(VENC_X_COLOR, config->x_color);
31362306a36Sopenharmony_ci	venc_write_reg(VENC_LINE21, config->line21);
31462306a36Sopenharmony_ci	venc_write_reg(VENC_LN_SEL, config->ln_sel);
31562306a36Sopenharmony_ci	venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
31662306a36Sopenharmony_ci	venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
31762306a36Sopenharmony_ci		       config->tvdetgp_int_start_stop_x);
31862306a36Sopenharmony_ci	venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
31962306a36Sopenharmony_ci		       config->tvdetgp_int_start_stop_y);
32062306a36Sopenharmony_ci	venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
32162306a36Sopenharmony_ci	venc_write_reg(VENC_F_CONTROL, config->f_control);
32262306a36Sopenharmony_ci	venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic void venc_reset(void)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	int t = 1000;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	venc_write_reg(VENC_F_CONTROL, 1<<8);
33062306a36Sopenharmony_ci	while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
33162306a36Sopenharmony_ci		if (--t == 0) {
33262306a36Sopenharmony_ci			DSSERR("Failed to reset venc\n");
33362306a36Sopenharmony_ci			return;
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci#ifdef CONFIG_FB_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
33862306a36Sopenharmony_ci	/* the magical sleep that makes things work */
33962306a36Sopenharmony_ci	/* XXX more info? What bug this circumvents? */
34062306a36Sopenharmony_ci	msleep(20);
34162306a36Sopenharmony_ci#endif
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int venc_runtime_get(void)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	int r;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	DSSDBG("venc_runtime_get\n");
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	r = pm_runtime_resume_and_get(&venc.pdev->dev);
35162306a36Sopenharmony_ci	if (WARN_ON(r < 0))
35262306a36Sopenharmony_ci		return r;
35362306a36Sopenharmony_ci	return 0;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void venc_runtime_put(void)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	int r;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	DSSDBG("venc_runtime_put\n");
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	r = pm_runtime_put_sync(&venc.pdev->dev);
36362306a36Sopenharmony_ci	WARN_ON(r < 0 && r != -ENOSYS);
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic const struct venc_config *venc_timings_to_config(
36762306a36Sopenharmony_ci		struct omap_video_timings *timings)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
37062306a36Sopenharmony_ci		return &venc_config_pal_trm;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
37362306a36Sopenharmony_ci		return &venc_config_ntsc_trm;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	BUG();
37662306a36Sopenharmony_ci	return NULL;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic int venc_power_on(struct omap_dss_device *dssdev)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct omap_overlay_manager *mgr = venc.output.manager;
38262306a36Sopenharmony_ci	u32 l;
38362306a36Sopenharmony_ci	int r;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	r = venc_runtime_get();
38662306a36Sopenharmony_ci	if (r)
38762306a36Sopenharmony_ci		goto err0;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	venc_reset();
39062306a36Sopenharmony_ci	venc_write_config(venc_timings_to_config(&venc.timings));
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	dss_set_venc_output(venc.type);
39362306a36Sopenharmony_ci	dss_set_dac_pwrdn_bgz(1);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	l = 0;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
39862306a36Sopenharmony_ci		l |= 1 << 1;
39962306a36Sopenharmony_ci	else /* S-Video */
40062306a36Sopenharmony_ci		l |= (1 << 0) | (1 << 2);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (venc.invert_polarity == false)
40362306a36Sopenharmony_ci		l |= 1 << 3;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	venc_write_reg(VENC_OUTPUT_CONTROL, l);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	dss_mgr_set_timings(mgr, &venc.timings);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	r = regulator_enable(venc.vdda_dac_reg);
41062306a36Sopenharmony_ci	if (r)
41162306a36Sopenharmony_ci		goto err1;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	r = dss_mgr_enable(mgr);
41462306a36Sopenharmony_ci	if (r)
41562306a36Sopenharmony_ci		goto err2;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	return 0;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cierr2:
42062306a36Sopenharmony_ci	regulator_disable(venc.vdda_dac_reg);
42162306a36Sopenharmony_cierr1:
42262306a36Sopenharmony_ci	venc_write_reg(VENC_OUTPUT_CONTROL, 0);
42362306a36Sopenharmony_ci	dss_set_dac_pwrdn_bgz(0);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	venc_runtime_put();
42662306a36Sopenharmony_cierr0:
42762306a36Sopenharmony_ci	return r;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void venc_power_off(struct omap_dss_device *dssdev)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct omap_overlay_manager *mgr = venc.output.manager;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	venc_write_reg(VENC_OUTPUT_CONTROL, 0);
43562306a36Sopenharmony_ci	dss_set_dac_pwrdn_bgz(0);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	dss_mgr_disable(mgr);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	regulator_disable(venc.vdda_dac_reg);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	venc_runtime_put();
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic int venc_display_enable(struct omap_dss_device *dssdev)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct omap_dss_device *out = &venc.output;
44762306a36Sopenharmony_ci	int r;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	DSSDBG("venc_display_enable\n");
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	mutex_lock(&venc.venc_lock);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (out->manager == NULL) {
45462306a36Sopenharmony_ci		DSSERR("Failed to enable display: no output/manager\n");
45562306a36Sopenharmony_ci		r = -ENODEV;
45662306a36Sopenharmony_ci		goto err0;
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	r = venc_power_on(dssdev);
46062306a36Sopenharmony_ci	if (r)
46162306a36Sopenharmony_ci		goto err0;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	venc.wss_data = 0;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	mutex_unlock(&venc.venc_lock);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	return 0;
46862306a36Sopenharmony_cierr0:
46962306a36Sopenharmony_ci	mutex_unlock(&venc.venc_lock);
47062306a36Sopenharmony_ci	return r;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic void venc_display_disable(struct omap_dss_device *dssdev)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	DSSDBG("venc_display_disable\n");
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	mutex_lock(&venc.venc_lock);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	venc_power_off(dssdev);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	mutex_unlock(&venc.venc_lock);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic void venc_set_timings(struct omap_dss_device *dssdev,
48562306a36Sopenharmony_ci		struct omap_video_timings *timings)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	DSSDBG("venc_set_timings\n");
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	mutex_lock(&venc.venc_lock);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* Reset WSS data when the TV standard changes. */
49262306a36Sopenharmony_ci	if (memcmp(&venc.timings, timings, sizeof(*timings)))
49362306a36Sopenharmony_ci		venc.wss_data = 0;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	venc.timings = *timings;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	dispc_set_tv_pclk(13500000);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	mutex_unlock(&venc.venc_lock);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic int venc_check_timings(struct omap_dss_device *dssdev,
50362306a36Sopenharmony_ci		struct omap_video_timings *timings)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	DSSDBG("venc_check_timings\n");
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
50862306a36Sopenharmony_ci		return 0;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
51162306a36Sopenharmony_ci		return 0;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	return -EINVAL;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic void venc_get_timings(struct omap_dss_device *dssdev,
51762306a36Sopenharmony_ci		struct omap_video_timings *timings)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	mutex_lock(&venc.venc_lock);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	*timings = venc.timings;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	mutex_unlock(&venc.venc_lock);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic u32 venc_get_wss(struct omap_dss_device *dssdev)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	/* Invert due to VENC_L21_WC_CTL:INV=1 */
52962306a36Sopenharmony_ci	return (venc.wss_data >> 8) ^ 0xfffff;
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	const struct venc_config *config;
53562306a36Sopenharmony_ci	int r;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	DSSDBG("venc_set_wss\n");
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	mutex_lock(&venc.venc_lock);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	config = venc_timings_to_config(&venc.timings);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* Invert due to VENC_L21_WC_CTL:INV=1 */
54462306a36Sopenharmony_ci	venc.wss_data = (wss ^ 0xfffff) << 8;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	r = venc_runtime_get();
54762306a36Sopenharmony_ci	if (r)
54862306a36Sopenharmony_ci		goto err;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
55162306a36Sopenharmony_ci			venc.wss_data);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	venc_runtime_put();
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cierr:
55662306a36Sopenharmony_ci	mutex_unlock(&venc.venc_lock);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return r;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic void venc_set_type(struct omap_dss_device *dssdev,
56262306a36Sopenharmony_ci		enum omap_dss_venc_type type)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	mutex_lock(&venc.venc_lock);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	venc.type = type;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	mutex_unlock(&venc.venc_lock);
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cistatic void venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
57262306a36Sopenharmony_ci		bool invert_polarity)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	mutex_lock(&venc.venc_lock);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	venc.invert_polarity = invert_polarity;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	mutex_unlock(&venc.venc_lock);
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic int venc_init_regulator(void)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct regulator *vdda_dac;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	if (venc.vdda_dac_reg != NULL)
58662306a36Sopenharmony_ci		return 0;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (venc.pdev->dev.of_node)
58962306a36Sopenharmony_ci		vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda");
59062306a36Sopenharmony_ci	else
59162306a36Sopenharmony_ci		vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac");
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (IS_ERR(vdda_dac)) {
59462306a36Sopenharmony_ci		if (PTR_ERR(vdda_dac) != -EPROBE_DEFER)
59562306a36Sopenharmony_ci			DSSERR("can't get VDDA_DAC regulator\n");
59662306a36Sopenharmony_ci		return PTR_ERR(vdda_dac);
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	venc.vdda_dac_reg = vdda_dac;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	return 0;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic void venc_dump_regs(struct seq_file *s)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (venc_runtime_get())
60962306a36Sopenharmony_ci		return;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	DUMPREG(VENC_F_CONTROL);
61262306a36Sopenharmony_ci	DUMPREG(VENC_VIDOUT_CTRL);
61362306a36Sopenharmony_ci	DUMPREG(VENC_SYNC_CTRL);
61462306a36Sopenharmony_ci	DUMPREG(VENC_LLEN);
61562306a36Sopenharmony_ci	DUMPREG(VENC_FLENS);
61662306a36Sopenharmony_ci	DUMPREG(VENC_HFLTR_CTRL);
61762306a36Sopenharmony_ci	DUMPREG(VENC_CC_CARR_WSS_CARR);
61862306a36Sopenharmony_ci	DUMPREG(VENC_C_PHASE);
61962306a36Sopenharmony_ci	DUMPREG(VENC_GAIN_U);
62062306a36Sopenharmony_ci	DUMPREG(VENC_GAIN_V);
62162306a36Sopenharmony_ci	DUMPREG(VENC_GAIN_Y);
62262306a36Sopenharmony_ci	DUMPREG(VENC_BLACK_LEVEL);
62362306a36Sopenharmony_ci	DUMPREG(VENC_BLANK_LEVEL);
62462306a36Sopenharmony_ci	DUMPREG(VENC_X_COLOR);
62562306a36Sopenharmony_ci	DUMPREG(VENC_M_CONTROL);
62662306a36Sopenharmony_ci	DUMPREG(VENC_BSTAMP_WSS_DATA);
62762306a36Sopenharmony_ci	DUMPREG(VENC_S_CARR);
62862306a36Sopenharmony_ci	DUMPREG(VENC_LINE21);
62962306a36Sopenharmony_ci	DUMPREG(VENC_LN_SEL);
63062306a36Sopenharmony_ci	DUMPREG(VENC_L21__WC_CTL);
63162306a36Sopenharmony_ci	DUMPREG(VENC_HTRIGGER_VTRIGGER);
63262306a36Sopenharmony_ci	DUMPREG(VENC_SAVID__EAVID);
63362306a36Sopenharmony_ci	DUMPREG(VENC_FLEN__FAL);
63462306a36Sopenharmony_ci	DUMPREG(VENC_LAL__PHASE_RESET);
63562306a36Sopenharmony_ci	DUMPREG(VENC_HS_INT_START_STOP_X);
63662306a36Sopenharmony_ci	DUMPREG(VENC_HS_EXT_START_STOP_X);
63762306a36Sopenharmony_ci	DUMPREG(VENC_VS_INT_START_X);
63862306a36Sopenharmony_ci	DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
63962306a36Sopenharmony_ci	DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
64062306a36Sopenharmony_ci	DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
64162306a36Sopenharmony_ci	DUMPREG(VENC_VS_EXT_STOP_Y);
64262306a36Sopenharmony_ci	DUMPREG(VENC_AVID_START_STOP_X);
64362306a36Sopenharmony_ci	DUMPREG(VENC_AVID_START_STOP_Y);
64462306a36Sopenharmony_ci	DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
64562306a36Sopenharmony_ci	DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
64662306a36Sopenharmony_ci	DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
64762306a36Sopenharmony_ci	DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
64862306a36Sopenharmony_ci	DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
64962306a36Sopenharmony_ci	DUMPREG(VENC_GEN_CTRL);
65062306a36Sopenharmony_ci	DUMPREG(VENC_OUTPUT_CONTROL);
65162306a36Sopenharmony_ci	DUMPREG(VENC_OUTPUT_TEST);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	venc_runtime_put();
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci#undef DUMPREG
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic int venc_get_clocks(struct platform_device *pdev)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	struct clk *clk;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
66362306a36Sopenharmony_ci		clk = devm_clk_get(&pdev->dev, "tv_dac_clk");
66462306a36Sopenharmony_ci		if (IS_ERR(clk)) {
66562306a36Sopenharmony_ci			DSSERR("can't get tv_dac_clk\n");
66662306a36Sopenharmony_ci			return PTR_ERR(clk);
66762306a36Sopenharmony_ci		}
66862306a36Sopenharmony_ci	} else {
66962306a36Sopenharmony_ci		clk = NULL;
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	venc.tv_dac_clk = clk;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	return 0;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic int venc_connect(struct omap_dss_device *dssdev,
67862306a36Sopenharmony_ci		struct omap_dss_device *dst)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct omap_overlay_manager *mgr;
68162306a36Sopenharmony_ci	int r;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	r = venc_init_regulator();
68462306a36Sopenharmony_ci	if (r)
68562306a36Sopenharmony_ci		return r;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
68862306a36Sopenharmony_ci	if (!mgr)
68962306a36Sopenharmony_ci		return -ENODEV;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	r = dss_mgr_connect(mgr, dssdev);
69262306a36Sopenharmony_ci	if (r)
69362306a36Sopenharmony_ci		return r;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	r = omapdss_output_set_device(dssdev, dst);
69662306a36Sopenharmony_ci	if (r) {
69762306a36Sopenharmony_ci		DSSERR("failed to connect output to new device: %s\n",
69862306a36Sopenharmony_ci				dst->name);
69962306a36Sopenharmony_ci		dss_mgr_disconnect(mgr, dssdev);
70062306a36Sopenharmony_ci		return r;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	return 0;
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic void venc_disconnect(struct omap_dss_device *dssdev,
70762306a36Sopenharmony_ci		struct omap_dss_device *dst)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	WARN_ON(dst != dssdev->dst);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (dst != dssdev->dst)
71262306a36Sopenharmony_ci		return;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	omapdss_output_unset_device(dssdev);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	if (dssdev->manager)
71762306a36Sopenharmony_ci		dss_mgr_disconnect(dssdev->manager, dssdev);
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic const struct omapdss_atv_ops venc_ops = {
72162306a36Sopenharmony_ci	.connect = venc_connect,
72262306a36Sopenharmony_ci	.disconnect = venc_disconnect,
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	.enable = venc_display_enable,
72562306a36Sopenharmony_ci	.disable = venc_display_disable,
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	.check_timings = venc_check_timings,
72862306a36Sopenharmony_ci	.set_timings = venc_set_timings,
72962306a36Sopenharmony_ci	.get_timings = venc_get_timings,
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	.set_type = venc_set_type,
73262306a36Sopenharmony_ci	.invert_vid_out_polarity = venc_invert_vid_out_polarity,
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	.set_wss = venc_set_wss,
73562306a36Sopenharmony_ci	.get_wss = venc_get_wss,
73662306a36Sopenharmony_ci};
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic void venc_init_output(struct platform_device *pdev)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct omap_dss_device *out = &venc.output;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	out->dev = &pdev->dev;
74362306a36Sopenharmony_ci	out->id = OMAP_DSS_OUTPUT_VENC;
74462306a36Sopenharmony_ci	out->output_type = OMAP_DISPLAY_TYPE_VENC;
74562306a36Sopenharmony_ci	out->name = "venc.0";
74662306a36Sopenharmony_ci	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
74762306a36Sopenharmony_ci	out->ops.atv = &venc_ops;
74862306a36Sopenharmony_ci	out->owner = THIS_MODULE;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	omapdss_register_output(out);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic void venc_uninit_output(struct platform_device *pdev)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	struct omap_dss_device *out = &venc.output;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	omapdss_unregister_output(out);
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic int venc_probe_of(struct platform_device *pdev)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
76362306a36Sopenharmony_ci	struct device_node *ep;
76462306a36Sopenharmony_ci	u32 channels;
76562306a36Sopenharmony_ci	int r;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	ep = omapdss_of_get_first_endpoint(node);
76862306a36Sopenharmony_ci	if (!ep)
76962306a36Sopenharmony_ci		return 0;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	r = of_property_read_u32(ep, "ti,channels", &channels);
77462306a36Sopenharmony_ci	if (r) {
77562306a36Sopenharmony_ci		dev_err(&pdev->dev,
77662306a36Sopenharmony_ci			"failed to read property 'ti,channels': %d\n", r);
77762306a36Sopenharmony_ci		goto err;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	switch (channels) {
78162306a36Sopenharmony_ci	case 1:
78262306a36Sopenharmony_ci		venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
78362306a36Sopenharmony_ci		break;
78462306a36Sopenharmony_ci	case 2:
78562306a36Sopenharmony_ci		venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
78662306a36Sopenharmony_ci		break;
78762306a36Sopenharmony_ci	default:
78862306a36Sopenharmony_ci		dev_err(&pdev->dev, "bad channel property '%d'\n", channels);
78962306a36Sopenharmony_ci		r = -EINVAL;
79062306a36Sopenharmony_ci		goto err;
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	of_node_put(ep);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	return 0;
79662306a36Sopenharmony_cierr:
79762306a36Sopenharmony_ci	of_node_put(ep);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	return 0;
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci/* VENC HW IP initialisation */
80362306a36Sopenharmony_cistatic int venc_bind(struct device *dev, struct device *master, void *data)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
80662306a36Sopenharmony_ci	u8 rev_id;
80762306a36Sopenharmony_ci	struct resource *venc_mem;
80862306a36Sopenharmony_ci	int r;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	venc.pdev = pdev;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	mutex_init(&venc.venc_lock);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	venc.wss_data = 0;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
81762306a36Sopenharmony_ci	if (!venc_mem) {
81862306a36Sopenharmony_ci		DSSERR("can't get IORESOURCE_MEM VENC\n");
81962306a36Sopenharmony_ci		return -EINVAL;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	venc.base = devm_ioremap(&pdev->dev, venc_mem->start,
82362306a36Sopenharmony_ci				 resource_size(venc_mem));
82462306a36Sopenharmony_ci	if (!venc.base) {
82562306a36Sopenharmony_ci		DSSERR("can't ioremap VENC\n");
82662306a36Sopenharmony_ci		return -ENOMEM;
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	r = venc_get_clocks(pdev);
83062306a36Sopenharmony_ci	if (r)
83162306a36Sopenharmony_ci		return r;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	r = venc_runtime_get();
83662306a36Sopenharmony_ci	if (r)
83762306a36Sopenharmony_ci		goto err_runtime_get;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
84062306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	venc_runtime_put();
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	if (pdev->dev.of_node) {
84562306a36Sopenharmony_ci		r = venc_probe_of(pdev);
84662306a36Sopenharmony_ci		if (r) {
84762306a36Sopenharmony_ci			DSSERR("Invalid DT data\n");
84862306a36Sopenharmony_ci			goto err_probe_of;
84962306a36Sopenharmony_ci		}
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	dss_debugfs_create_file("venc", venc_dump_regs);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	venc_init_output(pdev);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	return 0;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cierr_probe_of:
85962306a36Sopenharmony_cierr_runtime_get:
86062306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
86162306a36Sopenharmony_ci	return r;
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic void venc_unbind(struct device *dev, struct device *master, void *data)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	venc_uninit_output(pdev);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_cistatic const struct component_ops venc_component_ops = {
87462306a36Sopenharmony_ci	.bind	= venc_bind,
87562306a36Sopenharmony_ci	.unbind	= venc_unbind,
87662306a36Sopenharmony_ci};
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic int venc_probe(struct platform_device *pdev)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	return component_add(&pdev->dev, &venc_component_ops);
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistatic void venc_remove(struct platform_device *pdev)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	component_del(&pdev->dev, &venc_component_ops);
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic int venc_runtime_suspend(struct device *dev)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	clk_disable_unprepare(venc.tv_dac_clk);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	dispc_runtime_put();
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	return 0;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic int venc_runtime_resume(struct device *dev)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	int r;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	r = dispc_runtime_get();
90262306a36Sopenharmony_ci	if (r < 0)
90362306a36Sopenharmony_ci		return r;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	clk_prepare_enable(venc.tv_dac_clk);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	return 0;
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic const struct dev_pm_ops venc_pm_ops = {
91162306a36Sopenharmony_ci	.runtime_suspend = venc_runtime_suspend,
91262306a36Sopenharmony_ci	.runtime_resume = venc_runtime_resume,
91362306a36Sopenharmony_ci};
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic const struct of_device_id venc_of_match[] = {
91662306a36Sopenharmony_ci	{ .compatible = "ti,omap2-venc", },
91762306a36Sopenharmony_ci	{ .compatible = "ti,omap3-venc", },
91862306a36Sopenharmony_ci	{ .compatible = "ti,omap4-venc", },
91962306a36Sopenharmony_ci	{},
92062306a36Sopenharmony_ci};
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic struct platform_driver omap_venchw_driver = {
92362306a36Sopenharmony_ci	.probe		= venc_probe,
92462306a36Sopenharmony_ci	.remove_new	= venc_remove,
92562306a36Sopenharmony_ci	.driver         = {
92662306a36Sopenharmony_ci		.name   = "omapdss_venc",
92762306a36Sopenharmony_ci		.pm	= &venc_pm_ops,
92862306a36Sopenharmony_ci		.of_match_table = venc_of_match,
92962306a36Sopenharmony_ci		.suppress_bind_attrs = true,
93062306a36Sopenharmony_ci	},
93162306a36Sopenharmony_ci};
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ciint __init venc_init_platform_driver(void)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci	return platform_driver_register(&omap_venchw_driver);
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_civoid venc_uninit_platform_driver(void)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	platform_driver_unregister(&omap_venchw_driver);
94162306a36Sopenharmony_ci}
942