[PATCH v2 08/14] spi: dw: Switch to capabilities
Sean Anderson
seanga2 at gmail.com
Fri Feb 5 05:11:13 CET 2021
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 <seanga2 at gmail.com>
---
(no changes since v1)
drivers/spi/designware_spi.c | 151 +++++++++++++++++------------------
1 file changed, 73 insertions(+), 78 deletions(-)
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 4ef948a0b9..6375e6d778 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, 0);
+
+ /*
+ * 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);
/*
@@ -271,7 +271,6 @@ static void spi_hw_init(struct udevice *bus, struct dw_spi_priv *priv)
priv->fifo_len = (fifo == 1) ? 0 : fifo;
dw_write(priv, DW_SPI_TXFTLR, 0);
}
- dev_dbg(bus, "fifo_len=%d\n", priv->fifo_len);
}
/*
@@ -337,11 +336,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,25 +354,21 @@ static int dw_spi_probe(struct udevice *bus)
if (ret)
return ret;
- if (!init)
- return -EINVAL;
- ret = init(bus, priv);
- if (ret)
- return ret;
-
- 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);
-
/* Currently only bits_per_word == 8 supported */
priv->bits_per_word = 8;
priv->tmode = 0; /* Tx & Rx */
/* Basic HW init */
+ priv->caps = dev_get_driver_data(bus);
spi_hw_init(bus, priv);
+ version = dw_read(priv, DW_SPI_VERSION);
+ dev_dbg(bus,
+ "ssi_version_id=%c.%c%c%c ssi_rx_fifo_depth=%u ssi_max_xfer_size=%u\n",
+ version >> 24, version >> 16, version >> 8, version,
+ priv->fifo_len, priv->caps & DW_SPI_CAP_DFS32 ? 32 : 16);
+
return 0;
}
@@ -510,7 +502,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 +574,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 +734,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 +751,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
More information about the U-Boot
mailing list