diff --git a/fel-spiflash.c b/fel-spiflash.c index 5a22581..467c504 100644 --- a/fel-spiflash.c +++ b/fel-spiflash.c @@ -81,6 +81,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) @@ -92,35 +96,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); @@ -142,6 +172,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. */ @@ -179,27 +220,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; diff --git a/soc_info.c b/soc_info.c index 846e255..56a158c 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, @@ -250,6 +265,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 */ } 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");