1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-04 10:12:14 +02: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:
Ondrej Jirman
2018-07-09 16:34:18 +02:00
parent 4ac85c4059
commit 2f11a4fa77
4 changed files with 55 additions and 10 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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"
};