Created
January 3, 2019 17:33
-
-
Save olemmela/83bf430448bbb86608618944d60f673c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From ffdd7cc3da6c913f86548fb502978271b3ddca96 Mon Sep 17 00:00:00 2001 | |
From: Oskari Lemmela <oskari@lemmela.net> | |
Date: Sat, 29 Dec 2018 10:55:20 +0200 | |
Subject: [PATCH] arm: sunxi: Allwinner SPI driver sun6i support | |
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@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 | 115 ++++++++++++++++-- | |
4 files changed, 106 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 b86b5a00ad..75ae1a041e 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,41 @@ | |
#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 +161,7 @@ struct sun4i_spi_regs { | |
u32 tc; | |
u32 fifo_sta; | |
}; | |
+#endif | |
struct sun4i_spi_platdata { | |
u32 base_addr; | |
@@ -148,7 +204,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); | |
@@ -158,7 +214,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) | |
@@ -230,7 +286,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); | |
} | |
@@ -243,10 +302,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); | |
@@ -268,7 +344,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; | |
@@ -281,9 +356,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; | |
} | |
@@ -295,6 +378,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; | |
} | |
@@ -322,10 +406,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... */ | |
@@ -334,16 +418,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"); | |
@@ -416,7 +502,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) | |
@@ -426,7 +512,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,6 +527,9 @@ static const struct dm_spi_ops sun4i_spi_ops = { | |
static const struct udevice_id sun4i_spi_ids[] = { | |
{ .compatible = "allwinner,sun4i-a10-spi" }, | |
+ { .compatible = "allwinner,sun6i-a31-spi" }, | |
+ { .compatible = "allwinner,sun8i-h3-spi" }, | |
+ { .compatible = "allwinner,sun50i-a64-spi" }, | |
{ } | |
}; | |
-- | |
2.17.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment