Since Linux commit cc760f3143f5 ("spi: dw: Convert CS-override to DW SPI
capabilities"), the Linux driver has used capability flags instead of
using ad-hoc flags and functions. This is a great idea, and we should use
it as well.

The .data field in the compatible array has switched from being an
initialization function to being a set of default capabilities. This is
necessary since some capabilities cannot be determined at runtime.

Signed-off-by: Sean Anderson <sean...@gmail.com>
---

 drivers/spi/designware_spi.c | 141 +++++++++++++++++------------------
 1 file changed, 69 insertions(+), 72 deletions(-)

diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 29ec1503fd..9a30a677c8 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -123,9 +123,13 @@ struct dw_spi_priv {
        struct reset_ctl_bulk resets;
        struct gpio_desc cs_gpio;       /* External chip-select gpio */
 
-       u32 (*update_cr0)(struct dw_spi_priv *priv);
-
        void __iomem *regs;
+/* DW SPI capabilities */
+#define DW_SPI_CAP_CS_OVERRIDE         BIT(0) /* Unimplemented */
+#define DW_SPI_CAP_KEEMBAY_MST         BIT(1) /* Unimplemented */
+#define DW_SPI_CAP_DWC_SSI             BIT(2)
+#define DW_SPI_CAP_DFS32               BIT(3)
+       unsigned long caps;
        unsigned long bus_clk_rate;
        unsigned int freq;              /* Default frequency */
        unsigned int mode;
@@ -135,7 +139,6 @@ struct dw_spi_priv {
        void *rx;
        void *rx_end;
        u32 fifo_len;                   /* depth of the FIFO buffer */
-       u32 max_xfer;                   /* Maximum transfer size (in bits) */
 
        int bits_per_word;
        int len;
@@ -154,51 +157,30 @@ static inline void dw_write(struct dw_spi_priv *priv, u32 
offset, u32 val)
        __raw_writel(val, priv->regs + offset);
 }
 
-static u32 dw_spi_dw16_update_cr0(struct dw_spi_priv *priv)
+static u32 dw_spi_update_cr0(struct dw_spi_priv *priv)
 {
-       return FIELD_PREP(CTRLR0_DFS_MASK, priv->bits_per_word - 1)
-            | FIELD_PREP(CTRLR0_FRF_MASK, priv->type)
-            | FIELD_PREP(CTRLR0_MODE_MASK, priv->mode)
-            | FIELD_PREP(CTRLR0_TMOD_MASK, priv->tmode);
-}
+       u32 cr0;
 
-static u32 dw_spi_dw32_update_cr0(struct dw_spi_priv *priv)
-{
-       return FIELD_PREP(CTRLR0_DFS_32_MASK, priv->bits_per_word - 1)
-            | FIELD_PREP(CTRLR0_FRF_MASK, priv->type)
-            | FIELD_PREP(CTRLR0_MODE_MASK, priv->mode)
-            | FIELD_PREP(CTRLR0_TMOD_MASK, priv->tmode);
-}
-
-static u32 dw_spi_dwc_update_cr0(struct dw_spi_priv *priv)
-{
-       return FIELD_PREP(DWC_SSI_CTRLR0_DFS_MASK, priv->bits_per_word - 1)
-            | FIELD_PREP(DWC_SSI_CTRLR0_FRF_MASK, priv->type)
-            | FIELD_PREP(DWC_SSI_CTRLR0_MODE_MASK, priv->mode)
-            | FIELD_PREP(DWC_SSI_CTRLR0_TMOD_MASK, priv->tmode);
-}
-
-static int dw_spi_apb_init(struct udevice *bus, struct dw_spi_priv *priv)
-{
-       /* If we read zeros from DFS, then we need to use DFS_32 instead */
-       dw_write(priv, DW_SPI_SSIENR, 0);
-       dw_write(priv, DW_SPI_CTRLR0, 0xffffffff);
-       if (FIELD_GET(CTRLR0_DFS_MASK, dw_read(priv, DW_SPI_CTRLR0))) {
-               priv->max_xfer = 16;
-               priv->update_cr0 = dw_spi_dw16_update_cr0;
+       if (priv->caps & DW_SPI_CAP_DWC_SSI) {
+               cr0 = FIELD_PREP(DWC_SSI_CTRLR0_DFS_MASK,
+                                priv->bits_per_word - 1)
+                   | FIELD_PREP(DWC_SSI_CTRLR0_FRF_MASK, priv->type)
+                   | FIELD_PREP(DWC_SSI_CTRLR0_MODE_MASK, priv->mode)
+                   | FIELD_PREP(DWC_SSI_CTRLR0_TMOD_MASK, priv->tmode);
        } else {
-               priv->max_xfer = 32;
-               priv->update_cr0 = dw_spi_dw32_update_cr0;
+               if (priv->caps & DW_SPI_CAP_DFS32)
+                       cr0 = FIELD_PREP(CTRLR0_DFS_32_MASK,
+                                        priv->bits_per_word - 1);
+               else
+                       cr0 = FIELD_PREP(CTRLR0_DFS_MASK,
+                                        priv->bits_per_word - 1);
+
+               cr0 |= FIELD_PREP(CTRLR0_FRF_MASK, priv->type)
+                   |  FIELD_PREP(CTRLR0_MODE_MASK, priv->mode)
+                   |  FIELD_PREP(CTRLR0_TMOD_MASK, priv->tmode);
        }
 
-       return 0;
-}
-
-static int dw_spi_dwc_init(struct udevice *bus, struct dw_spi_priv *priv)
-{
-       priv->max_xfer = 32;
-       priv->update_cr0 = dw_spi_dwc_update_cr0;
-       return 0;
+       return cr0;
 }
 
 static int request_gpio_cs(struct udevice *bus)
@@ -251,8 +233,26 @@ static int dw_spi_of_to_plat(struct udevice *bus)
 /* Restart the controller, disable all interrupts, clean rx fifo */
 static void spi_hw_init(struct udevice *bus, struct dw_spi_priv *priv)
 {
+       u32 cr0;
+
        dw_write(priv, DW_SPI_SSIENR, 0);
        dw_write(priv, DW_SPI_IMR, 0xFFFFFFFF);
+
+       /*
+        * Detect features by writing CTRLR0 and seeing which fields remain
+        * zeroed.
+        */
+       dw_write(priv, DW_SPI_SSIENR, 0);
+       dw_write(priv, DW_SPI_CTRLR0, 0xffffffff);
+       cr0 = dw_read(priv, DW_SPI_CTRLR0);
+
+       /*
+        * DWC_SPI always has DFS_32. If we read zeros from DFS, then we need to
+        * use DFS_32 instead
+        */
+       if (priv->caps & DW_SPI_CAP_DWC_SSI || !FIELD_GET(CTRLR0_DFS_MASK, cr0))
+               priv->caps |= DW_SPI_CAP_DFS32;
+
        dw_write(priv, DW_SPI_SSIENR, 1);
 
        /*
@@ -337,11 +337,8 @@ static int dw_spi_reset(struct udevice *bus)
        return 0;
 }
 
-typedef int (*dw_spi_init_t)(struct udevice *bus, struct dw_spi_priv *priv);
-
 static int dw_spi_probe(struct udevice *bus)
 {
-       dw_spi_init_t init = (dw_spi_init_t)dev_get_driver_data(bus);
        struct dw_spi_plat *plat = dev_get_plat(bus);
        struct dw_spi_priv *priv = dev_get_priv(bus);
        int ret;
@@ -358,16 +355,13 @@ static int dw_spi_probe(struct udevice *bus)
        if (ret)
                return ret;
 
-       if (!init)
-               return -EINVAL;
-       ret = init(bus, priv);
-       if (ret)
-               return ret;
+       priv->caps = dev_get_driver_data(bus);
+       dw_spi_detect_caps(bus, priv);
 
        version = dw_read(priv, DW_SPI_VERSION);
        dev_dbg(bus, "ssi_version_id=%c.%c%c%c ssi_max_xfer_size=%u\n",
                version >> 24, version >> 16, version >> 8, version,
-               priv->max_xfer);
+               priv->caps & DW_SPI_CAP_DFS32 ? 32 : 16);
 
        /* Currently only bits_per_word == 8 supported */
        priv->bits_per_word = 8;
@@ -510,7 +504,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int 
bitlen,
                 */
                priv->tmode = CTRLR0_TMOD_TR;
 
-       cr0 = priv->update_cr0(priv);
+       cr0 = dw_spi_update_cr0(priv);
 
        priv->len = bitlen >> 3;
 
@@ -582,7 +576,7 @@ static int dw_spi_exec_op(struct spi_slave *slave, const 
struct spi_mem_op *op)
        else
                priv->tmode = CTRLR0_TMOD_TO;
 
-       cr0 = priv->update_cr0(priv);
+       cr0 = dw_spi_update_cr0(priv);
        dev_dbg(bus, "cr0=%08x buf=%p len=%u [bytes]\n", cr0, op->data.buf.in,
                op->data.nbytes);
 
@@ -742,15 +736,15 @@ static const struct dm_spi_ops dw_spi_ops = {
 static const struct udevice_id dw_spi_ids[] = {
        /* Generic compatible strings */
 
-       { .compatible = "snps,dw-apb-ssi", .data = (ulong)dw_spi_apb_init },
-       { .compatible = "snps,dw-apb-ssi-3.20a", .data = (ulong)dw_spi_apb_init 
},
-       { .compatible = "snps,dw-apb-ssi-3.22a", .data = (ulong)dw_spi_apb_init 
},
+       { .compatible = "snps,dw-apb-ssi" },
+       { .compatible = "snps,dw-apb-ssi-3.20a" },
+       { .compatible = "snps,dw-apb-ssi-3.22a" },
        /* First version with SSI_MAX_XFER_SIZE */
-       { .compatible = "snps,dw-apb-ssi-3.23a", .data = (ulong)dw_spi_apb_init 
},
-       /* First version with Dual/Quad SPI; unused by this driver */
-       { .compatible = "snps,dw-apb-ssi-4.00a", .data = (ulong)dw_spi_apb_init 
},
-       { .compatible = "snps,dw-apb-ssi-4.01", .data = (ulong)dw_spi_apb_init 
},
-       { .compatible = "snps,dwc-ssi-1.01a", .data = (ulong)dw_spi_dwc_init },
+       { .compatible = "snps,dw-apb-ssi-3.23a" },
+       /* First version with Dual/Quad SPI */
+       { .compatible = "snps,dw-apb-ssi-4.00a" },
+       { .compatible = "snps,dw-apb-ssi-4.01" },
+       { .compatible = "snps,dwc-ssi-1.01a", .data = DW_SPI_CAP_DWC_SSI },
 
        /* Compatible strings for specific SoCs */
 
@@ -759,16 +753,19 @@ static const struct udevice_id dw_spi_ids[] = {
         * version of this device. This compatible string is used for those
         * devices, and is not used for sofpgas in general.
         */
-       { .compatible = "altr,socfpga-spi", .data = (ulong)dw_spi_apb_init },
-       { .compatible = "altr,socfpga-arria10-spi", .data = 
(ulong)dw_spi_apb_init },
-       { .compatible = "canaan,kendryte-k210-spi", .data = 
(ulong)dw_spi_apb_init },
-       { .compatible = "canaan,kendryte-k210-ssi", .data = 
(ulong)dw_spi_dwc_init },
-       { .compatible = "intel,stratix10-spi", .data = (ulong)dw_spi_apb_init },
-       { .compatible = "intel,agilex-spi", .data = (ulong)dw_spi_apb_init },
-       { .compatible = "mscc,ocelot-spi", .data = (ulong)dw_spi_apb_init },
-       { .compatible = "mscc,jaguar2-spi", .data = (ulong)dw_spi_apb_init },
-       { .compatible = "snps,axs10x-spi", .data = (ulong)dw_spi_apb_init },
-       { .compatible = "snps,hsdk-spi", .data = (ulong)dw_spi_apb_init },
+       { .compatible = "altr,socfpga-spi" },
+       { .compatible = "altr,socfpga-arria10-spi" },
+       { .compatible = "canaan,kendryte-k210-spi" },
+       {
+               .compatible = "canaan,kendryte-k210-ssi",
+               .data = DW_SPI_CAP_DWC_SSI,
+       },
+       { .compatible = "intel,stratix10-spi" },
+       { .compatible = "intel,agilex-spi" },
+       { .compatible = "mscc,ocelot-spi" },
+       { .compatible = "mscc,jaguar2-spi" },
+       { .compatible = "snps,axs10x-spi" },
+       { .compatible = "snps,hsdk-spi" },
        { }
 };
 
-- 
2.29.2

Reply via email to