コード例 #1
0
ファイル: dpi.c プロジェクト: Master-Traders/linux
static int dpi_set_mode(struct omap_overlay_manager *mgr)
{
	struct omap_video_timings *t = &dpi.timings;
	int lck_div = 0, pck_div = 0;
	unsigned long fck = 0;
	unsigned long pck;
	int r = 0;

	if (dpi.dsidev)
		r = dpi_set_dsi_clk(mgr->id, t->pixel_clock * 1000, &fck,
				&lck_div, &pck_div);
	else
		r = dpi_set_dispc_clk(t->pixel_clock * 1000, &fck,
				&lck_div, &pck_div);
	if (r)
		return r;

	pck = fck / lck_div / pck_div / 1000;

	if (pck != t->pixel_clock) {
		DSSWARN("Could not find exact pixel clock. "
				"Requested %d kHz, got %lu kHz\n",
				t->pixel_clock, pck);

		t->pixel_clock = pck;
	}

	dss_mgr_set_timings(mgr, t);

	return 0;
}
コード例 #2
0
ファイル: rfbi.c プロジェクト: 020gzh/linux
static int rfbi_transfer_area(struct omap_dss_device *dssdev,
		void (*callback)(void *data), void *data)
{
	u32 l;
	int r;
	struct omap_overlay_manager *mgr = rfbi.output.manager;
	u16 width = rfbi.timings.x_res;
	u16 height = rfbi.timings.y_res;

	/*BUG_ON(callback == 0);*/
	BUG_ON(rfbi.framedone_callback != NULL);

	DSSDBG("rfbi_transfer_area %dx%d\n", width, height);

	dss_mgr_set_timings(mgr, &rfbi.timings);

	r = dss_mgr_enable(mgr);
	if (r)
		return r;

	rfbi.framedone_callback = callback;
	rfbi.framedone_callback_data = data;

	rfbi_write_reg(RFBI_PIXEL_CNT, width * height);

	l = rfbi_read_reg(RFBI_CONTROL);
	l = FLD_MOD(l, 1, 0, 0); /* enable */
	if (!rfbi.te_enabled)
		l = FLD_MOD(l, 1, 4, 4); /* ITE */

	rfbi_write_reg(RFBI_CONTROL, l);

	return 0;
}
コード例 #3
0
static int rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
		u16 height, void (*callback)(void *data), void *data)
{
	u32 l;
	int r;
	struct omap_video_timings timings = {
		.hsw		= 1,
		.hfp		= 1,
		.hbp		= 1,
		.vsw		= 1,
		.vfp		= 0,
		.vbp		= 0,
		.x_res		= width,
		.y_res		= height,
	};

	/*BUG_ON(callback == 0);*/
	BUG_ON(rfbi.framedone_callback != NULL);

	DSSDBG("rfbi_transfer_area %dx%d\n", width, height);

	dss_mgr_set_timings(dssdev->manager, &timings);

	r = dss_mgr_enable(dssdev->manager);
	if (r)
		return r;

	rfbi.framedone_callback = callback;
	rfbi.framedone_callback_data = data;

	rfbi_write_reg(RFBI_PIXEL_CNT, width * height);

	l = rfbi_read_reg(RFBI_CONTROL);
	l = FLD_MOD(l, 1, 0, 0); /* enable */
	if (!rfbi.te_enabled)
		l = FLD_MOD(l, 1, 4, 4); /* ITE */

	rfbi_write_reg(RFBI_CONTROL, l);

	return 0;
}

static void framedone_callback(void *data, u32 mask)
{
	void (*callback)(void *data);

	DSSDBG("FRAMEDONE\n");

	REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);

	callback = rfbi.framedone_callback;
	rfbi.framedone_callback = NULL;

	if (callback != NULL)
		callback(rfbi.framedone_callback_data);
}
コード例 #4
0
ファイル: dpi.c プロジェクト: AllenWeb/linux
void dpi_set_timings(struct omap_dss_device *dssdev,
			struct omap_video_timings *timings)
{
	int r;

	DSSDBG("dpi_set_timings\n");
	dssdev->panel.timings = *timings;
	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
		r = dispc_runtime_get();
		if (r)
			return;

		dpi_set_mode(dssdev);

		dispc_runtime_put();
	} else {
		dss_mgr_set_timings(dssdev->manager, timings);
	}
}
コード例 #5
0
ファイル: rfbi.c プロジェクト: 020gzh/linux
static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
{
	struct omap_overlay_manager *mgr = rfbi.output.manager;
	struct dss_lcd_mgr_config mgr_config;

	mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;

	mgr_config.stallmode = true;
	/* Do we need fifohandcheck for RFBI? */
	mgr_config.fifohandcheck = false;

	mgr_config.video_port_width = rfbi.pixel_size;
	mgr_config.lcden_sig_polarity = 0;

	dss_mgr_set_lcd_config(mgr, &mgr_config);

	/*
	 * Set rfbi.timings with default values, the x_res and y_res fields
	 * are expected to be already configured by the panel driver via
	 * omapdss_rfbi_set_size()
	 */
	rfbi.timings.hsw = 1;
	rfbi.timings.hfp = 1;
	rfbi.timings.hbp = 1;
	rfbi.timings.vsw = 1;
	rfbi.timings.vfp = 0;
	rfbi.timings.vbp = 0;

	rfbi.timings.interlace = false;
	rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
	rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
	rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
	rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
	rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;

	dss_mgr_set_timings(mgr, &rfbi.timings);
}
コード例 #6
0
ファイル: dpi.c プロジェクト: AllenWeb/linux
static int dpi_set_mode(struct omap_dss_device *dssdev)
{
	struct omap_video_timings *t = &dssdev->panel.timings;
	int lck_div = 0, pck_div = 0;
	unsigned long fck = 0;
	unsigned long pck;
	bool is_tft;
	int r = 0;

	dispc_mgr_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
			dssdev->panel.acbi, dssdev->panel.acb);

	is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;

	if (dpi_use_dsi_pll(dssdev))
		r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000,
				&fck, &lck_div, &pck_div);
	else
		r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000,
				&fck, &lck_div, &pck_div);
	if (r)
		return r;

	pck = fck / lck_div / pck_div / 1000;

	if (pck != t->pixel_clock) {
		DSSWARN("Could not find exact pixel clock. "
				"Requested %d kHz, got %lu kHz\n",
				t->pixel_clock, pck);

		t->pixel_clock = pck;
	}

	dss_mgr_set_timings(dssdev->manager, t);

	return 0;
}
コード例 #7
0
ファイル: hdmi5.c プロジェクト: 513855417/linux
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
{
	int r;
	struct omap_video_timings *p;
	struct omap_overlay_manager *mgr = hdmi.output.manager;
	struct dss_pll_clock_info hdmi_cinfo = { 0 };

	r = hdmi_power_on_core(dssdev);
	if (r)
		return r;

	p = &hdmi.cfg.timings;

	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);

	hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);

	/* disable and clear irqs */
	hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
	hdmi_wp_set_irqstatus(&hdmi.wp,
			hdmi_wp_get_irqstatus(&hdmi.wp));

	r = dss_pll_enable(&hdmi.pll.pll);
	if (r) {
		DSSERR("Failed to enable PLL\n");
		goto err_pll_enable;
	}

	r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
	if (r) {
		DSSERR("Failed to configure PLL\n");
		goto err_pll_cfg;
	}

	r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
		hdmi_cinfo.clkout[0]);
	if (r) {
		DSSDBG("Failed to start PHY\n");
		goto err_phy_cfg;
	}

	r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON);
	if (r)
		goto err_phy_pwr;

	hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);

	/* bypass TV gamma table */
	dispc_enable_gamma_table(0);

	/* tv size */
	dss_mgr_set_timings(mgr, p);

	r = hdmi_wp_video_start(&hdmi.wp);
	if (r)
		goto err_vid_enable;

	r = dss_mgr_enable(mgr);
	if (r)
		goto err_mgr_enable;

	hdmi_wp_set_irqenable(&hdmi.wp,
			HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);

	return 0;

err_mgr_enable:
	hdmi_wp_video_stop(&hdmi.wp);
err_vid_enable:
	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
err_phy_pwr:
err_phy_cfg:
err_pll_cfg:
	dss_pll_disable(&hdmi.pll.pll);
err_pll_enable:
	hdmi_power_off_core(dssdev);
	return -EIO;
}
コード例 #8
0
ファイル: sdi.c プロジェクト: krzk/linux
static int sdi_display_enable(struct omap_dss_device *dssdev)
{
	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
	struct videomode *vm = &sdi->vm;
	unsigned long fck;
	struct dispc_clock_info dispc_cinfo;
	unsigned long pck;
	int r;

	if (!sdi->output.dispc_channel_connected) {
		DSSERR("failed to enable display: no output/manager\n");
		return -ENODEV;
	}

	r = regulator_enable(sdi->vdds_sdi_reg);
	if (r)
		goto err_reg_enable;

	r = dispc_runtime_get(sdi->dss->dispc);
	if (r)
		goto err_get_dispc;

	/* 15.5.9.1.2 */
	vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE | DISPLAY_FLAGS_SYNC_POSEDGE;

	r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo);
	if (r)
		goto err_calc_clock_div;

	sdi->mgr_config.clock_info = dispc_cinfo;

	pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;

	if (pck != vm->pixelclock) {
		DSSWARN("Could not find exact pixel clock. Requested %lu Hz, got %lu Hz\n",
			vm->pixelclock, pck);

		vm->pixelclock = pck;
	}


	dss_mgr_set_timings(&sdi->output, vm);

	r = dss_set_fck_rate(sdi->dss, fck);
	if (r)
		goto err_set_dss_clock_div;

	sdi_config_lcd_manager(sdi);

	/*
	 * LCLK and PCLK divisors are located in shadow registers, and we
	 * normally write them to DISPC registers when enabling the output.
	 * However, SDI uses pck-free as source clock for its PLL, and pck-free
	 * is affected by the divisors. And as we need the PLL before enabling
	 * the output, we need to write the divisors early.
	 *
	 * It seems just writing to the DISPC register is enough, and we don't
	 * need to care about the shadow register mechanism for pck-free. The
	 * exact reason for this is unknown.
	 */
	dispc_mgr_set_clock_div(sdi->dss->dispc, sdi->output.dispc_channel,
				&sdi->mgr_config.clock_info);

	dss_sdi_init(sdi->dss, sdi->datapairs);
	r = dss_sdi_enable(sdi->dss);
	if (r)
		goto err_sdi_enable;
	mdelay(2);

	r = dss_mgr_enable(&sdi->output);
	if (r)
		goto err_mgr_enable;

	return 0;

err_mgr_enable:
	dss_sdi_disable(sdi->dss);
err_sdi_enable:
err_set_dss_clock_div:
err_calc_clock_div:
	dispc_runtime_put(sdi->dss->dispc);
err_get_dispc:
	regulator_disable(sdi->vdds_sdi_reg);
err_reg_enable:
	return r;
}
コード例 #9
0
ファイル: sdi.c プロジェクト: Master-Traders/linux
static int sdi_display_enable(struct omap_dss_device *dssdev)
{
	struct omap_dss_device *out = &sdi.output;
	struct omap_video_timings *t = &sdi.timings;
	unsigned long fck;
	struct dispc_clock_info dispc_cinfo;
	unsigned long pck;
	int r;

	if (out == NULL || out->manager == NULL) {
		DSSERR("failed to enable display: no output/manager\n");
		return -ENODEV;
	}

	r = regulator_enable(sdi.vdds_sdi_reg);
	if (r)
		goto err_reg_enable;

	r = dispc_runtime_get();
	if (r)
		goto err_get_dispc;

	/* 15.5.9.1.2 */
	t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
	t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;

	r = sdi_calc_clock_div(t->pixel_clock * 1000, &fck, &dispc_cinfo);
	if (r)
		goto err_calc_clock_div;

	sdi.mgr_config.clock_info = dispc_cinfo;

	pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div / 1000;

	if (pck != t->pixel_clock) {
		DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
				"got %lu kHz\n",
				t->pixel_clock, pck);

		t->pixel_clock = pck;
	}


	dss_mgr_set_timings(out->manager, t);

	r = dss_set_fck_rate(fck);
	if (r)
		goto err_set_dss_clock_div;

	sdi_config_lcd_manager(dssdev);

	/*
	 * LCLK and PCLK divisors are located in shadow registers, and we
	 * normally write them to DISPC registers when enabling the output.
	 * However, SDI uses pck-free as source clock for its PLL, and pck-free
	 * is affected by the divisors. And as we need the PLL before enabling
	 * the output, we need to write the divisors early.
	 *
	 * It seems just writing to the DISPC register is enough, and we don't
	 * need to care about the shadow register mechanism for pck-free. The
	 * exact reason for this is unknown.
	 */
	dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);

	dss_sdi_init(sdi.datapairs);
	r = dss_sdi_enable();
	if (r)
		goto err_sdi_enable;
	mdelay(2);

	r = dss_mgr_enable(out->manager);
	if (r)
		goto err_mgr_enable;

	return 0;

err_mgr_enable:
	dss_sdi_disable();
err_sdi_enable:
err_set_dss_clock_div:
err_calc_clock_div:
	dispc_runtime_put();
err_get_dispc:
	regulator_disable(sdi.vdds_sdi_reg);
err_reg_enable:
	return r;
}
コード例 #10
0
ファイル: hdmi.c プロジェクト: AdrianHuang/linux-3.8.13
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
{
	int r;
	struct omap_video_timings *p;
	struct omap_overlay_manager *mgr = dssdev->output->manager;
	unsigned long phy;

	r = hdmi_power_on_core(dssdev);
	if (r)
		return r;

	dss_mgr_disable(mgr);

	p = &hdmi.ip_data.cfg.timings;

	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);

	phy = p->pixel_clock;

	hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);

	hdmi.ip_data.ops->video_disable(&hdmi.ip_data);

	/* config the PLL and PHY hdmi_set_pll_pwrfirst */
	r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
	if (r) {
		DSSDBG("Failed to lock PLL\n");
		goto err_pll_enable;
	}

	r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data);
	if (r) {
		DSSDBG("Failed to start PHY\n");
		goto err_phy_enable;
	}

	hdmi.ip_data.ops->video_configure(&hdmi.ip_data);

	/* bypass TV gamma table */
	dispc_enable_gamma_table(0);

	/* tv size */
	dss_mgr_set_timings(mgr, p);

	r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
	if (r)
		goto err_vid_enable;

	r = dss_mgr_enable(mgr);
	if (r)
		goto err_mgr_enable;

	return 0;

err_mgr_enable:
	hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
err_vid_enable:
	hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
err_phy_enable:
	hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
err_pll_enable:
	hdmi_power_off_core(dssdev);
	return -EIO;
}
コード例 #11
0
ファイル: hdmi.c プロジェクト: FoundYa/linux
static int hdmi_power_on(struct omap_dss_device *dssdev)
{
	int r;
	struct omap_video_timings *p;
	struct omap_overlay_manager *mgr = dssdev->output->manager;
	unsigned long phy;

	gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
	gpio_set_value(hdmi.ls_oe_gpio, 1);

	/* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */
	udelay(300);

	r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
	if (r)
		goto err_vdac_enable;

	r = hdmi_runtime_get();
	if (r)
		goto err_runtime_get;

	dss_mgr_disable(mgr);

	p = &hdmi.ip_data.cfg.timings;

	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);

	phy = p->pixel_clock;

	hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);

	hdmi.ip_data.ops->video_disable(&hdmi.ip_data);

	/* config the PLL and PHY hdmi_set_pll_pwrfirst */
	r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
	if (r) {
		DSSDBG("Failed to lock PLL\n");
		goto err_pll_enable;
	}

	r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data);
	if (r) {
		DSSDBG("Failed to start PHY\n");
		goto err_phy_enable;
	}

	hdmi.ip_data.ops->video_configure(&hdmi.ip_data);

	/* Make selection of HDMI in DSS */
	dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);

	/* Select the dispc clock source as PRCM clock, to ensure that it is not
	 * DSI PLL source as the clock selected by DSI PLL might not be
	 * sufficient for the resolution selected / that can be changed
	 * dynamically by user. This can be moved to single location , say
	 * Boardfile.
	 */
	dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);

	/* bypass TV gamma table */
	dispc_enable_gamma_table(0);

	/* tv size */
	dss_mgr_set_timings(mgr, p);

	r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
	if (r)
		goto err_vid_enable;

	r = dss_mgr_enable(mgr);
	if (r)
		goto err_mgr_enable;

	return 0;

err_mgr_enable:
	hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
err_vid_enable:
	hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
err_phy_enable:
	hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
err_pll_enable:
	hdmi_runtime_put();
err_runtime_get:
	regulator_disable(hdmi.vdda_hdmi_dac_reg);
err_vdac_enable:
	gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
	gpio_set_value(hdmi.ls_oe_gpio, 0);
	return -EIO;
}
コード例 #12
0
ファイル: hdmi4.c プロジェクト: 513855417/linux
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
{
	int r;
	struct omap_video_timings *p;
	enum omap_channel channel = dssdev->dispc_channel;
	struct hdmi_wp_data *wp = &hdmi.wp;
	struct dss_pll_clock_info hdmi_cinfo = { 0 };
	unsigned pc;

	r = hdmi_power_on_core(dssdev);
	if (r)
		return r;

	/* disable and clear irqs */
	hdmi_wp_clear_irqenable(wp, 0xffffffff);
	hdmi_wp_set_irqstatus(wp, 0xffffffff);

	p = &hdmi.cfg.timings;

	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);

	pc = p->pixelclock;
	if (p->double_pixel)
		pc *= 2;

	hdmi_pll_compute(&hdmi.pll, pc, &hdmi_cinfo);

	r = dss_pll_enable(&hdmi.pll.pll);
	if (r) {
		DSSERR("Failed to enable PLL\n");
		goto err_pll_enable;
	}

	r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
	if (r) {
		DSSERR("Failed to configure PLL\n");
		goto err_pll_cfg;
	}

	r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
		hdmi_cinfo.clkout[0]);
	if (r) {
		DSSDBG("Failed to configure PHY\n");
		goto err_phy_cfg;
	}

	r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
	if (r)
		goto err_phy_pwr;

	hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);

	/* bypass TV gamma table */
	dispc_enable_gamma_table(0);

	/* tv size */
	dss_mgr_set_timings(channel, p);

	r = dss_mgr_enable(channel);
	if (r)
		goto err_mgr_enable;

	r = hdmi_wp_video_start(&hdmi.wp);
	if (r)
		goto err_vid_enable;

	hdmi_wp_set_irqenable(wp,
		HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);

	return 0;

err_vid_enable:
	dss_mgr_disable(channel);
err_mgr_enable:
	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
err_phy_pwr:
err_phy_cfg:
err_pll_cfg:
	dss_pll_disable(&hdmi.pll.pll);
err_pll_enable:
	hdmi_power_off_core(dssdev);
	return -EIO;
}
コード例 #13
0
ファイル: hdmi5.c プロジェクト: vishnupatekar/linux
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
{
	int r;
	struct omap_video_timings *p;
	struct omap_overlay_manager *mgr = hdmi.output.manager;
	struct dss_pll_clock_info hdmi_cinfo = { 0 };

	r = hdmi_power_on_core(dssdev);
	if (r)
		return r;

	p = &hdmi.cfg.timings;

	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);

	hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);

	/* disable and clear irqs */
	hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
	hdmi_wp_set_irqstatus(&hdmi.wp,
			hdmi_wp_get_irqstatus(&hdmi.wp));

	r = dss_pll_enable(&hdmi.pll.pll);
	if (r) {
		DSSERR("Failed to enable PLL\n");
		goto err_pll_enable;
	}

	r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
	if (r) {
		DSSERR("Failed to configure PLL\n");
		goto err_pll_cfg;
	}

	r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
		hdmi_cinfo.clkout[0]);
	if (r) {
		DSSDBG("Failed to start PHY\n");
		goto err_phy_cfg;
	}

	r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON);
	if (r)
		goto err_phy_pwr;

	hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);

	/* bypass TV gamma table */
	dispc_enable_gamma_table(0);

	/* tv size */
	dss_mgr_set_timings(mgr, p);

	r = hdmi_wp_video_start(&hdmi.wp);
	if (r)
		goto err_vid_enable;

	/*
	 * XXX Seems that on we easily get a flood of sync-lost errors when
	 * enabling the output. This seems to be related to the time between
	 * HDMI VSYNC and enabling the DISPC output.
	 *
	 * Testing shows that the sync-lost errors do not happen if we enable
	 * the DISPC output very soon after HDMI VBLANK. So wait here for
	 * VBLANK to reduce the chances of sync-losts.
	 */
	hdmi_write_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_VSYNC);

	while (true) {
		u32 v = hdmi_read_reg(hdmi.wp.base, HDMI_WP_IRQSTATUS_RAW);

		if (v & HDMI_IRQ_VIDEO_VSYNC)
			break;

		usleep_range(500, 1000);
	}

	r = dss_mgr_enable(mgr);
	if (r)
		goto err_mgr_enable;

	hdmi_wp_set_irqenable(&hdmi.wp,
			HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);

	return 0;

err_mgr_enable:
	hdmi_wp_video_stop(&hdmi.wp);
err_vid_enable:
	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
err_phy_pwr:
err_phy_cfg:
err_pll_cfg:
	dss_pll_disable(&hdmi.pll.pll);
err_pll_enable:
	hdmi_power_off_core(dssdev);
	return -EIO;
}