From 2f11a4fa778c33c573d51a3e6567936a9c993019 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 9 Jul 2018 16:34:18 +0200 Subject: [PATCH] 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 --- .../include/asm/arch-sunxi/clock_sun8i_a83t.h | 8 ++++- arch/arm/include/asm/arch-sunxi/lcdc.h | 12 +++++-- drivers/video/sunxi/lcdc.c | 31 ++++++++++++++++--- drivers/video/sunxi/sunxi_lcd.c | 14 +++++++-- 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun8i_a83t.h b/arch/arm/include/asm/arch-sunxi/clock_sun8i_a83t.h index e45e88818c3..ab6604711ac 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun8i_a83t.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun8i_a83t.h @@ -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 diff --git a/arch/arm/include/asm/arch-sunxi/lcdc.h b/arch/arm/include/asm/arch-sunxi/lcdc.h index 90216bcfd51..ba61c071a46 100644 --- a/arch/arm/include/asm/arch-sunxi/lcdc.h +++ b/arch/arm/include/asm/arch-sunxi/lcdc.h @@ -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) diff --git a/drivers/video/sunxi/lcdc.c b/drivers/video/sunxi/lcdc.c index 4cf3a0eb751..f030ba83d92 100644 --- a/drivers/video/sunxi/lcdc.c +++ b/drivers/video/sunxi/lcdc.c @@ -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 diff --git a/drivers/video/sunxi/sunxi_lcd.c b/drivers/video/sunxi/sunxi_lcd.c index 619f5892f58..4c6da6d4f4f 100644 --- a/drivers/video/sunxi/sunxi_lcd.c +++ b/drivers/video/sunxi/sunxi_lcd.c @@ -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" };