[U-Boot] [PATCH 1/2] arm: sunxi: allwinner spi driver sun6i support

Oskari Lemmela oskari at lemmela.net
Sat Jan 5 17:52:15 UTC 2019


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 <oskari at 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



More information about the U-Boot mailing list