mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/5] Add fsl-dspi driver support
@ 2020-03-25  8:36 Sascha Hauer
  2020-03-25  8:36 ` [PATCH 1/5] regmap-mmio: Add missing pieces for 64bit support Sascha Hauer
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Sascha Hauer @ 2020-03-25  8:36 UTC (permalink / raw)
  To: Barebox List

The fsl-dspi is a SPI core that is found on Freescale Layerscape SoCs. This
series adds support for it. It uses regmap to access registers and it's
connected in big-endian, so we need some regmap patches to support such
maps.

Sascha Hauer (5):
  regmap-mmio: Add missing pieces for 64bit support
  regmap-mmio: Add big endian support
  spi: validate spi messages
  spi: Add fsl-dspi driver
  mtd: spi-nor: Add support for cy15x104q

 drivers/base/regmap/internal.h    |   4 +
 drivers/base/regmap/regmap-mmio.c |  94 ++++-
 drivers/base/regmap/regmap.c      |  44 ++
 drivers/mtd/spi-nor/spi-nor.c     |   3 +
 drivers/spi/Kconfig               |   7 +
 drivers/spi/Makefile              |   1 +
 drivers/spi/spi-fsl-dspi.c        | 655 ++++++++++++++++++++++++++++++
 drivers/spi/spi.c                 |  46 +++
 include/regmap.h                  |  13 +
 include/spi/spi.h                 |   4 +
 10 files changed, 857 insertions(+), 14 deletions(-)
 create mode 100644 drivers/spi/spi-fsl-dspi.c

-- 
2.26.0.rc2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/5] regmap-mmio: Add missing pieces for 64bit support
  2020-03-25  8:36 [PATCH 0/5] Add fsl-dspi driver support Sascha Hauer
@ 2020-03-25  8:36 ` Sascha Hauer
  2020-03-25  8:36 ` [PATCH 2/5] regmap-mmio: Add big endian support Sascha Hauer
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2020-03-25  8:36 UTC (permalink / raw)
  To: Barebox List

The 64bit accessor functions are present, but unused. Hook them up when
needed.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/base/regmap/regmap-mmio.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index f8d2cda843..ef6a7db6fd 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -197,6 +197,12 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
 		ctx->reg_read = regmap_mmio_read32le;
 		ctx->reg_write = regmap_mmio_write32le;
 		break;
+#ifdef CONFIG_64BIT
+	case 64:
+		ctx->reg_read = regmap_mmio_read64le;
+		ctx->reg_write = regmap_mmio_write64le;
+		break;
+#endif
 	default:
 		ret = -EINVAL;
 		goto err_free;
-- 
2.26.0.rc2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/5] regmap-mmio: Add big endian support
  2020-03-25  8:36 [PATCH 0/5] Add fsl-dspi driver support Sascha Hauer
  2020-03-25  8:36 ` [PATCH 1/5] regmap-mmio: Add missing pieces for 64bit support Sascha Hauer
@ 2020-03-25  8:36 ` Sascha Hauer
  2020-03-25  8:36 ` [PATCH 3/5] spi: validate spi messages Sascha Hauer
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2020-03-25  8:36 UTC (permalink / raw)
  To: Barebox List

Add support for parsing the big-endian device tree property.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/base/regmap/internal.h    |  4 ++
 drivers/base/regmap/regmap-mmio.c | 98 +++++++++++++++++++++++++------
 drivers/base/regmap/regmap.c      | 44 ++++++++++++++
 include/regmap.h                  | 13 ++++
 4 files changed, 140 insertions(+), 19 deletions(-)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 5b19459828..4c7460fa4c 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -22,4 +22,8 @@ struct regmap {
 	struct cdev cdev;
 };
 
+enum regmap_endian regmap_get_val_endian(struct device_d *dev,
+					 const struct regmap_bus *bus,
+					 const struct regmap_config *config);
+
 #endif
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index ef6a7db6fd..492dd16ff5 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -86,6 +86,20 @@ static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
 	writel(val, ctx->regs + reg);
 }
 
+static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
+				  unsigned int reg,
+				  unsigned int val)
+{
+	iowrite16be(val, ctx->regs + reg);
+}
+
+static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
+				  unsigned int reg,
+				  unsigned int val)
+{
+	iowrite32be(val, ctx->regs + reg);
+}
+
 #ifdef CONFIG_64BIT
 static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
 				  unsigned int reg,
@@ -137,6 +151,18 @@ static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
 }
 #endif
 
+static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
+				         unsigned int reg)
+{
+	return ioread16be(ctx->regs + reg);
+}
+
+static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
+				         unsigned int reg)
+{
+	return ioread32be(ctx->regs + reg);
+}
+
 static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
 {
 	struct regmap_mmio_context *ctx = context;
@@ -158,7 +184,8 @@ static const struct regmap_bus regmap_mmio = {
 	.reg_read = regmap_mmio_read,
 };
 
-static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
+static struct regmap_mmio_context *regmap_mmio_gen_context(struct device_d *dev,
+					void __iomem *regs,
 					const struct regmap_config *config)
 {
 	struct regmap_mmio_context *ctx;
@@ -184,25 +211,58 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
 	ctx->regs = regs;
 	ctx->val_bytes = config->val_bits / 8;
 
-	switch (config->val_bits) {
-	case 8:
-		ctx->reg_read = regmap_mmio_read8;
-		ctx->reg_write = regmap_mmio_write8;
-		break;
-	case 16:
-		ctx->reg_read = regmap_mmio_read16le;
-		ctx->reg_write = regmap_mmio_write16le;
-		break;
-	case 32:
-		ctx->reg_read = regmap_mmio_read32le;
-		ctx->reg_write = regmap_mmio_write32le;
-		break;
+	switch (regmap_get_val_endian(dev, &regmap_mmio, config)) {
+	case REGMAP_ENDIAN_DEFAULT:
+	case REGMAP_ENDIAN_LITTLE:
+#ifdef __LITTLE_ENDIAN
+	case REGMAP_ENDIAN_NATIVE:
+#endif
+		switch (config->val_bits) {
+		case 8:
+			ctx->reg_read = regmap_mmio_read8;
+			ctx->reg_write = regmap_mmio_write8;
+			break;
+		case 16:
+			ctx->reg_read = regmap_mmio_read16le;
+			ctx->reg_write = regmap_mmio_write16le;
+			break;
+		case 32:
+			ctx->reg_read = regmap_mmio_read32le;
+			ctx->reg_write = regmap_mmio_write32le;
+			break;
 #ifdef CONFIG_64BIT
-	case 64:
-		ctx->reg_read = regmap_mmio_read64le;
-		ctx->reg_write = regmap_mmio_write64le;
+		case 64:
+			ctx->reg_read = regmap_mmio_read64le;
+			ctx->reg_write = regmap_mmio_write64le;
+			break;
+#endif
+		default:
+			ret = -EINVAL;
+			goto err_free;
+		}
 		break;
+	case REGMAP_ENDIAN_BIG:
+#ifdef __BIG_ENDIAN
+	case REGMAP_ENDIAN_NATIVE:
 #endif
+		switch (config->val_bits) {
+		case 8:
+			ctx->reg_read = regmap_mmio_read8;
+			ctx->reg_write = regmap_mmio_write8;
+			break;
+		case 16:
+			ctx->reg_read = regmap_mmio_read16be;
+			ctx->reg_write = regmap_mmio_write16be;
+			break;
+		case 32:
+			ctx->reg_read = regmap_mmio_read32be;
+			ctx->reg_write = regmap_mmio_write32be;
+			break;
+		default:
+			ret = -EINVAL;
+			goto err_free;
+		}
+		break;
 	default:
 		ret = -EINVAL;
 		goto err_free;
@@ -223,7 +283,7 @@ struct regmap *regmap_init_mmio_clk(struct device_d *dev,
 {
 	struct regmap_mmio_context *ctx;
 
-	ctx = regmap_mmio_gen_context(regs, config);
+	ctx = regmap_mmio_gen_context(dev, regs, config);
 	if (IS_ERR(ctx))
 		return ERR_CAST(ctx);
 
@@ -245,7 +305,7 @@ struct regmap *of_regmap_init_mmio_clk(struct device_node *np,
 {
 	struct regmap_mmio_context *ctx;
 
-	ctx = regmap_mmio_gen_context(regs, config);
+	ctx = regmap_mmio_gen_context(NULL, regs, config);
 	if (IS_ERR(ctx))
 		return ERR_CAST(ctx);
 
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index dc7b4f276f..374d3ea3d6 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -28,6 +28,50 @@
 
 static LIST_HEAD(regmaps);
 
+enum regmap_endian regmap_get_val_endian(struct device_d *dev,
+					 const struct regmap_bus *bus,
+					 const struct regmap_config *config)
+{
+	struct device_node *np;
+	enum regmap_endian endian;
+
+	/* Retrieve the endianness specification from the regmap config */
+	endian = config->val_format_endian;
+
+	/* If the regmap config specified a non-default value, use that */
+	if (endian != REGMAP_ENDIAN_DEFAULT)
+		return endian;
+
+	/* If the dev and dev->device_node exist try to get endianness from DT */
+	if (dev && dev->device_node) {
+		np = dev->device_node;
+
+		/* Parse the device's DT node for an endianness specification */
+		if (of_property_read_bool(np, "big-endian"))
+			endian = REGMAP_ENDIAN_BIG;
+		else if (of_property_read_bool(np, "little-endian"))
+			endian = REGMAP_ENDIAN_LITTLE;
+		else if (of_property_read_bool(np, "native-endian"))
+			endian = REGMAP_ENDIAN_NATIVE;
+
+		/* If the endianness was specified in DT, use that */
+		if (endian != REGMAP_ENDIAN_DEFAULT)
+			return endian;
+	}
+
+	/* Retrieve the endianness specification from the bus config */
+	if (bus && bus->val_format_endian_default)
+		endian = bus->val_format_endian_default;
+
+	/* If the bus specified a non-default value, use that */
+	if (endian != REGMAP_ENDIAN_DEFAULT)
+		return endian;
+
+	/* Use this if no other value was found */
+	return REGMAP_ENDIAN_BIG;
+}
+EXPORT_SYMBOL_GPL(regmap_get_val_endian);
+
 /*
  * regmap_init - initialize and register a regmap
  *
diff --git a/include/regmap.h b/include/regmap.h
index 3bcd9fe038..139ac33ec3 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -2,6 +2,14 @@
 #ifndef __REGMAP_H
 #define __REGMAP_H
 
+enum regmap_endian {
+	/* Unspecified -> 0 -> Backwards compatible default */
+	REGMAP_ENDIAN_DEFAULT = 0,
+	REGMAP_ENDIAN_BIG,
+	REGMAP_ENDIAN_LITTLE,
+	REGMAP_ENDIAN_NATIVE,
+};
+
 /**
  * Configuration for the register map of a device.
  *
@@ -26,6 +34,9 @@ struct regmap_config {
 	int val_bits;
 
 	unsigned int max_register;
+
+	enum regmap_endian reg_format_endian;
+	enum regmap_endian val_format_endian;
 };
 
 typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg,
@@ -36,6 +47,8 @@ typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg,
 struct regmap_bus {
 	regmap_hw_reg_write reg_write;
 	regmap_hw_reg_read reg_read;
+	enum regmap_endian reg_format_endian_default;
+	enum regmap_endian val_format_endian_default;
 };
 
 struct device_d;
-- 
2.26.0.rc2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/5] spi: validate spi messages
  2020-03-25  8:36 [PATCH 0/5] Add fsl-dspi driver support Sascha Hauer
  2020-03-25  8:36 ` [PATCH 1/5] regmap-mmio: Add missing pieces for 64bit support Sascha Hauer
  2020-03-25  8:36 ` [PATCH 2/5] regmap-mmio: Add big endian support Sascha Hauer
@ 2020-03-25  8:36 ` Sascha Hauer
  2020-03-25  8:36 ` [PATCH 4/5] spi: Add fsl-dspi driver Sascha Hauer
  2020-03-25  8:36 ` [PATCH 5/5] mtd: spi-nor: Add support for cy15x104q Sascha Hauer
  4 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2020-03-25  8:36 UTC (permalink / raw)
  To: Barebox List

This adds __spi_validate() to validate spi messages. This function is a
stripped down version from the Kernel. The motivation for adding this
was to fill in xfer->bits_per_word from spi->bits_per_word so that a
spi bus driver can use the former.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/spi/spi.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 include/spi/spi.h |  4 ++++
 2 files changed, 50 insertions(+)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index bd615b4e99..0694f14c39 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -297,8 +297,54 @@ struct spi_controller *spi_get_controller(int bus)
 	return NULL;
 }
 
+static int __spi_validate(struct spi_device *spi, struct spi_message *message)
+{
+	struct spi_controller *ctlr = spi->controller;
+	struct spi_transfer *xfer;
+	int w_size;
+
+	if (list_empty(&message->transfers))
+		return -EINVAL;
+
+	list_for_each_entry(xfer, &message->transfers, transfer_list) {
+		if (!xfer->bits_per_word)
+			xfer->bits_per_word = spi->bits_per_word;
+
+		if (!xfer->speed_hz)
+			xfer->speed_hz = spi->max_speed_hz;
+
+		if (ctlr->max_speed_hz && xfer->speed_hz > ctlr->max_speed_hz)
+			xfer->speed_hz = ctlr->max_speed_hz;
+
+		/*
+		 * SPI transfer length should be multiple of SPI word size
+		 * where SPI word size should be power-of-two multiple
+		 */
+		if (xfer->bits_per_word <= 8)
+			w_size = 1;
+		else if (xfer->bits_per_word <= 16)
+			w_size = 2;
+		else
+			w_size = 4;
+
+		/* No partial transfers accepted */
+		if (xfer->len % w_size)
+			return -EINVAL;
+	}
+
+	message->status = -EINPROGRESS;
+
+	return 0;
+}
+
 int spi_sync(struct spi_device *spi, struct spi_message *message)
 {
+	int status;
+
+	status = __spi_validate(spi, message);
+	if (status != 0)
+		return status;
+
 	return spi->controller->transfer(spi, message);
 }
 
diff --git a/include/spi/spi.h b/include/spi/spi.h
index 48a90bcca7..66e0500d04 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -126,6 +126,7 @@ struct spi_message;
  *	SPI slaves, and are numbered from zero to num_chipselects.
  *	each slave has a chipselect signal, but it's common that not
  *	every chipselect is connected to a slave.
+ * @max_speed_hz: Highest supported transfer speed
  * @setup: updates the device mode and clocking records used by a
  *	device's SPI controller; protocol code may call this.  This
  *	must fail if an unrecognized or unsupported mode is requested.
@@ -171,6 +172,9 @@ struct spi_controller {
 	 */
 	u16			num_chipselect;
 
+	/* limits on transfer speed */
+	u32			max_speed_hz;
+
 	/* setup mode and clock, etc (spi driver may call many times) */
 	int			(*setup)(struct spi_device *spi);
 
-- 
2.26.0.rc2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 4/5] spi: Add fsl-dspi driver
  2020-03-25  8:36 [PATCH 0/5] Add fsl-dspi driver support Sascha Hauer
                   ` (2 preceding siblings ...)
  2020-03-25  8:36 ` [PATCH 3/5] spi: validate spi messages Sascha Hauer
@ 2020-03-25  8:36 ` Sascha Hauer
  2020-04-04 19:14   ` Andrey Smirnov
  2020-03-25  8:36 ` [PATCH 5/5] mtd: spi-nor: Add support for cy15x104q Sascha Hauer
  4 siblings, 1 reply; 8+ messages in thread
From: Sascha Hauer @ 2020-03-25  8:36 UTC (permalink / raw)
  To: Barebox List

The fsl-dspi is found on Freescale Vybrid, Coldfire and Layerscape SoCs.
This adds the driver based on the Linux driver as of v5.5. Coldfire
support has been dropped as it's rather obsolete. Vybrid support has
been dropped because it needs the DMA engine support we do not have in
barebox. What's left is support for Layerscape where this driver has
been tested on.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/spi/Kconfig        |   7 +
 drivers/spi/Makefile       |   1 +
 drivers/spi/spi-fsl-dspi.c | 655 +++++++++++++++++++++++++++++++++++++
 3 files changed, 663 insertions(+)
 create mode 100644 drivers/spi/spi-fsl-dspi.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 3758a0fad9..96235a1be2 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -44,6 +44,13 @@ config DRIVER_SPI_FSL_QUADSPI
           This controller does not support generic SPI messages. It only
           supports the high-level SPI memory interface.
 
+config SPI_FSL_DSPI
+	bool "Freescale DSPI controller"
+	depends on ARCH_LAYERSCAPE
+	help
+	  This enables support for the Freescale DSPI controller in master
+	  mode. VF610, LS1021A and ColdFire platforms uses the controller.
+
 config DRIVER_SPI_GPIO
 	bool "GPIO SPI Master driver"
 	depends on GPIOLIB
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 75a89ef38e..908d514a01 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DRIVER_SPI_MVEBU) += mvebu_spi.o
 obj-$(CONFIG_DRIVER_SPI_MXS) += mxs_spi.o
 obj-$(CONFIG_DRIVER_SPI_ALTERA) += altera_spi.o
 obj-$(CONFIG_DRIVER_SPI_ATMEL) += atmel_spi.o
+obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o
 obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o
 obj-$(CONFIG_DRIVER_SPI_OMAP3) += omap3_spi.o
 obj-$(CONFIG_DRIVER_SPI_DSPI) += dspi_spi.o
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
new file mode 100644
index 0000000000..a7ceb854e9
--- /dev/null
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -0,0 +1,655 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2013 Freescale Semiconductor, Inc.
+//
+// Freescale DSPI driver
+// This file contains a driver for the Freescale DSPI
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <init.h>
+#include <io.h>
+#include <regmap.h>
+#include <spi/spi.h>
+#include <linux/clk.h>
+#include <linux/math64.h>
+
+#define DRIVER_NAME			"fsl-dspi"
+
+#define DSPI_FIFO_SIZE			4
+#define DSPI_DMA_BUFSIZE		(DSPI_FIFO_SIZE * 1024)
+
+#define SPI_MCR				0x00
+#define SPI_MCR_MASTER			BIT(31)
+#define SPI_MCR_PCSIS			(0x3F << 16)
+#define SPI_MCR_CLR_TXF			BIT(11)
+#define SPI_MCR_CLR_RXF			BIT(10)
+#define SPI_MCR_XSPI			BIT(3)
+
+#define SPI_TCR				0x08
+#define SPI_TCR_GET_TCNT(x)		(((x) & GENMASK(31, 16)) >> 16)
+
+#define SPI_CTAR(x)			(0x0c + (((x) & GENMASK(1, 0)) * 4))
+#define SPI_CTAR_FMSZ(x)		(((x) << 27) & GENMASK(30, 27))
+#define SPI_CTAR_CPOL			BIT(26)
+#define SPI_CTAR_CPHA			BIT(25)
+#define SPI_CTAR_LSBFE			BIT(24)
+#define SPI_CTAR_PCSSCK(x)		(((x) << 22) & GENMASK(23, 22))
+#define SPI_CTAR_PASC(x)		(((x) << 20) & GENMASK(21, 20))
+#define SPI_CTAR_PDT(x)			(((x) << 18) & GENMASK(19, 18))
+#define SPI_CTAR_PBR(x)			(((x) << 16) & GENMASK(17, 16))
+#define SPI_CTAR_CSSCK(x)		(((x) << 12) & GENMASK(15, 12))
+#define SPI_CTAR_ASC(x)			(((x) << 8) & GENMASK(11, 8))
+#define SPI_CTAR_DT(x)			(((x) << 4) & GENMASK(7, 4))
+#define SPI_CTAR_BR(x)			((x) & GENMASK(3, 0))
+#define SPI_CTAR_SCALE_BITS		0xf
+
+#define SPI_CTAR0_SLAVE			0x0c
+
+#define SPI_SR				0x2c
+#define SPI_SR_TCFQF			BIT(31)
+#define SPI_SR_EOQF			BIT(28)
+#define SPI_SR_TFUF			BIT(27)
+#define SPI_SR_TFFF			BIT(25)
+#define SPI_SR_CMDTCF			BIT(23)
+#define SPI_SR_SPEF			BIT(21)
+#define SPI_SR_RFOF			BIT(19)
+#define SPI_SR_TFIWF			BIT(18)
+#define SPI_SR_RFDF			BIT(17)
+#define SPI_SR_CMDFFF			BIT(16)
+#define SPI_SR_CLEAR			(SPI_SR_TCFQF | SPI_SR_EOQF | \
+					SPI_SR_TFUF | SPI_SR_TFFF | \
+					SPI_SR_CMDTCF | SPI_SR_SPEF | \
+					SPI_SR_RFOF | SPI_SR_TFIWF | \
+					SPI_SR_RFDF | SPI_SR_CMDFFF)
+
+#define SPI_RSER_TFFFE			BIT(25)
+#define SPI_RSER_TFFFD			BIT(24)
+#define SPI_RSER_RFDFE			BIT(17)
+#define SPI_RSER_RFDFD			BIT(16)
+
+#define SPI_RSER			0x30
+#define SPI_RSER_TCFQE			BIT(31)
+#define SPI_RSER_EOQFE			BIT(28)
+
+#define SPI_PUSHR			0x34
+#define SPI_PUSHR_CMD_CONT		BIT(15)
+#define SPI_PUSHR_CMD_CTAS(x)		(((x) << 12 & GENMASK(14, 12)))
+#define SPI_PUSHR_CMD_EOQ		BIT(11)
+#define SPI_PUSHR_CMD_CTCNT		BIT(10)
+#define SPI_PUSHR_CMD_PCS(x)		(BIT(x) & GENMASK(5, 0))
+
+#define SPI_PUSHR_SLAVE			0x34
+
+#define SPI_POPR			0x38
+
+#define SPI_TXFR0			0x3c
+#define SPI_TXFR1			0x40
+#define SPI_TXFR2			0x44
+#define SPI_TXFR3			0x48
+#define SPI_RXFR0			0x7c
+#define SPI_RXFR1			0x80
+#define SPI_RXFR2			0x84
+#define SPI_RXFR3			0x88
+
+#define SPI_CTARE(x)			(0x11c + (((x) & GENMASK(1, 0)) * 4))
+#define SPI_CTARE_FMSZE(x)		(((x) & 0x1) << 16)
+#define SPI_CTARE_DTCP(x)		((x) & 0x7ff)
+
+#define SPI_SREX			0x13c
+
+#define SPI_FRAME_BITS(bits)		SPI_CTAR_FMSZ((bits) - 1)
+#define SPI_FRAME_EBITS(bits)		SPI_CTARE_FMSZE(((bits) - 1) >> 4)
+
+/* Register offsets for regmap_pushr */
+#define PUSHR_CMD			0x0
+#define PUSHR_TX			0x2
+
+#define DMA_COMPLETION_TIMEOUT		msecs_to_jiffies(3000)
+
+struct chip_data {
+	u32			ctar_val;
+	u16			void_write_data;
+};
+
+struct fsl_dspi_devtype_data {
+	u8			max_clock_factor;
+	bool			ptp_sts_supported;
+	bool			xspi_mode;
+};
+
+static const struct fsl_dspi_devtype_data ls1021a_v1_data = {
+	.max_clock_factor	= 8,
+	.ptp_sts_supported	= true,
+	.xspi_mode		= true,
+};
+
+static const struct fsl_dspi_devtype_data ls2085a_data = {
+	.max_clock_factor	= 8,
+	.ptp_sts_supported	= true,
+};
+
+struct fsl_dspi {
+	struct spi_controller			ctlr;
+	struct device_d				*dev;
+
+	struct regmap				*regmap;
+	struct regmap				*regmap_pushr;
+	int					irq;
+	struct clk				*clk;
+
+	struct spi_transfer			*cur_transfer;
+	struct spi_message			*cur_msg;
+	struct chip_data			*cur_chip;
+	size_t					progress;
+	size_t					len;
+	const void				*tx;
+	void					*rx;
+	void					*rx_end;
+	u16					void_write_data;
+	u16					tx_cmd;
+	u8					bits_per_word;
+	u8					bytes_per_word;
+	const struct fsl_dspi_devtype_data	*devtype_data;
+};
+
+static u32 dspi_pop_tx(struct fsl_dspi *dspi)
+{
+	u32 txdata = 0;
+
+	if (dspi->tx) {
+		if (dspi->bytes_per_word == 1)
+			txdata = *(u8 *)dspi->tx;
+		else if (dspi->bytes_per_word == 2)
+			txdata = *(u16 *)dspi->tx;
+		else  /* dspi->bytes_per_word == 4 */
+			txdata = *(u32 *)dspi->tx;
+		dspi->tx += dspi->bytes_per_word;
+	}
+	dspi->len -= dspi->bytes_per_word;
+	return txdata;
+}
+
+static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
+{
+	u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
+
+	if (dspi->len > 0)
+		cmd |= SPI_PUSHR_CMD_CONT;
+	return cmd << 16 | data;
+}
+
+static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
+{
+	if (!dspi->rx)
+		return;
+
+	/* Mask off undefined bits */
+	rxdata &= (1 << dspi->bits_per_word) - 1;
+
+	if (dspi->bytes_per_word == 1)
+		*(u8 *)dspi->rx = rxdata;
+	else if (dspi->bytes_per_word == 2)
+		*(u16 *)dspi->rx = rxdata;
+	else /* dspi->bytes_per_word == 4 */
+		*(u32 *)dspi->rx = rxdata;
+	dspi->rx += dspi->bytes_per_word;
+}
+
+static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
+			   unsigned long clkrate)
+{
+	/* Valid baud rate pre-scaler values */
+	int pbr_tbl[4] = {2, 3, 5, 7};
+	int brs[16] = {	2,	4,	6,	8,
+			16,	32,	64,	128,
+			256,	512,	1024,	2048,
+			4096,	8192,	16384,	32768 };
+	int scale_needed, scale, minscale = INT_MAX;
+	int i, j;
+
+	scale_needed = clkrate / speed_hz;
+	if (clkrate % speed_hz)
+		scale_needed++;
+
+	for (i = 0; i < ARRAY_SIZE(brs); i++)
+		for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) {
+			scale = brs[i] * pbr_tbl[j];
+			if (scale >= scale_needed) {
+				if (scale < minscale) {
+					minscale = scale;
+					*br = i;
+					*pbr = j;
+				}
+				break;
+			}
+		}
+
+	if (minscale == INT_MAX) {
+		pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld, we use the max prescaler value.\n",
+			speed_hz, clkrate);
+		*pbr = ARRAY_SIZE(pbr_tbl) - 1;
+		*br =  ARRAY_SIZE(brs) - 1;
+	}
+}
+
+static void ns_delay_scale(char *psc, char *sc, int delay_ns,
+			   unsigned long clkrate)
+{
+	int scale_needed, scale, minscale = INT_MAX;
+	int pscale_tbl[4] = {1, 3, 5, 7};
+	u32 remainder;
+	int i, j;
+
+	scale_needed = div_u64_rem((u64)delay_ns * clkrate, NSEC_PER_SEC,
+				   &remainder);
+	if (remainder)
+		scale_needed++;
+
+	for (i = 0; i < ARRAY_SIZE(pscale_tbl); i++)
+		for (j = 0; j <= SPI_CTAR_SCALE_BITS; j++) {
+			scale = pscale_tbl[i] * (2 << j);
+			if (scale >= scale_needed) {
+				if (scale < minscale) {
+					minscale = scale;
+					*psc = i;
+					*sc = j;
+				}
+				break;
+			}
+		}
+
+	if (minscale == INT_MAX) {
+		pr_warn("Cannot find correct scale values for %dns delay at clkrate %ld, using max prescaler value",
+			delay_ns, clkrate);
+		*psc = ARRAY_SIZE(pscale_tbl) - 1;
+		*sc = SPI_CTAR_SCALE_BITS;
+	}
+}
+
+static void fifo_write(struct fsl_dspi *dspi)
+{
+	regmap_write(dspi->regmap, SPI_PUSHR, dspi_pop_tx_pushr(dspi));
+}
+
+static void cmd_fifo_write(struct fsl_dspi *dspi)
+{
+	u16 cmd = dspi->tx_cmd;
+
+	if (dspi->len > 0)
+		cmd |= SPI_PUSHR_CMD_CONT;
+	regmap_write(dspi->regmap_pushr, PUSHR_CMD, cmd);
+}
+
+static void tx_fifo_write(struct fsl_dspi *dspi, u16 txdata)
+{
+	regmap_write(dspi->regmap_pushr, PUSHR_TX, txdata);
+}
+
+static void dspi_tcfq_write(struct fsl_dspi *dspi)
+{
+	/* Clear transfer count */
+	dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
+
+	if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) {
+		/* Write the CMD FIFO entry first, and then the two
+		 * corresponding TX FIFO entries.
+		 */
+		u32 data = dspi_pop_tx(dspi);
+
+		cmd_fifo_write(dspi);
+		tx_fifo_write(dspi, data & 0xFFFF);
+		tx_fifo_write(dspi, data >> 16);
+	} else {
+		/* Write one entry to both TX FIFO and CMD FIFO
+		 * simultaneously.
+		 */
+		fifo_write(dspi);
+	}
+}
+
+static u32 fifo_read(struct fsl_dspi *dspi)
+{
+	u32 rxdata = 0;
+
+	regmap_read(dspi->regmap, SPI_POPR, &rxdata);
+	return rxdata;
+}
+
+static void dspi_tcfq_read(struct fsl_dspi *dspi)
+{
+	dspi_push_rx(dspi, fifo_read(dspi));
+}
+
+static int dspi_rxtx(struct fsl_dspi *dspi)
+{
+	struct spi_message *msg = dspi->cur_msg;
+	u16 spi_tcnt;
+	u32 spi_tcr;
+
+	/* Get transfer counter (in number of SPI transfers). It was
+	 * reset to 0 when transfer(s) were started.
+	 */
+	regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
+	spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
+	/* Update total number of bytes that were transferred */
+	msg->actual_length += spi_tcnt * dspi->bytes_per_word;
+	dspi->progress += spi_tcnt;
+
+	dspi_tcfq_read(dspi);
+	if (!dspi->len)
+		/* Success! */
+		return 0;
+
+	dspi_tcfq_write(dspi);
+
+	return -EINPROGRESS;
+}
+
+static int dspi_poll(struct fsl_dspi *dspi)
+{
+	int tries = 1000;
+	u32 spi_sr;
+
+	do {
+		regmap_read(dspi->regmap, SPI_SR, &spi_sr);
+		regmap_write(dspi->regmap, SPI_SR, spi_sr);
+
+		if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF))
+			break;
+		udelay(1);
+	} while (--tries);
+
+	if (!tries)
+		return -ETIMEDOUT;
+
+	return dspi_rxtx(dspi);
+}
+
+static int dspi_transfer_one_message(struct spi_device *spi,
+				     struct spi_message *message)
+{
+	struct fsl_dspi *dspi = container_of(spi->master, struct fsl_dspi, ctlr);
+	struct spi_transfer *transfer;
+	int status = 0;
+
+	message->actual_length = 0;
+
+	list_for_each_entry(transfer, &message->transfers, transfer_list) {
+		dspi->cur_transfer = transfer;
+		dspi->cur_msg = message;
+		dspi->cur_chip = spi->controller_data;
+		/* Prepare command word for CMD FIFO */
+		dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0) |
+			       SPI_PUSHR_CMD_PCS(spi->chip_select);
+		if (list_is_last(&dspi->cur_transfer->transfer_list,
+				 &dspi->cur_msg->transfers)) {
+			/* Leave PCS activated after last transfer when
+			 * cs_change is set.
+			 */
+			if (transfer->cs_change)
+				dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
+		} else {
+			/* Keep PCS active between transfers in same message
+			 * when cs_change is not set, and de-activate PCS
+			 * between transfers in the same message when
+			 * cs_change is set.
+			 */
+			if (!transfer->cs_change)
+				dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
+		}
+
+		dspi->void_write_data = dspi->cur_chip->void_write_data;
+
+		dspi->tx = transfer->tx_buf;
+		dspi->rx = transfer->rx_buf;
+		dspi->rx_end = dspi->rx + transfer->len;
+		dspi->len = transfer->len;
+		dspi->progress = 0;
+		/* Validated transfer specific frame size (defaults applied) */
+		dspi->bits_per_word = transfer->bits_per_word;
+
+		if (transfer->bits_per_word <= 8)
+			dspi->bytes_per_word = 1;
+		else if (transfer->bits_per_word <= 16)
+			dspi->bytes_per_word = 2;
+		else
+			dspi->bytes_per_word = 4;
+
+		regmap_update_bits(dspi->regmap, SPI_MCR,
+				   SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
+				   SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
+		regmap_write(dspi->regmap, SPI_CTAR(0),
+			     dspi->cur_chip->ctar_val |
+			     SPI_FRAME_BITS(transfer->bits_per_word));
+		if (dspi->devtype_data->xspi_mode)
+			regmap_write(dspi->regmap, SPI_CTARE(0),
+				     SPI_FRAME_EBITS(transfer->bits_per_word) |
+				     SPI_CTARE_DTCP(1));
+
+		regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE);
+		dspi_tcfq_write(dspi);
+
+		do {
+			status = dspi_poll(dspi);
+		} while (status == -EINPROGRESS);
+
+		if (status)
+			dev_err(dspi->dev,
+				"Waiting for transfer to complete failed!\n");
+	}
+
+	message->status = status;
+
+	return status;
+}
+
+static int dspi_setup(struct spi_device *spi)
+{
+	struct fsl_dspi *dspi = container_of(spi->master, struct fsl_dspi, ctlr);
+	unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
+	u32 cs_sck_delay = 0, sck_cs_delay = 0;
+	unsigned char pasc = 0, asc = 0;
+	struct chip_data *chip;
+	unsigned long clkrate;
+
+	/* Only alloc on first setup */
+	chip = spi->controller_data;
+	if (chip == NULL) {
+		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+	}
+
+	of_property_read_u32(spi->dev.device_node, "fsl,spi-cs-sck-delay",
+			     &cs_sck_delay);
+
+	of_property_read_u32(spi->dev.device_node, "fsl,spi-sck-cs-delay",
+			     &sck_cs_delay);
+
+	chip->void_write_data = 0;
+
+	clkrate = clk_get_rate(dspi->clk);
+	hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
+
+	/* Set PCS to SCK delay scale values */
+	ns_delay_scale(&pcssck, &cssck, cs_sck_delay, clkrate);
+
+	/* Set After SCK delay scale values */
+	ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate);
+
+	chip->ctar_val = 0;
+	if (spi->mode & SPI_CPOL)
+		chip->ctar_val |= SPI_CTAR_CPOL;
+	if (spi->mode & SPI_CPHA)
+		chip->ctar_val |= SPI_CTAR_CPHA;
+
+	chip->ctar_val |= SPI_CTAR_PCSSCK(pcssck) |
+			  SPI_CTAR_CSSCK(cssck) |
+			  SPI_CTAR_PASC(pasc) |
+			  SPI_CTAR_ASC(asc) |
+			  SPI_CTAR_PBR(pbr) |
+			  SPI_CTAR_BR(br);
+
+	if (spi->mode & SPI_LSB_FIRST)
+		chip->ctar_val |= SPI_CTAR_LSBFE;
+
+	spi->controller_data = chip;
+
+	return 0;
+}
+
+static void dspi_cleanup(struct spi_device *spi)
+{
+	struct chip_data *chip = spi->controller_data;
+
+	dev_dbg(&spi->dev, "spi_device %u.%u cleanup\n",
+		spi->controller->bus_num, spi->chip_select);
+
+	kfree(chip);
+}
+
+static const struct of_device_id fsl_dspi_dt_ids[] = {
+	{ .compatible = "fsl,ls1021a-v1.0-dspi", .data = &ls1021a_v1_data, },
+	{ .compatible = "fsl,ls2085a-dspi", .data = &ls2085a_data, },
+	{ /* sentinel */ }
+};
+
+static const struct regmap_config dspi_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= 0x88,
+};
+
+static const struct regmap_config dspi_xspi_regmap_config[] = {
+	{
+		.reg_bits	= 32,
+		.val_bits	= 32,
+		.reg_stride	= 4,
+		.max_register	= 0x13c,
+	}, {
+		.name		= "pushr",
+		.reg_bits	= 16,
+		.val_bits	= 16,
+		.reg_stride	= 2,
+		.max_register	= 0x2,
+	},
+};
+
+static void dspi_init(struct fsl_dspi *dspi)
+{
+	unsigned int mcr = SPI_MCR_PCSIS;
+
+	if (dspi->devtype_data->xspi_mode)
+		mcr |= SPI_MCR_XSPI;
+	mcr |= SPI_MCR_MASTER;
+
+	regmap_write(dspi->regmap, SPI_MCR, mcr);
+	regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
+	if (dspi->devtype_data->xspi_mode)
+		regmap_write(dspi->regmap, SPI_CTARE(0),
+			     SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1));
+}
+
+static int dspi_probe(struct device_d *dev)
+{
+	struct device_node *np = dev->device_node;
+	const struct regmap_config *regmap_config;
+	struct spi_master *master;
+	int ret, cs_num, bus_num = -1;
+	struct fsl_dspi *dspi;
+	struct resource *res;
+	void __iomem *base;
+
+	dspi = xzalloc(sizeof(*dspi));
+
+	dspi->dev = dev;
+	master = &dspi->ctlr;
+
+	master->dev = dev;
+	master->setup = dspi_setup;
+	master->transfer = dspi_transfer_one_message;
+
+	master->cleanup = dspi_cleanup;
+
+	ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
+	if (ret < 0) {
+		dev_err(dev, "can't get spi-num-chipselects\n");
+		goto out_ctlr_put;
+	}
+	master->num_chipselect = cs_num;
+
+	of_property_read_u32(np, "bus-num", &bus_num);
+	master->bus_num = bus_num;
+
+	ret = dev_get_drvdata(dev, (const void **)&dspi->devtype_data);
+	if (ret)
+		return -ENODEV;
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	base = IOMEM(res->start);
+
+	if (dspi->devtype_data->xspi_mode)
+		regmap_config = &dspi_xspi_regmap_config[0];
+	else
+		regmap_config = &dspi_regmap_config;
+
+	dspi->regmap = regmap_init_mmio(dev, base, regmap_config);
+	if (IS_ERR(dspi->regmap)) {
+		dev_err(dev, "failed to init regmap: %ld\n",
+				PTR_ERR(dspi->regmap));
+		ret = PTR_ERR(dspi->regmap);
+		goto out_ctlr_put;
+	}
+
+	if (dspi->devtype_data->xspi_mode) {
+		dspi->regmap_pushr = regmap_init_mmio(
+			dev, base + SPI_PUSHR,
+			&dspi_xspi_regmap_config[1]);
+		if (IS_ERR(dspi->regmap_pushr)) {
+			dev_err(dev,
+				"failed to init pushr regmap: %ld\n",
+				PTR_ERR(dspi->regmap_pushr));
+			ret = PTR_ERR(dspi->regmap_pushr);
+			goto out_ctlr_put;
+		}
+	}
+
+	dspi->clk = clk_get(dev, "dspi");
+	if (IS_ERR(dspi->clk)) {
+		ret = PTR_ERR(dspi->clk);
+		dev_err(dev, "unable to get clock\n");
+		goto out_ctlr_put;
+	}
+	ret = clk_enable(dspi->clk);
+	if (ret)
+		goto out_ctlr_put;
+
+	dspi_init(dspi);
+
+	ret = spi_register_master(master);
+	if (ret != 0) {
+		dev_err(dev, "Problem registering DSPI ctlr\n");
+		goto out_clk_put;
+	}
+
+	return ret;
+
+out_clk_put:
+	clk_disable(dspi->clk);
+out_ctlr_put:
+
+	return ret;
+}
+
+static struct driver_d fsl_dspi_driver = {
+	.name  = "fsl-dspi",
+	.probe = dspi_probe,
+	.of_compatible = DRV_OF_COMPAT(fsl_dspi_dt_ids),
+};
+coredevice_platform_driver(fsl_dspi_driver);
-- 
2.26.0.rc2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 5/5] mtd: spi-nor: Add support for cy15x104q
  2020-03-25  8:36 [PATCH 0/5] Add fsl-dspi driver support Sascha Hauer
                   ` (3 preceding siblings ...)
  2020-03-25  8:36 ` [PATCH 4/5] spi: Add fsl-dspi driver Sascha Hauer
@ 2020-03-25  8:36 ` Sascha Hauer
  4 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2020-03-25  8:36 UTC (permalink / raw)
  To: Barebox List

The Cypress cy15b104q and cy15v104q are 4Mbit serial SPI F-RAM devices.
Add support for them to the spi-nor driver.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/mtd/spi-nor/spi-nor.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 038d7072aa..5cc4573178 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -640,6 +640,9 @@ static const struct spi_device_id spi_nor_ids[] = {
 
 	{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
 
+	/* Cypress */
+	{ "cy15x104q",  INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1, SPI_NOR_NO_ERASE) },
+
 	/* EON -- en25xxx */
 	{ "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, SECT_4K) },
 	{ "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 0) },
-- 
2.26.0.rc2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/5] spi: Add fsl-dspi driver
  2020-03-25  8:36 ` [PATCH 4/5] spi: Add fsl-dspi driver Sascha Hauer
@ 2020-04-04 19:14   ` Andrey Smirnov
  2020-04-14 10:30     ` Sascha Hauer
  0 siblings, 1 reply; 8+ messages in thread
From: Andrey Smirnov @ 2020-04-04 19:14 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List

On Wed, Mar 25, 2020 at 1:36 AM Sascha Hauer <s.hauer@pengutronix.de> wrote:
>
> The fsl-dspi is found on Freescale Vybrid, Coldfire and Layerscape SoCs.
> This adds the driver based on the Linux driver as of v5.5. Coldfire
> support has been dropped as it's rather obsolete. Vybrid support has
> been dropped because it needs the DMA engine support we do not have in
> barebox. What's left is support for Layerscape where this driver has
> been tested on.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/spi/Kconfig        |   7 +
>  drivers/spi/Makefile       |   1 +
>  drivers/spi/spi-fsl-dspi.c | 655 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 663 insertions(+)
>  create mode 100644 drivers/spi/spi-fsl-dspi.c
>
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 3758a0fad9..96235a1be2 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -44,6 +44,13 @@ config DRIVER_SPI_FSL_QUADSPI
>            This controller does not support generic SPI messages. It only
>            supports the high-level SPI memory interface.
>
> +config SPI_FSL_DSPI
> +       bool "Freescale DSPI controller"
> +       depends on ARCH_LAYERSCAPE
> +       help
> +         This enables support for the Freescale DSPI controller in master
> +         mode. VF610, LS1021A and ColdFire platforms uses the controller.

Sorry I didn't notice this patch earlier. Maybe we should drop the
wording about VF610 here since there a separate DSPI driver for Vybrid
as well:  https://git.pengutronix.de/cgit/barebox/tree/drivers/spi/Kconfig?h=next#n90


> +
>  config DRIVER_SPI_GPIO
>         bool "GPIO SPI Master driver"
>         depends on GPIOLIB
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 75a89ef38e..908d514a01 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_DRIVER_SPI_MVEBU) += mvebu_spi.o
>  obj-$(CONFIG_DRIVER_SPI_MXS) += mxs_spi.o
>  obj-$(CONFIG_DRIVER_SPI_ALTERA) += altera_spi.o
>  obj-$(CONFIG_DRIVER_SPI_ATMEL) += atmel_spi.o
> +obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o
>  obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o
>  obj-$(CONFIG_DRIVER_SPI_OMAP3) += omap3_spi.o
>  obj-$(CONFIG_DRIVER_SPI_DSPI) += dspi_spi.o
> diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
> new file mode 100644
> index 0000000000..a7ceb854e9
> --- /dev/null
> +++ b/drivers/spi/spi-fsl-dspi.c
> @@ -0,0 +1,655 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +//
> +// Copyright 2013 Freescale Semiconductor, Inc.
> +//
> +// Freescale DSPI driver
> +// This file contains a driver for the Freescale DSPI
> +
> +#include <common.h>
> +#include <driver.h>
> +#include <errno.h>
> +#include <init.h>
> +#include <io.h>
> +#include <regmap.h>
> +#include <spi/spi.h>
> +#include <linux/clk.h>
> +#include <linux/math64.h>
> +
> +#define DRIVER_NAME                    "fsl-dspi"
> +
> +#define DSPI_FIFO_SIZE                 4
> +#define DSPI_DMA_BUFSIZE               (DSPI_FIFO_SIZE * 1024)
> +
> +#define SPI_MCR                                0x00
> +#define SPI_MCR_MASTER                 BIT(31)
> +#define SPI_MCR_PCSIS                  (0x3F << 16)
> +#define SPI_MCR_CLR_TXF                        BIT(11)
> +#define SPI_MCR_CLR_RXF                        BIT(10)
> +#define SPI_MCR_XSPI                   BIT(3)
> +
> +#define SPI_TCR                                0x08
> +#define SPI_TCR_GET_TCNT(x)            (((x) & GENMASK(31, 16)) >> 16)
> +
> +#define SPI_CTAR(x)                    (0x0c + (((x) & GENMASK(1, 0)) * 4))
> +#define SPI_CTAR_FMSZ(x)               (((x) << 27) & GENMASK(30, 27))
> +#define SPI_CTAR_CPOL                  BIT(26)
> +#define SPI_CTAR_CPHA                  BIT(25)
> +#define SPI_CTAR_LSBFE                 BIT(24)
> +#define SPI_CTAR_PCSSCK(x)             (((x) << 22) & GENMASK(23, 22))
> +#define SPI_CTAR_PASC(x)               (((x) << 20) & GENMASK(21, 20))
> +#define SPI_CTAR_PDT(x)                        (((x) << 18) & GENMASK(19, 18))
> +#define SPI_CTAR_PBR(x)                        (((x) << 16) & GENMASK(17, 16))
> +#define SPI_CTAR_CSSCK(x)              (((x) << 12) & GENMASK(15, 12))
> +#define SPI_CTAR_ASC(x)                        (((x) << 8) & GENMASK(11, 8))
> +#define SPI_CTAR_DT(x)                 (((x) << 4) & GENMASK(7, 4))
> +#define SPI_CTAR_BR(x)                 ((x) & GENMASK(3, 0))
> +#define SPI_CTAR_SCALE_BITS            0xf
> +
> +#define SPI_CTAR0_SLAVE                        0x0c
> +
> +#define SPI_SR                         0x2c
> +#define SPI_SR_TCFQF                   BIT(31)
> +#define SPI_SR_EOQF                    BIT(28)
> +#define SPI_SR_TFUF                    BIT(27)
> +#define SPI_SR_TFFF                    BIT(25)
> +#define SPI_SR_CMDTCF                  BIT(23)
> +#define SPI_SR_SPEF                    BIT(21)
> +#define SPI_SR_RFOF                    BIT(19)
> +#define SPI_SR_TFIWF                   BIT(18)
> +#define SPI_SR_RFDF                    BIT(17)
> +#define SPI_SR_CMDFFF                  BIT(16)
> +#define SPI_SR_CLEAR                   (SPI_SR_TCFQF | SPI_SR_EOQF | \
> +                                       SPI_SR_TFUF | SPI_SR_TFFF | \
> +                                       SPI_SR_CMDTCF | SPI_SR_SPEF | \
> +                                       SPI_SR_RFOF | SPI_SR_TFIWF | \
> +                                       SPI_SR_RFDF | SPI_SR_CMDFFF)
> +
> +#define SPI_RSER_TFFFE                 BIT(25)
> +#define SPI_RSER_TFFFD                 BIT(24)
> +#define SPI_RSER_RFDFE                 BIT(17)
> +#define SPI_RSER_RFDFD                 BIT(16)
> +
> +#define SPI_RSER                       0x30
> +#define SPI_RSER_TCFQE                 BIT(31)
> +#define SPI_RSER_EOQFE                 BIT(28)
> +
> +#define SPI_PUSHR                      0x34
> +#define SPI_PUSHR_CMD_CONT             BIT(15)
> +#define SPI_PUSHR_CMD_CTAS(x)          (((x) << 12 & GENMASK(14, 12)))
> +#define SPI_PUSHR_CMD_EOQ              BIT(11)
> +#define SPI_PUSHR_CMD_CTCNT            BIT(10)
> +#define SPI_PUSHR_CMD_PCS(x)           (BIT(x) & GENMASK(5, 0))
> +
> +#define SPI_PUSHR_SLAVE                        0x34
> +
> +#define SPI_POPR                       0x38
> +
> +#define SPI_TXFR0                      0x3c
> +#define SPI_TXFR1                      0x40
> +#define SPI_TXFR2                      0x44
> +#define SPI_TXFR3                      0x48
> +#define SPI_RXFR0                      0x7c
> +#define SPI_RXFR1                      0x80
> +#define SPI_RXFR2                      0x84
> +#define SPI_RXFR3                      0x88
> +
> +#define SPI_CTARE(x)                   (0x11c + (((x) & GENMASK(1, 0)) * 4))
> +#define SPI_CTARE_FMSZE(x)             (((x) & 0x1) << 16)
> +#define SPI_CTARE_DTCP(x)              ((x) & 0x7ff)
> +
> +#define SPI_SREX                       0x13c
> +
> +#define SPI_FRAME_BITS(bits)           SPI_CTAR_FMSZ((bits) - 1)
> +#define SPI_FRAME_EBITS(bits)          SPI_CTARE_FMSZE(((bits) - 1) >> 4)
> +
> +/* Register offsets for regmap_pushr */
> +#define PUSHR_CMD                      0x0
> +#define PUSHR_TX                       0x2
> +
> +#define DMA_COMPLETION_TIMEOUT         msecs_to_jiffies(3000)
> +
> +struct chip_data {
> +       u32                     ctar_val;
> +       u16                     void_write_data;
> +};
> +
> +struct fsl_dspi_devtype_data {
> +       u8                      max_clock_factor;
> +       bool                    ptp_sts_supported;
> +       bool                    xspi_mode;
> +};
> +
> +static const struct fsl_dspi_devtype_data ls1021a_v1_data = {
> +       .max_clock_factor       = 8,
> +       .ptp_sts_supported      = true,
> +       .xspi_mode              = true,
> +};
> +
> +static const struct fsl_dspi_devtype_data ls2085a_data = {
> +       .max_clock_factor       = 8,
> +       .ptp_sts_supported      = true,
> +};
> +
> +struct fsl_dspi {
> +       struct spi_controller                   ctlr;
> +       struct device_d                         *dev;
> +
> +       struct regmap                           *regmap;
> +       struct regmap                           *regmap_pushr;
> +       int                                     irq;
> +       struct clk                              *clk;
> +
> +       struct spi_transfer                     *cur_transfer;
> +       struct spi_message                      *cur_msg;
> +       struct chip_data                        *cur_chip;
> +       size_t                                  progress;
> +       size_t                                  len;
> +       const void                              *tx;
> +       void                                    *rx;
> +       void                                    *rx_end;
> +       u16                                     void_write_data;
> +       u16                                     tx_cmd;
> +       u8                                      bits_per_word;
> +       u8                                      bytes_per_word;
> +       const struct fsl_dspi_devtype_data      *devtype_data;
> +};
> +
> +static u32 dspi_pop_tx(struct fsl_dspi *dspi)
> +{
> +       u32 txdata = 0;
> +
> +       if (dspi->tx) {
> +               if (dspi->bytes_per_word == 1)
> +                       txdata = *(u8 *)dspi->tx;
> +               else if (dspi->bytes_per_word == 2)
> +                       txdata = *(u16 *)dspi->tx;
> +               else  /* dspi->bytes_per_word == 4 */
> +                       txdata = *(u32 *)dspi->tx;
> +               dspi->tx += dspi->bytes_per_word;
> +       }
> +       dspi->len -= dspi->bytes_per_word;
> +       return txdata;
> +}
> +
> +static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
> +{
> +       u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
> +
> +       if (dspi->len > 0)
> +               cmd |= SPI_PUSHR_CMD_CONT;
> +       return cmd << 16 | data;
> +}
> +
> +static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
> +{
> +       if (!dspi->rx)
> +               return;
> +
> +       /* Mask off undefined bits */
> +       rxdata &= (1 << dspi->bits_per_word) - 1;
> +
> +       if (dspi->bytes_per_word == 1)
> +               *(u8 *)dspi->rx = rxdata;
> +       else if (dspi->bytes_per_word == 2)
> +               *(u16 *)dspi->rx = rxdata;
> +       else /* dspi->bytes_per_word == 4 */
> +               *(u32 *)dspi->rx = rxdata;
> +       dspi->rx += dspi->bytes_per_word;
> +}
> +
> +static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
> +                          unsigned long clkrate)
> +{
> +       /* Valid baud rate pre-scaler values */
> +       int pbr_tbl[4] = {2, 3, 5, 7};
> +       int brs[16] = { 2,      4,      6,      8,
> +                       16,     32,     64,     128,
> +                       256,    512,    1024,   2048,
> +                       4096,   8192,   16384,  32768 };
> +       int scale_needed, scale, minscale = INT_MAX;
> +       int i, j;
> +
> +       scale_needed = clkrate / speed_hz;
> +       if (clkrate % speed_hz)
> +               scale_needed++;
> +
> +       for (i = 0; i < ARRAY_SIZE(brs); i++)
> +               for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) {
> +                       scale = brs[i] * pbr_tbl[j];
> +                       if (scale >= scale_needed) {
> +                               if (scale < minscale) {
> +                                       minscale = scale;
> +                                       *br = i;
> +                                       *pbr = j;
> +                               }
> +                               break;
> +                       }
> +               }
> +
> +       if (minscale == INT_MAX) {
> +               pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld, we use the max prescaler value.\n",
> +                       speed_hz, clkrate);
> +               *pbr = ARRAY_SIZE(pbr_tbl) - 1;
> +               *br =  ARRAY_SIZE(brs) - 1;
> +       }
> +}
> +
> +static void ns_delay_scale(char *psc, char *sc, int delay_ns,
> +                          unsigned long clkrate)
> +{
> +       int scale_needed, scale, minscale = INT_MAX;
> +       int pscale_tbl[4] = {1, 3, 5, 7};
> +       u32 remainder;
> +       int i, j;
> +
> +       scale_needed = div_u64_rem((u64)delay_ns * clkrate, NSEC_PER_SEC,
> +                                  &remainder);
> +       if (remainder)
> +               scale_needed++;
> +
> +       for (i = 0; i < ARRAY_SIZE(pscale_tbl); i++)
> +               for (j = 0; j <= SPI_CTAR_SCALE_BITS; j++) {
> +                       scale = pscale_tbl[i] * (2 << j);
> +                       if (scale >= scale_needed) {
> +                               if (scale < minscale) {
> +                                       minscale = scale;
> +                                       *psc = i;
> +                                       *sc = j;
> +                               }
> +                               break;
> +                       }
> +               }
> +
> +       if (minscale == INT_MAX) {
> +               pr_warn("Cannot find correct scale values for %dns delay at clkrate %ld, using max prescaler value",
> +                       delay_ns, clkrate);
> +               *psc = ARRAY_SIZE(pscale_tbl) - 1;
> +               *sc = SPI_CTAR_SCALE_BITS;
> +       }
> +}
> +
> +static void fifo_write(struct fsl_dspi *dspi)
> +{
> +       regmap_write(dspi->regmap, SPI_PUSHR, dspi_pop_tx_pushr(dspi));
> +}
> +
> +static void cmd_fifo_write(struct fsl_dspi *dspi)
> +{
> +       u16 cmd = dspi->tx_cmd;
> +
> +       if (dspi->len > 0)
> +               cmd |= SPI_PUSHR_CMD_CONT;
> +       regmap_write(dspi->regmap_pushr, PUSHR_CMD, cmd);
> +}
> +
> +static void tx_fifo_write(struct fsl_dspi *dspi, u16 txdata)
> +{
> +       regmap_write(dspi->regmap_pushr, PUSHR_TX, txdata);
> +}
> +
> +static void dspi_tcfq_write(struct fsl_dspi *dspi)
> +{
> +       /* Clear transfer count */
> +       dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
> +
> +       if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) {
> +               /* Write the CMD FIFO entry first, and then the two
> +                * corresponding TX FIFO entries.
> +                */
> +               u32 data = dspi_pop_tx(dspi);
> +
> +               cmd_fifo_write(dspi);
> +               tx_fifo_write(dspi, data & 0xFFFF);
> +               tx_fifo_write(dspi, data >> 16);
> +       } else {
> +               /* Write one entry to both TX FIFO and CMD FIFO
> +                * simultaneously.
> +                */
> +               fifo_write(dspi);
> +       }
> +}
> +
> +static u32 fifo_read(struct fsl_dspi *dspi)
> +{
> +       u32 rxdata = 0;
> +
> +       regmap_read(dspi->regmap, SPI_POPR, &rxdata);
> +       return rxdata;
> +}
> +
> +static void dspi_tcfq_read(struct fsl_dspi *dspi)
> +{
> +       dspi_push_rx(dspi, fifo_read(dspi));
> +}
> +
> +static int dspi_rxtx(struct fsl_dspi *dspi)
> +{
> +       struct spi_message *msg = dspi->cur_msg;
> +       u16 spi_tcnt;
> +       u32 spi_tcr;
> +
> +       /* Get transfer counter (in number of SPI transfers). It was
> +        * reset to 0 when transfer(s) were started.
> +        */
> +       regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
> +       spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
> +       /* Update total number of bytes that were transferred */
> +       msg->actual_length += spi_tcnt * dspi->bytes_per_word;
> +       dspi->progress += spi_tcnt;
> +
> +       dspi_tcfq_read(dspi);
> +       if (!dspi->len)
> +               /* Success! */
> +               return 0;
> +
> +       dspi_tcfq_write(dspi);
> +
> +       return -EINPROGRESS;
> +}
> +
> +static int dspi_poll(struct fsl_dspi *dspi)
> +{
> +       int tries = 1000;
> +       u32 spi_sr;
> +
> +       do {
> +               regmap_read(dspi->regmap, SPI_SR, &spi_sr);
> +               regmap_write(dspi->regmap, SPI_SR, spi_sr);
> +
> +               if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF))
> +                       break;
> +               udelay(1);
> +       } while (--tries);
> +
> +       if (!tries)
> +               return -ETIMEDOUT;
> +
> +       return dspi_rxtx(dspi);
> +}
> +
> +static int dspi_transfer_one_message(struct spi_device *spi,
> +                                    struct spi_message *message)
> +{
> +       struct fsl_dspi *dspi = container_of(spi->master, struct fsl_dspi, ctlr);
> +       struct spi_transfer *transfer;
> +       int status = 0;
> +
> +       message->actual_length = 0;
> +
> +       list_for_each_entry(transfer, &message->transfers, transfer_list) {
> +               dspi->cur_transfer = transfer;
> +               dspi->cur_msg = message;
> +               dspi->cur_chip = spi->controller_data;
> +               /* Prepare command word for CMD FIFO */
> +               dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0) |
> +                              SPI_PUSHR_CMD_PCS(spi->chip_select);
> +               if (list_is_last(&dspi->cur_transfer->transfer_list,
> +                                &dspi->cur_msg->transfers)) {
> +                       /* Leave PCS activated after last transfer when
> +                        * cs_change is set.
> +                        */
> +                       if (transfer->cs_change)
> +                               dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
> +               } else {
> +                       /* Keep PCS active between transfers in same message
> +                        * when cs_change is not set, and de-activate PCS
> +                        * between transfers in the same message when
> +                        * cs_change is set.
> +                        */
> +                       if (!transfer->cs_change)
> +                               dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
> +               }
> +
> +               dspi->void_write_data = dspi->cur_chip->void_write_data;
> +
> +               dspi->tx = transfer->tx_buf;
> +               dspi->rx = transfer->rx_buf;
> +               dspi->rx_end = dspi->rx + transfer->len;
> +               dspi->len = transfer->len;
> +               dspi->progress = 0;
> +               /* Validated transfer specific frame size (defaults applied) */
> +               dspi->bits_per_word = transfer->bits_per_word;
> +
> +               if (transfer->bits_per_word <= 8)
> +                       dspi->bytes_per_word = 1;
> +               else if (transfer->bits_per_word <= 16)
> +                       dspi->bytes_per_word = 2;
> +               else
> +                       dspi->bytes_per_word = 4;
> +
> +               regmap_update_bits(dspi->regmap, SPI_MCR,
> +                                  SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
> +                                  SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
> +               regmap_write(dspi->regmap, SPI_CTAR(0),
> +                            dspi->cur_chip->ctar_val |
> +                            SPI_FRAME_BITS(transfer->bits_per_word));
> +               if (dspi->devtype_data->xspi_mode)
> +                       regmap_write(dspi->regmap, SPI_CTARE(0),
> +                                    SPI_FRAME_EBITS(transfer->bits_per_word) |
> +                                    SPI_CTARE_DTCP(1));
> +
> +               regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE);
> +               dspi_tcfq_write(dspi);
> +
> +               do {
> +                       status = dspi_poll(dspi);
> +               } while (status == -EINPROGRESS);
> +
> +               if (status)
> +                       dev_err(dspi->dev,
> +                               "Waiting for transfer to complete failed!\n");
> +       }
> +
> +       message->status = status;
> +
> +       return status;
> +}
> +
> +static int dspi_setup(struct spi_device *spi)
> +{
> +       struct fsl_dspi *dspi = container_of(spi->master, struct fsl_dspi, ctlr);
> +       unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
> +       u32 cs_sck_delay = 0, sck_cs_delay = 0;
> +       unsigned char pasc = 0, asc = 0;
> +       struct chip_data *chip;
> +       unsigned long clkrate;
> +
> +       /* Only alloc on first setup */
> +       chip = spi->controller_data;
> +       if (chip == NULL) {
> +               chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
> +               if (!chip)
> +                       return -ENOMEM;
> +       }
> +
> +       of_property_read_u32(spi->dev.device_node, "fsl,spi-cs-sck-delay",
> +                            &cs_sck_delay);
> +
> +       of_property_read_u32(spi->dev.device_node, "fsl,spi-sck-cs-delay",
> +                            &sck_cs_delay);
> +
> +       chip->void_write_data = 0;
> +
> +       clkrate = clk_get_rate(dspi->clk);
> +       hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
> +
> +       /* Set PCS to SCK delay scale values */
> +       ns_delay_scale(&pcssck, &cssck, cs_sck_delay, clkrate);
> +
> +       /* Set After SCK delay scale values */
> +       ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate);
> +
> +       chip->ctar_val = 0;
> +       if (spi->mode & SPI_CPOL)
> +               chip->ctar_val |= SPI_CTAR_CPOL;
> +       if (spi->mode & SPI_CPHA)
> +               chip->ctar_val |= SPI_CTAR_CPHA;
> +
> +       chip->ctar_val |= SPI_CTAR_PCSSCK(pcssck) |
> +                         SPI_CTAR_CSSCK(cssck) |
> +                         SPI_CTAR_PASC(pasc) |
> +                         SPI_CTAR_ASC(asc) |
> +                         SPI_CTAR_PBR(pbr) |
> +                         SPI_CTAR_BR(br);
> +
> +       if (spi->mode & SPI_LSB_FIRST)
> +               chip->ctar_val |= SPI_CTAR_LSBFE;
> +
> +       spi->controller_data = chip;
> +
> +       return 0;
> +}
> +
> +static void dspi_cleanup(struct spi_device *spi)
> +{
> +       struct chip_data *chip = spi->controller_data;
> +
> +       dev_dbg(&spi->dev, "spi_device %u.%u cleanup\n",
> +               spi->controller->bus_num, spi->chip_select);
> +
> +       kfree(chip);
> +}
> +
> +static const struct of_device_id fsl_dspi_dt_ids[] = {
> +       { .compatible = "fsl,ls1021a-v1.0-dspi", .data = &ls1021a_v1_data, },
> +       { .compatible = "fsl,ls2085a-dspi", .data = &ls2085a_data, },
> +       { /* sentinel */ }
> +};
> +
> +static const struct regmap_config dspi_regmap_config = {
> +       .reg_bits       = 32,
> +       .val_bits       = 32,
> +       .reg_stride     = 4,
> +       .max_register   = 0x88,
> +};
> +
> +static const struct regmap_config dspi_xspi_regmap_config[] = {
> +       {
> +               .reg_bits       = 32,
> +               .val_bits       = 32,
> +               .reg_stride     = 4,
> +               .max_register   = 0x13c,
> +       }, {
> +               .name           = "pushr",
> +               .reg_bits       = 16,
> +               .val_bits       = 16,
> +               .reg_stride     = 2,
> +               .max_register   = 0x2,
> +       },
> +};
> +
> +static void dspi_init(struct fsl_dspi *dspi)
> +{
> +       unsigned int mcr = SPI_MCR_PCSIS;
> +
> +       if (dspi->devtype_data->xspi_mode)
> +               mcr |= SPI_MCR_XSPI;
> +       mcr |= SPI_MCR_MASTER;
> +
> +       regmap_write(dspi->regmap, SPI_MCR, mcr);
> +       regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
> +       if (dspi->devtype_data->xspi_mode)
> +               regmap_write(dspi->regmap, SPI_CTARE(0),
> +                            SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1));
> +}
> +
> +static int dspi_probe(struct device_d *dev)
> +{
> +       struct device_node *np = dev->device_node;
> +       const struct regmap_config *regmap_config;
> +       struct spi_master *master;
> +       int ret, cs_num, bus_num = -1;
> +       struct fsl_dspi *dspi;
> +       struct resource *res;
> +       void __iomem *base;
> +
> +       dspi = xzalloc(sizeof(*dspi));
> +
> +       dspi->dev = dev;
> +       master = &dspi->ctlr;
> +
> +       master->dev = dev;
> +       master->setup = dspi_setup;
> +       master->transfer = dspi_transfer_one_message;
> +
> +       master->cleanup = dspi_cleanup;
> +
> +       ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
> +       if (ret < 0) {
> +               dev_err(dev, "can't get spi-num-chipselects\n");
> +               goto out_ctlr_put;
> +       }
> +       master->num_chipselect = cs_num;
> +
> +       of_property_read_u32(np, "bus-num", &bus_num);
> +       master->bus_num = bus_num;
> +
> +       ret = dev_get_drvdata(dev, (const void **)&dspi->devtype_data);
> +       if (ret)
> +               return -ENODEV;
> +
> +       res = dev_request_mem_resource(dev, 0);
> +       if (IS_ERR(res))
> +               return PTR_ERR(res);
> +
> +       base = IOMEM(res->start);
> +
> +       if (dspi->devtype_data->xspi_mode)
> +               regmap_config = &dspi_xspi_regmap_config[0];
> +       else
> +               regmap_config = &dspi_regmap_config;
> +
> +       dspi->regmap = regmap_init_mmio(dev, base, regmap_config);
> +       if (IS_ERR(dspi->regmap)) {
> +               dev_err(dev, "failed to init regmap: %ld\n",
> +                               PTR_ERR(dspi->regmap));
> +               ret = PTR_ERR(dspi->regmap);
> +               goto out_ctlr_put;
> +       }
> +
> +       if (dspi->devtype_data->xspi_mode) {
> +               dspi->regmap_pushr = regmap_init_mmio(
> +                       dev, base + SPI_PUSHR,
> +                       &dspi_xspi_regmap_config[1]);
> +               if (IS_ERR(dspi->regmap_pushr)) {
> +                       dev_err(dev,
> +                               "failed to init pushr regmap: %ld\n",
> +                               PTR_ERR(dspi->regmap_pushr));
> +                       ret = PTR_ERR(dspi->regmap_pushr);
> +                       goto out_ctlr_put;
> +               }
> +       }
> +
> +       dspi->clk = clk_get(dev, "dspi");
> +       if (IS_ERR(dspi->clk)) {
> +               ret = PTR_ERR(dspi->clk);
> +               dev_err(dev, "unable to get clock\n");
> +               goto out_ctlr_put;
> +       }
> +       ret = clk_enable(dspi->clk);
> +       if (ret)
> +               goto out_ctlr_put;
> +
> +       dspi_init(dspi);
> +
> +       ret = spi_register_master(master);
> +       if (ret != 0) {
> +               dev_err(dev, "Problem registering DSPI ctlr\n");
> +               goto out_clk_put;
> +       }
> +
> +       return ret;
> +
> +out_clk_put:
> +       clk_disable(dspi->clk);
> +out_ctlr_put:
> +
> +       return ret;
> +}
> +
> +static struct driver_d fsl_dspi_driver = {
> +       .name  = "fsl-dspi",
> +       .probe = dspi_probe,
> +       .of_compatible = DRV_OF_COMPAT(fsl_dspi_dt_ids),
> +};
> +coredevice_platform_driver(fsl_dspi_driver);
> --
> 2.26.0.rc2
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/5] spi: Add fsl-dspi driver
  2020-04-04 19:14   ` Andrey Smirnov
@ 2020-04-14 10:30     ` Sascha Hauer
  0 siblings, 0 replies; 8+ messages in thread
From: Sascha Hauer @ 2020-04-14 10:30 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: Barebox List

On Sat, Apr 04, 2020 at 12:14:33PM -0700, Andrey Smirnov wrote:
> On Wed, Mar 25, 2020 at 1:36 AM Sascha Hauer <s.hauer@pengutronix.de> wrote:
> >
> > The fsl-dspi is found on Freescale Vybrid, Coldfire and Layerscape SoCs.
> > This adds the driver based on the Linux driver as of v5.5. Coldfire
> > support has been dropped as it's rather obsolete. Vybrid support has
> > been dropped because it needs the DMA engine support we do not have in
> > barebox. What's left is support for Layerscape where this driver has
> > been tested on.
> >
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > ---
> >  drivers/spi/Kconfig        |   7 +
> >  drivers/spi/Makefile       |   1 +
> >  drivers/spi/spi-fsl-dspi.c | 655 +++++++++++++++++++++++++++++++++++++
> >  3 files changed, 663 insertions(+)
> >  create mode 100644 drivers/spi/spi-fsl-dspi.c
> >
> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> > index 3758a0fad9..96235a1be2 100644
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -44,6 +44,13 @@ config DRIVER_SPI_FSL_QUADSPI
> >            This controller does not support generic SPI messages. It only
> >            supports the high-level SPI memory interface.
> >
> > +config SPI_FSL_DSPI
> > +       bool "Freescale DSPI controller"
> > +       depends on ARCH_LAYERSCAPE
> > +       help
> > +         This enables support for the Freescale DSPI controller in master
> > +         mode. VF610, LS1021A and ColdFire platforms uses the controller.
> 
> Sorry I didn't notice this patch earlier. Maybe we should drop the
> wording about VF610 here since there a separate DSPI driver for Vybrid
> as well:  https://git.pengutronix.de/cgit/barebox/tree/drivers/spi/Kconfig?h=next#n90

So there already is a driver for this hardware in barebox. I missed that :(

I dropped the wording about VF610 for now, but the real solution should
be to use the existing driver or at least merge them. I'll see when and
if I can find time for this.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2020-04-14 10:30 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-25  8:36 [PATCH 0/5] Add fsl-dspi driver support Sascha Hauer
2020-03-25  8:36 ` [PATCH 1/5] regmap-mmio: Add missing pieces for 64bit support Sascha Hauer
2020-03-25  8:36 ` [PATCH 2/5] regmap-mmio: Add big endian support Sascha Hauer
2020-03-25  8:36 ` [PATCH 3/5] spi: validate spi messages Sascha Hauer
2020-03-25  8:36 ` [PATCH 4/5] spi: Add fsl-dspi driver Sascha Hauer
2020-04-04 19:14   ` Andrey Smirnov
2020-04-14 10:30     ` Sascha Hauer
2020-03-25  8:36 ` [PATCH 5/5] mtd: spi-nor: Add support for cy15x104q Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox