Minimal changes to support sun6i based Allwinner SOCs Changes are based to SPL driver arch/arm/mach-sunxi/spl_spi_sunxi.c
Signed-off-by: Oskari Lemmela <osk...@lemmela.net> --- arch/arm/include/asm/arch-sunxi/clock_sun6i.h | 1 + arch/arm/include/asm/arch-sunxi/clock_sun9i.h | 1 + drivers/spi/Kconfig | 4 +- drivers/spi/sun4i_spi.c | 116 ++++++++++++++++-- 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h index ee387127f3..4aaa0932d7 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h @@ -321,6 +321,7 @@ struct sunxi_ccm_reg { #define AHB_GATE_OFFSET_MMC(n) (AHB_GATE_OFFSET_MMC0 + (n)) #define AHB_GATE_OFFSET_DMA 6 #define AHB_GATE_OFFSET_SS 5 +#define AHB_GATE_OFFSET_SPI0 20 /* ahb_gate1 offsets */ #define AHB_GATE_OFFSET_DRC0 25 diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun9i.h b/arch/arm/include/asm/arch-sunxi/clock_sun9i.h index 530e0dd73b..9bbd4d319e 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun9i.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun9i.h @@ -194,6 +194,7 @@ struct sunxi_ccm_reg { /* ahb gate1 field */ #define AHB_GATE_OFFSET_DMA 24 +#define AHB_GATE_OFFSET_SPI0 20 /* apb1_gate fields */ #define APB1_GATE_UART_SHIFT 16 diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a7bb5b35c2..88e772cb1a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -219,9 +219,9 @@ config STM32_QSPI this ST IP core. config SUN4I_SPI - bool "Allwinner A10 SoCs SPI controller" + bool "Allwinner SoCs SPI driver" help - SPI driver for Allwinner sun4i, sun5i and sun7i SoCs + SPI driver for Allwinner SoCs config TEGRA114_SPI bool "nVidia Tegra114 SPI driver" diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c index 38cc743c61..7af8be15cf 100644 --- a/drivers/spi/sun4i_spi.c +++ b/drivers/spi/sun4i_spi.c @@ -37,6 +37,30 @@ #define SUN4I_TXDATA_REG 0x04 +#ifdef CONFIG_SUNXI_GEN_SUN6I +#define SUN4I_CTL_REG 0x04 +#define SUN4I_CTL_ENABLE BIT(0) +#define SUN4I_CTL_MASTER BIT(1) +#define SUN4I_CTL_TP BIT(7) +#define SUN4I_CTL_SRST BIT(31) + +#define SUN4I_CTL_CPHA BIT(0) +#define SUN4I_CTL_CPOL BIT(1) +#define SUN4I_CTL_CS_ACTIVE_LOW BIT(2) +#define SUN4I_CTL_CS_MASK 0x30 +#define SUN4I_CTL_CS(cs) (((cs) << 4) & SUN4I_CTL_CS_MASK) +#define SUN4I_CTL_CS_MANUAL BIT(6) +#define SUN4I_CTL_CS_LEVEL BIT(7) +#define SUN4I_CTL_DHB BIT(8) +#define SUN4I_CTL_XCH_MASK 0x80000000 +#define SUN4I_CTL_XCH BIT(31) + +#define SUN4I_CTL_RF_RST BIT(15) +#define SUN4I_CTL_TF_RST BIT(31) + +#else +#define SUN4I_CTL_SRST 0 + #define SUN4I_CTL_REG 0x08 #define SUN4I_CTL_ENABLE BIT(0) #define SUN4I_CTL_MASTER BIT(1) @@ -54,6 +78,7 @@ #define SUN4I_CTL_CS_MANUAL BIT(16) #define SUN4I_CTL_CS_LEVEL BIT(17) #define SUN4I_CTL_TP BIT(18) +#endif #define SUN4I_INT_CTL_REG 0x0c #define SUN4I_INT_CTL_RF_F34 BIT(4) @@ -92,11 +117,39 @@ #define SUN4I_SPI_DEFAULT_RATE 1000000 #define SUN4I_SPI_TIMEOUT_US 1000000 +#ifdef CONFIG_SUNXI_GEN_SUN6I +/* sun6i spi register set */ +struct sun4i_spi_regs { + u32 res0; + u32 ctl; /* 0x04 */ + u32 tctl; /* 0x08 */ + u32 res1; + u32 intctl; /* 0x10 */ + u32 st; /* 0x14 */ + u32 fifo_ctl; /* 0x18 */ + u32 fifo_sta; /* 0x1c */ + u32 wait; /* 0x20 */ + u32 cctl; /* 0x24 */ + u32 res2[2]; + u32 bc; /* 0x30 */ + u32 tc; /* 0x34 */ + u32 bctl; /* 0x38 */ + u32 res3[113]; + u32 txdata; /* 0x200 */ + u32 res4[63]; + u32 rxdata; /* 0x300 */ +}; +#else /* sun4i spi register set */ struct sun4i_spi_regs { u32 rxdata; u32 txdata; - u32 ctl; + union { + u32 ctl; + u32 tctl; + u32 fifo_ctl; + u32 bctl; + }; u32 intctl; u32 st; u32 dmactl; @@ -106,6 +159,7 @@ struct sun4i_spi_regs { u32 tc; u32 fifo_sta; }; +#endif struct sun4i_spi_platdata { u32 base_addr; @@ -149,7 +203,7 @@ static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable) struct sun4i_spi_priv *priv = dev_get_priv(bus); u32 reg; - reg = readl(&priv->regs->ctl); + reg = readl(&priv->regs->tctl); reg &= ~SUN4I_CTL_CS_MASK; reg |= SUN4I_CTL_CS(cs); @@ -159,7 +213,7 @@ static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable) else reg |= SUN4I_CTL_CS_LEVEL; - writel(reg, &priv->regs->ctl); + writel(reg, &priv->regs->tctl); } static int sun4i_spi_parse_pins(struct udevice *dev) @@ -231,7 +285,10 @@ static int sun4i_spi_parse_pins(struct udevice *dev) if (pin < 0) break; - sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0); + if (IS_ENABLED(CONFIG_MACH_SUN50I)) + sunxi_gpio_set_cfgpin(pin, SUN50I_GPC_SPI0); + else + sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0); sunxi_gpio_set_drv(pin, drive); sunxi_gpio_set_pull(pin, pull); } @@ -244,10 +301,27 @@ static inline void sun4i_spi_enable_clock(void) struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *const)SUNXI_CCM_BASE; +#ifdef CONFIG_SUNXI_GEN_SUN6I + setbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_SPI0)); +#endif + setbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_SPI0)); writel((1 << 31), &ccm->spi0_clk_cfg); } +static inline void sun4i_spi_disable_clock(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *const)SUNXI_CCM_BASE; + + writel(0, &ccm->spi0_clk_cfg); + clrbits_le32(&ccm->ahb_gate0, (1 << AHB_GATE_OFFSET_SPI0)); + +#ifdef CONFIG_SUNXI_GEN_SUN6I + clrbits_le32(&ccm->ahb_reset0_cfg, (1 << AHB_GATE_OFFSET_SPI0)); +#endif +} + static int sun4i_spi_ofdata_to_platdata(struct udevice *bus) { struct sun4i_spi_platdata *plat = dev_get_platdata(bus); @@ -269,7 +343,6 @@ static int sun4i_spi_probe(struct udevice *bus) struct sun4i_spi_platdata *plat = dev_get_platdata(bus); struct sun4i_spi_priv *priv = dev_get_priv(bus); - sun4i_spi_enable_clock(); sun4i_spi_parse_pins(bus); priv->regs = (struct sun4i_spi_regs *)(uintptr_t)plat->base_addr; @@ -282,9 +355,17 @@ static int sun4i_spi_claim_bus(struct udevice *dev) { struct sun4i_spi_priv *priv = dev_get_priv(dev->parent); + sun4i_spi_enable_clock(); writel(SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP | - SUN4I_CTL_CS_MANUAL | SUN4I_CTL_CS_ACTIVE_LOW, + SUN4I_CTL_SRST, &priv->regs->ctl); + + if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) + while (readl(&priv->regs->ctl) & SUN4I_CTL_SRST) + ; + + setbits_le32(&priv->regs->tctl, SUN4I_CTL_CS_MANUAL | + SUN4I_CTL_CS_ACTIVE_LOW); return 0; } @@ -296,6 +377,7 @@ static int sun4i_spi_release_bus(struct udevice *dev) reg = readl(&priv->regs->ctl); reg &= ~SUN4I_CTL_ENABLE; writel(reg, &priv->regs->ctl); + sun4i_spi_disable_clock(); return 0; } @@ -323,10 +405,10 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, if (flags & SPI_XFER_BEGIN) sun4i_spi_set_cs(bus, slave_plat->cs, true); - reg = readl(&priv->regs->ctl); + reg = readl(&priv->regs->fifo_ctl); /* Reset FIFOs */ - writel(reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST, &priv->regs->ctl); + writel(reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST, &priv->regs->fifo_ctl); while (len) { /* Setup the transfer now... */ @@ -335,16 +417,18 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Setup the counters */ writel(SUN4I_BURST_CNT(nbytes), &priv->regs->bc); writel(SUN4I_XMIT_CNT(nbytes), &priv->regs->tc); + if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) + writel(SUN4I_BURST_CNT(nbytes), &priv->regs->bctl); /* Fill the TX FIFO */ sun4i_spi_fill_fifo(priv, nbytes); /* Start the transfer */ - reg = readl(&priv->regs->ctl); - writel(reg | SUN4I_CTL_XCH, &priv->regs->ctl); + reg = readl(&priv->regs->tctl); + writel(reg | SUN4I_CTL_XCH, &priv->regs->tctl); /* Wait transfer to complete */ - ret = wait_for_bit_le32(&priv->regs->ctl, SUN4I_CTL_XCH_MASK, + ret = wait_for_bit_le32(&priv->regs->tctl, SUN4I_CTL_XCH_MASK, false, SUN4I_SPI_TIMEOUT_US, false); if (ret) { printf("ERROR: sun4i_spi: Timeout transferring data\n"); @@ -417,7 +501,7 @@ static int sun4i_spi_set_mode(struct udevice *dev, uint mode) struct sun4i_spi_priv *priv = dev_get_priv(dev); u32 reg; - reg = readl(&priv->regs->ctl); + reg = readl(&priv->regs->tctl); reg &= ~(SUN4I_CTL_CPOL | SUN4I_CTL_CPHA); if (mode & SPI_CPOL) @@ -427,7 +511,7 @@ static int sun4i_spi_set_mode(struct udevice *dev, uint mode) reg |= SUN4I_CTL_CPHA; priv->mode = mode; - writel(reg, &priv->regs->ctl); + writel(reg, &priv->regs->tctl); return 0; } @@ -441,7 +525,13 @@ static const struct dm_spi_ops sun4i_spi_ops = { }; static const struct udevice_id sun4i_spi_ids[] = { +#ifndef CONFIG_SUNXI_GEN_SUN6I { .compatible = "allwinner,sun4i-a10-spi" }, +#else + { .compatible = "allwinner,sun6i-a31-spi" }, + { .compatible = "allwinner,sun8i-h3-spi" }, + { .compatible = "allwinner,sun50i-a64-spi" }, +#endif { } }; -- 2.17.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot