brintos

brintos / linux-shallow public Read only

0
0
Text · 22.6 KiB · f163d52 Raw
923 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2009 Nokia Corporation4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>5 *6 * VENC settings from TI's DSS driver7 */8 9#define DSS_SUBSYS_NAME "VENC"10 11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/clk.h>14#include <linux/err.h>15#include <linux/io.h>16#include <linux/completion.h>17#include <linux/delay.h>18#include <linux/string.h>19#include <linux/seq_file.h>20#include <linux/platform_device.h>21#include <linux/regulator/consumer.h>22#include <linux/pm_runtime.h>23#include <linux/of.h>24#include <linux/of_graph.h>25#include <linux/component.h>26#include <linux/sys_soc.h>27 28#include <drm/drm_bridge.h>29 30#include "omapdss.h"31#include "dss.h"32 33/* Venc registers */34#define VENC_REV_ID				0x0035#define VENC_STATUS				0x0436#define VENC_F_CONTROL				0x0837#define VENC_VIDOUT_CTRL			0x1038#define VENC_SYNC_CTRL				0x1439#define VENC_LLEN				0x1C40#define VENC_FLENS				0x2041#define VENC_HFLTR_CTRL				0x2442#define VENC_CC_CARR_WSS_CARR			0x2843#define VENC_C_PHASE				0x2C44#define VENC_GAIN_U				0x3045#define VENC_GAIN_V				0x3446#define VENC_GAIN_Y				0x3847#define VENC_BLACK_LEVEL			0x3C48#define VENC_BLANK_LEVEL			0x4049#define VENC_X_COLOR				0x4450#define VENC_M_CONTROL				0x4851#define VENC_BSTAMP_WSS_DATA			0x4C52#define VENC_S_CARR				0x5053#define VENC_LINE21				0x5454#define VENC_LN_SEL				0x5855#define VENC_L21__WC_CTL			0x5C56#define VENC_HTRIGGER_VTRIGGER			0x6057#define VENC_SAVID__EAVID			0x6458#define VENC_FLEN__FAL				0x6859#define VENC_LAL__PHASE_RESET			0x6C60#define VENC_HS_INT_START_STOP_X		0x7061#define VENC_HS_EXT_START_STOP_X		0x7462#define VENC_VS_INT_START_X			0x7863#define VENC_VS_INT_STOP_X__VS_INT_START_Y	0x7C64#define VENC_VS_INT_STOP_Y__VS_EXT_START_X	0x8065#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y	0x8466#define VENC_VS_EXT_STOP_Y			0x8867#define VENC_AVID_START_STOP_X			0x9068#define VENC_AVID_START_STOP_Y			0x9469#define VENC_FID_INT_START_X__FID_INT_START_Y	0xA070#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X	0xA471#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y	0xA872#define VENC_TVDETGP_INT_START_STOP_X		0xB073#define VENC_TVDETGP_INT_START_STOP_Y		0xB474#define VENC_GEN_CTRL				0xB875#define VENC_OUTPUT_CONTROL			0xC476#define VENC_OUTPUT_TEST			0xC877#define VENC_DAC_B__DAC_C			0xC878 79struct venc_config {80	u32 f_control;81	u32 vidout_ctrl;82	u32 sync_ctrl;83	u32 llen;84	u32 flens;85	u32 hfltr_ctrl;86	u32 cc_carr_wss_carr;87	u32 c_phase;88	u32 gain_u;89	u32 gain_v;90	u32 gain_y;91	u32 black_level;92	u32 blank_level;93	u32 x_color;94	u32 m_control;95	u32 bstamp_wss_data;96	u32 s_carr;97	u32 line21;98	u32 ln_sel;99	u32 l21__wc_ctl;100	u32 htrigger_vtrigger;101	u32 savid__eavid;102	u32 flen__fal;103	u32 lal__phase_reset;104	u32 hs_int_start_stop_x;105	u32 hs_ext_start_stop_x;106	u32 vs_int_start_x;107	u32 vs_int_stop_x__vs_int_start_y;108	u32 vs_int_stop_y__vs_ext_start_x;109	u32 vs_ext_stop_x__vs_ext_start_y;110	u32 vs_ext_stop_y;111	u32 avid_start_stop_x;112	u32 avid_start_stop_y;113	u32 fid_int_start_x__fid_int_start_y;114	u32 fid_int_offset_y__fid_ext_start_x;115	u32 fid_ext_start_y__fid_ext_offset_y;116	u32 tvdetgp_int_start_stop_x;117	u32 tvdetgp_int_start_stop_y;118	u32 gen_ctrl;119};120 121/* from TRM */122static const struct venc_config venc_config_pal_trm = {123	.f_control				= 0,124	.vidout_ctrl				= 1,125	.sync_ctrl				= 0x40,126	.llen					= 0x35F, /* 863 */127	.flens					= 0x270, /* 624 */128	.hfltr_ctrl				= 0,129	.cc_carr_wss_carr			= 0x2F7225ED,130	.c_phase				= 0,131	.gain_u					= 0x111,132	.gain_v					= 0x181,133	.gain_y					= 0x140,134	.black_level				= 0x3B,135	.blank_level				= 0x3B,136	.x_color				= 0x7,137	.m_control				= 0x2,138	.bstamp_wss_data			= 0x3F,139	.s_carr					= 0x2A098ACB,140	.line21					= 0,141	.ln_sel					= 0x01290015,142	.l21__wc_ctl				= 0x0000F603,143	.htrigger_vtrigger			= 0,144 145	.savid__eavid				= 0x06A70108,146	.flen__fal				= 0x00180270,147	.lal__phase_reset			= 0x00040135,148	.hs_int_start_stop_x			= 0x00880358,149	.hs_ext_start_stop_x			= 0x000F035F,150	.vs_int_start_x				= 0x01A70000,151	.vs_int_stop_x__vs_int_start_y		= 0x000001A7,152	.vs_int_stop_y__vs_ext_start_x		= 0x01AF0000,153	.vs_ext_stop_x__vs_ext_start_y		= 0x000101AF,154	.vs_ext_stop_y				= 0x00000025,155	.avid_start_stop_x			= 0x03530083,156	.avid_start_stop_y			= 0x026C002E,157	.fid_int_start_x__fid_int_start_y	= 0x0001008A,158	.fid_int_offset_y__fid_ext_start_x	= 0x002E0138,159	.fid_ext_start_y__fid_ext_offset_y	= 0x01380001,160 161	.tvdetgp_int_start_stop_x		= 0x00140001,162	.tvdetgp_int_start_stop_y		= 0x00010001,163	.gen_ctrl				= 0x00FF0000,164};165 166/* from TRM */167static const struct venc_config venc_config_ntsc_trm = {168	.f_control				= 0,169	.vidout_ctrl				= 1,170	.sync_ctrl				= 0x8040,171	.llen					= 0x359,172	.flens					= 0x20C,173	.hfltr_ctrl				= 0,174	.cc_carr_wss_carr			= 0x043F2631,175	.c_phase				= 0,176	.gain_u					= 0x102,177	.gain_v					= 0x16C,178	.gain_y					= 0x12F,179	.black_level				= 0x43,180	.blank_level				= 0x38,181	.x_color				= 0x7,182	.m_control				= 0x1,183	.bstamp_wss_data			= 0x38,184	.s_carr					= 0x21F07C1F,185	.line21					= 0,186	.ln_sel					= 0x01310011,187	.l21__wc_ctl				= 0x0000F003,188	.htrigger_vtrigger			= 0,189 190	.savid__eavid				= 0x069300F4,191	.flen__fal				= 0x0016020C,192	.lal__phase_reset			= 0x00060107,193	.hs_int_start_stop_x			= 0x008E0350,194	.hs_ext_start_stop_x			= 0x000F0359,195	.vs_int_start_x				= 0x01A00000,196	.vs_int_stop_x__vs_int_start_y		= 0x020701A0,197	.vs_int_stop_y__vs_ext_start_x		= 0x01AC0024,198	.vs_ext_stop_x__vs_ext_start_y		= 0x020D01AC,199	.vs_ext_stop_y				= 0x00000006,200	.avid_start_stop_x			= 0x03480078,201	.avid_start_stop_y			= 0x02060024,202	.fid_int_start_x__fid_int_start_y	= 0x0001008A,203	.fid_int_offset_y__fid_ext_start_x	= 0x01AC0106,204	.fid_ext_start_y__fid_ext_offset_y	= 0x01060006,205 206	.tvdetgp_int_start_stop_x		= 0x00140001,207	.tvdetgp_int_start_stop_y		= 0x00010001,208	.gen_ctrl				= 0x00F90000,209};210 211enum venc_videomode {212	VENC_MODE_UNKNOWN,213	VENC_MODE_PAL,214	VENC_MODE_NTSC,215};216 217static const struct drm_display_mode omap_dss_pal_mode = {218	.hdisplay	= 720,219	.hsync_start	= 732,220	.hsync_end	= 796,221	.htotal		= 864,222	.vdisplay	= 574,223	.vsync_start	= 579,224	.vsync_end	= 584,225	.vtotal		= 625,226	.clock		= 13500,227 228	.flags		= DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |229			  DRM_MODE_FLAG_NVSYNC,230};231 232static const struct drm_display_mode omap_dss_ntsc_mode = {233	.hdisplay	= 720,234	.hsync_start	= 736,235	.hsync_end	= 800,236	.htotal		= 858,237	.vdisplay	= 482,238	.vsync_start	= 488,239	.vsync_end	= 494,240	.vtotal		= 525,241	.clock		= 13500,242 243	.flags		= DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |244			  DRM_MODE_FLAG_NVSYNC,245};246 247struct venc_device {248	struct platform_device *pdev;249	void __iomem *base;250	struct regulator *vdda_dac_reg;251	struct dss_device *dss;252 253	struct dss_debugfs_entry *debugfs;254 255	struct clk	*tv_dac_clk;256 257	const struct venc_config *config;258	enum omap_dss_venc_type type;259	bool invert_polarity;260	bool requires_tv_dac_clk;261 262	struct omap_dss_device output;263	struct drm_bridge bridge;264};265 266#define drm_bridge_to_venc(b) container_of(b, struct venc_device, bridge)267 268static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val)269{270	__raw_writel(val, venc->base + idx);271}272 273static inline u32 venc_read_reg(struct venc_device *venc, int idx)274{275	u32 l = __raw_readl(venc->base + idx);276	return l;277}278 279static void venc_write_config(struct venc_device *venc,280			      const struct venc_config *config)281{282	DSSDBG("write venc conf\n");283 284	venc_write_reg(venc, VENC_LLEN, config->llen);285	venc_write_reg(venc, VENC_FLENS, config->flens);286	venc_write_reg(venc, VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);287	venc_write_reg(venc, VENC_C_PHASE, config->c_phase);288	venc_write_reg(venc, VENC_GAIN_U, config->gain_u);289	venc_write_reg(venc, VENC_GAIN_V, config->gain_v);290	venc_write_reg(venc, VENC_GAIN_Y, config->gain_y);291	venc_write_reg(venc, VENC_BLACK_LEVEL, config->black_level);292	venc_write_reg(venc, VENC_BLANK_LEVEL, config->blank_level);293	venc_write_reg(venc, VENC_M_CONTROL, config->m_control);294	venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data);295	venc_write_reg(venc, VENC_S_CARR, config->s_carr);296	venc_write_reg(venc, VENC_L21__WC_CTL, config->l21__wc_ctl);297	venc_write_reg(venc, VENC_SAVID__EAVID, config->savid__eavid);298	venc_write_reg(venc, VENC_FLEN__FAL, config->flen__fal);299	venc_write_reg(venc, VENC_LAL__PHASE_RESET, config->lal__phase_reset);300	venc_write_reg(venc, VENC_HS_INT_START_STOP_X,301		       config->hs_int_start_stop_x);302	venc_write_reg(venc, VENC_HS_EXT_START_STOP_X,303		       config->hs_ext_start_stop_x);304	venc_write_reg(venc, VENC_VS_INT_START_X, config->vs_int_start_x);305	venc_write_reg(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y,306		       config->vs_int_stop_x__vs_int_start_y);307	venc_write_reg(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X,308		       config->vs_int_stop_y__vs_ext_start_x);309	venc_write_reg(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y,310		       config->vs_ext_stop_x__vs_ext_start_y);311	venc_write_reg(venc, VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);312	venc_write_reg(venc, VENC_AVID_START_STOP_X, config->avid_start_stop_x);313	venc_write_reg(venc, VENC_AVID_START_STOP_Y, config->avid_start_stop_y);314	venc_write_reg(venc, VENC_FID_INT_START_X__FID_INT_START_Y,315		       config->fid_int_start_x__fid_int_start_y);316	venc_write_reg(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,317		       config->fid_int_offset_y__fid_ext_start_x);318	venc_write_reg(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,319		       config->fid_ext_start_y__fid_ext_offset_y);320 321	venc_write_reg(venc, VENC_DAC_B__DAC_C,322		       venc_read_reg(venc, VENC_DAC_B__DAC_C));323	venc_write_reg(venc, VENC_VIDOUT_CTRL, config->vidout_ctrl);324	venc_write_reg(venc, VENC_HFLTR_CTRL, config->hfltr_ctrl);325	venc_write_reg(venc, VENC_X_COLOR, config->x_color);326	venc_write_reg(venc, VENC_LINE21, config->line21);327	venc_write_reg(venc, VENC_LN_SEL, config->ln_sel);328	venc_write_reg(venc, VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);329	venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_X,330		       config->tvdetgp_int_start_stop_x);331	venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_Y,332		       config->tvdetgp_int_start_stop_y);333	venc_write_reg(venc, VENC_GEN_CTRL, config->gen_ctrl);334	venc_write_reg(venc, VENC_F_CONTROL, config->f_control);335	venc_write_reg(venc, VENC_SYNC_CTRL, config->sync_ctrl);336}337 338static void venc_reset(struct venc_device *venc)339{340	int t = 1000;341 342	venc_write_reg(venc, VENC_F_CONTROL, 1<<8);343	while (venc_read_reg(venc, VENC_F_CONTROL) & (1<<8)) {344		if (--t == 0) {345			DSSERR("Failed to reset venc\n");346			return;347		}348	}349 350#ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET351	/* the magical sleep that makes things work */352	/* XXX more info? What bug this circumvents? */353	msleep(20);354#endif355}356 357static int venc_runtime_get(struct venc_device *venc)358{359	int r;360 361	DSSDBG("venc_runtime_get\n");362 363	r = pm_runtime_get_sync(&venc->pdev->dev);364	if (WARN_ON(r < 0)) {365		pm_runtime_put_noidle(&venc->pdev->dev);366		return r;367	}368	return 0;369}370 371static void venc_runtime_put(struct venc_device *venc)372{373	int r;374 375	DSSDBG("venc_runtime_put\n");376 377	r = pm_runtime_put_sync(&venc->pdev->dev);378	WARN_ON(r < 0 && r != -ENOSYS);379}380 381static int venc_power_on(struct venc_device *venc)382{383	u32 l;384	int r;385 386	r = venc_runtime_get(venc);387	if (r)388		goto err0;389 390	venc_reset(venc);391	venc_write_config(venc, venc->config);392 393	dss_set_venc_output(venc->dss, venc->type);394	dss_set_dac_pwrdn_bgz(venc->dss, 1);395 396	l = 0;397 398	if (venc->type == OMAP_DSS_VENC_TYPE_COMPOSITE)399		l |= 1 << 1;400	else /* S-Video */401		l |= (1 << 0) | (1 << 2);402 403	if (venc->invert_polarity == false)404		l |= 1 << 3;405 406	venc_write_reg(venc, VENC_OUTPUT_CONTROL, l);407 408	r = regulator_enable(venc->vdda_dac_reg);409	if (r)410		goto err1;411 412	r = dss_mgr_enable(&venc->output);413	if (r)414		goto err2;415 416	return 0;417 418err2:419	regulator_disable(venc->vdda_dac_reg);420err1:421	venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0);422	dss_set_dac_pwrdn_bgz(venc->dss, 0);423 424	venc_runtime_put(venc);425err0:426	return r;427}428 429static void venc_power_off(struct venc_device *venc)430{431	venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0);432	dss_set_dac_pwrdn_bgz(venc->dss, 0);433 434	dss_mgr_disable(&venc->output);435 436	regulator_disable(venc->vdda_dac_reg);437 438	venc_runtime_put(venc);439}440 441static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode)442{443	if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))444		return VENC_MODE_UNKNOWN;445 446	if (mode->clock == omap_dss_pal_mode.clock &&447	    mode->hdisplay == omap_dss_pal_mode.hdisplay &&448	    mode->vdisplay == omap_dss_pal_mode.vdisplay)449		return VENC_MODE_PAL;450 451	if (mode->clock == omap_dss_ntsc_mode.clock &&452	    mode->hdisplay == omap_dss_ntsc_mode.hdisplay &&453	    mode->vdisplay == omap_dss_ntsc_mode.vdisplay)454		return VENC_MODE_NTSC;455 456	return VENC_MODE_UNKNOWN;457}458 459static int venc_dump_regs(struct seq_file *s, void *p)460{461	struct venc_device *venc = s->private;462 463#define DUMPREG(venc, r) \464	seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(venc, r))465 466	if (venc_runtime_get(venc))467		return 0;468 469	DUMPREG(venc, VENC_F_CONTROL);470	DUMPREG(venc, VENC_VIDOUT_CTRL);471	DUMPREG(venc, VENC_SYNC_CTRL);472	DUMPREG(venc, VENC_LLEN);473	DUMPREG(venc, VENC_FLENS);474	DUMPREG(venc, VENC_HFLTR_CTRL);475	DUMPREG(venc, VENC_CC_CARR_WSS_CARR);476	DUMPREG(venc, VENC_C_PHASE);477	DUMPREG(venc, VENC_GAIN_U);478	DUMPREG(venc, VENC_GAIN_V);479	DUMPREG(venc, VENC_GAIN_Y);480	DUMPREG(venc, VENC_BLACK_LEVEL);481	DUMPREG(venc, VENC_BLANK_LEVEL);482	DUMPREG(venc, VENC_X_COLOR);483	DUMPREG(venc, VENC_M_CONTROL);484	DUMPREG(venc, VENC_BSTAMP_WSS_DATA);485	DUMPREG(venc, VENC_S_CARR);486	DUMPREG(venc, VENC_LINE21);487	DUMPREG(venc, VENC_LN_SEL);488	DUMPREG(venc, VENC_L21__WC_CTL);489	DUMPREG(venc, VENC_HTRIGGER_VTRIGGER);490	DUMPREG(venc, VENC_SAVID__EAVID);491	DUMPREG(venc, VENC_FLEN__FAL);492	DUMPREG(venc, VENC_LAL__PHASE_RESET);493	DUMPREG(venc, VENC_HS_INT_START_STOP_X);494	DUMPREG(venc, VENC_HS_EXT_START_STOP_X);495	DUMPREG(venc, VENC_VS_INT_START_X);496	DUMPREG(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y);497	DUMPREG(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X);498	DUMPREG(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y);499	DUMPREG(venc, VENC_VS_EXT_STOP_Y);500	DUMPREG(venc, VENC_AVID_START_STOP_X);501	DUMPREG(venc, VENC_AVID_START_STOP_Y);502	DUMPREG(venc, VENC_FID_INT_START_X__FID_INT_START_Y);503	DUMPREG(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);504	DUMPREG(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);505	DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_X);506	DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_Y);507	DUMPREG(venc, VENC_GEN_CTRL);508	DUMPREG(venc, VENC_OUTPUT_CONTROL);509	DUMPREG(venc, VENC_OUTPUT_TEST);510 511	venc_runtime_put(venc);512 513#undef DUMPREG514	return 0;515}516 517static int venc_get_clocks(struct venc_device *venc)518{519	struct clk *clk;520 521	if (venc->requires_tv_dac_clk) {522		clk = devm_clk_get(&venc->pdev->dev, "tv_dac_clk");523		if (IS_ERR(clk)) {524			DSSERR("can't get tv_dac_clk\n");525			return PTR_ERR(clk);526		}527	} else {528		clk = NULL;529	}530 531	venc->tv_dac_clk = clk;532 533	return 0;534}535 536/* -----------------------------------------------------------------------------537 * DRM Bridge Operations538 */539 540static int venc_bridge_attach(struct drm_bridge *bridge,541			      enum drm_bridge_attach_flags flags)542{543	struct venc_device *venc = drm_bridge_to_venc(bridge);544 545	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))546		return -EINVAL;547 548	return drm_bridge_attach(bridge->encoder, venc->output.next_bridge,549				 bridge, flags);550}551 552static enum drm_mode_status553venc_bridge_mode_valid(struct drm_bridge *bridge,554		       const struct drm_display_info *info,555		       const struct drm_display_mode *mode)556{557	switch (venc_get_videomode(mode)) {558	case VENC_MODE_PAL:559	case VENC_MODE_NTSC:560		return MODE_OK;561 562	default:563		return MODE_BAD;564	}565}566 567static bool venc_bridge_mode_fixup(struct drm_bridge *bridge,568				   const struct drm_display_mode *mode,569				   struct drm_display_mode *adjusted_mode)570{571	const struct drm_display_mode *venc_mode;572 573	switch (venc_get_videomode(adjusted_mode)) {574	case VENC_MODE_PAL:575		venc_mode = &omap_dss_pal_mode;576		break;577 578	case VENC_MODE_NTSC:579		venc_mode = &omap_dss_ntsc_mode;580		break;581 582	default:583		return false;584	}585 586	drm_mode_copy(adjusted_mode, venc_mode);587	drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);588	drm_mode_set_name(adjusted_mode);589 590	return true;591}592 593static void venc_bridge_mode_set(struct drm_bridge *bridge,594				 const struct drm_display_mode *mode,595				 const struct drm_display_mode *adjusted_mode)596{597	struct venc_device *venc = drm_bridge_to_venc(bridge);598	enum venc_videomode venc_mode = venc_get_videomode(adjusted_mode);599 600	switch (venc_mode) {601	default:602		WARN_ON_ONCE(1);603		fallthrough;604	case VENC_MODE_PAL:605		venc->config = &venc_config_pal_trm;606		break;607 608	case VENC_MODE_NTSC:609		venc->config = &venc_config_ntsc_trm;610		break;611	}612 613	dispc_set_tv_pclk(venc->dss->dispc, 13500000);614}615 616static void venc_bridge_enable(struct drm_bridge *bridge)617{618	struct venc_device *venc = drm_bridge_to_venc(bridge);619 620	venc_power_on(venc);621}622 623static void venc_bridge_disable(struct drm_bridge *bridge)624{625	struct venc_device *venc = drm_bridge_to_venc(bridge);626 627	venc_power_off(venc);628}629 630static int venc_bridge_get_modes(struct drm_bridge *bridge,631				 struct drm_connector *connector)632{633	static const struct drm_display_mode *modes[] = {634		&omap_dss_pal_mode,635		&omap_dss_ntsc_mode,636	};637	unsigned int i;638 639	for (i = 0; i < ARRAY_SIZE(modes); ++i) {640		struct drm_display_mode *mode;641 642		mode = drm_mode_duplicate(connector->dev, modes[i]);643		if (!mode)644			return i;645 646		mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;647		drm_mode_set_name(mode);648		drm_mode_probed_add(connector, mode);649	}650 651	return ARRAY_SIZE(modes);652}653 654static const struct drm_bridge_funcs venc_bridge_funcs = {655	.attach = venc_bridge_attach,656	.mode_valid = venc_bridge_mode_valid,657	.mode_fixup = venc_bridge_mode_fixup,658	.mode_set = venc_bridge_mode_set,659	.enable = venc_bridge_enable,660	.disable = venc_bridge_disable,661	.get_modes = venc_bridge_get_modes,662};663 664static void venc_bridge_init(struct venc_device *venc)665{666	venc->bridge.funcs = &venc_bridge_funcs;667	venc->bridge.of_node = venc->pdev->dev.of_node;668	venc->bridge.ops = DRM_BRIDGE_OP_MODES;669	venc->bridge.type = DRM_MODE_CONNECTOR_SVIDEO;670	venc->bridge.interlace_allowed = true;671 672	drm_bridge_add(&venc->bridge);673}674 675static void venc_bridge_cleanup(struct venc_device *venc)676{677	drm_bridge_remove(&venc->bridge);678}679 680/* -----------------------------------------------------------------------------681 * Component Bind & Unbind682 */683 684static int venc_bind(struct device *dev, struct device *master, void *data)685{686	struct dss_device *dss = dss_get_device(master);687	struct venc_device *venc = dev_get_drvdata(dev);688	u8 rev_id;689	int r;690 691	venc->dss = dss;692 693	r = venc_runtime_get(venc);694	if (r)695		return r;696 697	rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff);698	dev_dbg(dev, "OMAP VENC rev %d\n", rev_id);699 700	venc_runtime_put(venc);701 702	venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs,703						venc);704 705	return 0;706}707 708static void venc_unbind(struct device *dev, struct device *master, void *data)709{710	struct venc_device *venc = dev_get_drvdata(dev);711 712	dss_debugfs_remove_file(venc->debugfs);713}714 715static const struct component_ops venc_component_ops = {716	.bind	= venc_bind,717	.unbind	= venc_unbind,718};719 720/* -----------------------------------------------------------------------------721 * Probe & Remove, Suspend & Resume722 */723 724static int venc_init_output(struct venc_device *venc)725{726	struct omap_dss_device *out = &venc->output;727	int r;728 729	venc_bridge_init(venc);730 731	out->dev = &venc->pdev->dev;732	out->id = OMAP_DSS_OUTPUT_VENC;733	out->type = OMAP_DISPLAY_TYPE_VENC;734	out->name = "venc.0";735	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;736	out->of_port = 0;737 738	r = omapdss_device_init_output(out, &venc->bridge);739	if (r < 0) {740		venc_bridge_cleanup(venc);741		return r;742	}743 744	omapdss_device_register(out);745 746	return 0;747}748 749static void venc_uninit_output(struct venc_device *venc)750{751	omapdss_device_unregister(&venc->output);752	omapdss_device_cleanup_output(&venc->output);753 754	venc_bridge_cleanup(venc);755}756 757static int venc_probe_of(struct venc_device *venc)758{759	struct device_node *node = venc->pdev->dev.of_node;760	struct device_node *ep;761	u32 channels;762	int r;763 764	ep = of_graph_get_endpoint_by_regs(node, 0, 0);765	if (!ep)766		return 0;767 768	venc->invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");769 770	r = of_property_read_u32(ep, "ti,channels", &channels);771	if (r) {772		dev_err(&venc->pdev->dev,773			"failed to read property 'ti,channels': %d\n", r);774		goto err;775	}776 777	switch (channels) {778	case 1:779		venc->type = OMAP_DSS_VENC_TYPE_COMPOSITE;780		break;781	case 2:782		venc->type = OMAP_DSS_VENC_TYPE_SVIDEO;783		break;784	default:785		dev_err(&venc->pdev->dev, "bad channel property '%d'\n",786			channels);787		r = -EINVAL;788		goto err;789	}790 791	of_node_put(ep);792 793	return 0;794 795err:796	of_node_put(ep);797	return r;798}799 800static const struct soc_device_attribute venc_soc_devices[] = {801	{ .machine = "OMAP3[45]*" },802	{ .machine = "AM35*" },803	{ /* sentinel */ }804};805 806static int venc_probe(struct platform_device *pdev)807{808	struct venc_device *venc;809	int r;810 811	venc = kzalloc(sizeof(*venc), GFP_KERNEL);812	if (!venc)813		return -ENOMEM;814 815	venc->pdev = pdev;816 817	platform_set_drvdata(pdev, venc);818 819	/* The OMAP34xx, OMAP35xx and AM35xx VENC require the TV DAC clock. */820	if (soc_device_match(venc_soc_devices))821		venc->requires_tv_dac_clk = true;822 823	venc->config = &venc_config_pal_trm;824 825	venc->base = devm_platform_ioremap_resource(pdev, 0);826	if (IS_ERR(venc->base)) {827		r = PTR_ERR(venc->base);828		goto err_free;829	}830 831	venc->vdda_dac_reg = devm_regulator_get(&pdev->dev, "vdda");832	if (IS_ERR(venc->vdda_dac_reg)) {833		r = PTR_ERR(venc->vdda_dac_reg);834		if (r != -EPROBE_DEFER)835			DSSERR("can't get VDDA_DAC regulator\n");836		goto err_free;837	}838 839	r = venc_get_clocks(venc);840	if (r)841		goto err_free;842 843	r = venc_probe_of(venc);844	if (r)845		goto err_free;846 847	pm_runtime_enable(&pdev->dev);848 849	r = venc_init_output(venc);850	if (r)851		goto err_pm_disable;852 853	r = component_add(&pdev->dev, &venc_component_ops);854	if (r)855		goto err_uninit_output;856 857	return 0;858 859err_uninit_output:860	venc_uninit_output(venc);861err_pm_disable:862	pm_runtime_disable(&pdev->dev);863err_free:864	kfree(venc);865	return r;866}867 868static void venc_remove(struct platform_device *pdev)869{870	struct venc_device *venc = platform_get_drvdata(pdev);871 872	component_del(&pdev->dev, &venc_component_ops);873 874	venc_uninit_output(venc);875 876	pm_runtime_disable(&pdev->dev);877 878	kfree(venc);879}880 881static __maybe_unused int venc_runtime_suspend(struct device *dev)882{883	struct venc_device *venc = dev_get_drvdata(dev);884 885	if (venc->tv_dac_clk)886		clk_disable_unprepare(venc->tv_dac_clk);887 888	return 0;889}890 891static __maybe_unused int venc_runtime_resume(struct device *dev)892{893	struct venc_device *venc = dev_get_drvdata(dev);894 895	if (venc->tv_dac_clk)896		clk_prepare_enable(venc->tv_dac_clk);897 898	return 0;899}900 901static const struct dev_pm_ops venc_pm_ops = {902	SET_RUNTIME_PM_OPS(venc_runtime_suspend, venc_runtime_resume, NULL)903	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)904};905 906static const struct of_device_id venc_of_match[] = {907	{ .compatible = "ti,omap2-venc", },908	{ .compatible = "ti,omap3-venc", },909	{ .compatible = "ti,omap4-venc", },910	{},911};912 913struct platform_driver omap_venchw_driver = {914	.probe		= venc_probe,915	.remove_new	= venc_remove,916	.driver         = {917		.name   = "omapdss_venc",918		.pm	= &venc_pm_ops,919		.of_match_table = venc_of_match,920		.suppress_bind_attrs = true,921	},922};923