Ejemplo n.º 1
0
static void pfit_landscape(int hsrc_sz, int vsrc_sz,
			int hdst_sz, int vdst_sz)
{
	int hmsb, vmsb, hratio, vratio;

	hdmi_write32(IPIL_PFIT_CONTROL,
			IPIL_PFIT_ENABLE |
			IPIL_PFIT_PIPE_SELECT_B |
			IPIL_PFIT_SCALING_PROGRAM);

	/* handling scaling up and down */
	if (hsrc_sz >= hdst_sz) {
		/* scaling down: msb = 1 */
		hratio = IPIL_PFIT_FRACTIONAL_VALUE * (hsrc_sz - hdst_sz) /
							(hdst_sz + 1);
		hmsb = 1;
	} else {
		/* scaling up: msb = 0 */
		hratio = IPIL_PFIT_FRACTIONAL_VALUE * (hsrc_sz + 1) /
							(hdst_sz + 1);
		hmsb = 0;
	}
	if (vsrc_sz >= vdst_sz) {
		/* scaling down: msb = 1 */
		vratio = IPIL_PFIT_FRACTIONAL_VALUE * (vsrc_sz - vdst_sz) /
							(vdst_sz + 1);
		vmsb = 1;
	} else {
		/* scaling up: msb = 0 */
		vratio = IPIL_PFIT_FRACTIONAL_VALUE * (vsrc_sz + 1) /
							(vdst_sz + 1);
		vmsb = 0;
	}

	pr_debug("\nhdisp = %d, vdisp = %d\n", hdst_sz, vdst_sz);
	pr_debug("\nhratio = %d, vratio = %d\n", hratio, vratio);
	hdmi_write32(IPIL_PFIT_PGM_RATIOS,
		vmsb << IPIL_PFIT_VERT_MSB_SHIFT |
		hmsb << IPIL_PFIT_HORIZ_MSB_SHIFT |
		vratio << IPIL_PFIT_VERT_SCALE_SHIFT |
		hratio << IPIL_PFIT_HORIZ_SCALE_SHIFT);
}
/**
 * Description: Write to DPLL register via IOSF
 *
 * @ep_id:	IOSF endpoint ID (0x13 for DPLL)
 * @reg:        address of register
 * @val:        value to write to register
 *
 * Returns:	none
 */
void gunit_iosf_write32(u32 ep_id, u32 reg, u32 val)
{
	u32 ret;
	int retry = 0;
	u32 sb_pkt = (1 << 16) | (ep_id << 8) | 0xf0;

	/* Write value to side band register */
	hdmi_write32(0x2108, reg);
	hdmi_write32(0x2104, val);
	hdmi_write32(0x2100, sb_pkt);

	/* Check if transaction is complete */
	ret = hdmi_read32(0x210C);
	while ((retry++ < 0x1000) && (ret != 0x2)) {
		usleep_range(500, 1000);
		ret = hdmi_read32(0x210C);
	}

	if (ret != 2)
		pr_err("%s: failed to program DPLL\n", __func__);
}
/**
 * Description: programs dpll clocks, enables dpll and waits
 *		till it locks with DSI PLL
 *
 * @dev:	hdmi_device_t
 * @dclk:	refresh rate dot clock in kHz of current mode
 *
 * Returns:	OTM_HDMI_SUCCESS on success
 *		OTM_HDMI_ERR_INVAL on NULL input arguments
 */
otm_hdmi_ret_t	ips_hdmi_crtc_mode_set_program_dpll(hdmi_device_t *dev,
							unsigned long dclk)
{
	otm_hdmi_ret_t rc = OTM_HDMI_SUCCESS;
	u32 dpll_adj, fp;
	u32 dpll;
	int timeout = 0;

	/* NULL checks */
	if (dev == NULL) {
		pr_debug("\ninvalid argument\n");
		return OTM_HDMI_ERR_INVAL;
	}

	rc = __ips_hdmi_get_adjusted_clk(dclk, &dpll_adj, &fp, &dev->clock_khz);
	dpll = hdmi_read32(IPIL_DPLL_B);
	if (dpll & IPIL_DPLL_VCO_ENABLE) {
		dpll &= ~IPIL_DPLL_VCO_ENABLE;
		hdmi_write32(IPIL_DPLL_B, dpll);
		hdmi_read32(IPIL_DPLL_B);

		/* reset M1, N1 & P1 */
		hdmi_write32(IPIL_DPLL_DIV0, 0);
		dpll &= ~IPIL_P1_MASK;
		hdmi_write32(IPIL_DPLL_B, dpll);
	}

	/*
	 * When ungating power of DPLL, needs to wait 0.5us
	 * before enable the VCO
	 */
	if (dpll & IPIL_PWR_GATE_EN) {
		dpll &= ~IPIL_PWR_GATE_EN;
		hdmi_write32(IPIL_DPLL_B, dpll);
		udelay(1);
	}

	dpll = dpll_adj;
	hdmi_write32(IPIL_DPLL_DIV0, fp);
	hdmi_write32(IPIL_DPLL_B, dpll);
	udelay(1);

	dpll |= IPIL_DPLL_VCO_ENABLE;
	hdmi_write32(IPIL_DPLL_B, dpll);
	hdmi_read32(IPIL_DPLL_B);

	/* wait for DSI PLL to lock */
	while ((timeout < 20000) && !(hdmi_read32(IPIL_PIPEBCONF) &
					IPIL_PIPECONF_PLL_LOCK)) {
		udelay(150);
		timeout++;
	}

	return OTM_HDMI_SUCCESS;
}
/**
 * Description: Read DPLL register via IOSF
 *
 * @ep_id:	IOSF endpoint ID (0x13 for DPLL)
 * @reg:        address of register
 *
 * Returns:	value of register
 */
u32 gunit_iosf_read32(u32 ep_id, u32 reg)
{
	u32 ret;
	int retry = 0;
	u32 sb_pkt = (0 << 16) | (ep_id << 8) | 0xf0;

	/* Read side band register */
	hdmi_write32(0x2108, reg);
	hdmi_write32(0x2100, sb_pkt);

	/* Check if transaction is complete */
	ret = hdmi_read32(0x210C);
	while ((retry++ < 0x1000) && (ret != 2)) {
		usleep_range(500, 1000);
		ret = hdmi_read32(0x210C);
	}

	if (ret != 2)
		pr_err("%s: Failed to read\n", __func__);
	else
		ret = hdmi_read32(0x2104);

	return ret;
}
static void __ips_hdmi_clk_lanes(unsigned long clk)
{
	if ((clk > IPS_PIXEL_CLOCK_145) || (clk == IPS_PIXEL_CLOCK_145)) {
		hdmi_write32(IPS_HDMIB_LANES02, IPS_M_LANES_145);
		hdmi_write32(IPS_HDMIB_LANES3, IPS_M_LANES_145);
	} else if ((clk > IPS_PIXEL_CLOCK_54) || (clk == IPS_PIXEL_CLOCK_54)) {
		hdmi_write32(IPS_HDMIB_LANES02, IPS_M_LANES_54);
		hdmi_write32(IPS_HDMIB_LANES3, IPS_M_LANES_54);
	} else {
		hdmi_write32(IPS_HDMIB_LANES02, IPS_M_LANES_27);
		hdmi_write32(IPS_HDMIB_LANES3, IPS_M_LANES_27);
	}
}
Ejemplo n.º 6
0
/**
 * Description: programs hdmi pipe src and size of the input.
 *
 * @dev:		hdmi_device_t
 * @scalingtype:	scaling type (FULL_SCREEN, CENTER, NO_SCALE etc.)
 * @mode:		mode requested
 * @adjusted_mode:	adjusted mode
 * @fb_width, fb_height:allocated frame buffer dimensions
 *
 * Returns:	OTM_HDMI_SUCCESS on success
 *		OTM_HDMI_ERR_INVAL on NULL input arguments
 */
otm_hdmi_ret_t ipil_hdmi_crtc_mode_set_program_dspregs(hdmi_device_t *dev,
					int scalingtype,
					ipil_timings_t *mode,
					ipil_timings_t *adjusted_mode,
					int fb_width, int fb_height)
{
	int sprite_pos_x = 0, sprite_pos_y = 0;
	int sprite_width = 0, sprite_height = 0;
	int src_image_hor = 0, src_image_vert = 0;
	int wa;

	pr_debug("Enter %s\n", __func__);

	/* NULL checks */
	if (dev == NULL || mode == NULL || adjusted_mode == NULL) {
		pr_debug("\ninvalid argument\n");
		return OTM_HDMI_ERR_INVAL;
	}

	/*
	 * Frame buffer size may beyond active region in case of
	 * panning mode.
	 */
	sprite_width = min_t(int, fb_width, adjusted_mode->width);
	sprite_height = min_t(int, fb_height, adjusted_mode->height);

	switch (scalingtype) {
	case OTM_HDMI_SCALE_NONE:
	case OTM_HDMI_SCALE_CENTER:
		/*
		 * This mode is used to support centering the screen
		 * by setting reg in DISPLAY controller
		 */
		src_image_hor = adjusted_mode->width;
		src_image_vert = adjusted_mode->height;
		sprite_pos_x = (src_image_hor - sprite_width) / 2;
		sprite_pos_y = (src_image_vert - sprite_height) / 2;

		hdmi_write32(IPIL_PFIT_CONTROL,
				hdmi_read32(IPIL_PFIT_CONTROL) &
						~IPIL_PFIT_ENABLE);
		break;

	case OTM_HDMI_SCALE_FULLSCREEN:
		src_image_hor = sprite_width;
		src_image_vert = sprite_height;
		sprite_pos_x = 0;
		sprite_pos_y = 0;

		if ((adjusted_mode->width > sprite_width) ||
			(adjusted_mode->height > sprite_height))
			hdmi_write32(IPIL_PFIT_CONTROL,
					IPIL_PFIT_ENABLE |
					IPIL_PFIT_PIPE_SELECT_B |
					IPIL_PFIT_SCALING_AUTO);
		break;

	case OTM_HDMI_SCALE_ASPECT:
		sprite_pos_x = 0;
		sprite_pos_y = 0;
		sprite_height = fb_height;
		sprite_width = fb_width;
		src_image_hor = fb_width;
		src_image_vert = fb_height;

		/* Use panel fitting when the display does not match
		 * with the framebuffer size */
		if ((adjusted_mode->width != fb_width) ||
		    (adjusted_mode->height != fb_height)) {
			if (fb_width > fb_height) {
				/* Landscape mode */
				pr_debug("Landscape mode...\n");

				/* Landscape mode: program ratios is
				 * used because 480p does not work with
				 * auto */
				if (adjusted_mode->height == 480)
					pfit_landscape(sprite_width,
						sprite_height,
						adjusted_mode->width,
						adjusted_mode->height);
				else
					hdmi_write32(IPIL_PFIT_CONTROL,
						IPIL_PFIT_ENABLE |
						IPIL_PFIT_PIPE_SELECT_B |
						IPIL_PFIT_SCALING_AUTO);
			} else {
				/* Portrait mode */
				pr_debug("Portrait mode...\n");

				/* Panel fitter HW has some limitations/bugs
				 * which forces us to tweak the way we use
				 * PILLARBOX mode.
				 */
				wa = pfit_pillarbox_wa(fb_height,
							adjusted_mode->height);
				pr_debug("wa = %d\n", wa);

				src_image_hor = max_t(int, fb_width,
						     adjusted_mode->width) + wa;
				src_image_vert = max_t(int, fb_height,
						      adjusted_mode->height);
				sprite_pos_x = (src_image_hor - fb_width) / 2;
				hdmi_write32(IPIL_PFIT_CONTROL,
					     IPIL_PFIT_ENABLE |
					     IPIL_PFIT_PIPE_SELECT_B |
					     IPIL_PFIT_SCALING_PILLARBOX);
			}
		} else
			hdmi_write32(IPIL_PFIT_CONTROL,
					IPIL_PFIT_ENABLE |
					IPIL_PFIT_PIPE_SELECT_B |
					IPIL_PFIT_SCALING_AUTO);

		break;

	default:
		/* The defined sprite rectangle must always be
		completely contained within the displayable area of the
		screen image (frame buffer). */
		sprite_pos_x = 0;
		sprite_pos_y = 0;
		sprite_height = fb_height;
		sprite_width = fb_width;
		src_image_hor = fb_width;
		src_image_vert = fb_height;
		if ((adjusted_mode->width != fb_width) ||
				(adjusted_mode->height != fb_height))
			hdmi_write32(IPIL_PFIT_CONTROL,
					IPIL_PFIT_ENABLE |
					IPIL_PFIT_PIPE_SELECT_B);

		break;
	}
/**
 * Description: restore HDMI display registers and enable display
 *
 * @dev:	hdmi_device_t
 *
 * Returns:	none
 */
void ips_hdmi_restore_and_enable_display(hdmi_device_t *dev)
{

	int i;

	if (NULL == dev)  {
		pr_debug("\n%s invalid argument\n", __func__);
		return;
	}
	if (dev->reg_state.valid == false) {
		pr_debug("\nhdmi no data to restore\n");
		return;
	}

	/*make sure VGA plane is off. it initializes to on after reset!*/
	hdmi_write32(IPIL_VGACNTRL, IPIL_VGA_DISP_DISABLE);

	ips_hdmi_crtc_mode_set_program_dpll(dev, dev->clock_khz);

	/* Restore mode */
	hdmi_write32(IPS_HTOTAL_B, dev->reg_state.saveHTOTAL_B);
	hdmi_write32(IPS_HBLANK_B, dev->reg_state.saveHBLANK_B);
	hdmi_write32(IPS_HSYNC_B, dev->reg_state.saveHSYNC_B);
	hdmi_write32(IPS_VTOTAL_B, dev->reg_state.saveVTOTAL_B);
	hdmi_write32(IPS_VBLANK_B, dev->reg_state.saveVBLANK_B);
	hdmi_write32(IPS_VSYNC_B, dev->reg_state.saveVSYNC_B);
	hdmi_write32(IPS_PIPEBSRC, dev->reg_state.savePIPEBSRC);
	hdmi_write32(IPS_DSPBSTAT, dev->reg_state.saveDSPBSTATUS);

	/*set up the plane*/
	hdmi_write32(IPS_DSPBSTRIDE, dev->reg_state.saveDSPBSTRIDE);
	hdmi_write32(IPS_DSPBLINOFF, dev->reg_state.saveDSPBLINOFF);
	hdmi_write32(IPS_DSPBTILEOFF, dev->reg_state.saveDSPBTILEOFF);
	hdmi_write32(IPS_DSPBSIZE, dev->reg_state.saveDSPBSIZE);
	hdmi_write32(IPS_DSPBPOS, dev->reg_state.saveDSPBPOS);
	hdmi_write32(IPS_DSPBSURF, dev->reg_state.saveDSPBSURF);

	hdmi_write32(IPS_PFIT_CONTROL, dev->reg_state.savePFIT_CONTROL);
	hdmi_write32(IPS_PFIT_PGM_RATIOS, dev->reg_state.savePFIT_PGM_RATIOS);
	hdmi_write32(IPS_HDMIPHYMISCCTL, dev->reg_state.saveHDMIPHYMISCCTL);
	hdmi_write32(IPS_HDMIB_CONTROL, dev->reg_state.saveHDMIB_CONTROL);

	/*enable the plane*/
	hdmi_write32(IPS_DSPBCNTR, dev->reg_state.saveDSPBCNTR);
	hdmi_write32(IPS_HDMIB_LANES02, dev->reg_state.saveHDMIB_DATALANES);
	hdmi_write32(IPS_HDMIB_LANES3, dev->reg_state.saveHDMIB_DATALANES);

	/*enable the pipe */
	hdmi_write32(IPS_PIPEBCONF, dev->reg_state.savePIPEBCONF);

	/* restore palette (gamma) */
	for (i = 0; i < 256; i++)
		hdmi_write32(IPS_PALETTE_B + (i<<2),
				dev->reg_state.save_palette_b[i]);

	dev->reg_state.valid = false;
}
/**
 * Description: programs dpll clocks, enables dpll and waits
 *		till it locks with DSI PLL
 *
 * @m1, m2:     DPLL m values
 * @n:          DPLL n value
 * @p1, p2:     DPLL p values
 *
 * Returns:	none
*/
static void __ips_hdmi_set_program_dpll(int n, int p1, int p2, int m1, int m2)
{
	u32 ret, tmp;
	int retry = 0;
	u32 div = (0x11 << 24) | (p1 << 21) | (p2 << 16) | (n << 12) |
		  (0x1 << 11)  | (m1 << 8)  | (m2);

	pr_debug("enter %s\n", __func__);

	/* Common reset */
	hdmi_write32(IPS_DPLL_B, 0x70006800);

	/* Program DPLL registers via IOSF (TNG display HAS) */

	/* Process monitor to 19.2MHz */
	gunit_iosf_write32(DPLL_IOSF_EP, REF_DWORD22, 0x19080000);

	/* LRC clock to 19.2MHz */
	gunit_iosf_write32(DPLL_IOSF_EP, DPLL_LRC_CLK, 0x00000F10);

	/* Disable periodic GRC IREF update for DPLL */
	tmp = gunit_iosf_read32(DPLL_IOSF_EP, PLLB_DWORD8);
	gunit_iosf_write32(DPLL_IOSF_EP, PLLB_DWORD8, tmp & 0x00FFFFFF);

	/* Enable Tx for periodic GRC update*/
	gunit_iosf_write32(DPLL_IOSF_EP, DPLL_Tx_GRC, 0x0100000F);

	/* GRC cal clock set to 19.2MHZ */
	gunit_iosf_write32(DPLL_IOSF_EP, REF_DWORD18, 0x30002400);

	/* Set lock time to 53us.
	 * Disable fast lock.
	 */
	gunit_iosf_write32(DPLL_IOSF_EP, CMN_DWORD8, 0x0);

	/* Set divisors*/
	gunit_iosf_write32(DPLL_IOSF_EP, PLLA_DWORD3_1, div);
	gunit_iosf_write32(DPLL_IOSF_EP, PLLA_DWORD3_2, div);

	/* Set up LCPLL in digital mode */
	gunit_iosf_write32(DPLL_IOSF_EP, PLLA_DWORD5_1, 0x0DF44300);
	gunit_iosf_write32(DPLL_IOSF_EP, PLLA_DWORD5_2, 0x0DF44300);

	/* LPF co-efficients for LCPLL in digital mode */
	gunit_iosf_write32(DPLL_IOSF_EP, PLLB_DWORD10_1, 0x005F0021);
	gunit_iosf_write32(DPLL_IOSF_EP, PLLB_DWORD10_2, 0x005F0021);

	/* Disable unused TLine clocks on right side */
	gunit_iosf_write32(DPLL_IOSF_EP, CMN_DWORD3, 0x14540000);

	/* Enable DPLL */
	tmp = hdmi_read32(IPS_DPLL_B);
	hdmi_write32(IPS_DPLL_B, tmp | IPIL_DPLL_VCO_ENABLE);

	/* Enable DCLP to core */
	tmp = gunit_iosf_read32(DPLL_IOSF_EP, PLLA_DWORD7_1);
	gunit_iosf_write32(DPLL_IOSF_EP, PLLA_DWORD7_1, tmp | (1 << 24));
	tmp = gunit_iosf_read32(DPLL_IOSF_EP, PLLA_DWORD7_2);
	gunit_iosf_write32(DPLL_IOSF_EP, PLLA_DWORD7_2, tmp | (1 << 24));

	/* Set HDMI lane CML clock */
	gunit_iosf_write32(DPLL_IOSF_EP, DPLL_CML_CLK1, 0x07760018);
	gunit_iosf_write32(DPLL_IOSF_EP, DPLL_CML_CLK2, 0x00400888);

	/* Swing settings */
	gunit_iosf_write32(DPLL_IOSF_EP, TX_SWINGS_1, 0x00000000);
	gunit_iosf_write32(DPLL_IOSF_EP, TX_SWINGS_2, 0x2B407055);
	gunit_iosf_write32(DPLL_IOSF_EP, TX_SWINGS_3, 0x55A0983A);
	gunit_iosf_write32(DPLL_IOSF_EP, TX_SWINGS_4, 0x0C782040);
	gunit_iosf_write32(DPLL_IOSF_EP, TX_SWINGS_5, 0x2B247878);
	gunit_iosf_write32(DPLL_IOSF_EP, TX_SWINGS_6, 0x00030000);
	gunit_iosf_write32(DPLL_IOSF_EP, TX_SWINGS_7, 0x00004000);
	gunit_iosf_write32(DPLL_IOSF_EP, TX_SWINGS_1, 0x80000000);

	/* Stagger Programming */
	gunit_iosf_write32(DPLL_IOSF_EP, PCS_DWORD12_1, 0x00401F00);
	gunit_iosf_write32(DPLL_IOSF_EP, PCS_DWORD12_2, 0x00451F00);

	/* Wait until DPLL is locked */
	ret = hdmi_read32(IPS_DPLL_B);
	ret &= 0x8000;
	while ((retry++ < 1000) && (ret != 0x8000)) {
		usleep_range(500, 1000);
		ret = hdmi_read32(IPS_DPLL_B);
		ret &= 0x8000;
	}

	if (ret != 0x8000) {
		pr_err("%s: DPLL failed to lock, exit...\n", __func__);
		return;
	}
}