[PATCH 10/14] spi: dw: Add DUAL/QUAD/OCTAL caps

Sean Anderson
2021-02-01T00:34:32Z

These capabilities correspond to SSIC_SPI_MODE of 1, 2, or 3, respectively.
This doesn't do much yet, but it does add support for detection and for
disallowing unsupported modes. Unfortunately, we cannot discriminate
between these modes (only that SSIC_SPI_MODE != 0), so we only assume DUAL
if something sticks to SPI_FRF.

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

drivers/spi/designware_spi.c | 41 +++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 683394a5a4..1dd83e6ca6 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -129,6 +129,9 @@ struct dw_spi_priv {
#define DW_SPI_CAP_KEEMBAY_MST BIT(1) /* Unimplemented */
#define DW_SPI_CAP_DWC_SSI BIT(2)
#define DW_SPI_CAP_DFS32 BIT(3)
+#define DW_SPI_CAP_DUAL BIT(4)
+#define DW_SPI_CAP_QUAD BIT(5)
+#define DW_SPI_CAP_OCTAL BIT(5)
unsigned long caps;
unsigned long bus_clk_rate;
unsigned int freq; /* Default frequency */
@@ -141,6 +144,7 @@ struct dw_spi_priv {
u8 cs; /* chip select pin */
u8 tmode; /* TR/TO/RO/EEPROM */
u8 type; /* SPI/SSP/MicroWire */
+ u8 spi_frf; /* BYTE/DUAL/QUAD/OCTAL */
};

static inline u32 dw_read(struct dw_spi_priv *priv, u32 offset)
@@ -267,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);
}

/*
@@ -351,22 +354,21 @@ static int dw_spi_probe(struct udevice *bus)
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->caps & DW_SPI_CAP_DFS32 ? 32 : 16);
-
/* 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;
}

@@ -748,13 +750,25 @@ static int dw_spi_set_mode(struct udevice *bus, uint mode)
{
struct dw_spi_priv *priv = dev_get_priv(bus);

+ if (!(priv->caps & DW_SPI_CAP_DUAL) &&
+ (mode & (SPI_RX_DUAL | SPI_TX_DUAL)))
+ return -EINVAL;
+
+ if (!(priv->caps & DW_SPI_CAP_QUAD) &&
+ (mode & (SPI_RX_QUAD | SPI_TX_QUAD)))
+ return -EINVAL;
+
+ if (!(priv->caps & DW_SPI_CAP_OCTAL) &&
+ (mode & (SPI_RX_OCTAL | SPI_TX_OCTAL)))
+ return -EINVAL;
+
/*
* Can't set mode yet. Since this depends on if rx, tx, or
* rx & tx is requested. So we have to defer this to the
* real transfer function.
*/
priv->mode = mode;
- dev_dbg(bus, "mode=%d\n", priv->mode);
+ dev_dbg(bus, "mode=%x\n", mode);

return 0;
}
@@ -813,10 +827,13 @@ static const struct udevice_id dw_spi_ids[] = {
*/
{ .compatible = "altr,socfpga-spi" },
{ .compatible = "altr,socfpga-arria10-spi" },
- { .compatible = "canaan,kendryte-k210-spi" },
+ {
+ .compatible = "canaan,kendryte-k210-spi",
+ .data = DW_SPI_CAP_QUAD | DW_SPI_CAP_OCTAL,
+ },
{
.compatible = "canaan,kendryte-k210-ssi",
- .data = DW_SPI_CAP_DWC_SSI,
+ .data = DW_SPI_CAP_DWC_SSI | DW_SPI_CAP_QUAD,
},
{ .compatible = "intel,stratix10-spi" },
{ .compatible = "intel,agilex-spi" },
--
2.29.2