From 47b611ccdcd19836c01c32e71c6eeb9056950037 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 30 Dec 2019 18:35:55 +0000 Subject: [PATCH 1/4] spi: Add support for R40 The R40 is closely related to the A20, but has in fact a newer generation SPI controller. Add the R40 SoC ID to the right places to enable SPI support. Tested on a Bananapi M2 Berry with SPI flash attached to header pins. Signed-off-by: Andre Przywara --- fel-spiflash.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fel-spiflash.c b/fel-spiflash.c index eef3c4f..26e0bea 100644 --- a/fel-spiflash.c +++ b/fel-spiflash.c @@ -136,6 +136,7 @@ static uint32_t spi_base(feldev_handle *dev) case 0x1623: /* A10 */ case 0x1625: /* A13 */ case 0x1651: /* A20 */ + case 0x1701: /* R40 */ return 0x01C05000; case 0x1817: /* V831 */ return 0x05010000; @@ -209,6 +210,7 @@ static bool spi0_init(feldev_handle *dev) 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); From 681403670889bb649b708a9cc77fca01b86359ce Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 19 Jun 2018 01:22:10 +0100 Subject: [PATCH 2/4] spi: Add support for H6 As Icenowy rightfully assumed, the V831 SPI support covers the H6 as well. The only difference was a slight deviation in the pinmux setup: the H6 has the SPI0-CS on pin PC5, the V831 on pin PC1. Just add the right SoC ID and tweak the pinmux setup to enable it. Tested on a Pine H64. Signed-off-by: Andre Przywara --- fel-spiflash.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fel-spiflash.c b/fel-spiflash.c index 26e0bea..b7a3546 100644 --- a/fel-spiflash.c +++ b/fel-spiflash.c @@ -123,6 +123,7 @@ static uint32_t gpio_base(feldev_handle *dev) soc_info_t *soc_info = dev->soc_info; switch (soc_info->soc_id) { case 0x1817: /* V831 */ + case 0x1728: /* H6 */ return 0x0300B000; default: return 0x01C20800; @@ -139,6 +140,7 @@ static uint32_t spi_base(feldev_handle *dev) case 0x1701: /* R40 */ return 0x01C05000; case 0x1817: /* V831 */ + case 0x1728: /* H6 */ return 0x05010000; default: return 0x01C68000; @@ -178,6 +180,7 @@ 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 */ + case 0x1728: /* H6 */ return true; default: return false; @@ -223,10 +226,14 @@ static bool spi0_init(feldev_handle *dev) gpio_set_cfgpin(dev, PC, 3, SUN50I_GPC_SPI0); break; 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, 1, 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; default: /* Unknown/Unsupported SoC */ printf("SPI support not implemented yet for %x (%s)!\n", From de784a7c7b00b6a1bbf9f5267c74e825f6f91365 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Mon, 20 Jan 2020 00:14:22 +0000 Subject: [PATCH 3/4] spi: Avoid signed shifts Shifting signed types to the left is dodgy, especially by 31 bits, since it depends on the result type whether the result is undefined or not. Do not take any chances here, and mark those shift bases as unsigned where we can or will hit bit 31, to avoid undefined behaviour. Signed-off-by: Andre Przywara --- fel-spiflash.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fel-spiflash.c b/fel-spiflash.c index b7a3546..6a556e4 100644 --- a/fel-spiflash.c +++ b/fel-spiflash.c @@ -94,7 +94,7 @@ void fel_writel(feldev_handle *dev, uint32_t addr, uint32_t val); #define SUN4I_CTL_RF_RST (1 << 9) #define SUN4I_CTL_XCH (1 << 10) -#define SUN6I_TCR_XCH (1 << 31) +#define SUN6I_TCR_XCH (1U << 31) #define SUN4I_SPI0_CCTL (spi_base(dev) + 0x1C) #define SUN4I_SPI0_CTL (spi_base(dev) + 0x08) @@ -271,10 +271,10 @@ static bool spi0_init(feldev_handle *dev) if (spi_is_sun6i(dev)) { /* Enable SPI in the master mode and do a soft reset */ reg_val = readl(SUN6I_SPI0_GCR); - reg_val |= (1 << 31) | 3; + reg_val |= (1U << 31) | 3; writel(reg_val, SUN6I_SPI0_GCR); /* Wait for completion */ - while (readl(SUN6I_SPI0_GCR) & (1 << 31)) {} + while (readl(SUN6I_SPI0_GCR) & (1U << 31)) {} } else { reg_val = readl(SUN4I_SPI0_CTL); reg_val |= SUN4I_CTL_MASTER; @@ -555,7 +555,7 @@ void aw_fel_spiflash_info(feldev_handle *dev) } printf("Manufacturer: %s (%02Xh), model: %02Xh, size: %d bytes.\n", - manufacturer, buf[3], buf[4], (1 << buf[5])); + manufacturer, buf[3], buf[4], (1U << buf[5])); } /* From 205e208a70cf6fac22ed12e8f233b6df68ae76c7 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Wed, 1 Jan 2020 18:49:49 +0000 Subject: [PATCH 4/4] spi: Observe proper clock initialisation order The CCU section in all Allwinner manuals asks to de-assert the reset signal first, then to ungate the bus clock. On a nearby note it also requires to switch dividers before changing the clock source. The SPI flash code violated those two rules, fix this to make the code more robust. Signed-off-by: Andre Przywara --- fel-spiflash.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/fel-spiflash.c b/fel-spiflash.c index 6a556e4..4e22f60 100644 --- a/fel-spiflash.c +++ b/fel-spiflash.c @@ -245,14 +245,7 @@ static bool spi0_init(feldev_handle *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); @@ -260,13 +253,16 @@ static bool spi0_init(feldev_handle *dev) writel(reg_val, SUN6I_BUS_SOFT_RST_REG0); } - /* 24MHz from OSC24M */ - writel((1 << 31), CCM_SPI0_CLK); + reg_val = readl(CCM_AHB_GATING0); + reg_val |= CCM_AHB_GATE_SPI0; + writel(reg_val, CCM_AHB_GATING0); } /* divide by 4 */ 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 (spi_is_sun6i(dev)) { /* Enable SPI in the master mode and do a soft reset */