public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Sean Anderson <seanga2@gmail.com>
To: u-boot@lists.denx.de
Subject: [PATCH 08/14] spi: dw: Switch to capabilities
Date: Sun, 31 Jan 2021 19:34:30 -0500	[thread overview]
Message-ID: <20210201003436.1180667-9-seanga2@gmail.com> (raw)
In-Reply-To: <20210201003436.1180667-1-seanga2@gmail.com>

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@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

  parent reply	other threads:[~2021-02-01  0:34 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-01  0:34 [PATCH 00/14] spi: dw: Add support for DUAL/QUAD/OCTAL modes Sean Anderson
2021-02-01  0:34 ` [PATCH 01/14] cmd: sf: Display errno on erase failure Sean Anderson
2021-02-01  5:06   ` Bin Meng
2021-02-01 12:51   ` Pratyush Yadav
2021-02-01  0:34 ` [PATCH 02/14] cmd: sf: Print error on test failure Sean Anderson
2021-02-01  5:06   ` Bin Meng
2021-02-01 12:54   ` Pratyush Yadav
2021-02-01  0:34 ` [PATCH 03/14] mtd: spi-nor-core: Fix typo in documentation Sean Anderson
2021-02-01  5:06   ` Bin Meng
2021-02-01 12:23   ` Pratyush Yadav
2021-02-01  0:34 ` [PATCH 04/14] mtd: spi-mem: Export spi_mem_default_supports_op Sean Anderson
2021-02-01  5:06   ` Bin Meng
2021-02-01 12:07   ` Pratyush Yadav
2021-02-01 15:15     ` Sean Anderson
2021-02-01  0:34 ` [PATCH 05/14] spi: spi-mem: Add debug message for spi-mem ops Sean Anderson
2021-02-01  5:06   ` Bin Meng
2021-02-01 12:18   ` Pratyush Yadav
2021-02-01 15:33     ` Sean Anderson
2021-02-01 16:34       ` Pratyush Yadav
2021-02-01  0:34 ` [PATCH 06/14] spi: dw: Log status register on timeout Sean Anderson
2021-02-01  0:34 ` [PATCH 07/14] spi: dw: Mask all possible interrupts Sean Anderson
2021-02-04  4:51   ` Sean Anderson
2021-02-01  0:34 ` Sean Anderson [this message]
2021-02-01  0:34 ` [PATCH 09/14] spi: dw: Rewrite poll_transfer logic Sean Anderson
2021-02-01  0:34 ` [PATCH 10/14] spi: dw: Add DUAL/QUAD/OCTAL caps Sean Anderson
2021-02-01 18:00   ` Sean Anderson
2021-02-01  0:34 ` [PATCH 11/14] spi: dw: Add registers necessary for DUAL/QUAD/OCTAL Sean Anderson
2021-02-01  0:34 ` [PATCH 12/14] spi: dw: Support DUAL/QUAD/OCTAL Sean Anderson
2021-02-01  0:34 ` [PATCH 13/14] spi: dw: Support clock stretching Sean Anderson
2021-02-01  0:34 ` [PATCH 14/14] riscv: k210: Enable QSPI for spi3 Sean Anderson
2021-02-01  5:16   ` Bin Meng
2021-02-04  2:32   ` Leo Liang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210201003436.1180667-9-seanga2@gmail.com \
    --to=seanga2@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox