From c6111193f6ee4994e1d07f5e6bc023ce183af560 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 12 Sep 2020 18:11:37 +0800 Subject: [PATCH 1/3] fel: add initial SoC info for V831 The non-IRQ stack is moved to near the end of the SRAM C, which is very high, and have no need to save. Signed-off-by: Icenowy Zheng --- soc_info.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/soc_info.c b/soc_info.c index b95dede..2078821 100644 --- a/soc_info.c +++ b/soc_info.c @@ -110,6 +110,21 @@ sram_swap_buffers h6_sram_swap_buffers[] = { { .size = 0 } /* End of the table */ }; +/* + * V831 has 96KiB SRAM A1 at 0x20000 where the SPL has to be loaded to. + * SRAM C is continuous with SRAM A1, and both SRAMs are tried to be used + * by BROM. Memory space is allocated both from the start of SRAM A1 and + * the end of SRAM C. + * The start of SRAM C is in between these areas, and can serve as backup + * of IRQ stack, which is inside the first 32KiB of SRAM A1. Other areas + * that are critical on older SoCs seem to be already in SRAM C, which + * we do not need to preserve. + */ +sram_swap_buffers v831_sram_swap_buffers[] = { + { .buf1 = 0x21000, .buf2 = 0x38000, .size = 0x1000 }, + { .size = 0 } /* End of the table */ +}; + const watchdog_info wd_a10_compat = { .reg_mode = 0x01C20C94, .reg_mode_value = 3, @@ -249,6 +264,15 @@ soc_info_t soc_info_table[] = { .rvbar_reg = 0x09010040, /* Check L.NOP in the OpenRISC reset vector */ .needs_smc_workaround_if_zero_word_at_addr = 0x100004, + },{ + .soc_id = 0x1817, /* Allwinner V831 */ + .name = "V831", + .spl_addr = 0x20000, + .scratch_addr = 0x21000, + .thunk_addr = 0x2A200, .thunk_size = 0x200, + .swap_buffers = v831_sram_swap_buffers, + .sid_base = 0x03006000, + .sid_offset = 0x200, },{ .swap_buffers = NULL /* End of the table */ } From 3c2faa16d58755b036aa9037db9bacde8acbaec7 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sun, 20 Sep 2020 07:30:21 +0800 Subject: [PATCH 2/3] uart0-helloworld-sdboot: add support for V831 SoC V831 SoC is one of sun8i family (with Cortex-A7 CPUs), and it follows a similar memory map with H6. Add support for it. The detection for H6-style memory map is positive on V831, because it have the same version of GIC at the same address. Signed-off-by: Icenowy Zheng --- uart0-helloworld-sdboot.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/uart0-helloworld-sdboot.c b/uart0-helloworld-sdboot.c index 2c509cf..a33584f 100644 --- a/uart0-helloworld-sdboot.c +++ b/uart0-helloworld-sdboot.c @@ -144,6 +144,7 @@ enum sunxi_gpio_number { #define SUN6I_GPH_UART0 (2) #define SUN8I_H3_GPA_UART0 (2) #define SUN8I_V3S_GPB_UART0 (3) +#define SUN8I_V831_GPH_UART0 (5) #define SUN50I_H5_GPA_UART0 (2) #define SUN50I_H6_GPH_UART0 (2) #define SUN50I_A64_GPB_UART0 (4) @@ -307,6 +308,7 @@ void soc_detection_init(void) #define soc_is_h6() (soc_id == 0x1728) #define soc_is_r40() (soc_id == 0x1701) #define soc_is_v3s() (soc_id == 0x1681) +#define soc_is_v831() (soc_id == 0x1817) /* A10s and A13 share the same ID, so we need a little more effort on those */ @@ -382,7 +384,7 @@ void clock_init_uart_h6(void) void clock_init_uart(void) { - if (soc_is_h6()) + if (soc_is_h6() || soc_is_v831()) clock_init_uart_h6(); else clock_init_uart_legacy(); @@ -436,6 +438,10 @@ void gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPB(8), SUN8I_V3S_GPB_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPB(9), SUN8I_V3S_GPB_UART0); sunxi_gpio_set_pull(SUNXI_GPB(9), SUNXI_GPIO_PULL_UP); + } else if (soc_is_v831()) { + sunxi_gpio_set_cfgpin(SUNXI_GPH(9), SUN8I_V831_GPH_UART0); + sunxi_gpio_set_cfgpin(SUNXI_GPH(10), SUN8I_V831_GPH_UART0); + sunxi_gpio_set_pull(SUNXI_GPH(10), SUNXI_GPIO_PULL_UP); } else { /* Unknown SoC */ while (1) {} @@ -512,7 +518,7 @@ int get_boot_device(void) u32 *spl_signature = (void *)0x4; if (soc_is_a64() || soc_is_a80() || soc_is_h5()) spl_signature = (void *)0x10004; - if (soc_is_h6()) + if (soc_is_h6() || soc_is_v831()) spl_signature = (void *)0x20004; /* Check the eGON.BT0 magic in the SPL header */ @@ -530,7 +536,7 @@ int get_boot_device(void) void bases_init(void) { - if (soc_is_h6()) { + if (soc_is_h6() || soc_is_v831()) { pio_base = H6_PIO_BASE; uart0_base = H6_UART0_BASE; } else { @@ -571,6 +577,8 @@ int main(void) uart0_puts("Allwinner R40!\n"); else if (soc_is_v3s()) uart0_puts("Allwinner V3s!\n"); + else if (soc_is_v831()) + uart0_puts("Allwinner V831!\n"); else uart0_puts("unknown Allwinner SoC!\n"); From eac43cf7e9ea23988bf4acb10e0e140883395300 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sun, 20 Sep 2020 07:33:23 +0800 Subject: [PATCH 3/3] spi: add support for V831 The Allwinner V831 SoC has similar memory map and CCU with H6. Add support for it by make the code to dynamically acquire the SPI0 memory base and add clock setup for V831. These code should work on H6 too, but I am too lazy to test it. Signed-off-by: Icenowy Zheng --- fel-spiflash.c | 112 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 86 insertions(+), 26 deletions(-) diff --git a/fel-spiflash.c b/fel-spiflash.c index 612c9a5..5c179bf 100644 --- a/fel-spiflash.c +++ b/fel-spiflash.c @@ -76,6 +76,10 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val); #define SUN6I_BUS_SOFT_RST_REG0 (0x01C20000 + 0x2C0) #define SUN6I_SPI0_RST (1 << 20) +#define H6_CCM_SPI0_CLK (0x03001000 + 0x940) +#define H6_CCM_SPI_BGR (0x03001000 + 0x96C) +#define H6_CCM_SPI0_GATE_RESET (1 << 0 | 1 << 16) + #define SUNXI_GPC_SPI0 (3) #define SUN50I_GPC_SPI0 (4) @@ -87,35 +91,61 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val); #define SUN6I_TCR_XCH (1 << 31) -#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 (spi_base(dev) + 0x1C) +#define SUN4I_SPI0_CTL (spi_base(dev) + 0x08) +#define SUN4I_SPI0_RX (spi_base(dev) + 0x00) +#define SUN4I_SPI0_TX (spi_base(dev) + 0x04) +#define SUN4I_SPI0_FIFO_STA (spi_base(dev) + 0x28) +#define SUN4I_SPI0_BC (spi_base(dev) + 0x20) +#define SUN4I_SPI0_TC (spi_base(dev) + 0x24) -#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 (spi_base(dev) + 0x24) +#define SUN6I_SPI0_GCR (spi_base(dev) + 0x04) +#define SUN6I_SPI0_TCR (spi_base(dev) + 0x08) +#define SUN6I_SPI0_FIFO_STA (spi_base(dev) + 0x1C) +#define SUN6I_SPI0_MBC (spi_base(dev) + 0x30) +#define SUN6I_SPI0_MTC (spi_base(dev) + 0x34) +#define SUN6I_SPI0_BCC (spi_base(dev) + 0x38) +#define SUN6I_SPI0_TXD (spi_base(dev) + 0x200) +#define SUN6I_SPI0_RXD (spi_base(dev) + 0x300) #define CCM_SPI0_CLK_DIV_BY_2 (0x1000) #define CCM_SPI0_CLK_DIV_BY_4 (0x1001) #define CCM_SPI0_CLK_DIV_BY_6 (0x1002) +static uint32_t gpio_base(feldev_handle *dev) +{ + soc_info_t *soc_info = dev->soc_info; + switch (soc_info->soc_id) { + case 0x1817: /* V831 */ + return 0x0300B000; + default: + return 0x01C28000; + } +} + +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 */ + return 0x01C05000; + case 0x1817: /* V831 */ + return 0x05010000; + default: + return 0x01C68000; + } +} + /* * Configure pin function on a GPIO port */ static void gpio_set_cfgpin(feldev_handle *dev, int port_num, int pin_num, int val) { - uint32_t port_base = 0x01C20800 + port_num * 0x24; + 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); @@ -137,6 +167,17 @@ 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 0x1817: /* V831 */ + return true; + default: + return false; + } +} + /* * Init the SPI0 controller and setup pins muxing. */ @@ -173,27 +214,46 @@ static bool spi0_init(feldev_handle *dev) gpio_set_cfgpin(dev, PC, 2, SUN50I_GPC_SPI0); gpio_set_cfgpin(dev, PC, 3, SUN50I_GPC_SPI0); break; + case 0x1817: /* Allwinner V831 */ + 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; default: /* Unknown/Unsupported SoC */ printf("SPI support not implemented yet for %x (%s)!\n", soc_info->soc_id, soc_info->name); return false; } - reg_val = readl(CCM_AHB_GATING0); - reg_val |= CCM_AHB_GATE_SPI0; - writel(reg_val, CCM_AHB_GATING0); + if (soc_is_h6_style(dev)) { + reg_val = readl(H6_CCM_SPI_BGR); + reg_val |= H6_CCM_SPI0_GATE_RESET; + writel(reg_val, H6_CCM_SPI_BGR); + + /* 24MHz from OSC24M */ + writel((1 << 31), H6_CCM_SPI0_CLK); + } else { + reg_val = readl(CCM_AHB_GATING0); + reg_val |= CCM_AHB_GATE_SPI0; + writel(reg_val, CCM_AHB_GATING0); + + if (spi_is_sun6i(dev)) { + /* Deassert SPI0 reset */ + reg_val = readl(SUN6I_BUS_SOFT_RST_REG0); + reg_val |= SUN6I_SPI0_RST; + writel(reg_val, SUN6I_BUS_SOFT_RST_REG0); + } + + /* 24MHz from OSC24M */ + writel((1 << 31), CCM_SPI0_CLK); + } - /* 24MHz from OSC24M */ - writel((1 << 31), CCM_SPI0_CLK); /* divide by 4 */ writel(CCM_SPI0_CLK_DIV_BY_4, spi_is_sun6i(dev) ? SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL); if (spi_is_sun6i(dev)) { - /* Deassert SPI0 reset */ - reg_val = readl(SUN6I_BUS_SOFT_RST_REG0); - reg_val |= SUN6I_SPI0_RST; - writel(reg_val, SUN6I_BUS_SOFT_RST_REG0); /* Enable SPI in the master mode and do a soft reset */ reg_val = readl(SUN6I_SPI0_GCR); reg_val |= (1 << 31) | 3;