diff options
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/usb_phy.c | 7 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-sunxi/clock_sun4i.h | 4 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-sunxi/display.h | 45 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-sunxi/gpio.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-sunxi/usb_phy.h | 1 | ||||
-rw-r--r-- | board/sunxi/Kconfig | 7 | ||||
-rw-r--r-- | board/sunxi/board.c | 27 | ||||
-rw-r--r-- | configs/Chuwi_V7_CW0825_defconfig | 1 | ||||
-rw-r--r-- | configs/Mele_M3_defconfig | 1 | ||||
-rw-r--r-- | configs/UTOO_P66_defconfig | 1 | ||||
-rw-r--r-- | configs/Wexler_TAB7200_defconfig | 5 | ||||
-rw-r--r-- | configs/jesurun_q5_defconfig | 2 | ||||
-rw-r--r-- | doc/README.video | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/Kconfig | 40 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/sunxi_nand_spl.c | 353 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sunxi.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/ohci-sunxi.c | 1 | ||||
-rw-r--r-- | drivers/usb/musb-new/sunxi.c | 28 | ||||
-rw-r--r-- | drivers/video/sunxi_display.c | 334 | ||||
-rw-r--r-- | include/configs/sunxi-common.h | 12 |
22 files changed, 786 insertions, 94 deletions
diff --git a/arch/arm/cpu/armv7/sunxi/usb_phy.c b/arch/arm/cpu/armv7/sunxi/usb_phy.c index 4d63a7449d7..b7ca5d423a9 100644 --- a/arch/arm/cpu/armv7/sunxi/usb_phy.c +++ b/arch/arm/cpu/armv7/sunxi/usb_phy.c @@ -232,6 +232,13 @@ void sunxi_usb_phy_power_off(int index) gpio_set_value(phy->gpio_vbus, 0); } +int sunxi_usb_phy_power_is_on(int index) +{ + struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; + + return phy->power_on_count > 0; +} + int sunxi_usb_phy_vbus_detect(int index) { struct sunxi_usb_phy *phy = &sunxi_usb_phy[index]; diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h index 58aff1687af..a7e25f46c82 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun4i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun4i.h @@ -267,6 +267,8 @@ struct sunxi_ccm_reg { #define CCM_MBUS_CTRL_CLK_SRC_PLL5 0x2 #define CCM_MBUS_CTRL_GATE (0x1 << 31) +#define CCM_NAND_CTRL_ENABLE (0x1 << 31) + #define CCM_MMC_CTRL_M(x) ((x) - 1) #define CCM_MMC_CTRL_OCLK_DLY(x) ((x) << 8) #define CCM_MMC_CTRL_N(x) ((x) << 16) @@ -289,7 +291,7 @@ struct sunxi_ccm_reg { #define CCM_LCD_CH0_CTRL_GATE (0x1 << 31) #define CCM_LCD_CH1_CTRL_M(n) ((((n) - 1) & 0xf) << 0) -/* We leave bit 11 set to 0, so sclk1 == sclk2 */ +#define CCM_LCD_CH1_CTRL_HALF_SCLK1 (1 << 11) #define CCM_LCD_CH1_CTRL_PLL3 (0 << 24) #define CCM_LCD_CH1_CTRL_PLL7 (1 << 24) #define CCM_LCD_CH1_CTRL_PLL3_2X (2 << 24) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index 8a26b9fc51a..06c6febba59 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -290,6 +290,7 @@ struct sunxi_ccm_reg { #define CCM_LCD_CH0_CTRL_GATE (0x1 << 31) #define CCM_LCD_CH1_CTRL_M(n) ((((n) - 1) & 0xf) << 0) +#define CCM_LCD_CH1_CTRL_HALF_SCLK1 0 /* no seperate sclk1 & 2 on sun6i */ #define CCM_LCD_CH1_CTRL_PLL3 (0 << 24) #define CCM_LCD_CH1_CTRL_PLL7 (1 << 24) #define CCM_LCD_CH1_CTRL_PLL3_2X (2 << 24) diff --git a/arch/arm/include/asm/arch-sunxi/display.h b/arch/arm/include/asm/arch-sunxi/display.h index ae954171f3b..2cc3916a01e 100644 --- a/arch/arm/include/asm/arch-sunxi/display.h +++ b/arch/arm/include/asm/arch-sunxi/display.h @@ -151,6 +151,10 @@ struct sunxi_de_be_reg { u32 layer1_attr1_ctrl; /* 0x8a4 */ u32 layer2_attr1_ctrl; /* 0x8a8 */ u32 layer3_attr1_ctrl; /* 0x8ac */ + u8 res5[0x110]; /* 0x8b0 */ + u32 output_color_ctrl; /* 0x9c0 */ + u8 res6[0xc]; /* 0x9c4 */ + u32 output_color_coef[12]; /* 0x9d0 */ }; struct sunxi_lcdc_reg { @@ -298,7 +302,7 @@ struct sunxi_tve_reg { u32 cbr_level; /* 0x10c */ u32 burst_phase; /* 0x110 */ u32 burst_width; /* 0x114 */ - u8 res2[0x04]; /* 0x118 */ + u32 unknown2; /* 0x118 */ u32 sync_vbi_level; /* 0x11c */ u32 white_level; /* 0x120 */ u32 active_num; /* 0x124 */ @@ -331,11 +335,14 @@ struct sunxi_tve_reg { #define SUNXI_DE_BE_HEIGHT(y) (((y) - 1) << 16) #define SUNXI_DE_BE_MODE_ENABLE (1 << 0) #define SUNXI_DE_BE_MODE_START (1 << 1) +#define SUNXI_DE_BE_MODE_DEFLICKER_ENABLE (1 << 4) #define SUNXI_DE_BE_MODE_LAYER0_ENABLE (1 << 8) +#define SUNXI_DE_BE_MODE_INTERLACE_ENABLE (1 << 28) #define SUNXI_DE_BE_LAYER_STRIDE(x) ((x) << 5) #define SUNXI_DE_BE_REG_CTRL_LOAD_REGS (1 << 0) #define SUNXI_DE_BE_LAYER_ATTR0_SRC_FE0 0x00000002 #define SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888 (0x09 << 8) +#define SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE 1 /* * LCDC register constants. @@ -372,11 +379,12 @@ struct sunxi_tve_reg { #define SUNXI_LCDC_TCON0_LVDS_INTF_ENABLE (1 << 31) #define SUNXI_LCDC_TCON0_IO_POL_DCLK_PHASE(x) ((x) << 28) #define SUNXI_LCDC_TCON1_CTRL_CLK_DELAY(n) (((n) & 0x1f) << 4) +#define SUNXI_LCDC_TCON1_CTRL_INTERLACE_ENABLE (1 << 20) #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_TCON1_TIMING_V_TOTAL(n) ((n) << 16) #ifdef CONFIG_SUNXI_GEN_SUN6I #define SUNXI_LCDC_LVDS_ANA0 0x40040320 #define SUNXI_LCDC_LVDS_ANA0_EN_MB (1 << 31) @@ -494,9 +502,22 @@ struct sunxi_tve_reg { */ #define SUNXI_TVE_GCTRL_DAC_INPUT_MASK(dac) (0xf << (((dac) + 1) * 4)) #define SUNXI_TVE_GCTRL_DAC_INPUT(dac, sel) ((sel) << (((dac) + 1) * 4)) -#define SUNXI_TVE_GCTRL_CFG0_VGA 0x20000000 -#define SUNXI_TVE_GCTRL_DAC_CFG0_VGA 0x403e1ac7 -#define SUNXI_TVE_GCTRL_UNKNOWN1_VGA 0x00000000 +#define SUNXI_TVE_CFG0_VGA 0x20000000 +#define SUNXI_TVE_CFG0_PAL 0x07030001 +#define SUNXI_TVE_CFG0_NTSC 0x07030000 +#define SUNXI_TVE_DAC_CFG0_VGA 0x403e1ac7 +#define SUNXI_TVE_DAC_CFG0_COMPOSITE 0x403f0008 +#define SUNXI_TVE_FILTER_COMPOSITE 0x00000120 +#define SUNXI_TVE_CHROMA_FREQ_PAL_M 0x21e6efe3 +#define SUNXI_TVE_CHROMA_FREQ_PAL_NC 0x21f69446 +#define SUNXI_TVE_PORCH_NUM_PAL 0x008a0018 +#define SUNXI_TVE_PORCH_NUM_NTSC 0x00760020 +#define SUNXI_TVE_LINE_NUM_PAL 0x00160271 +#define SUNXI_TVE_LINE_NUM_NTSC 0x0016020d +#define SUNXI_TVE_BLANK_BLACK_LEVEL_PAL 0x00fc00fc +#define SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC 0x00f0011a +#define SUNXI_TVE_UNKNOWN1_VGA 0x00000000 +#define SUNXI_TVE_UNKNOWN1_COMPOSITE 0x18181818 #define SUNXI_TVE_AUTO_DETECT_EN_DET_EN(dac) (1 << ((dac) + 0)) #define SUNXI_TVE_AUTO_DETECT_EN_INT_EN(dac) (1 << ((dac) + 16)) #define SUNXI_TVE_AUTO_DETECT_INT_STATUS(dac) (1 << ((dac) + 0)) @@ -512,6 +533,20 @@ struct sunxi_tve_reg { #define SUNXI_TVE_CSC_REG1 0x3b6dace1 #define SUNXI_TVE_CSC_REG2 0x0e1d13dc #define SUNXI_TVE_CSC_REG3 0x00108080 +#define SUNXI_TVE_COLOR_BURST_PAL_M 0x00000000 +#define SUNXI_TVE_CBR_LEVEL_PAL 0x00002828 +#define SUNXI_TVE_CBR_LEVEL_NTSC 0x0000004f +#define SUNXI_TVE_BURST_PHASE_NTSC 0x00000000 +#define SUNXI_TVE_BURST_WIDTH_COMPOSITE 0x0016447e +#define SUNXI_TVE_UNKNOWN2_PAL 0x0000e0e0 +#define SUNXI_TVE_UNKNOWN2_NTSC 0x0000a0a0 +#define SUNXI_TVE_SYNC_VBI_LEVEL_NTSC 0x001000f0 +#define SUNXI_TVE_ACTIVE_NUM_COMPOSITE 0x000005a0 +#define SUNXI_TVE_CHROMA_BW_GAIN_COMP 0x00000002 +#define SUNXI_TVE_NOTCH_WIDTH_COMPOSITE 0x00000101 +#define SUNXI_TVE_RESYNC_NUM_PAL 0x800d000c +#define SUNXI_TVE_RESYNC_NUM_NTSC 0x000e000c +#define SUNXI_TVE_SLAVE_PARA_COMPOSITE 0x00000000 int sunxi_simplefb_setup(void *blob); diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 8e67b3bcb87..8382101558c 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -158,6 +158,7 @@ enum sunxi_gpio_number { #define SUN8I_GPB_UART2 2 #define SUN8I_A33_GPB_UART0 3 +#define SUNXI_GPC_NAND 2 #define SUNXI_GPC_SDC2 3 #define SUN6I_GPC_SDC3 4 diff --git a/arch/arm/include/asm/arch-sunxi/usb_phy.h b/arch/arm/include/asm/arch-sunxi/usb_phy.h index cef6c985bc8..6a14cad3ff3 100644 --- a/arch/arm/include/asm/arch-sunxi/usb_phy.h +++ b/arch/arm/include/asm/arch-sunxi/usb_phy.h @@ -16,6 +16,7 @@ void sunxi_usb_phy_init(int index); void sunxi_usb_phy_exit(int index); void sunxi_usb_phy_power_on(int index); void sunxi_usb_phy_power_off(int index); +int sunxi_usb_phy_power_is_on(int index); int sunxi_usb_phy_vbus_detect(int index); int sunxi_usb_phy_id_detect(int index); void sunxi_usb_phy_enable_squelch_detect(int index, int enable); diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index c4b5a855a5e..13f453733f1 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -410,6 +410,13 @@ config VIDEO_VGA_EXTERNAL_DAC_EN Set the enable pin for the external VGA DAC. This takes a string in the format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H. +config VIDEO_COMPOSITE + boolean "Composite video output support" + depends on VIDEO && (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I) + default n + ---help--- + Say Y here to add support for outputting composite video. + config VIDEO_LCD_MODE string "LCD panel timing details" depends on VIDEO diff --git a/board/sunxi/board.c b/board/sunxi/board.c index afed6a31cab..f85e825891b 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -107,6 +107,28 @@ int dram_init(void) return 0; } +#if defined(CONFIG_SPL_NAND_SUNXI) && defined(CONFIG_SPL_BUILD) +static void nand_pinmux_setup(void) +{ + unsigned int pin; + for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(6); pin++) + sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_NAND); + + for (pin = SUNXI_GPC(8); pin <= SUNXI_GPC(22); pin++) + sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_NAND); + + sunxi_gpio_set_cfgpin(SUNXI_GPC(24), SUNXI_GPC_NAND); +} + +static void nand_clock_setup(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + setbits_le32(&ccm->ahb_gate0, (CLK_GATE_OPEN << AHB_GATE_OFFSET_NAND0)); + setbits_le32(&ccm->nand0_clk_cfg, CCM_NAND_CTRL_ENABLE | AHB_DIV_1); +} +#endif + #ifdef CONFIG_GENERIC_MMC static void mmc_pinmux_setup(int sdc) { @@ -431,6 +453,11 @@ void sunxi_board_init(void) power_failed |= axp221_set_eldo(3, CONFIG_AXP221_ELDO3_VOLT); #endif +#ifdef CONFIG_SPL_NAND_SUNXI + nand_pinmux_setup(); + nand_clock_setup(); +#endif + printf("DRAM:"); ramsize = sunxi_dram_init(); printf(" %lu MiB\n", ramsize >> 20); diff --git a/configs/Chuwi_V7_CW0825_defconfig b/configs/Chuwi_V7_CW0825_defconfig index 40113515951..f44aede2896 100644 --- a/configs/Chuwi_V7_CW0825_defconfig +++ b/configs/Chuwi_V7_CW0825_defconfig @@ -5,6 +5,7 @@ CONFIG_DRAM_CLK=408 CONFIG_DRAM_EMR1=4 CONFIG_USB0_VBUS_PIN="PB9" CONFIG_USB0_VBUS_DET="PH5" +CONFIG_USB0_ID_DET="PH4" CONFIG_VIDEO_LCD_MODE="x:1024,y:768,depth:24,pclk_khz:51000,le:19,ri:300,up:6,lo:31,hs:1,vs:1,sync:3,vmode:0" CONFIG_VIDEO_LCD_POWER="PH8" CONFIG_VIDEO_LCD_BL_EN="PH7" diff --git a/configs/Mele_M3_defconfig b/configs/Mele_M3_defconfig index d49826982f7..5c9796a77bc 100644 --- a/configs/Mele_M3_defconfig +++ b/configs/Mele_M3_defconfig @@ -5,6 +5,7 @@ CONFIG_DRAM_CLK=384 CONFIG_MMC0_CD_PIN="PH1" CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_VIDEO_VGA=y +CONFIG_VIDEO_COMPOSITE=y CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-m3" # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_SPL=y diff --git a/configs/UTOO_P66_defconfig b/configs/UTOO_P66_defconfig index 0266299f719..169c2e87c92 100644 --- a/configs/UTOO_P66_defconfig +++ b/configs/UTOO_P66_defconfig @@ -7,6 +7,7 @@ CONFIG_MMC0_CD_PIN="PG0" CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_USB0_VBUS_PIN="PB04" CONFIG_USB0_VBUS_DET="PG01" +CONFIG_USB0_ID_DET="PG2" CONFIG_AXP_GPIO=y CONFIG_VIDEO_LCD_MODE="x:480,y:800,depth:18,pclk_khz:25000,le:2,ri:93,up:2,lo:93,hs:1,vs:1,sync:3,vmode:0" CONFIG_VIDEO_LCD_DCLK_PHASE=0 diff --git a/configs/Wexler_TAB7200_defconfig b/configs/Wexler_TAB7200_defconfig index eadceb2757d..02504f9ea23 100644 --- a/configs/Wexler_TAB7200_defconfig +++ b/configs/Wexler_TAB7200_defconfig @@ -2,10 +2,15 @@ CONFIG_ARM=y CONFIG_ARCH_SUNXI=y CONFIG_MACH_SUN7I=y CONFIG_DRAM_CLK=384 +CONFIG_USB0_VBUS_PIN="PB9" +CONFIG_USB0_VBUS_DET="AXP0-VBUS-DETECT" +CONFIG_USB0_ID_DET="PH4" +CONFIG_AXP_GPIO=y CONFIG_VIDEO_LCD_MODE="x:800,y:480,depth:24,pclk_khz:33000,le:45,ri:210,up:22,lo:22,hs:1,vs:1,sync:3,vmode:0" CONFIG_VIDEO_LCD_POWER="PH8" CONFIG_VIDEO_LCD_BL_EN="PH7" CONFIG_VIDEO_LCD_BL_PWM="PB2" +CONFIG_USB_MUSB_HOST=y CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-wexler-tab7200" # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_SPL=y diff --git a/configs/jesurun_q5_defconfig b/configs/jesurun_q5_defconfig index a2115b6d390..b0d8621c659 100644 --- a/configs/jesurun_q5_defconfig +++ b/configs/jesurun_q5_defconfig @@ -10,3 +10,5 @@ CONFIG_SYS_EXTRA_OPTIONS="AXP209_POWER,SUNXI_EMAC,MACPWR=SUNXI_GPH(19)" # CONFIG_CMD_FLASH is not set # CONFIG_CMD_FPGA is not set CONFIG_USB_EHCI_HCD=y +CONFIG_USB_MUSB_HOST=y +CONFIG_USB0_VBUS_PIN="PB9" diff --git a/doc/README.video b/doc/README.video index d0a3ad6e8d4..4f7a4b5db54 100644 --- a/doc/README.video +++ b/doc/README.video @@ -40,12 +40,15 @@ requires the CONFIG_VIDEO_LCD_MODE Kconfig value to be set. The sunxi u-boot driver supports the following video-mode options: -- monitor=[none|dvi|hdmi|lcd] - Select the video output to use +- monitor=[none|dvi|hdmi|lcd|vga|composite-*] - Select the video output to use none: Disable video output. dvi/hdmi: Selects output over the hdmi connector with dvi resp. hdmi output format, if edid is used the format is automatically selected. lcd: Selects video output to a LCD screen. - vga: Selects bideo output over the VGA connector. + vga: Selects video output over the VGA connector. + composite-pal/composite-ntsc/composite-pal-m/composite-pal-nc: + Selects composite video output, note the specified resolution is + ignored with composite video output. Defaults to monitor=dvi. - hpd=[0|1] - Enable use of the hdmi HotPlug Detect feature diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 3024357de71..41ebfea3ced 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -85,6 +85,46 @@ config SPL_NAND_DENALI This is a small implementation of the Denali NAND controller for use on SPL. +config SPL_NAND_SUNXI + bool "Support for NAND on Allwinner A20 in SPL" + depends on MACH_SUN7I + ---help--- + Enable support for NAND. This option allows SPL to read from + sunxi NAND using DMA transfers. + Depending on the NAND chip, values like ECC strength and page sizes + have to be configured. + +config NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END + hex "Size of syndrome partitions in sunxi NAND" + default 0x400000 + depends on SPL_NAND_SUNXI + ---help--- + End address for boot partitions on NAND. Those partitions have a + different random seed that has to match the sunxi BROM setting. + +config NAND_SUNXI_SPL_ECC_STRENGTH + int "ECC Strength for sunxi NAND" + default 40 + depends on SPL_NAND_SUNXI + ---help--- + ECC strength used by the sunxi NAND SPL driver. This is specific to the + chosen NAND chip and has to match the value used by the sunxi BROM. + +config NAND_SUNXI_SPL_ECC_PAGE_SIZE + hex "ECC page size for sunxi NAND" + default 0x400 + depends on SPL_NAND_SUNXI + ---help--- + ECC page size used by the sunxi NAND SPL driver for syndrome partitions. + This setting has to match the value used by the sunxi BROM. + +config NAND_SUNXI_SPL_PAGE_SIZE + hex "Page size for sunxi NAND" + default 0x2000 + depends on SPL_NAND_SUNXI + ---help--- + Page size of the NAND flash used by the sunxi NAND SPL driver. This is + specific to the chosen NAND chip. endif endmenu diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 347ea62e0b3..b40dda890e8 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -12,6 +12,7 @@ NORMAL_DRIVERS=y endif obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o +obj-$(CONFIG_SPL_NAND_SUNXI) += sunxi_nand_spl.o obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c new file mode 100644 index 00000000000..ac5f56d066f --- /dev/null +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2014-2015, Antmicro Ltd <www.antmicro.com> + * Copyright (c) 2015, AW-SOM Technologies <www.aw-som.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <config.h> +#include <asm/io.h> +#include <nand.h> + +/* registers */ +#define NFC_CTL 0x00000000 +#define NFC_ST 0x00000004 +#define NFC_INT 0x00000008 +#define NFC_TIMING_CTL 0x0000000C +#define NFC_TIMING_CFG 0x00000010 +#define NFC_ADDR_LOW 0x00000014 +#define NFC_ADDR_HIGH 0x00000018 +#define NFC_SECTOR_NUM 0x0000001C +#define NFC_CNT 0x00000020 +#define NFC_CMD 0x00000024 +#define NFC_RCMD_SET 0x00000028 +#define NFC_WCMD_SET 0x0000002C +#define NFC_IO_DATA 0x00000030 +#define NFC_ECC_CTL 0x00000034 +#define NFC_ECC_ST 0x00000038 +#define NFC_DEBUG 0x0000003C +#define NFC_ECC_CNT0 0x00000040 +#define NFC_ECC_CNT1 0x00000044 +#define NFC_ECC_CNT2 0x00000048 +#define NFC_ECC_CNT3 0x0000004C +#define NFC_USER_DATA_BASE 0x00000050 +#define NFC_EFNAND_STATUS 0x00000090 +#define NFC_SPARE_AREA 0x000000A0 +#define NFC_PATTERN_ID 0x000000A4 +#define NFC_RAM0_BASE 0x00000400 +#define NFC_RAM1_BASE 0x00000800 + +#define NFC_CTL_EN (1 << 0) +#define NFC_CTL_RESET (1 << 1) +#define NFC_CTL_RAM_METHOD (1 << 14) + + +#define NFC_ECC_EN (1 << 0) +#define NFC_ECC_PIPELINE (1 << 3) +#define NFC_ECC_EXCEPTION (1 << 4) +#define NFC_ECC_BLOCK_SIZE (1 << 5) +#define NFC_ECC_RANDOM_EN (1 << 9) +#define NFC_ECC_RANDOM_DIRECTION (1 << 10) + + +#define NFC_ADDR_NUM_OFFSET 16 +#define NFC_SEND_ADR (1 << 19) +#define NFC_ACCESS_DIR (1 << 20) +#define NFC_DATA_TRANS (1 << 21) +#define NFC_SEND_CMD1 (1 << 22) +#define NFC_WAIT_FLAG (1 << 23) +#define NFC_SEND_CMD2 (1 << 24) +#define NFC_SEQ (1 << 25) +#define NFC_DATA_SWAP_METHOD (1 << 26) +#define NFC_ROW_AUTO_INC (1 << 27) +#define NFC_SEND_CMD3 (1 << 28) +#define NFC_SEND_CMD4 (1 << 29) + +#define NFC_CMD_INT_FLAG (1 << 1) + +#define NFC_READ_CMD_OFFSET 0 +#define NFC_RANDOM_READ_CMD0_OFFSET 8 +#define NFC_RANDOM_READ_CMD1_OFFSET 16 + +#define NFC_CMD_RNDOUTSTART 0xE0 +#define NFC_CMD_RNDOUT 0x05 +#define NFC_CMD_READSTART 0x30 + + +#define NFC_PAGE_CMD (2 << 30) + +#define SUNXI_DMA_CFG_REG0 0x300 +#define SUNXI_DMA_SRC_START_ADDR_REG0 0x304 +#define SUNXI_DMA_DEST_START_ADDRR_REG0 0x308 +#define SUNXI_DMA_DDMA_BC_REG0 0x30C +#define SUNXI_DMA_DDMA_PARA_REG0 0x318 + +#define SUNXI_DMA_DDMA_CFG_REG_LOADING (1 << 31) +#define SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 (2 << 25) +#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 (2 << 9) +#define SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO (1 << 5) +#define SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC (3 << 0) + +#define SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC (0x0F << 0) +#define SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE (0x7F << 8) + +/* minimal "boot0" style NAND support for Allwinner A20 */ + +/* temporary buffer in internal ram */ +unsigned char temp_buf[CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE] + __aligned(0x10) __section(".text#"); + +/* random seed used by linux */ +const uint16_t random_seed[128] = { + 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72, + 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436, + 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d, + 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130, + 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56, + 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55, + 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb, + 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17, + 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62, + 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064, + 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126, + 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e, + 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3, + 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b, + 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d, + 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db, +}; + +/* random seed used for syndrome calls */ +const uint16_t random_seed_syndrome = 0x4a80; + +#define MAX_RETRIES 10 + +static int check_value_inner(int offset, int expected_bits, + int max_number_of_retries, int negation) +{ + int retries = 0; + do { + int val = readl(offset) & expected_bits; + if (negation ? !val : val) + return 1; + mdelay(1); + retries++; + } while (retries < max_number_of_retries); + + return 0; +} + +static inline int check_value(int offset, int expected_bits, + int max_number_of_retries) +{ + return check_value_inner(offset, expected_bits, + max_number_of_retries, 0); +} + +static inline int check_value_negated(int offset, int unexpected_bits, + int max_number_of_retries) +{ + return check_value_inner(offset, unexpected_bits, + max_number_of_retries, 1); +} + +void nand_init(void) +{ + uint32_t val; + + val = readl(SUNXI_NFC_BASE + NFC_CTL); + /* enable and reset CTL */ + writel(val | NFC_CTL_EN | NFC_CTL_RESET, + SUNXI_NFC_BASE + NFC_CTL); + + if (!check_value_negated(SUNXI_NFC_BASE + NFC_CTL, + NFC_CTL_RESET, MAX_RETRIES)) { + printf("Couldn't initialize nand\n"); + } +} + +static void nand_read_page(unsigned int real_addr, int syndrome, + uint32_t *ecc_errors) +{ + uint32_t val; + int ecc_off = 0; + uint16_t ecc_mode = 0; + uint16_t rand_seed; + uint32_t page; + uint16_t column; + uint32_t oob_offset; + + switch (CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH) { + case 16: + ecc_mode = 0; + ecc_off = 0x20; + break; + case 24: + ecc_mode = 1; + ecc_off = 0x2e; + break; + case 28: + ecc_mode = 2; + ecc_off = 0x32; + break; + case 32: + ecc_mode = 3; + ecc_off = 0x3c; + break; + case 40: + ecc_mode = 4; + ecc_off = 0x4a; + break; + case 48: + ecc_mode = 4; + ecc_off = 0x52; + break; + case 56: + ecc_mode = 4; + ecc_off = 0x60; + break; + case 60: + ecc_mode = 4; + ecc_off = 0x0; + break; + case 64: + ecc_mode = 4; + ecc_off = 0x0; + break; + default: + ecc_mode = 0; + ecc_off = 0; + } + + if (ecc_off == 0) { + printf("Unsupported ECC strength (%d)!\n", + CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH); + return; + } + + /* clear temp_buf */ + memset(temp_buf, 0, CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE); + + /* set CMD */ + writel(NFC_SEND_CMD1 | NFC_WAIT_FLAG | NAND_CMD_RESET, + SUNXI_NFC_BASE + NFC_CMD); + + if (!check_value(SUNXI_NFC_BASE + NFC_ST, NFC_CMD_INT_FLAG, + MAX_RETRIES)) { + printf("Error while initilizing command interrupt\n"); + return; + } + + page = real_addr / CONFIG_NAND_SUNXI_SPL_PAGE_SIZE; + column = real_addr % CONFIG_NAND_SUNXI_SPL_PAGE_SIZE; + + if (syndrome) + column += (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) + * ecc_off; + + /* clear ecc status */ + writel(0, SUNXI_NFC_BASE + NFC_ECC_ST); + + /* Choose correct seed */ + if (syndrome) + rand_seed = random_seed_syndrome; + else + rand_seed = random_seed[page % 128]; + + writel((rand_seed << 16) | NFC_ECC_RANDOM_EN | NFC_ECC_EN + | NFC_ECC_PIPELINE | (ecc_mode << 12), + SUNXI_NFC_BASE + NFC_ECC_CTL); + + val = readl(SUNXI_NFC_BASE + NFC_CTL); + writel(val | NFC_CTL_RAM_METHOD, SUNXI_NFC_BASE + NFC_CTL); + + if (syndrome) { + writel(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE, + SUNXI_NFC_BASE + NFC_SPARE_AREA); + } else { + oob_offset = CONFIG_NAND_SUNXI_SPL_PAGE_SIZE + + (column / CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) + * ecc_off; + writel(oob_offset, SUNXI_NFC_BASE + NFC_SPARE_AREA); + } + + /* SUNXI_DMA */ + writel(0x0, SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); /* clr dma cmd */ + /* read from REG_IO_DATA */ + writel(SUNXI_NFC_BASE + NFC_IO_DATA, + SUNXI_DMA_BASE + SUNXI_DMA_SRC_START_ADDR_REG0); + /* read to RAM */ + writel((uint32_t)temp_buf, + SUNXI_DMA_BASE + SUNXI_DMA_DEST_START_ADDRR_REG0); + writel(SUNXI_DMA_DDMA_PARA_REG_SRC_WAIT_CYC + | SUNXI_DMA_DDMA_PARA_REG_SRC_BLK_SIZE, + SUNXI_DMA_BASE + SUNXI_DMA_DDMA_PARA_REG0); + writel(CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE, + SUNXI_DMA_BASE + SUNXI_DMA_DDMA_BC_REG0); /* 1kB */ + writel(SUNXI_DMA_DDMA_CFG_REG_LOADING + | SUNXI_DMA_DDMA_CFG_REG_DMA_DEST_DATA_WIDTH_32 + | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_DATA_WIDTH_32 + | SUNXI_DMA_DDMA_CFG_REG_DMA_SRC_ADDR_MODE_IO + | SUNXI_DMA_DDMA_CFG_REG_DDMA_SRC_DRQ_TYPE_NFC, + SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0); + + writel((NFC_CMD_RNDOUTSTART << NFC_RANDOM_READ_CMD1_OFFSET) + | (NFC_CMD_RNDOUT << NFC_RANDOM_READ_CMD0_OFFSET) + | (NFC_CMD_READSTART | NFC_READ_CMD_OFFSET), SUNXI_NFC_BASE + + NFC_RCMD_SET); + writel(1, SUNXI_NFC_BASE + NFC_SECTOR_NUM); + writel(((page & 0xFFFF) << 16) | column, + SUNXI_NFC_BASE + NFC_ADDR_LOW); + writel((page >> 16) & 0xFF, SUNXI_NFC_BASE + NFC_ADDR_HIGH); + writel(NFC_SEND_CMD1 | NFC_SEND_CMD2 | NFC_DATA_TRANS | + NFC_PAGE_CMD | NFC_WAIT_FLAG | (4 << NFC_ADDR_NUM_OFFSET) | + NFC_SEND_ADR | NFC_DATA_SWAP_METHOD | (syndrome ? NFC_SEQ : 0), + SUNXI_NFC_BASE + NFC_CMD); + + if (!check_value(SUNXI_NFC_BASE + NFC_ST, (1 << 2), + MAX_RETRIES)) { + printf("Error while initializing dma interrupt\n"); + return; + } + + if (!check_value_negated(SUNXI_DMA_BASE + SUNXI_DMA_CFG_REG0, + SUNXI_DMA_DDMA_CFG_REG_LOADING, MAX_RETRIES)) { + printf("Error while waiting for dma transfer to finish\n"); + return; + } + + if (readl(SUNXI_NFC_BASE + NFC_ECC_ST)) + (*ecc_errors)++; +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{ + void *current_dest; + uint32_t count; + uint32_t current_count; + uint32_t ecc_errors = 0; + + memset(dest, 0x0, size); /* clean destination memory */ + for (current_dest = dest; + current_dest < (dest + size); + current_dest += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) { + nand_read_page(offs, offs + < CONFIG_NAND_SUNXI_SPL_SYNDROME_PARTITIONS_END, + &ecc_errors); + count = current_dest - dest; + + if (size - count > CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE) + current_count = CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE; + else + current_count = size - count; + + memcpy(current_dest, + temp_buf, + current_count); + offs += CONFIG_NAND_SUNXI_SPL_ECC_PAGE_SIZE; + } + return ecc_errors ? -1 : 0; +} + +void nand_deselect(void) {} diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c index 34130f8443c..38d5f92ad0f 100644 --- a/drivers/usb/host/ehci-sunxi.c +++ b/drivers/usb/host/ehci-sunxi.c @@ -67,7 +67,6 @@ static int ehci_usb_remove(struct udevice *dev) if (ret) return ret; - sunxi_usb_phy_power_off(priv->phy_index); sunxi_usb_phy_exit(priv->phy_index); #ifdef CONFIG_SUNXI_GEN_SUN6I diff --git a/drivers/usb/host/ohci-sunxi.c b/drivers/usb/host/ohci-sunxi.c index e33a8f7ec2e..60792726ee3 100644 --- a/drivers/usb/host/ohci-sunxi.c +++ b/drivers/usb/host/ohci-sunxi.c @@ -69,7 +69,6 @@ static int ohci_usb_remove(struct udevice *dev) if (ret) return ret; - sunxi_usb_phy_power_off(priv->phy_index); sunxi_usb_phy_exit(priv->phy_index); #ifdef CONFIG_SUNXI_GEN_SUN6I diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c index 16a264a9dde..a146c0861ff 100644 --- a/drivers/usb/musb-new/sunxi.c +++ b/drivers/usb/musb-new/sunxi.c @@ -196,8 +196,6 @@ static bool enabled = false; static int sunxi_musb_enable(struct musb *musb) { - int ret; - pr_debug("%s():\n", __func__); musb_ep_select(musb->mregs, 0); @@ -210,17 +208,26 @@ static int sunxi_musb_enable(struct musb *musb) musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0); if (is_host_enabled(musb)) { - ret = sunxi_usb_phy_vbus_detect(0); - if (ret == 1) { - printf("A charger is plugged into the OTG: "); - return -ENODEV; + int id = sunxi_usb_phy_id_detect(0); + + if (id == 1 && sunxi_usb_phy_power_is_on(0)) + sunxi_usb_phy_power_off(0); + + if (!sunxi_usb_phy_power_is_on(0)) { + int vbus = sunxi_usb_phy_vbus_detect(0); + if (vbus == 1) { + printf("A charger is plugged into the OTG: "); + return -ENODEV; + } } - ret = sunxi_usb_phy_id_detect(0); - if (ret == 1) { + + if (id == 1) { printf("No host cable detected: "); return -ENODEV; } - sunxi_usb_phy_power_on(0); /* port power on */ + + if (!sunxi_usb_phy_power_is_on(0)) + sunxi_usb_phy_power_on(0); } USBC_ForceVbusValidToHigh(musb->mregs); @@ -236,9 +243,6 @@ static void sunxi_musb_disable(struct musb *musb) if (!enabled) return; - if (is_host_enabled(musb)) - sunxi_usb_phy_power_off(0); /* port power off */ - USBC_ForceVbusValidToLow(musb->mregs); mdelay(200); /* Wait for the current session to timeout */ diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c index 269083b6664..18681850587 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi_display.c @@ -2,7 +2,7 @@ * Display driver for Allwinner SoCs. * * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be> - * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com> + * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com> * * SPDX-License-Identifier: GPL-2.0+ */ @@ -40,8 +40,12 @@ enum sunxi_monitor { sunxi_monitor_hdmi, sunxi_monitor_lcd, sunxi_monitor_vga, + sunxi_monitor_composite_pal, + sunxi_monitor_composite_ntsc, + sunxi_monitor_composite_pal_m, + sunxi_monitor_composite_pal_nc, }; -#define SUNXI_MONITOR_LAST sunxi_monitor_vga +#define SUNXI_MONITOR_LAST sunxi_monitor_composite_pal_nc struct sunxi_display { GraphicDevice graphic_device; @@ -50,6 +54,12 @@ struct sunxi_display { unsigned int fb_size; } sunxi_display; +const struct ctfb_res_modes composite_video_modes[2] = { + /* x y hz pixclk ps/kHz le ri up lo hs vs s vmode */ + { 720, 576, 50, 37037, 27000, 137, 5, 20, 27, 2, 2, 0, FB_VMODE_INTERLACED }, + { 720, 480, 60, 37037, 27000, 116, 20, 16, 27, 2, 2, 0, FB_VMODE_INTERLACED }, +}; + #ifdef CONFIG_VIDEO_HDMI /* @@ -390,6 +400,25 @@ static void sunxi_frontend_mode_set(const struct ctfb_res_modes *mode, static void sunxi_frontend_enable(void) {} #endif +static bool sunxi_is_composite(void) +{ + switch (sunxi_display.monitor) { + case sunxi_monitor_none: + case sunxi_monitor_dvi: + case sunxi_monitor_hdmi: + case sunxi_monitor_lcd: + case sunxi_monitor_vga: + return false; + case sunxi_monitor_composite_pal: + case sunxi_monitor_composite_ntsc: + case sunxi_monitor_composite_pal_m: + case sunxi_monitor_composite_pal_nc: + return true; + } + + return false; /* Never reached */ +} + /* * This is the entity that mixes and matches the different layers and inputs. * Allwinner calls it the back-end, but i like composer better. @@ -423,11 +452,18 @@ static void sunxi_composer_init(void) setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_ENABLE); } +static u32 sunxi_rgb2yuv_coef[12] = { + 0x00000107, 0x00000204, 0x00000064, 0x00000108, + 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808, + 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 +}; + static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode, unsigned int address) { struct sunxi_de_be_reg * const de_be = (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE; + int i; sunxi_frontend_mode_set(mode, address); @@ -445,6 +481,18 @@ static void sunxi_composer_mode_set(const struct ctfb_res_modes *mode, writel(SUNXI_DE_BE_LAYER_ATTR1_FMT_XRGB8888, &de_be->layer0_attr1_ctrl); setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_LAYER0_ENABLE); + if (mode->vmode == FB_VMODE_INTERLACED) + setbits_le32(&de_be->mode, + SUNXI_DE_BE_MODE_DEFLICKER_ENABLE | + SUNXI_DE_BE_MODE_INTERLACE_ENABLE); + + if (sunxi_is_composite()) { + writel(SUNXI_DE_BE_OUTPUT_COLOR_CTRL_ENABLE, + &de_be->output_color_ctrl); + for (i = 0; i < 12; i++) + writel(sunxi_rgb2yuv_coef[i], + &de_be->output_color_coef[i]); + } } static void sunxi_composer_enable(void) @@ -535,6 +583,9 @@ static void sunxi_lcdc_pll_set(int tcon, int dotclock, (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X : CCM_LCD_CH1_CTRL_PLL3) | CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg); + if (sunxi_is_composite()) + setbits_le32(&ccm->lcd0_ch1_clk_cfg, + CCM_LCD_CH1_CTRL_HALF_SCLK1); } *clk_div = best_m; @@ -663,11 +714,16 @@ 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) +static int sunxi_lcdc_get_clk_delay(const struct ctfb_res_modes *mode, int tcon) { int delay; - delay = mode->lower_margin + mode->vsync_len + mode->upper_margin - 2; + delay = mode->lower_margin + mode->vsync_len + mode->upper_margin; + if (mode->vmode == FB_VMODE_INTERLACED) + delay /= 2; + if (tcon == 1) + delay -= 2; + return (delay > 30) ? 30 : delay; } @@ -692,7 +748,7 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, clrsetbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_IO_MAP_MASK, SUNXI_LCDC_CTRL_IO_MAP_TCON0); - clk_delay = sunxi_lcdc_get_clk_delay(mode); + 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); @@ -757,28 +813,33 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode, writel(0, &lcdc->tcon0_io_tristate); } -#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA +#if defined CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode, int *clk_div, int *clk_double, bool use_portd_hvsync) { struct sunxi_lcdc_reg * const lcdc = (struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE; - int bp, clk_delay, total, val; + 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); - clk_delay = sunxi_lcdc_get_clk_delay(mode); + 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); - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres), + 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(mode->yres), + writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres), &lcdc->tcon1_timing_scale); - writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(mode->yres), + writel(SUNXI_LCDC_X(mode->xres) | SUNXI_LCDC_Y(yres), &lcdc->tcon1_timing_out); bp = mode->hsync_len + mode->left_margin; @@ -788,6 +849,8 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode, 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); @@ -811,7 +874,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode, } sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double); } -#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA */ +#endif /* CONFIG_VIDEO_HDMI || defined CONFIG_VIDEO_VGA || CONFIG_VIDEO_COMPOSITE */ #ifdef CONFIG_VIDEO_HDMI @@ -925,9 +988,9 @@ static void sunxi_hdmi_enable(void) #endif /* CONFIG_VIDEO_HDMI */ -#ifdef CONFIG_VIDEO_VGA +#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE -static void sunxi_vga_mode_set(void) +static void sunxi_tvencoder_mode_set(void) { struct sunxi_ccm_reg * const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; @@ -937,16 +1000,75 @@ static void sunxi_vga_mode_set(void) /* Clock on */ setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_TVE0); - /* Set TVE in VGA mode */ - writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | - SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | - SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl); - writel(SUNXI_TVE_GCTRL_CFG0_VGA, &tve->cfg0); - writel(SUNXI_TVE_GCTRL_DAC_CFG0_VGA, &tve->dac_cfg0); - writel(SUNXI_TVE_GCTRL_UNKNOWN1_VGA, &tve->unknown1); + switch (sunxi_display.monitor) { + case sunxi_monitor_vga: + writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | + SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | + SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl); + writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0); + writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0); + writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1); + break; + case sunxi_monitor_composite_pal_nc: + writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq); + /* Fall through */ + case sunxi_monitor_composite_pal: + writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | + SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | + SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) | + SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl); + writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0); + writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); + writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter); + writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num); + writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num); + writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level); + writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1); + writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level); + writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width); + writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2); + writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num); + writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain); + writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width); + writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num); + writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para); + break; + case sunxi_monitor_composite_pal_m: + writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq); + writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst); + /* Fall through */ + case sunxi_monitor_composite_ntsc: + writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) | + SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) | + SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) | + SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl); + writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0); + writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0); + writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter); + writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num); + writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num); + writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level); + writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1); + writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level); + writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase); + writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width); + writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2); + writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level); + writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num); + writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain); + writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width); + writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num); + writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para); + break; + case sunxi_monitor_none: + case sunxi_monitor_dvi: + case sunxi_monitor_hdmi: + case sunxi_monitor_lcd: + break; + } } -static void sunxi_vga_enable(void) +static void sunxi_tvencoder_enable(void) { struct sunxi_tve_reg * const tve = (struct sunxi_tve_reg *)SUNXI_TVE0_BASE; @@ -954,7 +1076,7 @@ static void sunxi_vga_enable(void) setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE); } -#endif /* CONFIG_VIDEO_VGA */ +#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */ static void sunxi_drc_init(void) { @@ -1069,10 +1191,10 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, #ifdef CONFIG_VIDEO_VGA sunxi_composer_mode_set(mode, address); sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 1); - sunxi_vga_mode_set(); + sunxi_tvencoder_mode_set(); sunxi_composer_enable(); sunxi_lcdc_enable(); - sunxi_vga_enable(); + sunxi_tvencoder_enable(); #elif defined CONFIG_VIDEO_VGA_VIA_LCD sunxi_composer_mode_set(mode, address); sunxi_lcdc_tcon0_mode_set(mode, true); @@ -1081,17 +1203,34 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, sunxi_vga_external_dac_enable(); #endif break; + case sunxi_monitor_composite_pal: + case sunxi_monitor_composite_ntsc: + case sunxi_monitor_composite_pal_m: + case sunxi_monitor_composite_pal_nc: +#ifdef CONFIG_VIDEO_COMPOSITE + sunxi_composer_mode_set(mode, address); + sunxi_lcdc_tcon1_mode_set(mode, &clk_div, &clk_double, 0); + sunxi_tvencoder_mode_set(); + sunxi_composer_enable(); + sunxi_lcdc_enable(); + sunxi_tvencoder_enable(); +#endif + break; } } static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor) { switch (monitor) { - case sunxi_monitor_none: return "none"; - case sunxi_monitor_dvi: return "dvi"; - case sunxi_monitor_hdmi: return "hdmi"; - case sunxi_monitor_lcd: return "lcd"; - case sunxi_monitor_vga: return "vga"; + case sunxi_monitor_none: return "none"; + case sunxi_monitor_dvi: return "dvi"; + case sunxi_monitor_hdmi: return "hdmi"; + case sunxi_monitor_lcd: return "lcd"; + case sunxi_monitor_vga: return "vga"; + case sunxi_monitor_composite_pal: return "composite-pal"; + case sunxi_monitor_composite_ntsc: return "composite-ntsc"; + case sunxi_monitor_composite_pal_m: return "composite-pal-m"; + case sunxi_monitor_composite_pal_nc: return "composite-pal-nc"; } return NULL; /* never reached */ } @@ -1101,6 +1240,54 @@ ulong board_get_usable_ram_top(ulong total_size) return gd->ram_top - CONFIG_SUNXI_MAX_FB_SIZE; } +static bool sunxi_has_hdmi(void) +{ +#ifdef CONFIG_VIDEO_HDMI + return true; +#else + return false; +#endif +} + +static bool sunxi_has_lcd(void) +{ + char *lcd_mode = CONFIG_VIDEO_LCD_MODE; + + return lcd_mode[0] != 0; +} + +static bool sunxi_has_vga(void) +{ +#if defined CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_VGA_VIA_LCD + return true; +#else + return false; +#endif +} + +static bool sunxi_has_composite(void) +{ +#ifdef CONFIG_VIDEO_COMPOSITE + return true; +#else + return false; +#endif +} + +static enum sunxi_monitor sunxi_get_default_mon(bool allow_hdmi) +{ + if (allow_hdmi && sunxi_has_hdmi()) + return sunxi_monitor_dvi; + else if (sunxi_has_lcd()) + return sunxi_monitor_lcd; + else if (sunxi_has_vga()) + return sunxi_monitor_vga; + else if (sunxi_has_composite()) + return sunxi_monitor_composite_pal; + else + return sunxi_monitor_none; +} + void *video_hw_init(void) { static GraphicDevice *graphic_device = &sunxi_display.graphic_device; @@ -1122,12 +1309,8 @@ void *video_hw_init(void) hpd = video_get_option_int(options, "hpd", 1); hpd_delay = video_get_option_int(options, "hpd_delay", 500); edid = video_get_option_int(options, "edid", 1); - sunxi_display.monitor = sunxi_monitor_dvi; -#elif defined CONFIG_VIDEO_VGA_VIA_LCD - sunxi_display.monitor = sunxi_monitor_vga; -#else - sunxi_display.monitor = sunxi_monitor_lcd; #endif + sunxi_display.monitor = sunxi_get_default_mon(true); video_get_option_string(options, "monitor", mon, sizeof(mon), sunxi_get_mon_desc(sunxi_display.monitor)); for (i = 0; i <= SUNXI_MONITOR_LAST; i++) { @@ -1152,16 +1335,7 @@ void *video_hw_init(void) mode = &custom; } else if (hpd) { sunxi_hdmi_shutdown(); - /* Fallback to lcd / vga / none */ - if (lcd_mode[0]) { - sunxi_display.monitor = sunxi_monitor_lcd; - } else { -#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA - sunxi_display.monitor = sunxi_monitor_vga; -#else - sunxi_display.monitor = sunxi_monitor_none; -#endif - } + sunxi_display.monitor = sunxi_get_default_mon(false); } /* else continue with hdmi/dvi without a cable connected */ } #endif @@ -1171,39 +1345,45 @@ void *video_hw_init(void) return NULL; case sunxi_monitor_dvi: case sunxi_monitor_hdmi: -#ifdef CONFIG_VIDEO_HDMI + if (!sunxi_has_hdmi()) { + printf("HDMI/DVI not supported on this board\n"); + sunxi_display.monitor = sunxi_monitor_none; + return NULL; + } break; -#else - printf("HDMI/DVI not supported on this board\n"); - sunxi_display.monitor = sunxi_monitor_none; - return NULL; -#endif case sunxi_monitor_lcd: - if (lcd_mode[0]) { - sunxi_display.depth = video_get_params(&custom, lcd_mode); - mode = &custom; - break; + if (!sunxi_has_lcd()) { + printf("LCD not supported on this board\n"); + sunxi_display.monitor = sunxi_monitor_none; + return NULL; } - printf("LCD not supported on this board\n"); - sunxi_display.monitor = sunxi_monitor_none; - return NULL; + sunxi_display.depth = video_get_params(&custom, lcd_mode); + mode = &custom; + break; case sunxi_monitor_vga: -#if defined CONFIG_VIDEO_VGA_VIA_LCD || defined CONFIG_VIDEO_VGA + if (!sunxi_has_vga()) { + printf("VGA not supported on this board\n"); + sunxi_display.monitor = sunxi_monitor_none; + return NULL; + } sunxi_display.depth = 18; break; -#else - printf("VGA not supported on this board\n"); - sunxi_display.monitor = sunxi_monitor_none; - return NULL; -#endif - } - - if (mode->vmode != FB_VMODE_NONINTERLACED) { - printf("Only non-interlaced modes supported, falling back to 1024x768\n"); - mode = &res_mode_init[RES_MODE_1024x768]; - } else { - printf("Setting up a %dx%d %s console\n", mode->xres, - mode->yres, sunxi_get_mon_desc(sunxi_display.monitor)); + case sunxi_monitor_composite_pal: + case sunxi_monitor_composite_ntsc: + case sunxi_monitor_composite_pal_m: + case sunxi_monitor_composite_pal_nc: + if (!sunxi_has_composite()) { + printf("Composite video not supported on this board\n"); + sunxi_display.monitor = sunxi_monitor_none; + return NULL; + } + if (sunxi_display.monitor == sunxi_monitor_composite_pal || + sunxi_display.monitor == sunxi_monitor_composite_pal_nc) + mode = &composite_video_modes[0]; + else + mode = &composite_video_modes[1]; + sunxi_display.depth = 24; + break; } sunxi_display.fb_size = @@ -1215,6 +1395,10 @@ void *video_hw_init(void) return NULL; } + printf("Setting up a %dx%d%s %s console\n", mode->xres, mode->yres, + (mode->vmode == FB_VMODE_INTERLACED) ? "i" : "", + sunxi_get_mon_desc(sunxi_display.monitor)); + gd->fb_base = gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sunxi_display.fb_size; sunxi_engines_init(); @@ -1268,6 +1452,12 @@ int sunxi_simplefb_setup(void *blob) pipeline = PIPELINE_PREFIX "de_be0-lcd0"; #endif break; + case sunxi_monitor_composite_pal: + case sunxi_monitor_composite_ntsc: + case sunxi_monitor_composite_pal_m: + case sunxi_monitor_composite_pal_nc: + pipeline = PIPELINE_PREFIX "de_be0-lcd0-tve0"; + break; } /* Find a prefilled simpefb node, matching out pipeline config */ diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index edcacd5c148..a2cbcf5d954 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -139,6 +139,16 @@ #define CONFIG_INITRD_TAG #define CONFIG_SERIAL_TAG +#if defined(CONFIG_SPL_NAND_SUNXI) +#define CONFIG_SPL_NAND_DRIVERS +#define CONFIG_SPL_NAND_SUPPORT + +#define CONFIG_SYS_NAND_SPL_KERNEL_OFFS 0x280000 +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0x008000 + +#endif + + /* mmc config */ #if !defined(CONFIG_UART0_PORT_F) #define CONFIG_MMC @@ -252,6 +262,7 @@ extern int soft_i2c_gpio_scl; #define CONFIG_CONS_INDEX 1 /* UART0 */ #endif +#ifdef CONFIG_REQUIRE_SERIAL_CONSOLE #if CONFIG_CONS_INDEX == 1 #ifdef CONFIG_MACH_SUN9I #define OF_STDOUT_PATH "/soc/serial@07000000:115200" @@ -267,6 +278,7 @@ extern int soft_i2c_gpio_scl; #else #error Unsupported console port nr. Please fix stdout-path in sunxi-common.h. #endif +#endif /* ifdef CONFIG_REQUIRE_SERIAL_CONSOLE */ /* GPIO */ #define CONFIG_SUNXI_GPIO |