brintos

brintos / linux-shallow public Read only

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