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

49 views
Skip to first unread message

Andre Przywara

unread,
Jan 5, 2020, 8:29:34 PM1/5/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 2/6 and finalised
in patch 4/6.
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 3/6 and 5/6 take care of that.
Patch 6/6 enables this feature for the Pine H64 board, which comes with
soldered SPI flash.
Patch 1/6 deals with some annoyance in enabling SPI boot on new boards.

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. I will post this ASAP.

Cheers,
Andre.

Andre Przywara (6):
sunxi: move CONFIG_SYS_SPI_U_BOOT_OFFS out of defconfig
sunxi: SPL SPI: Split off SPI0 base address
sunxi: SPL SPI: Introduce is_new_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 +++++++++++++++++++----------
common/spl/Kconfig | 1 +
configs/A20-OLinuXino-Lime2-eMMC_defconfig | 1 -
configs/oceanic_5205_5inmfd_defconfig | 1 -
configs/orangepi_pc2_defconfig | 1 -
configs/orangepi_r1_defconfig | 1 -
configs/orangepi_win_defconfig | 1 -
configs/orangepi_zero_defconfig | 1 -
configs/pine64-lts_defconfig | 1 -
configs/pine_h64_defconfig | 1 +
configs/sopine_baseboard_defconfig | 1 -
12 files changed, 102 insertions(+), 63 deletions(-)

--
2.14.5

Andre Przywara

unread,
Jan 5, 2020, 8:29:36 PM1/5/20
to Maxime Ripard, Jagan Teki, u-b...@lists.denx.de, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux...@googlegroups.com
For Allwinner SoCs the CONFIG_SYS_SPI_U_BOOT_OFFS value is not really a
board choice: The boot ROM only loads the SPL from offset 0 of the SPI
NOR flash, and loads at most 32KB. This is a similar situation as on MMC,
so consequently we create our "joint" image (SPL + U-Boot proper) with
that 32KB offset during the build.

So define the value of this symbol to be 32KB by default for every
Allwinner SoC. This removes the definition of this symbol from the
_defconfig files, and avoids every board to define this over and over
again.

Signed-off-by: Andre Przywara <andre.p...@arm.com>
---
common/spl/Kconfig | 1 +
configs/A20-OLinuXino-Lime2-eMMC_defconfig | 1 -
configs/oceanic_5205_5inmfd_defconfig | 1 -
configs/orangepi_pc2_defconfig | 1 -
configs/orangepi_r1_defconfig | 1 -
configs/orangepi_win_defconfig | 1 -
configs/orangepi_zero_defconfig | 1 -
configs/pine64-lts_defconfig | 1 -
configs/sopine_baseboard_defconfig | 1 -
9 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index a72412718b..d85a5a6e2e 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -1078,6 +1078,7 @@ endif # SPL_SPI_FLASH_SUPPORT

config SYS_SPI_U_BOOT_OFFS
hex "address of u-boot payload in SPI flash"
+ default 0x8000 if ARCH_SUNXI
default 0x0
depends on SPL_SPI_LOAD || SPL_SPI_SUNXI
help
diff --git a/configs/A20-OLinuXino-Lime2-eMMC_defconfig b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
index 588758a8ca..7dc736e9e1 100644
--- a/configs/A20-OLinuXino-Lime2-eMMC_defconfig
+++ b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
@@ -15,7 +15,6 @@ CONFIG_AHCI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_USE_PREBOOT=y
CONFIG_SPL_I2C_SUPPORT=y
-CONFIG_SYS_SPI_U_BOOT_OFFS=0x8000
CONFIG_CMD_DFU=y
CONFIG_CMD_USB_MASS_STORAGE=y
# CONFIG_SPL_DOS_PARTITION is not set
diff --git a/configs/oceanic_5205_5inmfd_defconfig b/configs/oceanic_5205_5inmfd_defconfig
index caab5fdb19..f71be7f127 100644
--- a/configs/oceanic_5205_5inmfd_defconfig
+++ b/configs/oceanic_5205_5inmfd_defconfig
@@ -11,7 +11,6 @@ CONFIG_MMC0_CD_PIN=""
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_USE_PREBOOT=y
-CONFIG_SYS_SPI_U_BOOT_OFFS=0x8000
# CONFIG_SPL_DOS_PARTITION is not set
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-oceanic-5205-5inmfd"
diff --git a/configs/orangepi_pc2_defconfig b/configs/orangepi_pc2_defconfig
index 3d65b87d33..20209ec41b 100644
--- a/configs/orangepi_pc2_defconfig
+++ b/configs/orangepi_pc2_defconfig
@@ -10,7 +10,6 @@ CONFIG_MACPWR="PD6"
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_USE_PREBOOT=y
-CONFIG_SYS_SPI_U_BOOT_OFFS=0x8000
# CONFIG_SPL_DOS_PARTITION is not set
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_DEFAULT_DEVICE_TREE="sun50i-h5-orangepi-pc2"
diff --git a/configs/orangepi_r1_defconfig b/configs/orangepi_r1_defconfig
index b253d7f87b..0431fecb52 100644
--- a/configs/orangepi_r1_defconfig
+++ b/configs/orangepi_r1_defconfig
@@ -9,7 +9,6 @@ CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_USE_PREBOOT=y
CONFIG_CONSOLE_MUX=y
-CONFIG_SYS_SPI_U_BOOT_OFFS=0x8000
CONFIG_DEFAULT_DEVICE_TREE="sun8i-h2-plus-orangepi-r1"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_SUN8I_EMAC=y
diff --git a/configs/orangepi_win_defconfig b/configs/orangepi_win_defconfig
index ad74febe10..13bf266260 100644
--- a/configs/orangepi_win_defconfig
+++ b/configs/orangepi_win_defconfig
@@ -7,7 +7,6 @@ CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_USE_PREBOOT=y
-CONFIG_SYS_SPI_U_BOOT_OFFS=0x8000
# CONFIG_SPL_DOS_PARTITION is not set
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-orangepi-win"
diff --git a/configs/orangepi_zero_defconfig b/configs/orangepi_zero_defconfig
index 6fb2fbbda2..51d8ec001e 100644
--- a/configs/orangepi_zero_defconfig
+++ b/configs/orangepi_zero_defconfig
@@ -9,7 +9,6 @@ CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_USE_PREBOOT=y
CONFIG_CONSOLE_MUX=y
-CONFIG_SYS_SPI_U_BOOT_OFFS=0x8000
CONFIG_DEFAULT_DEVICE_TREE="sun8i-h2-plus-orangepi-zero"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_SUN8I_EMAC=y
diff --git a/configs/pine64-lts_defconfig b/configs/pine64-lts_defconfig
index a1c2d4245d..6e2c247c1a 100644
--- a/configs/pine64-lts_defconfig
+++ b/configs/pine64-lts_defconfig
@@ -11,7 +11,6 @@ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_USE_PREBOOT=y
-CONFIG_SYS_SPI_U_BOOT_OFFS=0x8000
# CONFIG_SPL_DOS_PARTITION is not set
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-pine64-lts"
diff --git a/configs/sopine_baseboard_defconfig b/configs/sopine_baseboard_defconfig
index f4ab9ba9ab..87ed55264d 100644
--- a/configs/sopine_baseboard_defconfig
+++ b/configs/sopine_baseboard_defconfig
@@ -12,7 +12,6 @@ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_USE_PREBOOT=y
-CONFIG_SYS_SPI_U_BOOT_OFFS=0x8000
# CONFIG_SPL_DOS_PARTITION is not set
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_DEFAULT_DEVICE_TREE="sun50i-a64-sopine-baseboard"
--
2.14.5

Andre Przywara

unread,
Jan 5, 2020, 8:29:38 PM1/5/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..b19f1bf4af 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_new_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_new_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_new_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_new_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_new_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_new_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_new_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_new_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_new_gen_spi()) {
sunxi_spi0_read_data(buf8, addr, chunk_len,
base + SUN6I_SPI0_TCR,
SUN6I_TCR_XCH,
--
2.14.5

Andre Przywara

unread,
Jan 5, 2020, 8:29:38 PM1/5/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 5, 2020, 8:29:41 PM1/5/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 16d41b83af..0e07be802f 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -993,7 +993,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 b19f1bf4af..c0b5a204fd 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_new_gen_spi(void)

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

--
2.14.5

Andre Przywara

unread,
Jan 5, 2020, 8:29:42 PM1/5/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 0e07be802f..364b81b24c 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -993,7 +993,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 c0b5a204fd..edfc46f275 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_new_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_new_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_new_gen_spi())
+ if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+ setbits_le32(CCM_H6_SPI_BGR_REG, (1U << 16) | 0x1);
+ else if (is_new_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_new_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_new_gen_spi())
+ if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+ clrbits_le32(CCM_H6_SPI_BGR_REG, (1U << 16) | 0x1);
+ else if (is_new_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 5, 2020, 8:29:43 PM1/5/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,
Jan 21, 2020, 3:20:26 AM1/21/20
to Andre Przywara, Maxime Ripard, U-Boot-Denx, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux-sunxi
Doesn't it confusing? new gen is H6, but it returns 6I?

Jagan Teki

unread,
Jan 24, 2020, 12:38:18 PM1/24/20
to Andre Przywara, Maxime Ripard, U-Boot-Denx, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux-sunxi
On Mon, Jan 6, 2020 at 6:59 AM Andre Przywara <andre.p...@arm.com> wrote:
>
> For Allwinner SoCs the CONFIG_SYS_SPI_U_BOOT_OFFS value is not really a
> board choice: The boot ROM only loads the SPL from offset 0 of the SPI
> NOR flash, and loads at most 32KB. This is a similar situation as on MMC,
> so consequently we create our "joint" image (SPL + U-Boot proper) with
> that 32KB offset during the build.
>
> So define the value of this symbol to be 32KB by default for every
> Allwinner SoC. This removes the definition of this symbol from the
> _defconfig files, and avoids every board to define this over and over
> again.
>
> Signed-off-by: Andre Przywara <andre.p...@arm.com>
> ---

Applied to u-boot-sunxi/master

André Przywara

unread,
Jan 26, 2020, 8:29:45 PM1/26/20
to Jagan Teki, Maxime Ripard, U-Boot-Denx, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux-sunxi
On 21/01/2020 08:20, Jagan Teki wrote:

Hi Jagan,

first: many thanks for merging those other patches of mine, much
appreciated!
Well, naming ...
For the purpose of U-Boot there are two generations of SPI controller
*register interfaces*, the "old" one used in the older SoCs like the
A20, and the "newer" one used in everything halfway recent. The H6 uses
the same "new" generation, just at a different address. Yes, it adds
quad-SPI, but this is not relevant for this driver.
I have seen this old/new terminology at different places, so just went
with it.
I could rename it to is_spi_sun6i_gen() or something if that makes you
happy...

Cheers,
Andre

Jagan Teki

unread,
Jan 27, 2020, 8:16:29 AM1/27/20
to André Przywara, Maxime Ripard, U-Boot-Denx, Siarhei Siamashka, Icenowy Zheng, Olliver Schinagl, Hauke Mehrtens, linux-sunxi
Please do, would be great if you can send the new changes as soon as
possible so-that I can send PR for the rc1.

Jagan.
Reply all
Reply to author
Forward
0 new messages