sunxi: SPL SPI: Add SPI boot support for the Allwinner H6 SoC
authorAndre Przywara <andre.przywara@arm.com>
Tue, 28 Jan 2020 00:46:43 +0000 (00:46 +0000)
committerJagan Teki <jagan@amarulasolutions.com>
Wed, 18 Mar 2020 12:42:04 +0000 (18:12 +0530)
The Allwinner H6 SoC uses a quite different memory map, also changes the
clocks quite a bit. This requires some changes to the SPL SPI routine,
which hardcodes these values so far.

Using the just introduced helper functions to determine base address
and SPI controller generation, we can cover some of these differences
easily.
The clock setup is different, so requires some explicit code changes
there (reset and clock gate in one register at a different address).
Also we need to change the pinmux function to use a different set of
pins that the H6 uses for SPI0.

Eventually we can enable the H6 to use SPI booting in Kconfig.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
arch/arm/mach-sunxi/Kconfig
arch/arm/mach-sunxi/spl_spi_sunxi.c

index eb04616..be0822b 100644 (file)
@@ -994,7 +994,7 @@ config SPL_STACK_R_ADDR
 
 config SPL_SPI_SUNXI
        bool "Support for SPI Flash on Allwinner SoCs in SPL"
-       depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40
+       depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6
        help
          Enable support for SPI Flash. This option allows SPL to read from
          sunxi SPI Flash. It uses the same method as the boot ROM, so does
index 357953c..a3997b2 100644 (file)
 /*****************************************************************************/
 
 #define CCM_AHB_GATING0             (0x01C20000 + 0x60)
+#define CCM_H6_SPI_BGR_REG          (0x03001000 + 0x96c)
+#ifdef CONFIG_MACH_SUN50I_H6
+#define CCM_SPI0_CLK                (0x03001000 + 0x940)
+#else
 #define CCM_SPI0_CLK                (0x01C20000 + 0xA0)
+#endif
 #define SUN6I_BUS_SOFT_RST_REG0     (0x01C20000 + 0x2C0)
 
 #define AHB_RESET_SPI0_SHIFT        20
 /*
  * Allwinner A10/A20 SoCs were using pins PC0,PC1,PC2,PC23 for booting
  * from SPI Flash, everything else is using pins PC0,PC1,PC2,PC3.
+ * The H6 uses PC0, PC2, PC3, PC5.
  */
 static void spi0_pinmux_setup(unsigned int pin_function)
 {
-       unsigned int pin;
+       /* All chips use PC0 and PC2. */
+       sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function);
+       sunxi_gpio_set_cfgpin(SUNXI_GPC(2), pin_function);
 
-       for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(2); pin++)
-               sunxi_gpio_set_cfgpin(pin, pin_function);
+       /* All chips except H6 use PC1, and only H6 uses PC5. */
+       if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+               sunxi_gpio_set_cfgpin(SUNXI_GPC(1), pin_function);
+       else
+               sunxi_gpio_set_cfgpin(SUNXI_GPC(5), pin_function);
 
+       /* Older generations use PC23 for CS, newer ones use PC3. */
        if (IS_ENABLED(CONFIG_MACH_SUN4I) || IS_ENABLED(CONFIG_MACH_SUN7I) ||
            IS_ENABLED(CONFIG_MACH_SUN8I_R40))
                sunxi_gpio_set_cfgpin(SUNXI_GPC(23), pin_function);
@@ -103,7 +115,8 @@ static void spi0_pinmux_setup(unsigned int pin_function)
 
 static bool is_sun6i_gen_spi(void)
 {
-       return IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I);
+       return IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ||
+              IS_ENABLED(CONFIG_MACH_SUN50I_H6);
 }
 
 static uintptr_t spi0_base_address(void)
@@ -111,6 +124,9 @@ static uintptr_t spi0_base_address(void)
        if (IS_ENABLED(CONFIG_MACH_SUN8I_R40))
                return 0x01C05000;
 
+       if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+               return 0x05010000;
+
        if (!is_sun6i_gen_spi())
                return 0x01C05000;
 
@@ -125,12 +141,15 @@ static void spi0_enable_clock(void)
        uintptr_t base = spi0_base_address();
 
        /* Deassert SPI0 reset on SUN6I */
-       if (is_sun6i_gen_spi())
+       if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+               setbits_le32(CCM_H6_SPI_BGR_REG, (1U << 16) | 0x1);
+       else if (is_sun6i_gen_spi())
                setbits_le32(SUN6I_BUS_SOFT_RST_REG0,
                             (1 << AHB_RESET_SPI0_SHIFT));
 
        /* Open the SPI0 gate */
-       setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+       if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+               setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
 
        /* Divide by 4 */
        writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ?
@@ -170,10 +189,13 @@ static void spi0_disable_clock(void)
        writel(0, CCM_SPI0_CLK);
 
        /* Close the SPI0 gate */
-       clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+       if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+               clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
 
        /* Assert SPI0 reset on SUN6I */
-       if (is_sun6i_gen_spi())
+       if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+               clrbits_le32(CCM_H6_SPI_BGR_REG, (1U << 16) | 0x1);
+       else if (is_sun6i_gen_spi())
                clrbits_le32(SUN6I_BUS_SOFT_RST_REG0,
                             (1 << AHB_RESET_SPI0_SHIFT));
 }
@@ -182,7 +204,8 @@ static void spi0_init(void)
 {
        unsigned int pin_function = SUNXI_GPC_SPI0;
 
-       if (IS_ENABLED(CONFIG_MACH_SUN50I))
+       if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
+           IS_ENABLED(CONFIG_MACH_SUN50I_H6))
                pin_function = SUN50I_GPC_SPI0;
 
        spi0_pinmux_setup(pin_function);