diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/sunxi_gpio.c | 1 | ||||
-rw-r--r-- | drivers/net/Kconfig | 17 | ||||
-rw-r--r-- | drivers/power/Kconfig | 16 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 11 | ||||
-rw-r--r-- | drivers/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/sunxi/Makefile | 8 | ||||
-rw-r--r-- | drivers/video/sunxi/lcdc.c | 209 | ||||
-rw-r--r-- | drivers/video/sunxi/sunxi_display.c (renamed from drivers/video/sunxi_display.c) | 220 |
8 files changed, 301 insertions, 183 deletions
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 8d2bb18504..3f40e83830 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -352,6 +352,7 @@ static const struct udevice_id sunxi_gpio_ids[] = { ID("allwinner,sun8i-a33-pinctrl", a_all), ID("allwinner,sun8i-a83t-pinctrl", a_all), ID("allwinner,sun8i-h3-pinctrl", a_all), + ID("allwinner,sun8i-r40-pinctrl", a_all), ID("allwinner,sun9i-a80-pinctrl", a_all), ID("allwinner,sun6i-a31-r-pinctrl", l_2), ID("allwinner,sun8i-a23-r-pinctrl", l_1), diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8aa92790f4..9cd0d94cbd 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -149,6 +149,12 @@ config PCH_GBE This MAC is present in Intel Platform Controller Hub EG20T. It supports 10/100/1000 Mbps operation. +config RGMII + bool "Enable RGMII" + help + Enable the support of the Reduced Gigabit Media-Independent + Interface (RGMII). + config RTL8139 bool "Realtek 8139 series Ethernet controller driver" help @@ -161,6 +167,17 @@ config RTL8169 This driver supports Realtek 8169 series gigabit ethernet family of PCI/PCIe chipsets/adapters. +config SUN7I_GMAC + bool "Enable Allwinner GMAC Ethernet support" + help + Enable the support for Sun7i GMAC Ethernet controller + +config SUN4I_EMAC + bool "Allwinner Sun4i Ethernet MAC support" + depends on DM_ETH + help + This driver supports the Allwinner based SUN4I Ethernet MAC. + config SUN8I_EMAC bool "Allwinner Sun8i Ethernet MAC support" depends on DM_ETH diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 64e5bc2f74..911ecb1144 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -10,7 +10,7 @@ choice prompt "Select Sunxi PMIC Variant" depends on ARCH_SUNXI default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I - default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 + default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40 default AXP818_POWER if MACH_SUN8I_A83T default SUNXI_NO_PMIC if MACH_SUNXI_H3_H5 || MACH_SUN50I @@ -37,7 +37,7 @@ config AXP209_POWER config AXP221_POWER bool "axp221 / axp223 pmic support" - depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 + depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40 select CMD_POWEROFF ---help--- Select this to enable support for the axp221/axp223 pmic found on most @@ -70,7 +70,7 @@ endchoice config AXP_DCDC1_VOLT int "axp pmic dcdc1 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER - default 3300 if AXP818_POWER + default 3300 if AXP818_POWER || MACH_SUN8I_R40 default 3000 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I ---help--- Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to @@ -97,6 +97,7 @@ config AXP_DCDC2_VOLT On A23/A33 boards dcdc2 is used for VDD-SYS and should be 1.1V. On A80 boards dcdc2 powers the GPU and can be left off. On A83T boards dcdc2 is used for VDD-CPUA(cluster 0) and should be 0.9V. + On R40 boards dcdc2 is VDD-CPU and should be 1.1V config AXP_DCDC3_VOLT int "axp pmic dcdc3 voltage" @@ -104,6 +105,7 @@ config AXP_DCDC3_VOLT default 900 if AXP809_POWER || AXP818_POWER default 1500 if AXP152_POWER default 1250 if AXP209_POWER + default 1100 if MACH_SUN8I_R40 default 1200 if MACH_SUN6I || MACH_SUN8I ---help--- Set the voltage (mV) to program the axp pmic dcdc3 at, set to 0 to @@ -114,6 +116,7 @@ config AXP_DCDC3_VOLT On A23 / A31 / A33 boards dcdc3 is VDD-CPU and should be 1.2V. On A80 boards dcdc3 is used for VDD-CPUA(cluster 0) and should be 0.9V. On A83T boards dcdc3 is used for VDD-CPUB(cluster 1) and should be 0.9V. + On R40 boards dcdc3 is VDD-SYS and VDD-GPU and should be 1.1V. config AXP_DCDC4_VOLT int "axp pmic dcdc4 voltage" @@ -138,13 +141,13 @@ config AXP_DCDC5_VOLT ---help--- Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to disable dcdc5. - On A23 / A31 / A33 / A80 / A83T boards dcdc5 is VCC-DRAM and + On A23 / A31 / A33 / A80 / A83T / R40 boards dcdc5 is VCC-DRAM and should be 1.5V, 1.35V if DDR3L is used. config AXP_ALDO1_VOLT int "axp pmic (a)ldo1 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER - default 0 if MACH_SUN6I + default 0 if MACH_SUN6I || MACH_SUN8I_R40 default 1800 if MACH_SUN8I_A83T default 3000 if MACH_SUN8I || MACH_SUN9I ---help--- @@ -183,7 +186,8 @@ config AXP_ALDO3_VOLT Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to disable aldo3. On A10(s) / A13 / A20 boards aldo3 should be 2.8V. - On A23 / A31 / A33 boards aldo3 is VCC-PLL and AVCC and should be 3.0V. + On A23 / A31 / A33 / R40 boards aldo3 is VCC-PLL and AVCC and should + be 3.0V. On A80 boards aldo3 is normally not used. On A83T / H8 boards aldo3 is AVCC, VCC-PL, and VCC-LED, and should be 3.0V. diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index c0ec2ec2e4..58320666b7 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -44,6 +44,17 @@ config SPL_SERIAL_PRESENT This option enables the full UART in SPL, so if is it disabled, the full UART driver will be omitted, thus saving space. +config CONS_INDEX + int "UART used for console" + depends on ARCH_SUNXI + default 2 if MACH_SUN5I + default 5 if MACH_SUN8I_A23 || MACH_SUN8I_A33 + default 1 + help + Configures the console index. + For Allwinner SoC., default values are 2 for SUN5I and 5 for A23/A33. + Otherwise, the index equals 1. + config DM_SERIAL bool "Enable Driver Model for serial drivers" depends on DM diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 7cd6d28658..a80af3104d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -51,7 +51,6 @@ obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o obj-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o obj-$(CONFIG_VIDEO_SM501) += sm501.o -obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o videomodes.o obj-$(CONFIG_VIDEO_TEGRA20) += tegra.o obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o obj-$(CONFIG_VIDEO_VESA) += vesa.o @@ -64,3 +63,4 @@ obj-${CONFIG_EXYNOS_FB} += exynos/ obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/ obj-y += bridge/ +obj-y += sunxi/ diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile new file mode 100644 index 0000000000..dfc9b47a1f --- /dev/null +++ b/drivers/video/sunxi/Makefile @@ -0,0 +1,8 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o ../videomodes.o diff --git a/drivers/video/sunxi/lcdc.c b/drivers/video/sunxi/lcdc.c new file mode 100644 index 0000000000..7d215b713e --- /dev/null +++ b/drivers/video/sunxi/lcdc.c @@ -0,0 +1,209 @@ +/* + * Timing controller driver for Allwinner SoCs. + * + * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be> + * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com> + * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#include <asm/arch/lcdc.h> +#include <asm/io.h> + +static int lcdc_get_clk_delay(const struct display_timing *mode, int tcon) +{ + int delay; + + delay = mode->vfront_porch.typ + mode->vsync_len.typ + + mode->vback_porch.typ; + if (mode->flags & DISPLAY_FLAGS_INTERLACED) + delay /= 2; + if (tcon == 1) + delay -= 2; + + return (delay > 30) ? 30 : delay; +} + +void lcdc_init(struct sunxi_lcdc_reg * const lcdc) +{ + /* Init lcdc */ + writel(0, &lcdc->ctrl); /* Disable tcon */ + writel(0, &lcdc->int0); /* Disable all interrupts */ + + /* Disable tcon0 dot clock */ + clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE); + + /* Set all io lines to tristate */ + writel(0xffffffff, &lcdc->tcon0_io_tristate); + writel(0xffffffff, &lcdc->tcon1_io_tristate); +} + +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 + 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_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 +#endif +} + +void lcdc_tcon0_mode_set(struct sunxi_lcdc_reg * const lcdc, + const struct display_timing *mode, + int clk_div, bool for_ext_vga_dac, + int depth, int dclk_phase) +{ + int bp, clk_delay, total, val; + +#ifndef CONFIG_SUNXI_DE2 + /* Use tcon0 */ + clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, + SUNXI_LCDC_CTRL_IO_MAP_TCON0); +#endif + + clk_delay = lcdc_get_clk_delay(mode, 0); + writel(SUNXI_LCDC_TCON0_CTRL_ENABLE | + SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl); + + writel(SUNXI_LCDC_TCON0_DCLK_ENABLE | + SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk); + + writel(SUNXI_LCDC_X(mode->hactive.typ) | + SUNXI_LCDC_Y(mode->vactive.typ), &lcdc->tcon0_timing_active); + + bp = mode->hsync_len.typ + mode->hback_porch.typ; + total = mode->hactive.typ + mode->hfront_porch.typ + bp; + writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) | + SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h); + + bp = mode->vsync_len.typ + mode->vback_porch.typ; + total = mode->vactive.typ + mode->vfront_porch.typ + bp; + 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.typ) | + SUNXI_LCDC_Y(mode->vsync_len.typ), &lcdc->tcon0_timing_sync); + + writel(0, &lcdc->tcon0_hv_intf); + writel(0, &lcdc->tcon0_cpu_intf); +#endif +#ifdef CONFIG_VIDEO_LCD_IF_LVDS + val = (depth == 18) ? 1 : 0; + writel(SUNXI_LCDC_TCON0_LVDS_INTF_BITWIDTH(val) | + SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &lcdc->tcon0_lvds_intf); +#endif + + if (depth == 18 || depth == 16) { + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[0]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]); + writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]); + writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]); + writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]); + writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]); + writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]); + writel(((depth == 18) ? + SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 : + SUNXI_LCDC_TCON0_FRM_CTRL_RGB565), + &lcdc->tcon0_frm_ctrl); + } + + val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(dclk_phase); + if (mode->flags & DISPLAY_FLAGS_HSYNC_LOW) + val |= SUNXI_LCDC_TCON_HSYNC_MASK; + if (mode->flags & DISPLAY_FLAGS_VSYNC_LOW) + val |= SUNXI_LCDC_TCON_VSYNC_MASK; + +#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH + if (for_ext_vga_dac) + val = 0; +#endif + writel(val, &lcdc->tcon0_io_polarity); + + writel(0, &lcdc->tcon0_io_tristate); +} + +void lcdc_tcon1_mode_set(struct sunxi_lcdc_reg * const lcdc, + const struct display_timing *mode, + bool ext_hvsync, bool is_composite) +{ + int bp, clk_delay, total, val, yres; + +#ifndef CONFIG_SUNXI_DE2 + /* Use tcon1 */ + clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, + SUNXI_LCDC_CTRL_IO_MAP_TCON1); +#endif + + clk_delay = lcdc_get_clk_delay(mode, 1); + writel(SUNXI_LCDC_TCON1_CTRL_ENABLE | + ((mode->flags & DISPLAY_FLAGS_INTERLACED) ? + SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) | + SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl); + + yres = mode->vactive.typ; + if (mode->flags & DISPLAY_FLAGS_INTERLACED) + yres /= 2; + writel(SUNXI_LCDC_X(mode->hactive.typ) | SUNXI_LCDC_Y(yres), + &lcdc->tcon1_timing_source); + writel(SUNXI_LCDC_X(mode->hactive.typ) | SUNXI_LCDC_Y(yres), + &lcdc->tcon1_timing_scale); + writel(SUNXI_LCDC_X(mode->hactive.typ) | SUNXI_LCDC_Y(yres), + &lcdc->tcon1_timing_out); + + bp = mode->hsync_len.typ + mode->hback_porch.typ; + total = mode->hactive.typ + mode->hfront_porch.typ + bp; + writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) | + SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h); + + bp = mode->vsync_len.typ + mode->vback_porch.typ; + total = mode->vactive.typ + mode->vfront_porch.typ + bp; + if (!(mode->flags & DISPLAY_FLAGS_INTERLACED)) + total *= 2; + writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) | + SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v); + + writel(SUNXI_LCDC_X(mode->hsync_len.typ) | + SUNXI_LCDC_Y(mode->vsync_len.typ), &lcdc->tcon1_timing_sync); + + if (ext_hvsync) { + val = 0; + if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) + val |= SUNXI_LCDC_TCON_HSYNC_MASK; + if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) + val |= SUNXI_LCDC_TCON_VSYNC_MASK; + writel(val, &lcdc->tcon1_io_polarity); + + clrbits_le32(&lcdc->tcon1_io_tristate, + SUNXI_LCDC_TCON_VSYNC_MASK | + SUNXI_LCDC_TCON_HSYNC_MASK); + } + +#ifdef CONFIG_MACH_SUN5I + if (is_composite) + clrsetbits_le32(&lcdc->mux_ctrl, SUNXI_LCDC_MUX_CTRL_SRC0_MASK, + SUNXI_LCDC_MUX_CTRL_SRC0(1)); +#endif +} diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c index 6f8ee01c10..92c9d06054 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi/sunxi_display.c @@ -12,6 +12,7 @@ #include <asm/arch/clock.h> #include <asm/arch/display.h> #include <asm/arch/gpio.h> +#include <asm/arch/lcdc.h> #include <asm/arch/pwm.h> #include <asm/global_data.h> #include <asm/gpio.h> @@ -23,10 +24,10 @@ #include <i2c.h> #include <malloc.h> #include <video_fb.h> -#include "videomodes.h" -#include "anx9804.h" -#include "hitachi_tx18d42vm_lcd.h" -#include "ssd2828.h" +#include "../videomodes.h" +#include "../anx9804.h" +#include "../hitachi_tx18d42vm_lcd.h" +#include "../ssd2828.h" #ifdef CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW #define PWM_ON 0 @@ -650,45 +651,7 @@ static void sunxi_lcdc_init(void) #endif #endif - /* Init lcdc */ - writel(0, &lcdc->ctrl); /* Disable tcon */ - writel(0, &lcdc->int0); /* Disable all interrupts */ - - /* Disable tcon0 dot clock */ - clrbits_le32(&lcdc->tcon0_dclk, SUNXI_LCDC_TCON0_DCLK_ENABLE); - - /* Set all io lines to tristate */ - writel(0xffffffff, &lcdc->tcon0_io_tristate); - writel(0xffffffff, &lcdc->tcon1_io_tristate); -} - -static void sunxi_lcdc_enable(void) -{ - struct sunxi_lcdc_reg * const lcdc = - (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); -#ifdef CONFIG_SUNXI_GEN_SUN6I - 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 (sunxi_display.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_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 -#endif + lcdc_init(lcdc); } static void sunxi_lcdc_panel_enable(void) @@ -758,17 +721,31 @@ static void sunxi_lcdc_backlight_enable(void) gpio_direction_output(pin, PWM_ON); } -static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon) +static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode, + struct display_timing *timing) { - int delay; + timing->pixelclock.typ = mode->pixclock_khz * 1000; - delay = mode->lower_margin + mode->vsync_len + mode->upper_margin; - if (mode->vmode == FB_VMODE_INTERLACED) - delay /= 2; - if (tcon == 1) - delay -= 2; + timing->hactive.typ = mode->xres; + timing->hfront_porch.typ = mode->right_margin; + timing->hback_porch.typ = mode->left_margin; + timing->hsync_len.typ = mode->hsync_len; - return (delay > 30) ? 30 : delay; + timing->vactive.typ = mode->yres; + timing->vfront_porch.typ = mode->lower_margin; + timing->vback_porch.typ = mode->upper_margin; + timing->vsync_len.typ = mode->vsync_len; + + if (mode->sync & FB_SYNC_HOR_HIGH_ACT) + timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH; + else + timing->flags |= DISPLAY_FLAGS_HSYNC_LOW; + if (mode->sync & FB_SYNC_VERT_HIGH_ACT) + timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH; + else + timing->flags |= DISPLAY_FLAGS_VSYNC_LOW; + if (mode->vmode == FB_VMODE_INTERLACED) + timing->flags |= DISPLAY_FLAGS_INTERLACED; } static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, @@ -776,7 +753,8 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, { struct sunxi_lcdc_reg * const lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; - int bp, clk_delay, clk_div, clk_double, pin, total, val; + int clk_div, clk_double, pin; + struct display_timing timing; #if defined CONFIG_MACH_SUN8I && defined CONFIG_VIDEO_LCD_IF_LVDS for (pin = SUNXI_GPD(18); pin <= SUNXI_GPD(27); pin++) { @@ -796,73 +774,9 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, sunxi_lcdc_pll_set(0, mode->pixclock_khz, &clk_div, &clk_double); - /* Use tcon0 */ - clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, - SUNXI_LCDC_CTRL_IO_MAP_TCON0); - - clk_delay = sunxi_lcdc_get_clk_delay(mode, 0); - writel(SUNXI_LCDC_TCON0_CTRL_ENABLE | - SUNXI_LCDC_TCON0_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon0_ctrl); - - writel(SUNXI_LCDC_TCON0_DCLK_ENABLE | - SUNXI_LCDC_TCON0_DCLK_DIV(clk_div), &lcdc->tcon0_dclk); - - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres), - &lcdc->tcon0_timing_active); - - bp = mode->hsync_len + mode->left_margin; - total = mode->xres + mode->right_margin + bp; - writel(SUNXI_LCDC_TCON0_TIMING_H_TOTAL(total) | - SUNXI_LCDC_TCON0_TIMING_H_BP(bp), &lcdc->tcon0_timing_h); - - bp = mode->vsync_len + mode->upper_margin; - total = mode->yres + mode->lower_margin + bp; - 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); - - 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) | - SUNXI_LCDC_TCON0_LVDS_CLK_SEL_TCON0, &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]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[1]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[2]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[3]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[4]); - writel(SUNXI_LCDC_TCON0_FRM_SEED, &lcdc->tcon0_frm_seed[5]); - writel(SUNXI_LCDC_TCON0_FRM_TAB0, &lcdc->tcon0_frm_table[0]); - writel(SUNXI_LCDC_TCON0_FRM_TAB1, &lcdc->tcon0_frm_table[1]); - writel(SUNXI_LCDC_TCON0_FRM_TAB2, &lcdc->tcon0_frm_table[2]); - writel(SUNXI_LCDC_TCON0_FRM_TAB3, &lcdc->tcon0_frm_table[3]); - writel(((sunxi_display.depth == 18) ? - SUNXI_LCDC_TCON0_FRM_CTRL_RGB666 : - SUNXI_LCDC_TCON0_FRM_CTRL_RGB565), - &lcdc->tcon0_frm_ctrl); - } - - val = SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(CONFIG_VIDEO_LCD_DCLK_PHASE); - if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) - val |= SUNXI_LCDC_TCON_HSYNC_MASK; - if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) - val |= SUNXI_LCDC_TCON_VSYNC_MASK; - -#ifdef CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH - if (for_ext_vga_dac) - val = 0; -#endif - writel(val, &lcdc->tcon0_io_polarity); - - writel(0, &lcdc->tcon0_io_tristate); + sunxi_ctfb_mode_to_display_timing(mode, &timing); + lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac, + sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE); } #if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE @@ -872,65 +786,17 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode, { struct sunxi_lcdc_reg * const lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; - int bp, clk_delay, total, val, yres; - - /* Use tcon1 */ - clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, - SUNXI_LCDC_CTRL_IO_MAP_TCON1); + struct display_timing timing; - clk_delay = sunxi_lcdc_get_clk_delay(mode, 1); - writel(SUNXI_LCDC_TCON1_CTRL_ENABLE | - ((mode->vmode == FB_VMODE_INTERLACED) ? - SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE : 0) | - SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(clk_delay), &lcdc->tcon1_ctrl); - - yres = mode->yres; - if (mode->vmode == FB_VMODE_INTERLACED) - yres /= 2; - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres), - &lcdc->tcon1_timing_source); - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres), - &lcdc->tcon1_timing_scale); - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres), - &lcdc->tcon1_timing_out); - - bp = mode->hsync_len + mode->left_margin; - total = mode->xres + mode->right_margin + bp; - writel(SUNXI_LCDC_TCON1_TIMING_H_TOTAL(total) | - SUNXI_LCDC_TCON1_TIMING_H_BP(bp), &lcdc->tcon1_timing_h); - - bp = mode->vsync_len + mode->upper_margin; - total = mode->yres + mode->lower_margin + bp; - if (mode->vmode == FB_VMODE_NONINTERLACED) - total *= 2; - writel(SUNXI_LCDC_TCON1_TIMING_V_TOTAL(total) | - SUNXI_LCDC_TCON1_TIMING_V_BP(bp), &lcdc->tcon1_timing_v); - - writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len), - &lcdc->tcon1_timing_sync); + sunxi_ctfb_mode_to_display_timing(mode, &timing); + lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync, + sunxi_is_composite()); if (use_portd_hvsync) { sunxi_gpio_set_cfgpin(SUNXI_GPD(26), SUNXI_GPD_LCD0); sunxi_gpio_set_cfgpin(SUNXI_GPD(27), SUNXI_GPD_LCD0); - - val = 0; - if (mode->sync & FB_SYNC_HOR_HIGH_ACT) - val |= SUNXI_LCDC_TCON_HSYNC_MASK; - if (mode->sync & FB_SYNC_VERT_HIGH_ACT) - val |= SUNXI_LCDC_TCON_VSYNC_MASK; - writel(val, &lcdc->tcon1_io_polarity); - - clrbits_le32(&lcdc->tcon1_io_tristate, - SUNXI_LCDC_TCON_VSYNC_MASK | - SUNXI_LCDC_TCON_HSYNC_MASK); } -#ifdef CONFIG_MACH_SUN5I - if (sunxi_is_composite()) - clrsetbits_le32(&lcdc->mux_ctrl, SUNXI_LCDC_MUX_CTRL_SRC0_MASK, - SUNXI_LCDC_MUX_CTRL_SRC0(1)); -#endif - sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double); } #endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */ @@ -1212,6 +1078,8 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, unsigned int address) { int __maybe_unused clk_div, clk_double; + struct sunxi_lcdc_reg * const lcdc = + (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; switch (sunxi_display.monitor) { case sunxi_monitor_none: @@ -1223,7 +1091,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0); sunxi_hdmi_mode_set(mode, clk_div, clk_double); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); sunxi_hdmi_enable(); #endif break; @@ -1253,7 +1121,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_composer_mode_set(mode, address); sunxi_lcdc_tcon0_mode_set(mode, false); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); #ifdef CONFIG_VIDEO_LCD_SSD2828 sunxi_ssd2828_init(mode); #endif @@ -1265,13 +1133,13 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1); sunxi_tvencoder_mode_set(); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); sunxi_tvencoder_enable(); #elif defined CONFIG_VIDEO_VGA_VIA_LCD sunxi_composer_mode_set(mode, address); sunxi_lcdc_tcon0_mode_set(mode, true); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); sunxi_vga_external_dac_enable(); #endif break; @@ -1284,7 +1152,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0); sunxi_tvencoder_mode_set(); sunxi_composer_enable(); - sunxi_lcdc_enable(); + lcdc_enable(lcdc, sunxi_display.depth); sunxi_tvencoder_enable(); #endif break; |