Since zynq_spi device is compatible with Linux Cadence SPI driver, which
supports chip select (CS) decoder, this patch adds the same logic for
u-boot Zynq SPI driver. As a reference, I have used Xilinx Linux kernel
93dc4dbd16d (xilinx-v2020.2).

The SPI decoder feature has been tested on ZynqMP ARM processor and
result has been compared with Linux Cadence SPI driver.

Signed-off-by: Nikita Vasilev <[email protected]>
Cc: Jagan Teki <[email protected]>
---
 drivers/spi/zynq_spi.c | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c
index b3e0858eb9..40a43612fb 100644
--- a/drivers/spi/zynq_spi.c
+++ b/drivers/spi/zynq_spi.c
@@ -29,6 +29,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #define ZYNQ_SPI_CR_CPHA_MASK          BIT(2)  /* Clock phase */
 #define ZYNQ_SPI_CR_CPOL_MASK          BIT(1)  /* Clock polarity */
 #define ZYNQ_SPI_CR_MSTREN_MASK                BIT(0)  /* Mode select */
+#define ZYNQ_SPI_CR_PERI_SEL           BIT(9)  /* Peripheral select decode */
 #define ZYNQ_SPI_IXR_RXNEMPTY_MASK     BIT(4)  /* RX_FIFO_not_empty */
 #define ZYNQ_SPI_IXR_TXOW_MASK         BIT(2)  /* TX_FIFO_not_full */
 #define ZYNQ_SPI_IXR_ALL_MASK          GENMASK(6, 0)   /* All IXR bits */
@@ -62,6 +63,7 @@ struct zynq_spi_plat {
        u32 speed_hz;
        uint deactivate_delay_us;       /* Delay to wait after deactivate */
        uint activate_delay_us;         /* Delay to wait after activate */
+       u32 is_decoded_cs;
 };
  /* zynq spi priv */
@@ -87,10 +89,13 @@ static int zynq_spi_of_to_plat(struct udevice *bus)
        plat->activate_delay_us = fdtdec_get_int(blob, node,
                                                 "spi-activate-delay", 0);
 +      plat->is_decoded_cs = dev_read_u32_default(bus, "is-decoded-cs", 0);
+
        return 0;
 }
 -static void zynq_spi_init_hw(struct zynq_spi_priv *priv)
+static void zynq_spi_init_hw(struct zynq_spi_priv *priv,
+                            struct zynq_spi_platdata const *plat)
 {
        struct zynq_spi_regs *regs = priv->regs;
        u32 confr;
@@ -114,6 +119,10 @@ static void zynq_spi_init_hw(struct zynq_spi_priv *priv)
        confr = ZYNQ_SPI_CR_MCS_MASK | ZYNQ_SPI_CR_CS_MASK |
                ZYNQ_SPI_CR_MSTREN_MASK;
        confr &= ~ZYNQ_SPI_CR_MSA_MASK;
+
+       if (plat->is_decoded_cs)
+               confr |= ZYNQ_SPI_CR_PERI_SEL;
+
        writel(confr, &regs->cr);
        /* Enable SPI */
@@ -150,7 +159,7 @@ static int zynq_spi_probe(struct udevice *bus)
        }
        /* init the zynq spi hw */
-       zynq_spi_init_hw(priv);
+       zynq_spi_init_hw(priv, plat);
        plat->frequency = clock;
        plat->speed_hz = plat->frequency / 2;
@@ -178,13 +187,19 @@ static void spi_cs_activate(struct udevice *dev)
        clrbits_le32(&regs->cr, ZYNQ_SPI_CR_CS_MASK);
        cr = readl(&regs->cr);
-       /*
-        * CS cal logic: CS[13:10]
-        * xxx0 - cs0
-        * xx01 - cs1
-        * x011 - cs2
-        */
-       cr |= (~(1 << priv->cs) << ZYNQ_SPI_CR_SS_SHIFT) & ZYNQ_SPI_CR_CS_MASK;
+
+       if (plat->is_decoded_cs) {
+               cr |= (priv->cs << ZYNQ_SPI_CR_SS_SHIFT) & ZYNQ_SPI_CR_CS_MASK;
+       } else {
+               /*
+                * CS cal logic: CS[13:10]
+                * xxx0 - cs0
+                * xx01 - cs1
+                * x011 - cs2
+                */
+               cr |= (~(1 << priv->cs) << ZYNQ_SPI_CR_SS_SHIFT) & 
ZYNQ_SPI_CR_CS_MASK;
+       }
+
        writel(cr, &regs->cr);
        if (plat->activate_delay_us)
--
2.32.0

Changes for v2:
- I have made a mistake when was trying to send patch and all tabs were gone. Since it's my first time when I send patches via email, I have some problems with it.

Reply via email to