237 lines
7.8 KiB
Diff
237 lines
7.8 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Marvin Wewer <mwewer37@proton.me>
|
|
Date: Mon, 10 Nov 2025 22:10:36 +0000
|
|
Subject: Add Allwinner A523 support for SPL SPI controllers
|
|
|
|
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
|
|
---
|
|
arch/arm/mach-sunxi/spl_spi_sunxi.c | 107 ++++++----
|
|
1 file changed, 68 insertions(+), 39 deletions(-)
|
|
|
|
diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
|
|
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
|
|
@@ -99,35 +99,44 @@
|
|
|
|
#define SPI0_CLK_DIV_BY_2 0x1000
|
|
#define SPI0_CLK_DIV_BY_4 0x1001
|
|
#define SPI0_CLK_DIV_BY_32 0x100f
|
|
|
|
+#define SUN55I_BUF_STA_REG 0x400
|
|
+
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* 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, the H616 PC0, PC2, PC3, PC4.
|
|
*/
|
|
static void spi0_pinmux_setup(unsigned int pin_function)
|
|
{
|
|
+ if (IS_ENABLED(CONFIG_MACH_SUN55I_A523)) {
|
|
+ sunxi_gpio_set_cfgpin(SUNXI_GPC(12), pin_function);
|
|
+ }
|
|
+
|
|
/* All chips use PC2. And all chips use PC0, except R528/T113 */
|
|
- if (!IS_ENABLED(CONFIG_MACH_SUN8I_R528))
|
|
+ if (!IS_ENABLED(CONFIG_MACH_SUN8I_R528) &&
|
|
+ !IS_ENABLED(CONFIG_MACH_SUN55I_A523))
|
|
sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function);
|
|
|
|
sunxi_gpio_set_cfgpin(SUNXI_GPC(2), pin_function);
|
|
|
|
/* All chips except H6/H616/R528/T113 use PC1. */
|
|
if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6) &&
|
|
- !IS_ENABLED(CONFIG_MACH_SUN8I_R528))
|
|
+ !IS_ENABLED(CONFIG_MACH_SUN8I_R528) &&
|
|
+ !IS_ENABLED(CONFIG_MACH_SUN55I_A523))
|
|
sunxi_gpio_set_cfgpin(SUNXI_GPC(1), pin_function);
|
|
|
|
if (IS_ENABLED(CONFIG_MACH_SUN50I_H6) ||
|
|
IS_ENABLED(CONFIG_MACH_SUN8I_R528))
|
|
sunxi_gpio_set_cfgpin(SUNXI_GPC(5), pin_function);
|
|
if (IS_ENABLED(CONFIG_MACH_SUN50I_H616) ||
|
|
- IS_ENABLED(CONFIG_MACH_SUN8I_R528))
|
|
+ IS_ENABLED(CONFIG_MACH_SUN8I_R528) ||
|
|
+ IS_ENABLED(CONFIG_MACH_SUN55I_A523))
|
|
sunxi_gpio_set_cfgpin(SUNXI_GPC(4), 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))
|
|
@@ -142,10 +151,15 @@ static bool is_sun6i_gen_spi(void)
|
|
IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
|
|
IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2) ||
|
|
IS_ENABLED(CONFIG_MACH_SUN8I_V3S);
|
|
}
|
|
|
|
+static bool is_sun55i_gen_spi(void)
|
|
+{
|
|
+ return IS_ENABLED(CONFIG_MACH_SUN55I_A523);
|
|
+}
|
|
+
|
|
static uintptr_t spi0_base_address(void)
|
|
{
|
|
if (IS_ENABLED(CONFIG_MACH_SUN8I_R40))
|
|
return 0x01C05000;
|
|
|
|
@@ -225,11 +239,11 @@ static void spi0_enable_clock(void)
|
|
static void spi0_disable_clock(void)
|
|
{
|
|
uintptr_t base = spi0_base_address();
|
|
|
|
/* Disable the SPI0 controller */
|
|
- if (is_sun6i_gen_spi())
|
|
+ if (is_sun6i_gen_spi() || is_sun55i_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);
|
|
@@ -255,11 +269,12 @@ static void spi0_disable_clock(void)
|
|
static void spi0_init(void)
|
|
{
|
|
unsigned int pin_function = SUNXI_GPC_SPI0;
|
|
|
|
if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
|
|
- IS_ENABLED(CONFIG_SUN50I_GEN_H6))
|
|
+ IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
|
|
+ IS_ENABLED(CONFIG_MACH_SUN55I_A523))
|
|
pin_function = SUN50I_GPC_SPI0;
|
|
else if (IS_ENABLED(CONFIG_MACH_SUNIV) ||
|
|
IS_ENABLED(CONFIG_MACH_SUN8I_R528))
|
|
pin_function = SUNIV_GPC_SPI0;
|
|
|
|
@@ -270,11 +285,12 @@ static void spi0_init(void)
|
|
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())
|
|
+ if (is_sun6i_gen_spi() ||
|
|
+ is_sun55i_gen_spi())
|
|
pin_function = SUNXI_GPIO_DISABLE;
|
|
|
|
spi0_disable_clock();
|
|
spi0_pinmux_setup(pin_function);
|
|
}
|
|
@@ -282,46 +298,49 @@ static void spi0_deinit(void)
|
|
/*****************************************************************************/
|
|
|
|
#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)
|
|
+ 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)
|
|
- ;
|
|
+ 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 */
|
|
+#if IS_ENABLED(CONFIG_MACH_SUN55I_A523)
|
|
+ while ((readl(spi_fifo_reg) & 0xFF) < 4 + bufsize);
|
|
+#else
|
|
+ while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize);
|
|
+#endif
|
|
|
|
- /* Skip 4 bytes */
|
|
- readl(spi_rx_reg);
|
|
+ /* Skip 4 bytes */
|
|
+ readl(spi_rx_reg);
|
|
|
|
- /* Read the data */
|
|
- while (bufsize-- > 0)
|
|
- *buf++ = readb(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);
|
|
+ /* 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;
|
|
@@ -331,20 +350,30 @@ static void spi0_read_data(void *buf, u32 addr, u32 len)
|
|
while (len > 0) {
|
|
chunk_len = len;
|
|
if (chunk_len > SPI_READ_MAX_SIZE)
|
|
chunk_len = SPI_READ_MAX_SIZE;
|
|
|
|
- if (is_sun6i_gen_spi()) {
|
|
+ if (is_sun6i_gen_spi() && !is_sun55i_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 if (is_sun55i_gen_spi()) {
|
|
+ sunxi_spi0_read_data(buf8, addr, chunk_len,
|
|
+ base + SUN6I_SPI0_TCR,
|
|
+ SUN6I_TCR_XCH,
|
|
+ base + SUN55I_BUF_STA_REG,
|
|
+ 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,
|
|
--
|
|
Armbian
|
|
|