mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	video: sunxi: Support LVDS output on A83T
- Enable LVDS pins (PD18-PD27) - De-assert LVDS interface reset line - Enable sunxi_lcd platform device for A83T - Really disable all interrupts - A83T does have only a simple clock gate for TCON0 clock (no need to select source) - Lifted some analog circuitry setup magic from the Linux driver Signed-off-by: Ondrej Jirman <megous@megous.com>
This commit is contained in:
		| @@ -280,11 +280,17 @@ struct sunxi_ccm_reg { | ||||
| #define CCM_DRAM_GATE_OFFSET_DE_BE0	26 | ||||
| #define CCM_DRAM_GATE_OFFSET_DE_BE1	27 | ||||
|  | ||||
|  | ||||
| #define MBUS_CLK_DEFAULT		0x81000002 /* PLL6 / 2 */ | ||||
|  | ||||
| #define MBUS_CLK_GATE			(0x1 << 31) | ||||
|  | ||||
| #define CCM_LCD_CH0_CTRL_PLL3		(0 << 24) | ||||
| #define CCM_LCD_CH0_CTRL_GATE		(0x1 << 31) | ||||
|  | ||||
| #define CCM_LCD_CH1_CTRL_M(n)		((((n) - 1) & 0xf) << 0) | ||||
| #define CCM_LCD_CH1_CTRL_PLL3		(0 << 24) | ||||
| #define CCM_LCD_CH1_CTRL_GATE		(0x1 << 31) | ||||
|  | ||||
| /* ahb_reset0 offsets */ | ||||
| #define AHB_RESET_OFFSET_GMAC		17 | ||||
| #define AHB_RESET_OFFSET_MCTL		14 | ||||
|   | ||||
| @@ -79,15 +79,18 @@ struct sunxi_lcdc_reg { | ||||
| #define SUNXI_LCDC_TCON0_CTRL_ENABLE		(1 << 31) | ||||
| #define SUNXI_LCDC_TCON0_DCLK_DIV(n)		((n) << 0) | ||||
| #define SUNXI_LCDC_TCON0_DCLK_ENABLE		(0xf << 28) | ||||
| #define SUNXI_LCDC_TCON0_DCLK_ENABLE_1		(1 << 31) | ||||
| #define SUNXI_LCDC_TCON0_TIMING_H_BP(n)		(((n) - 1) << 0) | ||||
| #define SUNXI_LCDC_TCON0_TIMING_H_TOTAL(n)	(((n) - 1) << 16) | ||||
| #define SUNXI_LCDC_TCON0_TIMING_V_BP(n)		(((n) - 1) << 0) | ||||
| #define SUNXI_LCDC_TCON0_TIMING_V_TOTAL(n)	(((n) * 2) << 16) | ||||
| #ifdef CONFIG_SUNXI_GEN_SUN6I | ||||
| #if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_MACH_SUN8I_A83T) | ||||
| #define SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0	(1 << 20) | ||||
| #else | ||||
| #define SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0	0 /* NA */ | ||||
| #endif | ||||
| #define SUNXI_LCDC_TCON0_LVDS_IF_CLK_POL_NORMAL		(1 << 4) | ||||
| #define SUNXI_LCDC_TCON0_LVDS_IF_DATA_POL_NORMAL	(0xf) | ||||
| #define SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(n)	((n) << 26) | ||||
| #define SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE	(1 << 31) | ||||
| #define SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(x)	((x) << 28) | ||||
| @@ -103,10 +106,15 @@ struct sunxi_lcdc_reg { | ||||
| #define SUNXI_LCDC_MUX_CTRL_SRC1_MASK		(0xf << 4) | ||||
| #define SUNXI_LCDC_MUX_CTRL_SRC1(x)		((x) << 4) | ||||
| #ifdef CONFIG_SUNXI_GEN_SUN6I | ||||
| #define SUNXI_LCDC_LVDS_ANA0			0x40040320 | ||||
| #define SUNXI_LCDC_LVDS_ANA0_EN_MB		(1 << 31) | ||||
| #define SUNXI_LCDC_LVDS_ANA0_DRVC		(1 << 24) | ||||
| #define SUNXI_LCDC_LVDS_ANA0_DRVD(x)		((x) << 20) | ||||
| #define SUNXI_LCDC_LVDS_ANA0_EN_LDO		(1 << 30) | ||||
| #define SUNXI_LCDC_LVDS_ANA0_EN_DRVC		(1 << 24) | ||||
| #define SUNXI_LCDC_LVDS_ANA0_EN_DRVD(x)		(((x) & 0xf) << 20) | ||||
| #define SUNXI_LCDC_LVDS_ANA0_C(x)		(((x) & 3) << 17) | ||||
| #define SUNXI_LCDC_LVDS_ANA0_V(x)		(((x) & 3) << 8) | ||||
| #define SUNXI_LCDC_LVDS_ANA0_PD(x)		(((x) & 3) << 4) | ||||
| #else | ||||
| #define SUNXI_LCDC_LVDS_ANA0			0x3f310000 | ||||
| #define SUNXI_LCDC_LVDS_ANA0_UPDATE		(1 << 22) | ||||
|   | ||||
| @@ -32,6 +32,7 @@ void lcdc_init(struct sunxi_lcdc_reg * const lcdc) | ||||
| 	/* Init lcdc */ | ||||
| 	writel(0, &lcdc->ctrl); /* Disable tcon */ | ||||
| 	writel(0, &lcdc->int0); /* Disable all interrupts */ | ||||
| 	writel(0, &lcdc->int1); | ||||
|  | ||||
| 	/* Disable tcon0 dot clock */ | ||||
| 	clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE); | ||||
| @@ -46,17 +47,26 @@ void lcdc_enable(struct sunxi_lcdc_reg * const lcdc, int depth) | ||||
| 	setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE); | ||||
| #ifdef CONFIG_VIDEO_LCD_IF_LVDS | ||||
| 	setbits_le32(&lcdc->tcon0_lvds_intf, SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE); | ||||
| 	setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0); | ||||
| #ifdef CONFIG_SUNXI_GEN_SUN6I | ||||
| 	writel(SUNXI_LCDC_LVDS_ANA0_C(2) | | ||||
| 	       SUNXI_LCDC_LVDS_ANA0_V(3) | | ||||
| 	       SUNXI_LCDC_LVDS_ANA0_PD(2) | | ||||
| 	       SUNXI_LCDC_LVDS_ANA0_EN_LDO, &lcdc->lvds_ana0); | ||||
|  | ||||
| 	udelay(2); /* delay at least 1200 ns */ | ||||
|  | ||||
| 	setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_EN_MB); | ||||
|  | ||||
| 	udelay(2); /* delay at least 1200 ns */ | ||||
|  | ||||
| 	setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVC); | ||||
|  | ||||
| 	if (depth == 18) | ||||
| 		setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0x7)); | ||||
| 	else | ||||
| 		setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_DRVD(0xf)); | ||||
| #else | ||||
| 	setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0); | ||||
| 	setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE); | ||||
| 	udelay(2); /* delay at least 1200 ns */ | ||||
| 	setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT1); | ||||
| @@ -84,7 +94,7 @@ void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc, | ||||
| 	writel(SUNXI_LCDC_TCON0_CTRL_ENABLE | | ||||
| 	       SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl); | ||||
|  | ||||
| 	writel(SUNXI_LCDC_TCON0_DCLK_ENABLE | | ||||
| 	writel(SUNXI_LCDC_TCON0_DCLK_ENABLE_1 | | ||||
| 	       SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk); | ||||
|  | ||||
| 	writel(SUNXI_LCDC_X(mode->hactive.typ) | | ||||
| @@ -110,6 +120,8 @@ void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc, | ||||
| #ifdef CONFIG_VIDEO_LCD_IF_LVDS | ||||
| 	val = (depth == 18) ? 1 : 0; | ||||
| 	writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) | | ||||
| 	       SUNXI_LCDC_TCON0_LVDS_IF_CLK_POL_NORMAL | | ||||
| 	       SUNXI_LCDC_TCON0_LVDS_IF_DATA_POL_NORMAL | | ||||
| 	       SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf); | ||||
| #endif | ||||
|  | ||||
| @@ -142,7 +154,7 @@ void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc, | ||||
| #endif | ||||
| 	writel(val, &lcdc->tcon0_io_polarity); | ||||
|  | ||||
| 	writel(0, &lcdc->tcon0_io_tristate); | ||||
| 	writel(0xe0000000, &lcdc->tcon0_io_tristate); | ||||
| } | ||||
|  | ||||
| void lcdc_tcon1_mode_set(struct sunxi_lcdc_reg * const lcdc, | ||||
| @@ -214,7 +226,9 @@ void lcdc_pll_set(struct sunxi_ccm_reg *ccm, int tcon, int dotclock, | ||||
| 	int value, n, m, min_m, max_m, diff, step; | ||||
| 	int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF; | ||||
| 	int best_double = 0; | ||||
| #ifdef CONFIG_MACH_SUN6I | ||||
| 	bool use_mipi_pll = false; | ||||
| #endif | ||||
|  | ||||
| #ifdef CONFIG_SUNXI_DE2 | ||||
| 	step = 6000; | ||||
| @@ -301,11 +315,17 @@ void lcdc_pll_set(struct sunxi_ccm_reg *ccm, int tcon, int dotclock, | ||||
| 	} | ||||
|  | ||||
| 	if (tcon == 0) { | ||||
| 		u32 pll; | ||||
| #ifdef CONFIG_MACH_SUN8I_A83T | ||||
| 		writel(CCM_LCD_CH0_CTRL_GATE, &ccm->lcd0_clk_cfg); | ||||
| #else | ||||
| 		u32 pll = 0; | ||||
|  | ||||
| #ifdef CONFIG_MACH_SUN6I | ||||
| 		if (use_mipi_pll) | ||||
| 			pll = CCM_LCD_CH0_CTRL_MIPI_PLL; | ||||
| 		else if (best_double) | ||||
| 		else | ||||
| #endif | ||||
| 		if (best_double) | ||||
| 			pll = CCM_LCD_CH0_CTRL_PLL3_2X; | ||||
| 		else | ||||
| 			pll = CCM_LCD_CH0_CTRL_PLL3; | ||||
| @@ -315,6 +335,7 @@ void lcdc_pll_set(struct sunxi_ccm_reg *ccm, int tcon, int dotclock, | ||||
| #else | ||||
| 		writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST | pll, | ||||
| 		       &ccm->lcd0_clk_cfg); | ||||
| #endif | ||||
| #endif | ||||
| 	} | ||||
| #ifndef CONFIG_SUNXI_DE2 | ||||
|   | ||||
| @@ -24,13 +24,19 @@ struct sunxi_lcd_priv { | ||||
|  | ||||
| static void sunxi_lcdc_config_pinmux(void) | ||||
| { | ||||
| #ifdef CONFIG_MACH_SUN50I | ||||
| #if defined(CONFIG_MACH_SUN50I) | ||||
| 	int pin; | ||||
|  | ||||
| 	for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(21); pin++) { | ||||
| 		sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LCD0); | ||||
| 		sunxi_gpio_set_drv(pin, 3); | ||||
| 	} | ||||
| #elif defined(CONFIG_MACH_SUN8I_A83T) && defined(CONFIG_VIDEO_LCD_IF_LVDS) | ||||
| 	int pin; | ||||
|  | ||||
| 	debug("configuring PD LVDS pins\n"); | ||||
| 	for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) | ||||
| 		sunxi_gpio_set_cfgpin(pin, SUNXI_GPD_LVDS0); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| @@ -50,6 +56,10 @@ static int sunxi_lcd_enable(struct udevice *dev, int bpp, | ||||
| 	/* Clock on */ | ||||
| 	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0); | ||||
|  | ||||
| #ifdef CONFIG_VIDEO_LCD_IF_LVDS | ||||
| 	setbits_le32(&ccm->ahb_reset2_cfg, 1 << AHB_RESET_OFFSET_LVDS); | ||||
| #endif | ||||
|  | ||||
| 	lcdc_init(lcdc); | ||||
| 	sunxi_lcdc_config_pinmux(); | ||||
| 	lcdc_pll_set(ccm, 0, edid->pixelclock.typ / 1000, | ||||
| @@ -144,7 +154,7 @@ U_BOOT_DRIVER(sunxi_lcd) = { | ||||
| 	.priv_auto_alloc_size = sizeof(struct sunxi_lcd_priv), | ||||
| }; | ||||
|  | ||||
| #ifdef CONFIG_MACH_SUN50I | ||||
| #if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I_A83T) | ||||
| U_BOOT_DEVICE(sunxi_lcd) = { | ||||
| 	.name = "sunxi_lcd" | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user