diff mbox series

[1/4] mach-sunxi: Refactor sunxi SPI-SPL

Message ID 2b893c4d-6657-364e-6d17-18903cda6cf0@bamkrs.de
State New
Headers show
Series [1/4] mach-sunxi: Refactor sunxi SPI-SPL | expand

Commit Message

=?UTF-8?Q?Benedikt-Alexander_Mokro=c3=9f?= April 28, 2020, 2:04 p.m. UTC
This patch splits the sunxi SPI-SPL in its two components:
  - SUNXI-SPI-Handling (spl_spi_sunxi.c)
  - SPI-NOR with SPI-NOR-SPL-Logic (spl_spi_sunxi_nor.c)

For this, the spl got moved in its own subdirectory.
This prepares the SPL to support more then just SPI-NOR.

Signed-off-by: Benedikt-Alexander Mokro? <u-boot at bamkrs.de>
---
  arch/arm/mach-sunxi/Kconfig                   |   2 +
  arch/arm/mach-sunxi/Makefile                  |   3 +-
  arch/arm/mach-sunxi/spl/Makefile              |   9 +
  arch/arm/mach-sunxi/spl/spi/Kconfig           |  29 ++
  arch/arm/mach-sunxi/spl/spi/Makefile          |  15 +
  arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.c   | 149 ++++++++
  arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.h   | 112 ++++++
  .../mach-sunxi/spl/spi/spl_spi_sunxi_nor.c    | 138 +++++++
  arch/arm/mach-sunxi/spl_spi_sunxi.c           | 356 ------------------
  9 files changed, 456 insertions(+), 358 deletions(-)
  create mode 100644 arch/arm/mach-sunxi/spl/Makefile
  create mode 100644 arch/arm/mach-sunxi/spl/spi/Kconfig
  create mode 100644 arch/arm/mach-sunxi/spl/spi/Makefile
  create mode 100644 arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.c
  create mode 100644 arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.h
  create mode 100644 arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi_nor.c
  delete mode 100644 arch/arm/mach-sunxi/spl_spi_sunxi.c

Comments

Jagan Teki May 1, 2020, 4:54 p.m. UTC | #1
On Tue, Apr 28, 2020 at 7:53 PM Benedikt-Alexander Mokro?
<u-boot at bamkrs.de> wrote:
>
> This patch splits the sunxi SPI-SPL in its two components:
>   - SUNXI-SPI-Handling (spl_spi_sunxi.c)
>   - SPI-NOR with SPI-NOR-SPL-Logic (spl_spi_sunxi_nor.c)
>
> For this, the spl got moved in its own subdirectory.
> This prepares the SPL to support more then just SPI-NOR.
>
> Signed-off-by: Benedikt-Alexander Mokro? <u-boot at bamkrs.de>
> ---

Please add a cover-letter to explain why these changes require? and
also I'm still thinking it can be possible to support both SPI
NOR/NAND in the same driver. Let me comment on the next version
changes.

Jagan.
=?UTF-8?Q?Benedikt-Alexander_Mokro=c3=9f?= May 2, 2020, 12:37 p.m. UTC | #2
Hello Jagan,

of course its possible to join them to one file, share the main SPL function and co-exist.
However, SPI-NAND boot isn?t that popular (for good reasons) and only very few sunxi 
SoCs are capable of doing so. Most of the time only one is used and the other
would unnecessary bloat the (very limited) SPL.
Thus I thought it would be much more readable and maintainable if those are 
split in multiple files and distinct functions instead of a lot of #ifdef or similar. 

Anyhow, if the maintainers prefer a single file for any reason, its no big deal to 
reimplement the series and keep everything as one file.

Im going to submit a cover-letter asap.

Best Regards
Benedikt

> Am 01.05.2020 um 18:54 schrieb Jagan Teki <jagan at amarulasolutions.com>:
> 
> On Tue, Apr 28, 2020 at 7:53 PM Benedikt-Alexander Mokro?
> <u-boot at bamkrs.de> wrote:
>> 
>> This patch splits the sunxi SPI-SPL in its two components:
>>  - SUNXI-SPI-Handling (spl_spi_sunxi.c)
>>  - SPI-NOR with SPI-NOR-SPL-Logic (spl_spi_sunxi_nor.c)
>> 
>> For this, the spl got moved in its own subdirectory.
>> This prepares the SPL to support more then just SPI-NOR.
>> 
>> Signed-off-by: Benedikt-Alexander Mokro? <u-boot at bamkrs.de>
>> ---
> 
> Please add a cover-letter to explain why these changes require? and
> also I'm still thinking it can be possible to support both SPI
> NOR/NAND in the same driver. Let me comment on the next version
> changes.
> 
> Jagan.
diff mbox series

Patch

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index be0822bfb7..7a0f0956c3 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -1010,4 +1010,6 @@  config PINE64_DT_SELECTION
  	  option, the device tree selection code specific to Pine64 which
  	  utilizes the DRAM size will be enabled.
  
+source "arch/arm/mach-sunxi/spl/spi/Kconfig"
+
  endif
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index d129f33479..077c88b6d4 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -35,7 +35,7 @@  obj-$(CONFIG_DRAM_SUN8I_A23)	+= dram_sun8i_a23.o
  obj-$(CONFIG_DRAM_SUN8I_A33)	+= dram_sun8i_a33.o
  obj-$(CONFIG_DRAM_SUN8I_A83T)	+= dram_sun8i_a83t.o
  obj-$(CONFIG_DRAM_SUN9I)	+= dram_sun9i.o
-obj-$(CONFIG_SPL_SPI_SUNXI)	+= spl_spi_sunxi.o
+obj-$(CONFIG_SPL_SPI_SUNXI)	+= spl/spi/
  obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_sunxi_dw.o
  obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_timings/
  obj-$(CONFIG_DRAM_SUN50I_H6)	+= dram_sun50i_h6.o
diff --git a/arch/arm/mach-sunxi/spl/spi/Kconfig b/arch/arm/mach-sunxi/spl/spi/Kconfig
new file mode 100644
index 0000000000..04e2e506d3
--- /dev/null
+++ b/arch/arm/mach-sunxi/spl/spi/Kconfig
@@ -0,0 +1,12 @@ 
+if SPL_SPI_SUNXI
+
+config SPL_SPI_SUNXI_NOR
+	bool "Support for SPI-NOR Flash on Allwinner SoCs in SPL"
+	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6
+	default y
+	help
+	  Enable support for SPI-NOR Flash. This option allows SPL to read from
+	  sunxi SPI-NOR Flash. It uses the same method as the boot ROM, so does
+	  not need any extra configuration.
+
+endif
diff --git a/arch/arm/mach-sunxi/spl/spi/Makefile b/arch/arm/mach-sunxi/spl/spi/Makefile
new file mode 100644
index 0000000000..52e58a3c65
--- /dev/null
+++ b/arch/arm/mach-sunxi/spl/spi/Makefile
@@ -0,0 +1,15 @@ 
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2020 Benedikt-Alexander Mokro? <u-boot at bamkrs.de>
+#
+# Based on some other Makefile
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+
+
+ifdef CONFIG_SPL_BUILD
+
+obj-$(CONFIG_SPL_SPI_SUNXI)	+= spl_spi_sunxi.o
+obj-$(CONFIG_SPL_SPI_SUNXI_NOR)		+= spl_spi_sunxi_nor.o
+
+endif
diff --git a/arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.c
new file mode 100644
index 0000000000..2b1fa6d336
--- /dev/null
+++ b/arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.c
@@ -0,0 +1,142 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Siarhei Siamashka <siarhei.siamashka at gmail.com>
+ */
+
+#include "spl_spi_sunxi.h"
+
+/*
+ * 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.
+ */
+void sunxi_spi0_pinmux_setup(unsigned int pin_function)
+{
+	/* All chips use PC0 and PC2. */
+	sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function);
+	sunxi_gpio_set_cfgpin(SUNXI_GPC(2), 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);
+	else
+		sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function);
+}
+
+bool is_sun6i_gen_spi(void)
+{
+	return IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ||
+	       IS_ENABLED(CONFIG_MACH_SUN50I_H6);
+}
+
+uintptr_t sunxi_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;
+
+	return 0x01C68000;
+}
+
+/*
+ * Setup 6 MHz from OSC24M (because the BROM is doing the same).
+ */
+void sunxi_spi0_enable_clock(void)
+{
+	uintptr_t base = sunxi_spi0_base_address();
+
+	/* Deassert SPI0 reset on SUN6I */
+	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 */
+	if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+		setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+
+	/* Clock divider */
+	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_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);
+		/* Wait for completion */
+		while (readl(base + SUN6I_SPI0_GCR) & SUN6I_CTL_SRST)
+			;
+	} else {
+		/* Enable SPI in the master mode and reset FIFO */
+		setbits_le32(base + SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
+						    SUN4I_CTL_ENABLE |
+						    SUN4I_CTL_TF_RST |
+						    SUN4I_CTL_RF_RST);
+	}
+}
+
+void sunxi_spi0_disable_clock(void)
+{
+	uintptr_t base = sunxi_spi0_base_address();
+
+	/* Disable the SPI0 controller */
+	if (is_sun6i_gen_spi())
+		clrbits_le32(base + SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
+					     SUN6I_CTL_ENABLE);
+	else
+		clrbits_le32(base + SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
+					     SUN4I_CTL_ENABLE);
+
+	/* Disable the SPI0 clock */
+	writel(0, CCM_SPI0_CLK);
+
+	/* Close the SPI0 gate */
+	if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+		clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+
+	/* Assert SPI0 reset on SUN6I */
+	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));
+}
+
+void sunxi_spi0_init(void)
+{
+	unsigned int pin_function = SUNXI_GPC_SPI0;
+
+	if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
+	    IS_ENABLED(CONFIG_MACH_SUN50I_H6))
+		pin_function = SUN50I_GPC_SPI0;
+
+	sunxi_spi0_pinmux_setup(pin_function);
+	sunxi_spi0_enable_clock();
+}
+
+void sunxi_spi0_deinit(void)
+{
+	/* New SoCs can disable pins, older could only set them as input */
+	unsigned int pin_function = SUNXI_GPIO_INPUT;
+
+	if (is_sun6i_gen_spi())
+		pin_function = SUNXI_GPIO_DISABLE;
+
+	sunxi_spi0_disable_clock();
+	sunxi_spi0_pinmux_setup(pin_function);
+}
diff --git a/arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.h b/arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.h
new file mode 100644
index 0000000000..5c9e1250e5
--- /dev/null
+++ b/arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi.h
@@ -0,0 +1,112 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Siarhei Siamashka <siarhei.siamashka at gmail.com>
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/libfdt.h>
+
+#ifdef CONFIG_SPL_OS_BOOT
+#error CONFIG_SPL_OS_BOOT is not supported yet
+#endif
+
+/*
+ * This is a very simple U-Boot image loading implementation, trying to
+ * replicate what the boot ROM is doing when loading the SPL. Because we
+ * know the exact pins where the SPI Flash is connected and also know
+ * that the Read Data Bytes (03h) command is supported, the hardware
+ * configuration is very simple and we don't need the extra flexibility
+ * of the SPI framework. Moreover, we rely on the default settings of
+ * the SPI controller hardware registers and only adjust what needs to
+ * be changed. This is good for the code size and this implementation
+ * adds less than 400 bytes to the SPL.
+ *
+ * There are two variants of the SPI controller in Allwinner SoCs:
+ * A10/A13/A20 (sun4i variant) and everything else (sun6i variant).
+ * Both of them are supported.
+ *
+ * The pin mixing part is SoC specific and only A10/A13/A20/H3/A64 are
+ * supported at the moment.
+ */
+
+/*****************************************************************************/
+/* SUN4I variant of the SPI controller                                       */
+/*****************************************************************************/
+
+#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)
+#define SUN4I_CTL_TF_RST            BIT(8)
+#define SUN4I_CTL_RF_RST            BIT(9)
+#define SUN4I_CTL_XCH               BIT(10)
+
+/*****************************************************************************/
+/* SUN6I variant of the SPI controller                                       */
+/*****************************************************************************/
+
+#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)
+#define SUN6I_CTL_SRST              BIT(31)
+#define SUN6I_TCR_XCH               BIT(31)
+
+/*****************************************************************************/
+
+#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
+#define AHB_GATE_OFFSET_SPI0        20
+
+#define SPI0_CLK_DIV_NONE			0x0000
+#define SPI0_CLK_DIV_BY_2           0x1000
+#define SPI0_CLK_DIV_BY_4           0x1001
+
+/*****************************************************************************/
+
+/*
+ * 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.
+ */
+void sunxi_spi0_pinmux_setup(unsigned int pin_function);
+
+bool is_sun6i_gen_spi(void);
+
+uintptr_t sunxi_spi0_base_address(void);
+
+/*
+ * Setup 6 MHz from OSC24M (because the BROM is doing the same).
+ */
+void sunxi_spi0_enable_clock(void);
+
+void sunxi_spi0_disable_clock(void);
+
+void sunxi_spi0_init(void);
+
+void sunxi_spi0_deinit(void);
diff --git a/arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi_nor.c b/arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi_nor.c
new file mode 100644
index 0000000000..cc5e142b4b
--- /dev/null
+++ b/arch/arm/mach-sunxi/spl/spi/spl_spi_sunxi_nor.c
@@ -0,0 +1,139 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Siarhei Siamashka <siarhei.siamashka at gmail.com>
+ */
+
+#include "spl_spi_sunxi.h"
+
+/*****************************************************************************/
+
+#define SPI_READ_MAX_SIZE 60 /* FIFO size, minus 4 bytes of the header */
+
+static void sunxi_spi0_read_data(u8 *buf, u32 addr, u32 bufsize,
+				 ulong spi_ctl_reg,
+				 ulong spi_ctl_xch_bitmask,
+				 ulong spi_fifo_reg,
+				 ulong spi_tx_reg,
+				 ulong spi_rx_reg,
+				 ulong spi_bc_reg,
+				 ulong spi_tc_reg,
+				 ulong spi_bcc_reg)
+{
+	writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */
+	writel(4, spi_tc_reg);           /* Transfer counter (bytes to send) */
+	if (spi_bcc_reg)
+		writel(4, spi_bcc_reg);  /* SUN6I also needs this */
+
+	/* Send the Read Data Bytes (03h) command header */
+	writeb(0x03, spi_tx_reg);
+	writeb((u8)(addr >> 16), spi_tx_reg);
+	writeb((u8)(addr >> 8), spi_tx_reg);
+	writeb((u8)(addr), spi_tx_reg);
+
+	/* Start the data transfer */
+	setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask);
+
+	/* Wait until everything is received in the RX FIFO */
+	while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize)
+		;
+
+	/* Skip 4 bytes */
+	readl(spi_rx_reg);
+
+	/* Read the data */
+	while (bufsize-- > 0)
+		*buf++ = readb(spi_rx_reg);
+
+	/* tSHSL time is up to 100 ns in various SPI flash datasheets */
+	udelay(1);
+}
+
+static void spi0_read_data(void *buf, u32 addr, u32 len)
+{
+	u8 *buf8 = buf;
+	u32 chunk_len;
+	uintptr_t base = sunxi_spi0_base_address();
+
+	while (len > 0) {
+		chunk_len = len;
+		if (chunk_len > SPI_READ_MAX_SIZE)
+			chunk_len = SPI_READ_MAX_SIZE;
+
+		if (is_sun6i_gen_spi()) {
+			sunxi_spi0_read_data(buf8, addr, chunk_len,
+					     base + SUN6I_SPI0_TCR,
+					     SUN6I_TCR_XCH,
+					     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,
+					     base + SUN4I_SPI0_CTL,
+					     SUN4I_CTL_XCH,
+					     base + SUN4I_SPI0_FIFO_STA,
+					     base + SUN4I_SPI0_TX,
+					     base + SUN4I_SPI0_RX,
+					     base + SUN4I_SPI0_BC,
+					     base + SUN4I_SPI0_TC,
+					     0);
+		}
+
+		len  -= chunk_len;
+		buf8 += chunk_len;
+		addr += chunk_len;
+	}
+}
+
+static ulong spi_load_read(struct spl_load_info *load, ulong sector,
+			   ulong count, void *buf)
+{
+	spi0_read_data(buf, sector, count);
+
+	return count;
+}
+
+/*****************************************************************************/
+
+static int spl_spi_nor_load_image(struct spl_image_info *spl_image,
+				  struct spl_boot_device *bootdev)
+{
+	int ret = 0;
+	struct image_header *header;
+
+	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+
+	sunxi_spi0_init();
+
+	spi0_read_data((void *)header, CONFIG_SYS_SPI_U_BOOT_OFFS, 0x40);
+
+	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
+	    image_get_magic(header) == FDT_MAGIC) {
+		struct spl_load_info load;
+
+		debug("Found FIT image\n");
+		load.dev = NULL;
+		load.priv = NULL;
+		load.filename = NULL;
+		load.bl_len = 1;
+		load.read = spi_load_read;
+		ret = spl_load_simple_fit(spl_image, &load,
+					  CONFIG_SYS_SPI_U_BOOT_OFFS, header);
+	} else {
+		ret = spl_parse_image_header(spl_image, header);
+		if (ret)
+			return ret;
+
+		spi0_read_data((void *)spl_image->load_addr,
+			       CONFIG_SYS_SPI_U_BOOT_OFFS, spl_image->size);
+	}
+
+	sunxi_spi0_deinit();
+
+	return ret;
+}
+
+/* Use priority 0 to override the default if it happens to be linked in */
+SPL_LOAD_IMAGE_METHOD("sunxi SPI-NOR", 0, BOOT_DEVICE_SPI, spl_spi_nor_load_image);
diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
deleted file mode 100644
index a3997b2590..0000000000
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ /dev/null
@@ -1,356 +0,0 @@ 
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Siarhei Siamashka <siarhei.siamashka at gmail.com>
- */
-
-#include <common.h>
-#include <spl.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
-#include <linux/libfdt.h>
-
-#ifdef CONFIG_SPL_OS_BOOT
-#error CONFIG_SPL_OS_BOOT is not supported yet
-#endif
-
-/*
- * This is a very simple U-Boot image loading implementation, trying to
- * replicate what the boot ROM is doing when loading the SPL. Because we
- * know the exact pins where the SPI Flash is connected and also know
- * that the Read Data Bytes (03h) command is supported, the hardware
- * configuration is very simple and we don't need the extra flexibility
- * of the SPI framework. Moreover, we rely on the default settings of
- * the SPI controler hardware registers and only adjust what needs to
- * be changed. This is good for the code size and this implementation
- * adds less than 400 bytes to the SPL.
- *
- * There are two variants of the SPI controller in Allwinner SoCs:
- * A10/A13/A20 (sun4i variant) and everything else (sun6i variant).
- * Both of them are supported.
- *
- * The pin mixing part is SoC specific and only A10/A13/A20/H3/A64 are
- * supported at the moment.
- */
-
-/*****************************************************************************/
-/* SUN4I variant of the SPI controller                                       */
-/*****************************************************************************/
-
-#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)
-#define SUN4I_CTL_TF_RST            BIT(8)
-#define SUN4I_CTL_RF_RST            BIT(9)
-#define SUN4I_CTL_XCH               BIT(10)
-
-/*****************************************************************************/
-/* SUN6I variant of the SPI controller                                       */
-/*****************************************************************************/
-
-#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)
-#define SUN6I_CTL_SRST              BIT(31)
-#define SUN6I_TCR_XCH               BIT(31)
-
-/*****************************************************************************/
-
-#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
-#define AHB_GATE_OFFSET_SPI0        20
-
-#define SPI0_CLK_DIV_BY_2           0x1000
-#define SPI0_CLK_DIV_BY_4           0x1001
-
-/*****************************************************************************/
-
-/*
- * 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)
-{
-	/* All chips use PC0 and PC2. */
-	sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function);
-	sunxi_gpio_set_cfgpin(SUNXI_GPC(2), 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);
-	else
-		sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function);
-}
-
-static bool is_sun6i_gen_spi(void)
-{
-	return IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ||
-	       IS_ENABLED(CONFIG_MACH_SUN50I_H6);
-}
-
-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;
-
-	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_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 */
-	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() ?
-				  SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL));
-	/* 24MHz from OSC24M */
-	writel((1 << 31), CCM_SPI0_CLK);
-
-	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);
-		/* Wait for completion */
-		while (readl(base + SUN6I_SPI0_GCR) & SUN6I_CTL_SRST)
-			;
-	} else {
-		/* Enable SPI in the master mode and reset FIFO */
-		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_sun6i_gen_spi())
-		clrbits_le32(base + SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
-					     SUN6I_CTL_ENABLE);
-	else
-		clrbits_le32(base + SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
-					     SUN4I_CTL_ENABLE);
-
-	/* Disable the SPI0 clock */
-	writel(0, CCM_SPI0_CLK);
-
-	/* Close the SPI0 gate */
-	if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
-		clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
-
-	/* Assert SPI0 reset on SUN6I */
-	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));
-}
-
-static void spi0_init(void)
-{
-	unsigned int pin_function = SUNXI_GPC_SPI0;
-
-	if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
-	    IS_ENABLED(CONFIG_MACH_SUN50I_H6))
-		pin_function = SUN50I_GPC_SPI0;
-
-	spi0_pinmux_setup(pin_function);
-	spi0_enable_clock();
-}
-
-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_sun6i_gen_spi())
-		pin_function = SUNXI_GPIO_DISABLE;
-
-	spi0_disable_clock();
-	spi0_pinmux_setup(pin_function);
-}
-
-/*****************************************************************************/
-
-#define SPI_READ_MAX_SIZE 60 /* FIFO size, minus 4 bytes of the header */
-
-static void sunxi_spi0_read_data(u8 *buf, u32 addr, u32 bufsize,
-				 ulong spi_ctl_reg,
-				 ulong spi_ctl_xch_bitmask,
-				 ulong spi_fifo_reg,
-				 ulong spi_tx_reg,
-				 ulong spi_rx_reg,
-				 ulong spi_bc_reg,
-				 ulong spi_tc_reg,
-				 ulong spi_bcc_reg)
-{
-	writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */
-	writel(4, spi_tc_reg);           /* Transfer counter (bytes to send) */
-	if (spi_bcc_reg)
-		writel(4, spi_bcc_reg);  /* SUN6I also needs this */
-
-	/* Send the Read Data Bytes (03h) command header */
-	writeb(0x03, spi_tx_reg);
-	writeb((u8)(addr >> 16), spi_tx_reg);
-	writeb((u8)(addr >> 8), spi_tx_reg);
-	writeb((u8)(addr), spi_tx_reg);
-
-	/* Start the data transfer */
-	setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask);
-
-	/* Wait until everything is received in the RX FIFO */
-	while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize)
-		;
-
-	/* Skip 4 bytes */
-	readl(spi_rx_reg);
-
-	/* Read the data */
-	while (bufsize-- > 0)
-		*buf++ = readb(spi_rx_reg);
-
-	/* tSHSL time is up to 100 ns in various SPI flash datasheets */
-	udelay(1);
-}
-
-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;
-		if (chunk_len > SPI_READ_MAX_SIZE)
-			chunk_len = SPI_READ_MAX_SIZE;
-
-		if (is_sun6i_gen_spi()) {
-			sunxi_spi0_read_data(buf8, addr, chunk_len,
-					     base + SUN6I_SPI0_TCR,
-					     SUN6I_TCR_XCH,
-					     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,
-					     base + SUN4I_SPI0_CTL,
-					     SUN4I_CTL_XCH,
-					     base + SUN4I_SPI0_FIFO_STA,
-					     base + SUN4I_SPI0_TX,
-					     base + SUN4I_SPI0_RX,
-					     base + SUN4I_SPI0_BC,
-					     base + SUN4I_SPI0_TC,
-					     0);
-		}
-
-		len  -= chunk_len;
-		buf8 += chunk_len;
-		addr += chunk_len;
-	}
-}
-
-static ulong spi_load_read(struct spl_load_info *load, ulong sector,
-			   ulong count, void *buf)
-{
-	spi0_read_data(buf, sector, count);
-
-	return count;
-}
-
-/*****************************************************************************/
-
-static int spl_spi_load_image(struct spl_image_info *spl_image,
-			      struct spl_boot_device *bootdev)
-{
-	int ret = 0;
-	struct image_header *header;
-	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
-
-	spi0_init();
-
-	spi0_read_data((void *)header, CONFIG_SYS_SPI_U_BOOT_OFFS, 0x40);
-
-        if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
-		image_get_magic(header) == FDT_MAGIC) {
-		struct spl_load_info load;
-
-		debug("Found FIT image\n");
-		load.dev = NULL;
-		load.priv = NULL;
-		load.filename = NULL;
-		load.bl_len = 1;
-		load.read = spi_load_read;
-		ret = spl_load_simple_fit(spl_image, &load,
-					  CONFIG_SYS_SPI_U_BOOT_OFFS, header);
-	} else {
-		ret = spl_parse_image_header(spl_image, header);
-		if (ret)
-			return ret;
-
-		spi0_read_data((void *)spl_image->load_addr,
-			       CONFIG_SYS_SPI_U_BOOT_OFFS, spl_image->size);
-	}
-
-	spi0_deinit();
-
-	return ret;
-}
-/* Use priorty 0 to override the default if it happens to be linked in */
-SPL_LOAD_IMAGE_METHOD("sunxi SPI", 0, BOOT_DEVICE_SPI, spl_spi_load_image);