[PATCH v3] spi: zynq_spi: add chip select decoder support

Nikita Vasilev vasilevnikitad at gmail.com
Sun Mar 20 21:45:26 CET 2022


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 <vasilevnikitad at gmail.com>
Cc: Jagan Teki <jteki at openedev.com>
---
  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 v3
  - Still had some problems with spaces when sending patch via email. I 
hope that I fixed it.

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.


More information about the U-Boot mailing list