[PATCH v2 0/5] sunxi: SPL SPI booting: Enable R40 and H6 SoCs

40 views
Skip to first unread message

Andre Przywara

unread,
Jan 27, 2020, 7:47:12 PM1/27/20
to Maxime Ripard, Jagan Teki, u-b...@lists.denx.de, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux...@googlegroups.com
This series enables the SPI booting feature for Allwinner R40 and H6
SoCs. To achieve this, we enable our spl_spi_sunxi.c driver to deal
with those two SoCs. The R40 is pretty straightforward, as it just needs
its base address adjusted. This is prepared in patch 1/5 and finalised
in patch 3/5.
For the H6, on top of yet another different base address, the new clocks
and slightly different pinmux setup need to be cared for.
Patch 2/5 and 4/5 take care of that.
Patch 5/5 enables this feature for the Pine H64 board, which comes with
soldered SPI flash.

This has been tested on the Pine H64 board and a Bananapi M2 Berry
(with SPI flash connected to the SPI0-PortC header pins).
For the existing SPI boot platforms this does not change the code size,
as the toolchain is clever enough to optimise this properly.

There is a similar series to enable SPI support for the sunxi-fel tool,
which was used to test this:
https://github.com/linux-sunxi/sunxi-tools/pull/129

Cheers,
Andre.

Changelog v1 .. v2:
- Drop already merged patch 1/6
- rename is_new_gen_spi() to is_sun6i_gen_spi()

Andre Przywara (5):
sunxi: SPL SPI: Split off SPI0 base address
sunxi: SPL SPI: Introduce is_sun6i_gen_spi()
sunxi: SPL SPI: Add SPI boot support for the Allwinner R40 SoC
sunxi: SPL SPI: Add SPI boot support for the Allwinner H6 SoC
sunxi: Pine H64: Enable SPI booting in defconfig

arch/arm/mach-sunxi/Kconfig | 2 +-
arch/arm/mach-sunxi/spl_spi_sunxi.c | 153 +++++++++++++++++++++++-------------
configs/pine_h64_defconfig | 1 +
3 files changed, 101 insertions(+), 55 deletions(-)

--
2.14.5

Andre Przywara

unread,
Jan 27, 2020, 7:47:16 PM1/27/20
to Maxime Ripard, Jagan Teki, u-b...@lists.denx.de, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux...@googlegroups.com
So far on all supported Allwinner SoCs we find the old generation SPI
controller always at address 0x1c05000, and the new generation one at
0x1c68000. However the Allwinner R40 SoC has a new generation SPI at
the old address, and the H6 uses a completely different address.

So split off the base address from the respective SPI registers, by
changing the #defines to just contain offsets.
The base address is provided by a function, so it can easily be extended
later when support for those SoCs materialises.

This does not change the code size (since the toolchain is clever enough
to optimise this properly), also does not bring any functional change at
this point.

Signed-off-by: Andre Przywara <andre.p...@arm.com>
---
arch/arm/mach-sunxi/spl_spi_sunxi.c | 94 +++++++++++++++++++++----------------
1 file changed, 53 insertions(+), 41 deletions(-)

diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
index 043d9f6ead..5b4598a25b 100644
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
@@ -36,13 +36,13 @@
/* SUN4I variant of the SPI controller */
/*****************************************************************************/

-#define SUN4I_SPI0_CCTL (0x01C05000 + 0x1C)
-#define SUN4I_SPI0_CTL (0x01C05000 + 0x08)
-#define SUN4I_SPI0_RX (0x01C05000 + 0x00)
-#define SUN4I_SPI0_TX (0x01C05000 + 0x04)
-#define SUN4I_SPI0_FIFO_STA (0x01C05000 + 0x28)
-#define SUN4I_SPI0_BC (0x01C05000 + 0x20)
-#define SUN4I_SPI0_TC (0x01C05000 + 0x24)
+#define SUN4I_SPI0_CCTL 0x1C
+#define SUN4I_SPI0_CTL 0x08
+#define SUN4I_SPI0_RX 0x00
+#define SUN4I_SPI0_TX 0x04
+#define SUN4I_SPI0_FIFO_STA 0x28
+#define SUN4I_SPI0_BC 0x20
+#define SUN4I_SPI0_TC 0x24

#define SUN4I_CTL_ENABLE BIT(0)
#define SUN4I_CTL_MASTER BIT(1)
@@ -54,15 +54,15 @@
/* SUN6I variant of the SPI controller */
/*****************************************************************************/

-#define SUN6I_SPI0_CCTL (0x01C68000 + 0x24)
-#define SUN6I_SPI0_GCR (0x01C68000 + 0x04)
-#define SUN6I_SPI0_TCR (0x01C68000 + 0x08)
-#define SUN6I_SPI0_FIFO_STA (0x01C68000 + 0x1C)
-#define SUN6I_SPI0_MBC (0x01C68000 + 0x30)
-#define SUN6I_SPI0_MTC (0x01C68000 + 0x34)
-#define SUN6I_SPI0_BCC (0x01C68000 + 0x38)
-#define SUN6I_SPI0_TXD (0x01C68000 + 0x200)
-#define SUN6I_SPI0_RXD (0x01C68000 + 0x300)
+#define SUN6I_SPI0_CCTL 0x24
+#define SUN6I_SPI0_GCR 0x04
+#define SUN6I_SPI0_TCR 0x08
+#define SUN6I_SPI0_FIFO_STA 0x1C
+#define SUN6I_SPI0_MBC 0x30
+#define SUN6I_SPI0_MTC 0x34
+#define SUN6I_SPI0_BCC 0x38
+#define SUN6I_SPI0_TXD 0x200
+#define SUN6I_SPI0_RXD 0x300

#define SUN6I_CTL_ENABLE BIT(0)
#define SUN6I_CTL_MASTER BIT(1)
@@ -100,11 +100,21 @@ static void spi0_pinmux_setup(unsigned int pin_function)
sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function);
}

+static uintptr_t spi0_base_address(void)
+{
+ if (!IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ return 0x01C05000;
+
+ return 0x01C68000;
+}
+
/*
* Setup 6 MHz from OSC24M (because the BROM is doing the same).
*/
static void spi0_enable_clock(void)
{
+ uintptr_t base = spi0_base_address();
+
/* Deassert SPI0 reset on SUN6I */
if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
setbits_le32(SUN6I_BUS_SOFT_RST_REG0,
@@ -114,36 +124,37 @@ static void spi0_enable_clock(void)
setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));

/* Divide by 4 */
- writel(SPI0_CLK_DIV_BY_4, IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ?
- SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL);
+ writel(SPI0_CLK_DIV_BY_4, base + (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ?
+ SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL));
/* 24MHz from OSC24M */
writel((1 << 31), CCM_SPI0_CLK);

if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
/* Enable SPI in the master mode and do a soft reset */
- setbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
- SUN6I_CTL_ENABLE |
- SUN6I_CTL_SRST);
+ setbits_le32(base + SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
+ SUN6I_CTL_ENABLE | SUN6I_CTL_SRST);
/* Wait for completion */
- while (readl(SUN6I_SPI0_GCR) & SUN6I_CTL_SRST)
+ while (readl(base + SUN6I_SPI0_GCR) & SUN6I_CTL_SRST)
;
} else {
/* Enable SPI in the master mode and reset FIFO */
- setbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
- SUN4I_CTL_ENABLE |
- SUN4I_CTL_TF_RST |
- SUN4I_CTL_RF_RST);
+ setbits_le32(base + SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
+ SUN4I_CTL_ENABLE |
+ SUN4I_CTL_TF_RST |
+ SUN4I_CTL_RF_RST);
}
}

static void spi0_disable_clock(void)
{
+ uintptr_t base = spi0_base_address();
+
/* Disable the SPI0 controller */
if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
- clrbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
+ clrbits_le32(base + SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
SUN6I_CTL_ENABLE);
else
- clrbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
+ clrbits_le32(base + SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
SUN4I_CTL_ENABLE);

/* Disable the SPI0 clock */
@@ -227,6 +238,7 @@ static void spi0_read_data(void *buf, u32 addr, u32 len)
{
u8 *buf8 = buf;
u32 chunk_len;
+ uintptr_t base = spi0_base_address();

while (len > 0) {
chunk_len = len;
@@ -235,23 +247,23 @@ static void spi0_read_data(void *buf, u32 addr, u32 len)

if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
sunxi_spi0_read_data(buf8, addr, chunk_len,
- SUN6I_SPI0_TCR,
+ base + SUN6I_SPI0_TCR,
SUN6I_TCR_XCH,
- SUN6I_SPI0_FIFO_STA,
- SUN6I_SPI0_TXD,
- SUN6I_SPI0_RXD,
- SUN6I_SPI0_MBC,
- SUN6I_SPI0_MTC,
- SUN6I_SPI0_BCC);
+ base + SUN6I_SPI0_FIFO_STA,
+ base + SUN6I_SPI0_TXD,
+ base + SUN6I_SPI0_RXD,
+ base + SUN6I_SPI0_MBC,
+ base + SUN6I_SPI0_MTC,
+ base + SUN6I_SPI0_BCC);
} else {
sunxi_spi0_read_data(buf8, addr, chunk_len,
- SUN4I_SPI0_CTL,
+ base + SUN4I_SPI0_CTL,
SUN4I_CTL_XCH,
- SUN4I_SPI0_FIFO_STA,
- SUN4I_SPI0_TX,
- SUN4I_SPI0_RX,
- SUN4I_SPI0_BC,
- SUN4I_SPI0_TC,
+ base + SUN4I_SPI0_FIFO_STA,
+ base + SUN4I_SPI0_TX,
+ base + SUN4I_SPI0_RX,
+ base + SUN4I_SPI0_BC,
+ base + SUN4I_SPI0_TC,
0);
}

--
2.14.5

Andre Przywara

unread,
Jan 27, 2020, 7:47:17 PM1/27/20
to Maxime Ripard, Jagan Teki, u-b...@lists.denx.de, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux...@googlegroups.com
So far we were using the CONFIG_SUNXI_GEN_SUN6I symbol to select between
the two SPI controller generations used on Allwinner SoCs. This is a
convenience symbol to roughly differentiate between "older" and "newer"
generation of SoCs.

The H6 SoCs is the newest SoC so far, but is sufficiently different to
not define this symbol. However it is using a SPI controller compatible
to the "new gen" SoCs.

To prepare for H6 support, we replace the check for this single symbol
with an explicit function, which can later be extended.
For now we just return CONFIG_SUNXI_GEN_SUN6I in there, so this does not
create a functional change.

Signed-off-by: Andre Przywara <andre.p...@arm.com>
---
arch/arm/mach-sunxi/spl_spi_sunxi.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
index 5b4598a25b..cab6affe8d 100644
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
@@ -100,9 +100,14 @@ static void spi0_pinmux_setup(unsigned int pin_function)
sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function);
}

+static bool is_sun6i_gen_spi(void)
+{
+ return IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I);
+}
+
static uintptr_t spi0_base_address(void)
{
- if (!IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ if (!is_sun6i_gen_spi())
return 0x01C05000;

return 0x01C68000;
@@ -116,7 +121,7 @@ static void spi0_enable_clock(void)
uintptr_t base = spi0_base_address();

/* Deassert SPI0 reset on SUN6I */
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ if (is_sun6i_gen_spi())
setbits_le32(SUN6I_BUS_SOFT_RST_REG0,
(1 << AHB_RESET_SPI0_SHIFT));

@@ -124,12 +129,12 @@ static void spi0_enable_clock(void)
setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));

/* Divide by 4 */
- writel(SPI0_CLK_DIV_BY_4, base + (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ?
+ writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ?
SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL));
/* 24MHz from OSC24M */
writel((1 << 31), CCM_SPI0_CLK);

- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
+ if (is_sun6i_gen_spi()) {
/* Enable SPI in the master mode and do a soft reset */
setbits_le32(base + SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
SUN6I_CTL_ENABLE | SUN6I_CTL_SRST);
@@ -150,7 +155,7 @@ static void spi0_disable_clock(void)
uintptr_t base = spi0_base_address();

/* Disable the SPI0 controller */
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ if (is_sun6i_gen_spi())
clrbits_le32(base + SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
SUN6I_CTL_ENABLE);
else
@@ -164,7 +169,7 @@ static void spi0_disable_clock(void)
clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));

/* Assert SPI0 reset on SUN6I */
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ if (is_sun6i_gen_spi())
clrbits_le32(SUN6I_BUS_SOFT_RST_REG0,
(1 << AHB_RESET_SPI0_SHIFT));
}
@@ -184,7 +189,8 @@ static void spi0_deinit(void)
{
/* New SoCs can disable pins, older could only set them as input */
unsigned int pin_function = SUNXI_GPIO_INPUT;
- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+
+ if (is_sun6i_gen_spi())
pin_function = SUNXI_GPIO_DISABLE;

spi0_disable_clock();
@@ -245,7 +251,7 @@ static void spi0_read_data(void *buf, u32 addr, u32 len)
if (chunk_len > SPI_READ_MAX_SIZE)
chunk_len = SPI_READ_MAX_SIZE;

- if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
+ if (is_sun6i_gen_spi()) {
sunxi_spi0_read_data(buf8, addr, chunk_len,
base + SUN6I_SPI0_TCR,
SUN6I_TCR_XCH,
--
2.14.5

Andre Przywara

unread,
Jan 27, 2020, 7:47:18 PM1/27/20
to Maxime Ripard, Jagan Teki, u-b...@lists.denx.de, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux...@googlegroups.com
Now that we can easily select an SoC specific SPI0 base address, adding
support for the Allwinner R40 is fairly trivial:
We set the base address, add this SoC to the ones that use PC23 and
enable it in Kconfig.

This allows booting from SPI flash on R40 boards.

Tested on a Bananapi M2 Berry with SPI flash connected to the header pins.

Signed-off-by: Andre Przywara <andre.p...@arm.com>
---
arch/arm/mach-sunxi/Kconfig | 2 +-
arch/arm/mach-sunxi/spl_spi_sunxi.c | 6 +++++-
2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 3a3b673430..eb046160e6 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -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
+ depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40
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
diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
index cab6affe8d..357953cfce 100644
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
@@ -94,7 +94,8 @@ static void spi0_pinmux_setup(unsigned int pin_function)
for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(2); pin++)
sunxi_gpio_set_cfgpin(pin, pin_function);

- if (IS_ENABLED(CONFIG_MACH_SUN4I) || IS_ENABLED(CONFIG_MACH_SUN7I))
+ 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);
else
sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function);
@@ -107,6 +108,9 @@ static bool is_sun6i_gen_spi(void)

static uintptr_t spi0_base_address(void)
{
+ if (IS_ENABLED(CONFIG_MACH_SUN8I_R40))
+ return 0x01C05000;
+
if (!is_sun6i_gen_spi())
return 0x01C05000;

--
2.14.5

Andre Przywara

unread,
Jan 27, 2020, 7:47:22 PM1/27/20
to Maxime Ripard, Jagan Teki, u-b...@lists.denx.de, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux...@googlegroups.com
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.p...@arm.com>
---
arch/arm/mach-sunxi/Kconfig | 2 +-
arch/arm/mach-sunxi/spl_spi_sunxi.c | 41 +++++++++++++++++++++++++++++--------
2 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index eb046160e6..be0822bfb7 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -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
diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
index 357953cfce..a3997b2590 100644
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
@@ -72,7 +72,12 @@
/*****************************************************************************/

#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
@@ -86,14 +91,21 @@
/*
* 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);
--
2.14.5

Andre Przywara

unread,
Jan 27, 2020, 7:47:23 PM1/27/20
to Maxime Ripard, Jagan Teki, u-b...@lists.denx.de, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux...@googlegroups.com
The Pine H64 board comes with some onboard SPI flash chip, which is
perfect for loading SPL, ATF and U-Boot proper from there.

Enable the functionality in the defconfig, so that we use sunxi-fel to
transfer a bootable image to the NOR flash.

Signed-off-by: Andre Przywara <andre.p...@arm.com>
---
configs/pine_h64_defconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/configs/pine_h64_defconfig b/configs/pine_h64_defconfig
index b49dbea4d4..c0adbf3dd0 100644
--- a/configs/pine_h64_defconfig
+++ b/configs/pine_h64_defconfig
@@ -16,3 +16,4 @@ CONFIG_DEFAULT_DEVICE_TREE="sun50i-h6-pine-h64"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
+CONFIG_SPL_SPI_SUNXI=y
--
2.14.5

Jagan Teki

unread,
Mar 18, 2020, 8:43:32 AM3/18/20
to Andre Przywara, Maxime Ripard, U-Boot-Denx, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux-sunxi
On Tue, Jan 28, 2020 at 6:17 AM Andre Przywara <andre.p...@arm.com> wrote:
>
> This series enables the SPI booting feature for Allwinner R40 and H6
> SoCs. To achieve this, we enable our spl_spi_sunxi.c driver to deal
> with those two SoCs. The R40 is pretty straightforward, as it just needs
> its base address adjusted. This is prepared in patch 1/5 and finalised
> in patch 3/5.
> For the H6, on top of yet another different base address, the new clocks
> and slightly different pinmux setup need to be cared for.
> Patch 2/5 and 4/5 take care of that.
> Patch 5/5 enables this feature for the Pine H64 board, which comes with
> soldered SPI flash.
>
> This has been tested on the Pine H64 board and a Bananapi M2 Berry
> (with SPI flash connected to the SPI0-PortC header pins).
> For the existing SPI boot platforms this does not change the code size,
> as the toolchain is clever enough to optimise this properly.
>
> There is a similar series to enable SPI support for the sunxi-fel tool,
> which was used to test this:
> https://github.com/linux-sunxi/sunxi-tools/pull/129
>
> Cheers,
> Andre.
>
> Changelog v1 .. v2:
> - Drop already merged patch 1/6
> - rename is_new_gen_spi() to is_sun6i_gen_spi()

Applied to u-boot-sunxi/master
Reply all
Reply to author
Forward
0 new messages