On 09/02/2019 13:14, Jagan Teki wrote: > Allwinner support two different SPI controllers one for A10 and > another for A31 with minimal changes in register offsets and > respective register bits, but the logic for accessing the SPI > master via SPI slave remains nearly similar. > > Add enum offsets for register set and register bits, so-that > it can access both classes of SPI controllers. > > Assign same control register for global, transfer and fifo control > registers to make the same code compatible with A31 SPI controller. > > Signed-off-by: Jagan Teki <ja...@amarulasolutions.com> > --- > drivers/spi/sun4i_spi.c | 162 +++++++++++++++++++++++++++++----------- > 1 file changed, 120 insertions(+), 42 deletions(-) > > diff --git a/drivers/spi/sun4i_spi.c b/drivers/spi/sun4i_spi.c > index 5446cebe7c..c06028890b 100644 > --- a/drivers/spi/sun4i_spi.c > +++ b/drivers/spi/sun4i_spi.c > @@ -83,7 +83,6 @@ > #define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) > > #define SUN4I_FIFO_STA_REG 0x28 > -#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f > #define SUN4I_FIFO_STA_RF_CNT_BITS 0 > #define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f > #define SUN4I_FIFO_STA_TF_CNT_BITS 16 > @@ -93,28 +92,49 @@ > #define SUN4I_SPI_DEFAULT_RATE 1000000 > #define SUN4I_SPI_TIMEOUT_US 1000000 > > -/* sun4i spi register set */ > -struct sun4i_spi_regs { > - u32 rxdata; > - u32 txdata; > - u32 ctl; > - u32 intctl; > - u32 st; > - u32 dmactl; > - u32 wait; > - u32 cctl; > - u32 bc; > - u32 tc; > - u32 fifo_sta; > +/* sun spi register set */ > +enum sun4i_spi_regs { > + SPI_GCR, > + SPI_TCR, > + SPI_FCR, > + SPI_FSR, > + SPI_CCR, > + SPI_BC, > + SPI_TC, > + SPI_BCTL, > + SPI_TXD, > + SPI_RXD, > +}; > + > +/* sun spi register bits */ > +enum sun4i_spi_bits { > + SPI_GCR_TP, > + SPI_TCR_CPHA, > + SPI_TCR_CPOL, > + SPI_TCR_CS_ACTIVE_LOW, > + SPI_TCR_CS_SEL, > + SPI_TCR_CS_MASK, > + SPI_TCR_XCH, > + SPI_TCR_CS_MANUAL, > + SPI_TCR_CS_LEVEL, > + SPI_FCR_TF_RST, > + SPI_FCR_RF_RST, > + SPI_FSR_RF_CNT_MASK, > +}; > + > +struct sun4i_spi_variant { > + const unsigned long *regs, *bits; > }; > > struct sun4i_spi_platdata { > + struct sun4i_spi_variant *variant; > u32 base_addr; > u32 max_hz; > }; > > struct sun4i_spi_priv { > - struct sun4i_spi_regs *regs; > + struct sun4i_spi_variant *variant; > + u32 base_addr; > u32 freq; > u32 mode; > > @@ -126,10 +146,11 @@ DECLARE_GLOBAL_DATA_PTR; > > static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len) > { > + struct sun4i_spi_variant *variant = priv->variant; > u8 byte; > > while (len--) { > - byte = readb(&priv->regs->rxdata); > + byte = readb(priv->base_addr + variant->regs[SPI_RXD]);
What about making this register address calculation a macro? That would also allow you to save the variant variable everywhere. #define SPI_REG(priv, reg) ((priv)->base_addr + \ (priv)->variant->regs[reg]) Cheers, Andre. > if (priv->rx_buf) > *priv->rx_buf++ = byte; > } > @@ -137,30 +158,33 @@ static inline void sun4i_spi_drain_fifo(struct > sun4i_spi_priv *priv, int len) > > static inline void sun4i_spi_fill_fifo(struct sun4i_spi_priv *priv, int len) > { > + struct sun4i_spi_variant *variant = priv->variant; > u8 byte; > > while (len--) { > byte = priv->tx_buf ? *priv->tx_buf++ : 0; > - writeb(byte, &priv->regs->txdata); > + writeb(byte, priv->base_addr + variant->regs[SPI_TXD]); > } > } > > static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable) > { > struct sun4i_spi_priv *priv = dev_get_priv(bus); > + struct sun4i_spi_variant *variant = priv->variant; > u32 reg; > > - reg = readl(&priv->regs->ctl); > + reg = readl(priv->base_addr + variant->regs[SPI_TCR]); > > - reg &= ~SUN4I_CTL_CS_MASK; > - reg |= SUN4I_CTL_CS(cs); > + reg &= ~variant->bits[SPI_TCR_CS_MASK]; > + reg |= ((cs << variant->bits[SPI_TCR_CS_SEL]) & > + variant->bits[SPI_TCR_CS_MASK]); > > if (enable) > - reg &= ~SUN4I_CTL_CS_LEVEL; > + reg &= ~variant->bits[SPI_TCR_CS_LEVEL]; > else > - reg |= SUN4I_CTL_CS_LEVEL; > + reg |= variant->bits[SPI_TCR_CS_LEVEL]; > > - writel(reg, &priv->regs->ctl); > + writel(reg, priv->base_addr + variant->regs[SPI_TCR]); > } > > static int sun4i_spi_parse_pins(struct udevice *dev) > @@ -255,6 +279,7 @@ static int sun4i_spi_ofdata_to_platdata(struct udevice > *bus) > int node = dev_of_offset(bus); > > plat->base_addr = devfdt_get_addr(bus); > + plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus); > plat->max_hz = fdtdec_get_int(gd->fdt_blob, node, > "spi-max-frequency", > SUN4I_SPI_DEFAULT_RATE); > @@ -273,7 +298,8 @@ static int sun4i_spi_probe(struct udevice *bus) > sun4i_spi_enable_clock(); > sun4i_spi_parse_pins(bus); > > - priv->regs = (struct sun4i_spi_regs *)(uintptr_t)plat->base_addr; > + priv->variant = plat->variant; > + priv->base_addr = plat->base_addr; > priv->freq = plat->max_hz; > > return 0; > @@ -282,10 +308,15 @@ static int sun4i_spi_probe(struct udevice *bus) > static int sun4i_spi_claim_bus(struct udevice *dev) > { > struct sun4i_spi_priv *priv = dev_get_priv(dev->parent); > + struct sun4i_spi_variant *variant = priv->variant; > + > + setbits_le32(priv->base_addr + variant->regs[SPI_GCR], > + SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | > + variant->bits[SPI_GCR_TP]); > > - setbits_le32(&priv->regs->ctl, SUN4I_CTL_ENABLE | > - SUN4I_CTL_MASTER | SUN4I_CTL_TP | > - SUN4I_CTL_CS_MANUAL | SUN4I_CTL_CS_ACTIVE_LOW); > + setbits_le32(priv->base_addr + variant->regs[SPI_TCR], > + variant->bits[SPI_TCR_CS_MANUAL] | > + variant->bits[SPI_TCR_CS_ACTIVE_LOW]); > > return 0; > } > @@ -293,8 +324,10 @@ static int sun4i_spi_claim_bus(struct udevice *dev) > static int sun4i_spi_release_bus(struct udevice *dev) > { > struct sun4i_spi_priv *priv = dev_get_priv(dev->parent); > + struct sun4i_spi_variant *variant = priv->variant; > > - clrbits_le32(&priv->regs->ctl, SUN4I_CTL_ENABLE); > + clrbits_le32(priv->base_addr + variant->regs[SPI_GCR], > + SUN4I_CTL_ENABLE); > > return 0; > } > @@ -304,6 +337,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned > int bitlen, > { > struct udevice *bus = dev->parent; > struct sun4i_spi_priv *priv = dev_get_priv(bus); > + struct sun4i_spi_variant *variant = priv->variant; > struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); > > u32 len = bitlen / 8; > @@ -323,25 +357,32 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned > int bitlen, > sun4i_spi_set_cs(bus, slave_plat->cs, true); > > /* Reset FIFOs */ > - setbits_le32(&priv->regs->ctl, SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST); > + setbits_le32(priv->base_addr + variant->regs[SPI_FCR], > + variant->bits[SPI_FCR_RF_RST] | > + variant->bits[SPI_FCR_TF_RST]); > > while (len) { > /* Setup the transfer now... */ > nbytes = min(len, (u32)(SUN4I_FIFO_DEPTH - 1)); > > /* Setup the counters */ > - writel(SUN4I_BURST_CNT(nbytes), &priv->regs->bc); > - writel(SUN4I_XMIT_CNT(nbytes), &priv->regs->tc); > + writel(SUN4I_BURST_CNT(nbytes), > + priv->base_addr + variant->regs[SPI_BC]); > + writel(SUN4I_XMIT_CNT(nbytes), > + priv->base_addr + variant->regs[SPI_TC]); > > /* Fill the TX FIFO */ > sun4i_spi_fill_fifo(priv, nbytes); > > /* Start the transfer */ > - setbits_le32(&priv->regs->ctl, SUN4I_CTL_XCH); > + setbits_le32(priv->base_addr + variant->regs[SPI_TCR], > + variant->bits[SPI_TCR_XCH]); > > /* Wait till RX FIFO to be empty */ > - ret = readl_poll_timeout(&priv->regs->ctl, rx_fifocnt, > - !(((rx_fifocnt & > SUN4I_FIFO_STA_RF_CNT_MASK) >> > + ret = readl_poll_timeout(priv->base_addr + > variant->regs[SPI_FSR], > + rx_fifocnt, > + !(((rx_fifocnt & > + variant->bits[SPI_FSR_RF_CNT_MASK]) >> > SUN4I_FIFO_STA_RF_CNT_BITS) < nbytes), > SUN4I_SPI_TIMEOUT_US); > if (ret < 0) { > @@ -366,6 +407,7 @@ static int sun4i_spi_set_speed(struct udevice *dev, uint > speed) > { > struct sun4i_spi_platdata *plat = dev_get_platdata(dev); > struct sun4i_spi_priv *priv = dev_get_priv(dev); > + struct sun4i_spi_variant *variant = priv->variant; > unsigned int div; > u32 reg; > > @@ -390,7 +432,7 @@ static int sun4i_spi_set_speed(struct udevice *dev, uint > speed) > */ > > div = SUN4I_SPI_MAX_RATE / (2 * speed); > - reg = readl(&priv->regs->cctl); > + reg = readl(priv->base_addr + variant->regs[SPI_CCR]); > > if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) { > if (div > 0) > @@ -405,7 +447,7 @@ static int sun4i_spi_set_speed(struct udevice *dev, uint > speed) > } > > priv->freq = speed; > - writel(reg, &priv->regs->cctl); > + writel(reg, priv->base_addr + variant->regs[SPI_CCR]); > > return 0; > } > @@ -413,19 +455,20 @@ static int sun4i_spi_set_speed(struct udevice *dev, > uint speed) > static int sun4i_spi_set_mode(struct udevice *dev, uint mode) > { > struct sun4i_spi_priv *priv = dev_get_priv(dev); > + struct sun4i_spi_variant *variant = priv->variant; > u32 reg; > > - reg = readl(&priv->regs->ctl); > - reg &= ~(SUN4I_CTL_CPOL | SUN4I_CTL_CPHA); > + reg = readl(priv->base_addr + variant->regs[SPI_TCR]); > + reg &= ~(variant->bits[SPI_TCR_CPOL] | variant->bits[SPI_TCR_CPHA]); > > if (mode & SPI_CPOL) > - reg |= SUN4I_CTL_CPOL; > + reg |= variant->bits[SPI_TCR_CPOL]; > > if (mode & SPI_CPHA) > - reg |= SUN4I_CTL_CPHA; > + reg |= variant->bits[SPI_TCR_CPHA]; > > priv->mode = mode; > - writel(reg, &priv->regs->ctl); > + writel(reg, priv->base_addr + variant->regs[SPI_TCR]); > > return 0; > } > @@ -438,8 +481,43 @@ static const struct dm_spi_ops sun4i_spi_ops = { > .set_mode = sun4i_spi_set_mode, > }; > > +static const unsigned long sun4i_spi_regs[] = { > + [SPI_GCR] = SUN4I_CTL_REG, > + [SPI_TCR] = SUN4I_CTL_REG, > + [SPI_FCR] = SUN4I_CTL_REG, > + [SPI_FSR] = SUN4I_FIFO_STA_REG, > + [SPI_CCR] = SUN4I_CLK_CTL_REG, > + [SPI_BC] = SUN4I_BURST_CNT_REG, > + [SPI_TC] = SUN4I_XMIT_CNT_REG, > + [SPI_TXD] = SUN4I_TXDATA_REG, > + [SPI_RXD] = SUN4I_RXDATA_REG, > +}; > + > +static const unsigned long sun4i_spi_bits[] = { > + [SPI_GCR_TP] = BIT(18), > + [SPI_TCR_CPHA] = BIT(2), > + [SPI_TCR_CPOL] = BIT(3), > + [SPI_TCR_CS_ACTIVE_LOW] = BIT(4), > + [SPI_TCR_XCH] = BIT(10), > + [SPI_TCR_CS_SEL] = 12, > + [SPI_TCR_CS_MASK] = 0x3000, > + [SPI_TCR_CS_MANUAL] = BIT(16), > + [SPI_TCR_CS_LEVEL] = BIT(17), > + [SPI_FCR_TF_RST] = BIT(8), > + [SPI_FCR_RF_RST] = BIT(9), > + [SPI_FSR_RF_CNT_MASK] = GENMASK(6, 0), > +}; > + > +static const struct sun4i_spi_variant sun4i_a10_spi_variant = { > + .regs = sun4i_spi_regs, > + .bits = sun4i_spi_bits, > +}; > + > static const struct udevice_id sun4i_spi_ids[] = { > - { .compatible = "allwinner,sun4i-a10-spi" }, > + { > + .compatible = "allwinner,sun4i-a10-spi", > + .data = (ulong)&sun4i_a10_spi_variant, > + }, > { } > }; > > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot