From 213480e12d880ef6782f56f1af95469b48cca539 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Jan 2015 22:04:34 +0100 Subject: [PATCH] sunxi: video: Add lvds support Add support for lvds lcd panels Signed-off-by: Hans de Goede Acked-by: Anatolij Gustschin --- arch/arm/include/asm/arch-sunxi/clock_sun4i.h | 2 + arch/arm/include/asm/arch-sunxi/display.h | 12 ++++++ arch/arm/include/asm/arch-sunxi/gpio.h | 1 + board/sunxi/Kconfig | 27 ++++++++++++++ drivers/video/sunxi_display.c | 37 ++++++++++++++++++- 5 files changed, 77 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h index 64b5c389e5..70b789e8e8 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h @@ -284,6 +284,8 @@ struct sunxi_ccm_reg { /* Enable / disable both ch1 sclk1 and sclk2 at the same time */ #define CCM_LCD_CH1_CTRL_GATE (0x1 << 31 | 0x1 << 15) +#define CCM_LVDS_CTRL_RST (1 << 0) + #define CCM_HDMI_CTRL_M(n) ((((n) - 1) & 0xf) << 0) #define CCM_HDMI_CTRL_PLL_MASK (3 << 24) #define CCM_HDMI_CTRL_PLL3 (0 << 24) diff --git a/arch/arm/include/asm/arch-sunxi/display.h b/arch/arm/include/asm/arch-sunxi/display.h index 5ce355d7b0..2ac8a879df 100644 --- a/arch/arm/include/asm/arch-sunxi/display.h +++ b/arch/arm/include/asm/arch-sunxi/display.h @@ -91,6 +91,9 @@ struct sunxi_lcdc_reg { u8 res3[0x44]; /* 0xac */ u32 tcon1_io_polarity; /* 0xf0 */ u32 tcon1_io_tristate; /* 0xf4 */ + u8 res4[0x128]; /* 0xf8 */ + u32 lvds_ana0; /* 0x220 */ + u32 lvds_ana1; /* 0x224 */ }; struct sunxi_hdmi_reg { @@ -244,12 +247,21 @@ struct sunxi_tve_reg { #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) +#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_PHASE0 (0 << 28) +#define SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE60 (1 << 28) +#define SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE120 (2 << 28) #define SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(n) (((n) & 0x1f) << 4) #define SUNXI_LCDC_TCON1_CTRL_ENABLE (1 << 31) #define SUNXI_LCDC_TCON1_TIMING_H_BP(n) (((n) - 1) << 0) #define SUNXI_LCDC_TCON1_TIMING_H_TOTAL(n) (((n) - 1) << 16) #define SUNXI_LCDC_TCON1_TIMING_V_BP(n) (((n) - 1) << 0) #define SUNXI_LCDC_TCON1_TIMING_V_TOTAL(n) (((n) * 2) << 16) +#define SUNXI_LCDC_LVDS_ANA0 0x3f310000 +#define SUNXI_LCDC_LVDS_ANA0_UPDATE (1 << 22) +#define SUNXI_LCDC_LVDS_ANA1_INIT1 (0x1f << 26 | 0x1f << 10) +#define SUNXI_LCDC_LVDS_ANA1_INIT2 (0x1f << 16 | 0x1f << 00) /* * HDMI register constants. diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 9438f5a262..71cc879c2b 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -151,6 +151,7 @@ enum sunxi_gpio_number { #define SUNXI_GPC6_SDC2 3 #define SUNXI_GPD0_LCD0 2 +#define SUNXI_GPD0_LVDS0 3 #define SUNXI_GPF0_SDC0 2 diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 9a0d8a2c01..bbe5c86e7b 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -348,6 +348,33 @@ config VIDEO_LCD_BL_PWM Set the backlight pwm pin for the LCD panel. This takes a string in the format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H. + +# Note only one of these may be selected at a time! But hidden choices are +# not supported by Kconfig +config VIDEO_LCD_IF_PARALLEL + bool + +config VIDEO_LCD_IF_LVDS + bool + + +choice + prompt "LCD panel support" + depends on VIDEO + ---help--- + Select which type of LCD panel to support. + +config VIDEO_LCD_PANEL_PARALLEL + bool "Generic parallel interface LCD panel" + select VIDEO_LCD_IF_PARALLEL + +config VIDEO_LCD_PANEL_LVDS + bool "Generic lvds interface LCD panel" + select VIDEO_LCD_IF_LVDS + +endchoice + + config USB_KEYBOARD boolean "Enable USB keyboard support" default y diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c index 82414925af..47d820d89f 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi_display.c @@ -339,8 +339,13 @@ static void sunxi_lcdc_pll_set(int tcon, int dotclock, int best_double = 0; if (tcon == 0) { +#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL min_m = 6; max_m = 127; +#endif +#ifdef CONFIG_VIDEO_LCD_IF_LVDS + min_m = max_m = 7; +#endif } else { min_m = 1; max_m = 15; @@ -420,6 +425,9 @@ static void sunxi_lcdc_init(void) /* Clock on */ setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_LCD0); +#ifdef CONFIG_VIDEO_LCD_IF_LVDS + setbits_le32(&ccm->lvds_clk_cfg, CCM_LVDS_CTRL_RST); +#endif /* Init lcdc */ writel(0, &lcdc->ctrl); /* Disable tcon */ @@ -439,6 +447,16 @@ static void sunxi_lcdc_enable(void) (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; 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); + 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); + udelay(1); /* delay at least 120 ns */ + setbits_le32(&lcdc->lvds_ana1, SUNXI_LCDC_LVDS_ANA1_INIT2); + setbits_le32(&lcdc->lvds_ana0, SUNXI_LCDC_LVDS_ANA0_UPDATE); +#endif } static void sunxi_lcdc_panel_enable(void) @@ -507,7 +525,12 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode) int bp, clk_delay, clk_div, clk_double, pin, total, val; for (pin = SUNXI_GPD(0); pin <= SUNXI_GPD(27); pin++) +#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LCD0); +#endif +#ifdef CONFIG_VIDEO_LCD_IF_LVDS + sunxi_gpio_set_cfgpin(pin, SUNXI_GPD0_LVDS0); +#endif sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double); @@ -535,12 +558,17 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode) writel(SUNXI_LCDC_TCON0_TIMING_V_TOTAL(total) | SUNXI_LCDC_TCON0_TIMING_V_BP(bp), &lcdc->tcon0_timing_v); +#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len), &lcdc->tcon0_timing_sync); - /* We only support hv-sync parallel lcd-s for now */ writel(0, &lcdc->tcon0_hv_intf); writel(0, &lcdc->tcon0_cpu_intf); +#endif +#ifdef CONFIG_VIDEO_LCD_IF_LVDS + val = (sunxi_display.depth == 18) ? 1 : 0; + writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val), &lcdc->tcon0_lvds_intf); +#endif if (sunxi_display.depth == 18 || sunxi_display.depth == 16) { writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]); @@ -559,7 +587,12 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode) &lcdc->tcon0_frm_ctrl); } - val = 0; +#ifdef CONFIG_VIDEO_LCD_IF_PARALLEL + val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE0; +#endif +#ifdef CONFIG_VIDEO_LCD_IF_LVDS + val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE60; +#endif if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) val |= SUNXI_LCDC_TCON_HSYNC_MASK; if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) -- 2.39.5