From 37ef96e20fbdc094ac22994528bbcd0535faba08 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sat, 16 Aug 2025 00:09:43 +0100 Subject: [PATCH 1/5] fel: soc_info: collect flags in one variable Our soc_info struct so far has three boolean flags. Replace those separate boolean members with one combined "flags" bitfield member, to allow adding flags later more easily. Signed-off-by: Andre Przywara --- fel.c | 4 ++-- fel_lib.c | 5 +++-- soc_info.c | 12 ++++++------ soc_info.h | 12 +++++++++--- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/fel.c b/fel.c index 79a7c24d0..b112506a6 100644 --- a/fel.c +++ b/fel.c @@ -426,7 +426,7 @@ void aw_fel_print_sid(feldev_handle *dev, bool force_workaround) return; } - if (soc_info->sid_fix || force_workaround) { + if (soc_info->flags & NEEDS_SID_FIX || force_workaround) { pr_info("Read SID key via registers, base = 0x%08X\n", soc_info->sid_base); } else { @@ -788,7 +788,7 @@ uint32_t aw_fel_write_and_execute_spl(feldev_handle *dev, uint8_t *buf, size_t l if (spl_checksum != 0) pr_fatal("SPL: checksum check failed\n"); - if (soc_info->needs_l2en) { + if (soc_info->flags & NEEDS_L2EN) { pr_info("Enabling the L2 cache\n"); aw_enable_l2_cache(dev, soc_info); } diff --git a/fel_lib.c b/fel_lib.c index b667dd16c..38a07c3f0 100644 --- a/fel_lib.c +++ b/fel_lib.c @@ -252,7 +252,8 @@ static void aw_disable_icache(feldev_handle *dev) void aw_fel_write(feldev_handle *dev, const void *buf, uint32_t offset, size_t len) { - if (dev->soc_info->icache_fix && !dev->usb->icache_hacked) { + if (dev->soc_info->flags & NEEDS_ICACHE_FIX && + !dev->usb->icache_hacked) { aw_disable_icache(dev); dev->usb->icache_hacked = true; } @@ -617,7 +618,7 @@ int fel_read_sid(feldev_handle *dev, uint32_t *result, if ((offset & 3) || (length & 3)) /* needs to be 32-bit aligned */ return -3; - if (soc->sid_fix || force_workaround) + if (soc->flags & NEEDS_SID_FIX || force_workaround) /* Work around SID issues by using ARM thunk code */ fel_get_sid_registers(dev, result, offset, length); else diff --git a/soc_info.c b/soc_info.c index 4cb6bcc44..b7055c43f 100644 --- a/soc_info.c +++ b/soc_info.c @@ -332,9 +332,9 @@ soc_info_t soc_info_table[] = { .thunk_addr = 0xA200, .thunk_size = 0x200, .swap_buffers = a10_a13_a20_sram_swap_buffers, .sram_size = 48 * 1024, - .needs_l2en = true, .sid_base = 0x01C23800, .watchdog = &wd_a10_compat, + .flags = NEEDS_L2EN, },{ .soc_id = 0x1625, /* Allwinner A10s, A13, R8 */ .name = "A13", @@ -342,9 +342,9 @@ soc_info_t soc_info_table[] = { .thunk_addr = 0xA200, .thunk_size = 0x200, .swap_buffers = a10_a13_a20_sram_swap_buffers, .sram_size = 48 * 1024, - .needs_l2en = true, .sid_base = 0x01C23800, .watchdog = &wd_a10_compat, + .flags = NEEDS_L2EN, },{ .soc_id = 0x1651, /* Allwinner A20 */ .name = "A20", @@ -441,11 +441,11 @@ soc_info_t soc_info_table[] = { .sram_size = 108 * 1024, .sid_base = 0x01C14000, .sid_offset = 0x200, - .sid_fix = true, .sid_sections = h3_sid_maps, /* Check L.NOP in the OpenRISC reset vector */ .needs_smc_workaround_if_zero_word_at_addr = 0x40004, .watchdog = &wd_h3_compat, + .flags = NEEDS_SID_FIX, },{ .soc_id = 0x1681, /* Allwinner V3s */ .name = "V3s", @@ -587,8 +587,8 @@ soc_info_t soc_info_table[] = { .sid_base = 0x03006000, .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, - .icache_fix = true, .watchdog = &wd_v853_compat, + .flags = NEEDS_ICACHE_FIX, },{ .soc_id = 0x1859, /* Allwinner D1/D1s/R528/T113-S3 */ .name = "R528", @@ -600,8 +600,8 @@ soc_info_t soc_info_table[] = { .sid_base = 0x03006000, .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, - .icache_fix = true, .watchdog = &wd_v853_compat, + .flags = NEEDS_ICACHE_FIX, },{ .soc_id = 0x1721, /* Allwinner V5 */ .name = "V5", @@ -626,8 +626,8 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, .rvbar_reg = 0x08000040, - .icache_fix = true, .watchdog = &wd_a523_compat, + .flags = NEEDS_ICACHE_FIX, },{ .soc_id = 0x1855, /* Allwinner A133 */ .name = "A133", diff --git a/soc_info.h b/soc_info.h index 508f29dab..93ff5b452 100644 --- a/soc_info.h +++ b/soc_info.h @@ -76,6 +76,14 @@ typedef struct { .size_bits = _size_bits, \ } +#define BIT(x) (1U << (x)) + +enum soc_flags { + NEEDS_L2EN = BIT(0), + NEEDS_SID_FIX = BIT(1), + NEEDS_ICACHE_FIX = BIT(2), +}; + /* * Each SoC variant may have its own list of memory buffers to be exchanged * and the information about the placement of the thunk code, which handles @@ -121,7 +129,6 @@ typedef struct { uint32_t scratch_addr; /* A safe place to upload & run code */ uint32_t thunk_addr; /* Address of the thunk code */ uint32_t thunk_size; /* Maximal size of the thunk code */ - bool needs_l2en; /* Set the L2EN bit */ uint32_t mmu_tt_addr; /* MMU translation table address */ uint32_t sid_base; /* base address for SID registers */ uint32_t sid_offset; /* offset for SID_KEY[0-3], "root key" */ @@ -130,13 +137,12 @@ typedef struct { uint32_t rvbar_reg_alt;/* alternative MMIO address of RVBARADDR0_L register */ uint32_t ver_reg; /* MMIO address of "Version Register" */ const watchdog_info *watchdog; /* Used for reset */ - bool sid_fix; /* Use SID workaround (read via register) */ /* Use I$ workaround (disable I$ before first write to prevent stale thunk */ - bool icache_fix; /* Use SMC workaround (enter secure mode) if can't read from this address */ uint32_t needs_smc_workaround_if_zero_word_at_addr; uint32_t sram_size; /* Usable contiguous SRAM at spl_addr */ sram_swap_buffers *swap_buffers; + uint32_t flags; } soc_info_t; From 7f501f37c8cf165d437426419a513879313e1261 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sat, 16 Aug 2025 00:52:30 +0100 Subject: [PATCH 2/5] fel: soc_info: add GPIO and CCU base address Some sunxi-fel features like the SPI flash access need to program the GPIO/pinctrl and clock controllers, located at different MMIO base addresses across all the various SoC generations. Add a GPIO and clock controller base address to our soc_info struct, and add the respective base addresses for each supported SoC to the SoC table. Also add flags to mark the generation of each IP: the D1 pinctrl change (each GPIO port uses 48 bytes instead of 36), and the H6 clock change (moving clock gates and resets into per-peripheral registers). This is not used at the moment, but will be soon. Signed-off-by: Andre Przywara --- soc_info.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++--- soc_info.h | 16 +++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/soc_info.c b/soc_info.c index b7055c43f..55ccf62a0 100644 --- a/soc_info.c +++ b/soc_info.c @@ -334,6 +334,8 @@ soc_info_t soc_info_table[] = { .sram_size = 48 * 1024, .sid_base = 0x01C23800, .watchdog = &wd_a10_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, .flags = NEEDS_L2EN, },{ .soc_id = 0x1625, /* Allwinner A10s, A13, R8 */ @@ -344,6 +346,8 @@ soc_info_t soc_info_table[] = { .sram_size = 48 * 1024, .sid_base = 0x01C23800, .watchdog = &wd_a10_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, .flags = NEEDS_L2EN, },{ .soc_id = 0x1651, /* Allwinner A20 */ @@ -355,6 +359,8 @@ soc_info_t soc_info_table[] = { .sid_base = 0x01C23800, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_a10_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1650, /* Allwinner A23 */ .name = "A23", @@ -365,6 +371,8 @@ soc_info_t soc_info_table[] = { .sid_base = 0x01C23800, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_h3_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1633, /* Allwinner A31 */ .name = "A31", @@ -373,6 +381,8 @@ soc_info_t soc_info_table[] = { .swap_buffers = a31_sram_swap_buffers, .sram_size = 32 * 1024, .watchdog = &wd_h3_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1667, /* Allwinner A33, R16 */ .name = "A33", @@ -383,6 +393,8 @@ soc_info_t soc_info_table[] = { .sid_base = 0x01C23800, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_h3_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1689, /* Allwinner A64 */ .name = "A64", @@ -398,6 +410,8 @@ soc_info_t soc_info_table[] = { /* Check L.NOP in the OpenRISC reset vector */ .needs_smc_workaround_if_zero_word_at_addr = 0x40004, .watchdog = &wd_h3_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1639, /* Allwinner A80 */ .name = "A80", @@ -410,6 +424,8 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_a80, + .gpio_base = A80_PIO_BASE, + .ccu_base = A80_CCM_BASE, },{ .soc_id = 0x1663, /* Allwinner F1C100s (all new sun3i?) */ .name = "F1C100s", @@ -419,6 +435,8 @@ soc_info_t soc_info_table[] = { .sram_size = 32 * 1024, /* No SID */ .watchdog = &wd_h3_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1673, /* Allwinner A83T */ .name = "A83T", @@ -431,6 +449,8 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_h3_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1680, /* Allwinner H3, H2+ */ .name = "H3", @@ -445,6 +465,8 @@ soc_info_t soc_info_table[] = { /* Check L.NOP in the OpenRISC reset vector */ .needs_smc_workaround_if_zero_word_at_addr = 0x40004, .watchdog = &wd_h3_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, .flags = NEEDS_SID_FIX, },{ .soc_id = 0x1681, /* Allwinner V3s */ @@ -457,6 +479,8 @@ soc_info_t soc_info_table[] = { .sid_base = 0x01C23800, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_h3_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1708, /* Allwinner T7 */ .name = "T7", @@ -469,6 +493,9 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = t7_sid_maps, .watchdog = &wd_h6_compat, + .gpio_base = H6_PIO_BASE, + .ccu_base = H6_CCM_BASE, + .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1718, /* Allwinner H5 */ .name = "H5", @@ -484,6 +511,8 @@ soc_info_t soc_info_table[] = { /* Check L.NOP in the OpenRISC reset vector */ .needs_smc_workaround_if_zero_word_at_addr = 0x40004, .watchdog = &wd_h3_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1701, /* Allwinner R40 */ .name = "R40", @@ -495,6 +524,8 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = r40_sid_maps, .watchdog = &wd_a10_compat, + .gpio_base = SUNXI_PIO_BASE, + .ccu_base = AW_CCM_BASE, },{ .soc_id = 0x1719, /* Allwinner A63 */ .name = "A63", @@ -508,6 +539,9 @@ soc_info_t soc_info_table[] = { .sid_sections = generic_2k_sid_maps, .rvbar_reg = 0x09010040, .watchdog = &wd_h6_compat, + .gpio_base = H6_PIO_BASE, + .ccu_base = H6_CCM_BASE, + .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1728, /* Allwinner H6 */ .name = "H6", @@ -523,6 +557,9 @@ soc_info_t soc_info_table[] = { /* Check L.NOP in the OpenRISC reset vector */ .needs_smc_workaround_if_zero_word_at_addr = 0x100004, .watchdog = &wd_h6_compat, + .gpio_base = H6_PIO_BASE, + .ccu_base = H6_CCM_BASE, + .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1816, /* Allwinner V536 */ .name = "V536", @@ -535,6 +572,9 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_h6_compat, + .gpio_base = H6_PIO_BASE, + .ccu_base = H6_CCM_BASE, + .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1817, /* Allwinner V831 */ .name = "V831", @@ -547,6 +587,9 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_h6_compat, + .gpio_base = H6_PIO_BASE, + .ccu_base = H6_CCM_BASE, + .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1823, /* Allwinner H616 */ .name = "H616", @@ -562,6 +605,9 @@ soc_info_t soc_info_table[] = { .rvbar_reg_alt= 0x08100040, .ver_reg = 0x03000024, .watchdog = &wd_h6_compat, + .gpio_base = H6_PIO_BASE, + .ccu_base = H6_CCM_BASE, + .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1851, /* Allwinner R329 */ .name = "R329", @@ -576,6 +622,9 @@ soc_info_t soc_info_table[] = { .sid_sections = generic_2k_sid_maps, .rvbar_reg = 0x08100040, .watchdog = &wd_h6_compat, + .gpio_base = R329_PIO_BASE, + .ccu_base = R329_CCM_BASE, + .flags = FLAGS_NCAT2, },{ .soc_id = 0x1886, /* Allwinner V853 */ .name = "V853", @@ -588,7 +637,9 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_v853_compat, - .flags = NEEDS_ICACHE_FIX, + .gpio_base = V853_PIO_BASE, + .ccu_base = R329_CCM_BASE, + .flags = NEEDS_ICACHE_FIX | FLAGS_NCAT2, },{ .soc_id = 0x1859, /* Allwinner D1/D1s/R528/T113-S3 */ .name = "R528", @@ -601,7 +652,9 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_v853_compat, - .flags = NEEDS_ICACHE_FIX, + .gpio_base = V853_PIO_BASE, + .ccu_base = R329_CCM_BASE, + .flags = NEEDS_ICACHE_FIX | FLAGS_NCAT2, },{ .soc_id = 0x1721, /* Allwinner V5 */ .name = "V5", @@ -614,6 +667,9 @@ soc_info_t soc_info_table[] = { .sid_offset = 0x200, .sid_sections = generic_2k_sid_maps, .watchdog = &wd_h6_compat, + .gpio_base = H6_PIO_BASE, + .ccu_base = H6_CCM_BASE, + .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1890, /* Allwinner A523 */ .name = "A523", @@ -627,7 +683,9 @@ soc_info_t soc_info_table[] = { .sid_sections = generic_2k_sid_maps, .rvbar_reg = 0x08000040, .watchdog = &wd_a523_compat, - .flags = NEEDS_ICACHE_FIX, + .gpio_base = V853_PIO_BASE, + .ccu_base = R329_CCM_BASE, + .flags = NEEDS_ICACHE_FIX | FLAGS_NCAT2, },{ .soc_id = 0x1855, /* Allwinner A133 */ .name = "A133", @@ -642,6 +700,9 @@ soc_info_t soc_info_table[] = { .rvbar_reg = 0x08100040, .needs_smc_workaround_if_zero_word_at_addr = 0x100004, .watchdog = &wd_h6_compat, + .gpio_base = H6_PIO_BASE, + .ccu_base = H6_CCM_BASE, + .flags = H6_STYLE_CLOCKS, },{ .swap_buffers = NULL /* End of the table */ } diff --git a/soc_info.h b/soc_info.h index 93ff5b452..b6c0affbd 100644 --- a/soc_info.h +++ b/soc_info.h @@ -82,8 +82,22 @@ enum soc_flags { NEEDS_L2EN = BIT(0), NEEDS_SID_FIX = BIT(1), NEEDS_ICACHE_FIX = BIT(2), + H6_STYLE_CLOCKS = BIT(3), + GPIO_NCAT2 = BIT(4), }; +#define FLAGS_NCAT2 (GPIO_NCAT2 | H6_STYLE_CLOCKS) + +#define AW_CCM_BASE 0x01c20000 +#define SUNXI_PIO_BASE 0x01c20800 +#define A80_CCM_BASE 0x06000000 +#define A80_PIO_BASE 0x06000800 +#define H6_PIO_BASE 0x0300b000 +#define H6_CCM_BASE 0x03001000 +#define V853_PIO_BASE 0x02000000 +#define R329_PIO_BASE 0x02000400 +#define R329_CCM_BASE 0x02001000 + /* * Each SoC variant may have its own list of memory buffers to be exchanged * and the information about the placement of the thunk code, which handles @@ -142,6 +156,8 @@ typedef struct { uint32_t needs_smc_workaround_if_zero_word_at_addr; uint32_t sram_size; /* Usable contiguous SRAM at spl_addr */ sram_swap_buffers *swap_buffers; + uint32_t gpio_base; + uint32_t ccu_base; uint32_t flags; } soc_info_t; From fa9fe769d6158164ec2b4a56686af35f98321966 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sat, 16 Aug 2025 01:11:16 +0100 Subject: [PATCH 3/5] spi: use GPIO and CCU base address from soc_info Now that we store the base addresses of the GPIO and clock controllers for each SoC in our soc table, let's use those values instead of determining them ourselves, in the SPI flash code. This involves several changes: - removing the base offset from each register address - supporting the NCAT2 pin controller, with a larger per-port size - using info about clock and pinctrl generation from soc table This will simplify future SoC support, as we can simply put the respective base addresses in the soc table, without touching the SPI flash code. Signed-off-by: Andre Przywara --- fel-spiflash.c | 91 +++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 53 deletions(-) diff --git a/fel-spiflash.c b/fel-spiflash.c index 95cab875c..1c75361c8 100644 --- a/fel-spiflash.c +++ b/fel-spiflash.c @@ -75,16 +75,16 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val); #define PB (1) #define PC (2) -#define CCM_SPI0_CLK (0x01C20000 + 0xA0) -#define CCM_AHB_GATING0 (0x01C20000 + 0x60) +#define CCM_SPI0_CLK_OFF 0xa0 +#define CCM_AHB_GATING0_OFF 0x60 #define CCM_AHB_GATE_SPI0 (1 << 20) -#define SUN6I_BUS_SOFT_RST_REG0 (0x01C20000 + 0x2C0) +#define SUN6I_BUS_SOFT_RST_REG0_OFF 0x2c0 #define SUN6I_SPI0_RST (1 << 20) -#define SUNIV_PLL6_CTL (0x01c20000 + 0x28) -#define SUNIV_AHB_APB_CFG (0x01c20000 + 0x54) +#define SUNIV_PLL6_CTL_OFF 0x28 +#define SUNIV_AHB_APB_CFG_OFF 0x54 -#define H6_CCM_SPI0_CLK (0x03001000 + 0x940) -#define H6_CCM_SPI_BGR (0x03001000 + 0x96C) +#define H6_CCM_SPI0_CLK_OFF 0x940 +#define H6_CCM_SPI_BGR_OFF 0x96c #define H6_CCM_SPI0_GATE_RESET (1 << 0 | 1 << 16) #define SUNIV_GPC_SPI0 (2) @@ -122,20 +122,6 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val); #define CCM_SPI0_CLK_DIV_BY_6 (0x1002) #define CCM_SPI0_CLK_DIV_BY_32 (0x100f) -static uint32_t gpio_base(feldev_handle *dev) -{ - soc_info_t *soc_info = dev->soc_info; - switch (soc_info->soc_id) { - case 0x1816: /* V536 */ - case 0x1817: /* V831 */ - case 0x1728: /* H6 */ - case 0x1823: /* H616 */ - return 0x0300B000; - default: - return 0x01C20800; - } -} - static uint32_t spi_base(feldev_handle *dev) { soc_info_t *soc_info = dev->soc_info; @@ -162,13 +148,21 @@ static uint32_t spi_base(feldev_handle *dev) static void gpio_set_cfgpin(feldev_handle *dev, int port_num, int pin_num, int val) { - uint32_t port_base = gpio_base(dev) + port_num * 0x24; - uint32_t cfg_reg = port_base + 4 * (pin_num / 8); - uint32_t pin_idx = pin_num % 8; - uint32_t x = readl(cfg_reg); - x &= ~(0x7 << (pin_idx * 4)); - x |= val << (pin_idx * 4); - writel(x, cfg_reg); + uint32_t cfg_reg; + uint32_t pin_idx = pin_num % 8; + uint32_t reg; + + cfg_reg = dev->soc_info->gpio_base; + if (dev->soc_info->flags & GPIO_NCAT2) + cfg_reg += port_num * 0x30; + else + cfg_reg += port_num * 0x24; + cfg_reg += 4 * (pin_num / 8); + + reg = readl(cfg_reg); + reg &= ~(0xf << (pin_idx * 4)); + reg |= val << (pin_idx * 4); + writel(reg, cfg_reg); } static bool spi_is_sun6i(feldev_handle *dev) @@ -184,20 +178,6 @@ static bool spi_is_sun6i(feldev_handle *dev) } } -static bool soc_is_h6_style(feldev_handle *dev) -{ - soc_info_t *soc_info = dev->soc_info; - switch (soc_info->soc_id) { - case 0x1816: /* V536 */ - case 0x1817: /* V831 */ - case 0x1728: /* H6 */ - case 0x1823: /* H616 */ - return true; - default: - return false; - } -} - /* * Init the SPI0 controller and setup pins muxing. */ @@ -205,6 +185,8 @@ static bool spi0_init(feldev_handle *dev) { uint32_t reg_val; soc_info_t *soc_info = dev->soc_info; + uint32_t ccu_base; + if (!soc_info) { printf("Unable to fetch device information. " "Possibly unknown device.\n"); @@ -265,21 +247,22 @@ static bool spi0_init(feldev_handle *dev) return false; } - if (soc_is_h6_style(dev)) { - reg_val = readl(H6_CCM_SPI_BGR); + ccu_base = dev->soc_info->ccu_base; + if (dev->soc_info->flags & H6_STYLE_CLOCKS) { + reg_val = readl(ccu_base + H6_CCM_SPI_BGR_OFF); reg_val |= H6_CCM_SPI0_GATE_RESET; - writel(reg_val, H6_CCM_SPI_BGR); + writel(reg_val, ccu_base + H6_CCM_SPI_BGR_OFF); } else { if (spi_is_sun6i(dev)) { /* Deassert SPI0 reset */ - reg_val = readl(SUN6I_BUS_SOFT_RST_REG0); + reg_val = readl(ccu_base + SUN6I_BUS_SOFT_RST_REG0_OFF); reg_val |= SUN6I_SPI0_RST; - writel(reg_val, SUN6I_BUS_SOFT_RST_REG0); + writel(reg_val, ccu_base + SUN6I_BUS_SOFT_RST_REG0_OFF); } - reg_val = readl(CCM_AHB_GATING0); + reg_val = readl(ccu_base + CCM_AHB_GATING0_OFF); reg_val |= CCM_AHB_GATE_SPI0; - writel(reg_val, CCM_AHB_GATING0); + writel(reg_val, ccu_base + CCM_AHB_GATING0_OFF); } if (soc_info->soc_id == 0x1663) { /* suniv F1C100s */ @@ -291,9 +274,9 @@ static bool spi0_init(feldev_handle *dev) */ /* Set PLL6 to 600MHz */ - writel(0x80041801, SUNIV_PLL6_CTL); + writel(0x80041801, ccu_base + SUNIV_PLL6_CTL_OFF); /* PLL6:AHB:APB = 6:2:1 */ - writel(0x00003180, SUNIV_AHB_APB_CFG); + writel(0x00003180, ccu_base + SUNIV_AHB_APB_CFG_OFF); /* divide by 32 */ writel(CCM_SPI0_CLK_DIV_BY_32, SUN6I_SPI0_CCTL); } else { @@ -301,8 +284,10 @@ static bool spi0_init(feldev_handle *dev) writel(CCM_SPI0_CLK_DIV_BY_4, spi_is_sun6i(dev) ? SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL); /* Choose 24MHz from OSC24M and enable clock */ - writel(1U << 31, - soc_is_h6_style(dev) ? H6_CCM_SPI0_CLK : CCM_SPI0_CLK); + if (dev->soc_info->flags & H6_STYLE_CLOCKS) + writel(1U << 31, ccu_base + H6_CCM_SPI0_CLK_OFF); + else + writel(1U << 31, ccu_base + CCM_SPI0_CLK_OFF); } if (spi_is_sun6i(dev)) { From ef7839a60932b832ff57d48904a3a56b09e2f251 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sat, 16 Aug 2025 01:24:54 +0100 Subject: [PATCH 4/5] spi: move SPI0 base address into soc_info Use the main soc table to also store the first SPI controller's MMIO base address, so that we don't need to decide this in the SPI flash code. Only SoCs that are covered by fel-spiflash.c get a base address assigned, so this value being not 0 is used as an indicator that the SoC is supported. This will simplify supporting future generations of SoCs. Signed-off-by: Andre Przywara --- fel-spiflash.c | 17 +---------------- soc_info.c | 13 +++++++++++++ soc_info.h | 4 ++++ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/fel-spiflash.c b/fel-spiflash.c index 1c75361c8..8b06174d6 100644 --- a/fel-spiflash.c +++ b/fel-spiflash.c @@ -124,22 +124,7 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val); static uint32_t spi_base(feldev_handle *dev) { - soc_info_t *soc_info = dev->soc_info; - switch (soc_info->soc_id) { - case 0x1623: /* A10 */ - case 0x1625: /* A13 */ - case 0x1651: /* A20 */ - case 0x1663: /* F1C100s */ - case 0x1701: /* R40 */ - return 0x01C05000; - case 0x1816: /* V536 */ - case 0x1817: /* V831 */ - case 0x1728: /* H6 */ - case 0x1823: /* H616 */ - return 0x05010000; - default: - return 0x01C68000; - } + return dev->soc_info->spi_base; } /* diff --git a/soc_info.c b/soc_info.c index 55ccf62a0..4824b7700 100644 --- a/soc_info.c +++ b/soc_info.c @@ -336,6 +336,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_a10_compat, .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, + .spi_base = SUN4I_SPI_BASE, .flags = NEEDS_L2EN, },{ .soc_id = 0x1625, /* Allwinner A10s, A13, R8 */ @@ -348,6 +349,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_a10_compat, .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, + .spi_base = SUN4I_SPI_BASE, .flags = NEEDS_L2EN, },{ .soc_id = 0x1651, /* Allwinner A20 */ @@ -361,6 +363,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_a10_compat, .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, + .spi_base = SUN4I_SPI_BASE, },{ .soc_id = 0x1650, /* Allwinner A23 */ .name = "A23", @@ -412,6 +415,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_h3_compat, .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, + .spi_base = SUN6I_SPI_BASE, },{ .soc_id = 0x1639, /* Allwinner A80 */ .name = "A80", @@ -437,6 +441,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_h3_compat, .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, + .spi_base = SUN4I_SPI_BASE, },{ .soc_id = 0x1673, /* Allwinner A83T */ .name = "A83T", @@ -467,6 +472,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_h3_compat, .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, + .spi_base = SUN6I_SPI_BASE, .flags = NEEDS_SID_FIX, },{ .soc_id = 0x1681, /* Allwinner V3s */ @@ -481,6 +487,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_h3_compat, .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, + .spi_base = SUN6I_SPI_BASE, },{ .soc_id = 0x1708, /* Allwinner T7 */ .name = "T7", @@ -513,6 +520,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_h3_compat, .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, + .spi_base = SUN6I_SPI_BASE, },{ .soc_id = 0x1701, /* Allwinner R40 */ .name = "R40", @@ -526,6 +534,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_a10_compat, .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, + .spi_base = SUN4I_SPI_BASE, },{ .soc_id = 0x1719, /* Allwinner A63 */ .name = "A63", @@ -559,6 +568,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_h6_compat, .gpio_base = H6_PIO_BASE, .ccu_base = H6_CCM_BASE, + .spi_base = H6_SPI_BASE, .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1816, /* Allwinner V536 */ @@ -574,6 +584,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_h6_compat, .gpio_base = H6_PIO_BASE, .ccu_base = H6_CCM_BASE, + .spi_base = H6_SPI_BASE, .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1817, /* Allwinner V831 */ @@ -589,6 +600,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_h6_compat, .gpio_base = H6_PIO_BASE, .ccu_base = H6_CCM_BASE, + .spi_base = H6_SPI_BASE, .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1823, /* Allwinner H616 */ @@ -607,6 +619,7 @@ soc_info_t soc_info_table[] = { .watchdog = &wd_h6_compat, .gpio_base = H6_PIO_BASE, .ccu_base = H6_CCM_BASE, + .spi_base = H6_SPI_BASE, .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1851, /* Allwinner R329 */ diff --git a/soc_info.h b/soc_info.h index b6c0affbd..00e0b5909 100644 --- a/soc_info.h +++ b/soc_info.h @@ -97,6 +97,9 @@ enum soc_flags { #define V853_PIO_BASE 0x02000000 #define R329_PIO_BASE 0x02000400 #define R329_CCM_BASE 0x02001000 +#define SUN4I_SPI_BASE 0x01c05000 +#define SUN6I_SPI_BASE 0x01c68000 +#define H6_SPI_BASE 0x05010000 /* * Each SoC variant may have its own list of memory buffers to be exchanged @@ -158,6 +161,7 @@ typedef struct { sram_swap_buffers *swap_buffers; uint32_t gpio_base; uint32_t ccu_base; + uint32_t spi_base; uint32_t flags; } soc_info_t; From c65c3b15c33ec2b9c5135fbfb5fb77481bddef72 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sat, 16 Aug 2025 01:43:48 +0100 Subject: [PATCH 5/5] spi: use pins and pinmux data from soc_info The bootable SPI flash is always connected to PortC pins, though the exact pin numbers within PortC and their pinmux differs between the SoCs. We always need four pins (MOSI, MISO, CLK, CS), so pack their pin numbers into one 32-bit word and store that in our soc table. Also store the required pinmux (which is always the same for all four pins) in the table. Then use this information in the SPI flash code to extract the pins again and configure them accordingly. This does away with the fragile switch/case construct we used to configure the pins so far. Signed-off-by: Andre Przywara --- fel-spiflash.c | 68 +++++++++++--------------------------------------- soc_info.c | 30 ++++++++++++++++++++++ soc_info.h | 6 +++++ 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/fel-spiflash.c b/fel-spiflash.c index 8b06174d6..f68593211 100644 --- a/fel-spiflash.c +++ b/fel-spiflash.c @@ -87,10 +87,6 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val); #define H6_CCM_SPI_BGR_OFF 0x96c #define H6_CCM_SPI0_GATE_RESET (1 << 0 | 1 << 16) -#define SUNIV_GPC_SPI0 (2) -#define SUNXI_GPC_SPI0 (3) -#define SUN50I_GPC_SPI0 (4) - #define SUN4I_CTL_ENABLE (1 << 0) #define SUN4I_CTL_MASTER (1 << 1) #define SUN4I_CTL_TF_RST (1 << 8) @@ -163,6 +159,14 @@ static bool spi_is_sun6i(feldev_handle *dev) } } +/* Extract a pin number from the packed representation (one byte per pin) */ +static uint8_t spi_pin(soc_info_t *soc_info, int pin) +{ + int shift = (pin - 1) * 8; + + return (soc_info->spi_pins >> shift) & 0xff; +} + /* * Init the SPI0 controller and setup pins muxing. */ @@ -178,60 +182,18 @@ static bool spi0_init(feldev_handle *dev) return false; } - /* Setup SPI0 pins muxing */ - switch (soc_info->soc_id) { - case 0x1663: /* Allwinner F1C100s/F1C600/R6/F1C100A/F1C500 */ - gpio_set_cfgpin(dev, PC, 0, SUNIV_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 1, SUNIV_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 2, SUNIV_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 3, SUNIV_GPC_SPI0); - break; - case 0x1625: /* Allwinner A13 */ - case 0x1680: /* Allwinner H3 */ - case 0x1681: /* Allwinner V3s */ - case 0x1718: /* Allwinner H5 */ - gpio_set_cfgpin(dev, PC, 0, SUNXI_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 1, SUNXI_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 2, SUNXI_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 3, SUNXI_GPC_SPI0); - break; - case 0x1623: /* Allwinner A10 */ - case 0x1651: /* Allwinner A20 */ - case 0x1701: /* Allwinner R40 */ - gpio_set_cfgpin(dev, PC, 0, SUNXI_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 1, SUNXI_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 2, SUNXI_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 23, SUNXI_GPC_SPI0); - break; - case 0x1689: /* Allwinner A64 */ - gpio_set_cfgpin(dev, PC, 0, SUN50I_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 1, SUN50I_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 2, SUN50I_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 3, SUN50I_GPC_SPI0); - break; - case 0x1816: /* Allwinner V536 */ - case 0x1817: /* Allwinner V831 */ - gpio_set_cfgpin(dev, PC, 1, SUN50I_GPC_SPI0); /* SPI0-CS */ - /* fall-through */ - case 0x1728: /* Allwinner H6 */ - gpio_set_cfgpin(dev, PC, 0, SUN50I_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 2, SUN50I_GPC_SPI0); - gpio_set_cfgpin(dev, PC, 3, SUN50I_GPC_SPI0); - /* PC5 is SPI0-CS on the H6, and SPI0-HOLD on the V831 */ - gpio_set_cfgpin(dev, PC, 5, SUN50I_GPC_SPI0); - break; - case 0x1823: /* Allwinner H616 */ - gpio_set_cfgpin(dev, PC, 0, SUN50I_GPC_SPI0); /* SPI0_CLK */ - gpio_set_cfgpin(dev, PC, 2, SUN50I_GPC_SPI0); /* SPI0_MOSI */ - gpio_set_cfgpin(dev, PC, 3, SUN50I_GPC_SPI0); /* SPI0_CS0 */ - gpio_set_cfgpin(dev, PC, 4, SUN50I_GPC_SPI0); /* SPI0_MISO */ - break; - default: /* Unknown/Unsupported SoC */ + if (!soc_info->spi_base) { printf("SPI support not implemented yet for %x (%s)!\n", soc_info->soc_id, soc_info->name); return false; } + /* Setup SPI0 pins muxing */ + gpio_set_cfgpin(dev, PC, spi_pin(soc_info, 1), soc_info->spi_pinmux); + gpio_set_cfgpin(dev, PC, spi_pin(soc_info, 2), soc_info->spi_pinmux); + gpio_set_cfgpin(dev, PC, spi_pin(soc_info, 3), soc_info->spi_pinmux); + gpio_set_cfgpin(dev, PC, spi_pin(soc_info, 4), soc_info->spi_pinmux); + ccu_base = dev->soc_info->ccu_base; if (dev->soc_info->flags & H6_STYLE_CLOCKS) { reg_val = readl(ccu_base + H6_CCM_SPI_BGR_OFF); diff --git a/soc_info.c b/soc_info.c index 4824b7700..0fb2f2884 100644 --- a/soc_info.c +++ b/soc_info.c @@ -324,6 +324,10 @@ static const sid_section generic_2k_sid_maps[] = { SID_SECTION(NULL, 0, 0), }; +/* Pack four pin numbers into one uint32_t, using one byte per pin */ +#define SPI_PINS(p1, p2, p3, p4) \ + ((p1) << 0 | (p2) << 8 | (p3) << 16 | (p4) << 24) + soc_info_t soc_info_table[] = { { .soc_id = 0x1623, /* Allwinner A10 */ @@ -337,6 +341,8 @@ soc_info_t soc_info_table[] = { .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, .spi_base = SUN4I_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 23), + .spi_pinmux = SUNXI_GPC_SPI0, .flags = NEEDS_L2EN, },{ .soc_id = 0x1625, /* Allwinner A10s, A13, R8 */ @@ -350,6 +356,8 @@ soc_info_t soc_info_table[] = { .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, .spi_base = SUN4I_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 3), + .spi_pinmux = SUNXI_GPC_SPI0, .flags = NEEDS_L2EN, },{ .soc_id = 0x1651, /* Allwinner A20 */ @@ -364,6 +372,8 @@ soc_info_t soc_info_table[] = { .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, .spi_base = SUN4I_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 23), + .spi_pinmux = SUNXI_GPC_SPI0, },{ .soc_id = 0x1650, /* Allwinner A23 */ .name = "A23", @@ -416,6 +426,8 @@ soc_info_t soc_info_table[] = { .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, .spi_base = SUN6I_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 3), + .spi_pinmux = SUN50I_GPC_SPI0, },{ .soc_id = 0x1639, /* Allwinner A80 */ .name = "A80", @@ -442,6 +454,8 @@ soc_info_t soc_info_table[] = { .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, .spi_base = SUN4I_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 3), + .spi_pinmux = SUNIV_GPC_SPI0, },{ .soc_id = 0x1673, /* Allwinner A83T */ .name = "A83T", @@ -473,6 +487,8 @@ soc_info_t soc_info_table[] = { .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, .spi_base = SUN6I_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 3), + .spi_pinmux = SUNXI_GPC_SPI0, .flags = NEEDS_SID_FIX, },{ .soc_id = 0x1681, /* Allwinner V3s */ @@ -488,6 +504,8 @@ soc_info_t soc_info_table[] = { .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, .spi_base = SUN6I_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 3), + .spi_pinmux = SUNXI_GPC_SPI0, },{ .soc_id = 0x1708, /* Allwinner T7 */ .name = "T7", @@ -521,6 +539,8 @@ soc_info_t soc_info_table[] = { .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, .spi_base = SUN6I_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 3), + .spi_pinmux = SUNXI_GPC_SPI0, },{ .soc_id = 0x1701, /* Allwinner R40 */ .name = "R40", @@ -535,6 +555,8 @@ soc_info_t soc_info_table[] = { .gpio_base = SUNXI_PIO_BASE, .ccu_base = AW_CCM_BASE, .spi_base = SUN4I_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 23), + .spi_pinmux = SUNXI_GPC_SPI0, },{ .soc_id = 0x1719, /* Allwinner A63 */ .name = "A63", @@ -569,6 +591,8 @@ soc_info_t soc_info_table[] = { .gpio_base = H6_PIO_BASE, .ccu_base = H6_CCM_BASE, .spi_base = H6_SPI_BASE, + .spi_pins = SPI_PINS(0, 2, 3, 5), + .spi_pinmux = SUN50I_GPC_SPI0, .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1816, /* Allwinner V536 */ @@ -585,6 +609,8 @@ soc_info_t soc_info_table[] = { .gpio_base = H6_PIO_BASE, .ccu_base = H6_CCM_BASE, .spi_base = H6_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 3), + .spi_pinmux = SUN50I_GPC_SPI0, .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1817, /* Allwinner V831 */ @@ -601,6 +627,8 @@ soc_info_t soc_info_table[] = { .gpio_base = H6_PIO_BASE, .ccu_base = H6_CCM_BASE, .spi_base = H6_SPI_BASE, + .spi_pins = SPI_PINS(0, 1, 2, 3), + .spi_pinmux = SUN50I_GPC_SPI0, .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1823, /* Allwinner H616 */ @@ -620,6 +648,8 @@ soc_info_t soc_info_table[] = { .gpio_base = H6_PIO_BASE, .ccu_base = H6_CCM_BASE, .spi_base = H6_SPI_BASE, + .spi_pins = SPI_PINS(0, 2, 3, 4), + .spi_pinmux = SUN50I_GPC_SPI0, .flags = H6_STYLE_CLOCKS, },{ .soc_id = 0x1851, /* Allwinner R329 */ diff --git a/soc_info.h b/soc_info.h index 00e0b5909..497c5cda5 100644 --- a/soc_info.h +++ b/soc_info.h @@ -101,6 +101,10 @@ enum soc_flags { #define SUN6I_SPI_BASE 0x01c68000 #define H6_SPI_BASE 0x05010000 +#define SUNIV_GPC_SPI0 2 +#define SUNXI_GPC_SPI0 3 +#define SUN50I_GPC_SPI0 4 + /* * Each SoC variant may have its own list of memory buffers to be exchanged * and the information about the placement of the thunk code, which handles @@ -162,6 +166,8 @@ typedef struct { uint32_t gpio_base; uint32_t ccu_base; uint32_t spi_base; + uint32_t spi_pins; /* PC offset for 4 pins, 1 byte each */ + uint8_t spi_pinmux; uint32_t flags; } soc_info_t;