Ejemplo n.º 1
0
void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
				 struct videomode *vm)
{
	u32 timing_h = 0;
	u32 timing_v = 0;
	unsigned hsync_len_offset = 1;

	DSSDBG("Enter hdmi_wp_video_config_timing\n");

	/*
	 * On OMAP4 and OMAP5 ES1 the HSW field is programmed as is. On OMAP5
	 * ES2+ (including DRA7/AM5 SoCs) HSW field is programmed to hsync_len-1.
	 * However, we don't support OMAP5 ES1 at all, so we can just check for
	 * OMAP4 here.
	 */
	if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
	    omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
	    omapdss_get_version() == OMAPDSS_VER_OMAP4)
		hsync_len_offset = 0;

	timing_h |= FLD_VAL(vm->hback_porch, 31, 20);
	timing_h |= FLD_VAL(vm->hfront_porch, 19, 8);
	timing_h |= FLD_VAL(vm->hsync_len - hsync_len_offset, 7, 0);
	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);

	timing_v |= FLD_VAL(vm->vback_porch, 31, 20);
	timing_v |= FLD_VAL(vm->vfront_porch, 19, 8);
	timing_v |= FLD_VAL(vm->vsync_len, 7, 0);
	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
}
Ejemplo n.º 2
0
static void hdmi_core_av_packet_config(struct hdmi_core_data *core,
		struct hdmi_core_packet_enable_repeat repeat_cfg)
{
	/* enable/repeat the infoframe */
	hdmi_write_reg(hdmi_av_base(core), HDMI_CORE_AV_PB_CTRL1,
		(repeat_cfg.audio_pkt << 5) |
		(repeat_cfg.audio_pkt_repeat << 4) |
		(repeat_cfg.avi_infoframe << 1) |
		(repeat_cfg.avi_infoframe_repeat));

	/* enable/repeat the packet */
	hdmi_write_reg(hdmi_av_base(core), HDMI_CORE_AV_PB_CTRL2,
		(repeat_cfg.gen_cntrl_pkt << 3) |
		(repeat_cfg.gen_cntrl_pkt_repeat << 2) |
		(repeat_cfg.generic_pkt << 1) |
		(repeat_cfg.generic_pkt_repeat));
}
Ejemplo n.º 3
0
void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
		struct hdmi_audio_dma *aud_dma)
{
	u32 r;

	DSSDBG("Enter hdmi_wp_audio_config_dma\n");

	r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);
	r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
	r = FLD_MOD(r, aud_dma->block_size, 7, 0);
	hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);

	r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);
	r = FLD_MOD(r, aud_dma->mode, 9, 9);
	r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
	hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);
}
Ejemplo n.º 4
0
void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
		struct omap_video_timings *timings)
{
	u32 timing_h = 0;
	u32 timing_v = 0;

	DSSDBG("Enter hdmi_wp_video_config_timing\n");

	timing_h |= FLD_VAL(timings->hbp, 31, 20);
	timing_h |= FLD_VAL(timings->hfp, 19, 8);
	timing_h |= FLD_VAL(timings->hsw, 7, 0);
	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);

	timing_v |= FLD_VAL(timings->vbp, 31, 20);
	timing_v |= FLD_VAL(timings->vfp, 19, 8);
	timing_v |= FLD_VAL(timings->vsw, 7, 0);
	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
}
Ejemplo n.º 5
0
/* HDMI_CORE_VIDEO_CONFIG */
static void hdmi_core_video_config(struct hdmi_core_data *core,
				struct hdmi_core_video_config *cfg)
{
	u32 r = 0;
	void __iomem *core_sys_base = core->base;
	void __iomem *core_av_base = hdmi_av_base(core);

	/* sys_ctrl1 default configuration not tunable */
	r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_SYS_CTRL1);
	r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_VEN_FOLLOWVSYNC, 5, 5);
	r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_HEN_FOLLOWHSYNC, 4, 4);
	r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_BSEL_24BITBUS, 2, 2);
	r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_EDGE_RISINGEDGE, 1, 1);
	hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_SYS_CTRL1, r);

	REG_FLD_MOD(core_sys_base,
			HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6);

	/* Vid_Mode */
	r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE);

	/* dither truncation configuration */
	if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) {
		r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6);
		r = FLD_MOD(r, 1, 5, 5);
	} else {
		r = FLD_MOD(r, cfg->op_dither_truc, 7, 6);
		r = FLD_MOD(r, 0, 5, 5);
	}
	hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE, r);

	/* HDMI_Ctrl */
	r = hdmi_read_reg(core_av_base, HDMI_CORE_AV_HDMI_CTRL);
	r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6);
	r = FLD_MOD(r, cfg->pkt_mode, 5, 3);
	r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0);
	hdmi_write_reg(core_av_base, HDMI_CORE_AV_HDMI_CTRL, r);

	/* TMDS_CTRL */
	REG_FLD_MOD(core_sys_base,
			HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5);
}
Ejemplo n.º 6
0
void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
		struct hdmi_video_format *video_fmt)
{
	u32 l = 0;

	REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,
		10, 8);

	l |= FLD_VAL(video_fmt->y_res, 31, 16);
	l |= FLD_VAL(video_fmt->x_res, 15, 0);
	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);
}
int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp,
			struct hdmi_config *cfg)
{
	u16 r = 0;
	u32 irqstatus;

	hdmi_wp_clear_irqenable(wp, 0xffffffff);

	irqstatus = hdmi_wp_get_irqstatus(wp);
	hdmi_wp_set_irqstatus(wp, irqstatus);

	r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
	if (r)
		return r;

	/*
	 * Read address 0 in order to get the SCP reset done completed
	 * Dummy access performed to make sure reset is done
	 */
	hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);

	/*
	 * Write to phy address 0 to configure the clock
	 * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
	 */
	REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);

	/* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
	hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);

	/* Setup max LDO voltage */
	REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);

	/* Write to phy address 3 to change the polarity control */
	REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);

	r = request_threaded_irq(phy->irq, NULL, hdmi_irq_handler,
				IRQF_ONESHOT, "OMAP HDMI", wp);
	if (r) {
		DSSERR("HDMI IRQ request failed\n");
		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
		return r;
	}

	hdmi_wp_set_irqenable(wp,
		HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);

	return 0;
}
Ejemplo n.º 8
0
void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
		struct omap_video_timings *timings)
{
	u32 r;
	bool vsync_pol, hsync_pol;
	DSSDBG("Enter hdmi_wp_video_config_interface\n");

	vsync_pol = timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
	hsync_pol = timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;

	r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
	r = FLD_MOD(r, vsync_pol, 7, 7);
	r = FLD_MOD(r, hsync_pol, 6, 6);
	r = FLD_MOD(r, timings->interlace, 3, 3);
	r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
}
Ejemplo n.º 9
0
void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
				    struct videomode *vm)
{
	u32 r;
	bool vsync_pol, hsync_pol;
	DSSDBG("Enter hdmi_wp_video_config_interface\n");

	vsync_pol = !!(vm->flags & DISPLAY_FLAGS_VSYNC_HIGH);
	hsync_pol = !!(vm->flags & DISPLAY_FLAGS_HSYNC_HIGH);

	r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
	r = FLD_MOD(r, vsync_pol, 7, 7);
	r = FLD_MOD(r, hsync_pol, 6, 6);
	r = FLD_MOD(r, !!(vm->flags & DISPLAY_FLAGS_INTERLACED), 3, 3);
	r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
}
Ejemplo n.º 10
0
static void hdmi_power_off_full(struct omap_dss_device *dssdev)
{
	struct omap_overlay_manager *mgr = hdmi.output.manager;
	const struct omap_video_timings *t;
	unsigned vblank;

	hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);

	/*
	 * XXX Seems that on we easily get a flood of sync-lost errors when
	 * disabling the output, and sometimes the DISPC seems to get stuck and
	 * we never get FRAMEDONE. This seems to happen if we disable DISPC
	 * output during HDMI VBLANK.
	 *
	 * To reduce the possibility for sync-lost errors, calculate the time
	 * for the vertical blanking, wait for VBLANK, then wait until VBLANK
	 * ends.
	 */
	t = &hdmi.cfg.timings;
	vblank = t->hfp + t->hsw + t->hbp + t->x_res;
	vblank *= t->vsw + t->vbp;
	vblank = (vblank * 1000) / (t->pixelclock / 1000);

	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);
	}

	usleep_range(vblank, vblank + 1000);

	dss_mgr_disable(mgr);

	hdmi_wp_video_stop(&hdmi.wp);

	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);

	dss_pll_disable(&hdmi.pll.pll);

	hdmi_power_off_core(dssdev);
}
Ejemplo n.º 11
0
static void hdmi_core_write_avi_infoframe(struct hdmi_core_data *core,
	struct hdmi_avi_infoframe *frame)
{
	void __iomem *av_base = hdmi_av_base(core);
	u8 data[HDMI_INFOFRAME_SIZE(AVI)];
	int i;

	hdmi_avi_infoframe_pack(frame, data, sizeof(data));

	print_hex_dump_debug("AVI: ", DUMP_PREFIX_NONE, 16, 1, data,
		HDMI_INFOFRAME_SIZE(AVI), false);

	for (i = 0; i < sizeof(data); ++i) {
		hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_BASE + i * 4,
			data[i]);
	}
}
Ejemplo n.º 12
0
int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
	unsigned long lfbitclk)
{
	u8 freqout;

	/*
	 * Read address 0 in order to get the SCP reset done completed
	 * Dummy access performed to make sure reset is done
	 */
	hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);

	/*
	 * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the
	 * HDMI_PHYPWRCMD_LDOON command.
	*/
	if (phy->features->bist_ctrl)
		REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);

	/*
	 * If the hfbitclk != lfbitclk, it means the lfbitclk was configured
	 * to be used for TMDS.
	 */
	if (hfbitclk != lfbitclk)
		freqout = 0;
	else if (hfbitclk / 10 < phy->features->max_phy)
		freqout = 1;
	else
		freqout = 2;

	/*
	 * Write to phy address 0 to configure the clock
	 * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
	 */
	REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30);

	/* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
	hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);

	/* Setup max LDO voltage */
	if (phy->features->ldo_voltage)
		REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);

	hdmi_phy_configure_lanes(phy);

	return 0;
}
Ejemplo n.º 13
0
static irqreturn_t hdmi_irq_handler(int irq, void *data)
{
	struct hdmi_wp_data *wp = data;
	u32 irqstatus;

	irqstatus = hdmi_wp_get_irqstatus(wp);
	hdmi_wp_set_irqstatus(wp, irqstatus);

	if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
			irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
		u32 v;
		/*
		 * If we get both connect and disconnect interrupts at the same
		 * time, turn off the PHY, clear interrupts, and restart, which
		 * raises connect interrupt if a cable is connected, or nothing
		 * if cable is not connected.
		 */

		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);

		/*
		 * We always get bogus CONNECT & DISCONNECT interrupts when
		 * setting the PHY to LDOON. To ignore those, we force the RXDET
		 * line to 0 until the PHY power state has been changed.
		 */
		v = hdmi_read_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL);
		v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */
		v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */
		hdmi_write_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v);

		hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
				HDMI_IRQ_LINK_DISCONNECT);

		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);

		REG_FLD_MOD(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15);

	} else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
	} else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
	}

	return IRQ_HANDLED;
}
Ejemplo n.º 14
0
void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
		struct hdmi_audio_format *aud_fmt)
{
	u32 r;

	DSSDBG("Enter hdmi_wp_audio_config_format\n");

	r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
	r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
	r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
	r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
	r = FLD_MOD(r, aud_fmt->type, 4, 4);
	r = FLD_MOD(r, aud_fmt->justification, 3, 3);
	r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
	r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
	r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
	hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);
}
Ejemplo n.º 15
0
void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
				    struct videomode *vm)
{
	u32 r;
	bool vsync_inv, hsync_inv;
	DSSDBG("Enter hdmi_wp_video_config_interface\n");

	vsync_inv = !!(vm->flags & DISPLAY_FLAGS_VSYNC_LOW);
	hsync_inv = !!(vm->flags & DISPLAY_FLAGS_HSYNC_LOW);

	r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
	r = FLD_MOD(r, 1, 7, 7);	/* VSYNC_POL to dispc active high */
	r = FLD_MOD(r, 1, 6, 6);	/* HSYNC_POL to dispc active high */
	r = FLD_MOD(r, vsync_inv, 5, 5);	/* CORE_VSYNC_INV */
	r = FLD_MOD(r, hsync_inv, 4, 4);	/* CORE_HSYNC_INV */
	r = FLD_MOD(r, !!(vm->flags & DISPLAY_FLAGS_INTERLACED), 3, 3);
	r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
}
Ejemplo n.º 16
0
void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
{
	int i;

	hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE);

	REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);

	for (i = 0; i < 50; ++i) {
		u32 v;

		msleep(20);

		v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW);
		if (v & HDMI_IRQ_VIDEO_FRAME_DONE)
			return;
	}

	DSSERR("no HDMI FRAMEDONE when disabling output\n");
}
Ejemplo n.º 17
0
void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)
{
	hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);
}
Ejemplo n.º 18
0
void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)
{
	hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);
}
Ejemplo n.º 19
0
void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)
{
	hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);
	/* flush posted write */
	hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
}
Ejemplo n.º 20
0
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;
}
Ejemplo n.º 21
0
static int hdmi_pll_config(struct hdmi_pll_data *pll)
{
	u32 r;
	struct hdmi_pll_info *fmt = &pll->info;

	/* PLL start always use manual mode */
	REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);

	r = hdmi_read_reg(pll->base, PLLCTRL_CFG1);
	r = FLD_MOD(r, fmt->regm, 20, 9);	/* CFG1_PLL_REGM */
	r = FLD_MOD(r, fmt->regn - 1, 8, 1);	/* CFG1_PLL_REGN */
	hdmi_write_reg(pll->base, PLLCTRL_CFG1, r);

	r = hdmi_read_reg(pll->base, PLLCTRL_CFG2);

	r = FLD_MOD(r, 0x0, 12, 12);	/* PLL_HIGHFREQ divide by 2 */
	r = FLD_MOD(r, 0x1, 13, 13);	/* PLL_REFEN */
	r = FLD_MOD(r, 0x0, 14, 14);	/* PHY_CLKINEN de-assert during locking */
	r = FLD_MOD(r, fmt->refsel, 22, 21);	/* REFSEL */

	if (fmt->dcofreq)
		r = FLD_MOD(r, 0x4, 3, 1);	/* 1000MHz and 2000MHz */
	else
		r = FLD_MOD(r, 0x2, 3, 1);	/* 500MHz and 1000MHz */

	hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);

	REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);

	r = hdmi_read_reg(pll->base, PLLCTRL_CFG4);
	r = FLD_MOD(r, fmt->regm2, 24, 18);
	r = FLD_MOD(r, fmt->regmf, 17, 0);
	hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);

	/* go now */
	REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);

	/* wait for bit change */
	if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO,
			0, 0, 0) != 0) {
		DSSERR("PLL GO bit not clearing\n");
		return -ETIMEDOUT;
	}

	/* Wait till the lock bit is set in PLL status */
	if (hdmi_wait_for_bit_change(pll->base,
			PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
		DSSERR("cannot lock PLL\n");
		DSSERR("CFG1 0x%x\n",
			hdmi_read_reg(pll->base, PLLCTRL_CFG1));
		DSSERR("CFG2 0x%x\n",
			hdmi_read_reg(pll->base, PLLCTRL_CFG2));
		DSSERR("CFG4 0x%x\n",
			hdmi_read_reg(pll->base, PLLCTRL_CFG4));
		return -ETIMEDOUT;
	}

	DSSDBG("PLL locked!\n");

	return 0;
}