lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20251002-spi-dw-target-v1-2-993e91c1a712@bootlin.com>
Date: Thu, 02 Oct 2025 14:14:38 +0200
From: Benoît Monin <benoit.monin@...tlin.com>
To: Mark Brown <broonie@...nel.org>
Cc: Thomas Petazzoni <thomas.petazzoni@...tlin.com>, 
 Vladimir Kondratiev <vladimir.kondratiev@...ileye.com>, 
 Tawfik Bayouk <tawfik.bayouk@...ileye.com>, linux-spi@...r.kernel.org, 
 linux-kernel@...r.kernel.org, 
 Benoît Monin <benoit.monin@...tlin.com>
Subject: [PATCH RFC 2/2] spi: dw: add target mode support

Implement target mode for the DesignWare controller with the following
changes:

Allocate an SPI controller of the correct type based on the spi-slave
property in dw_spi_add_controller() and set the controller properties
depending on its type. Since they are only relevant when acting as a host
controller, settings related to chip-select control and the set_cs()
callback are only set in host mode, as are the loopback support, the
memory operations and the maximum frequency. The target_abort() callback
is set only when configured in target mode.

The number of chip-select is set to 1 in dw_spi_hw_init() since the
controller only has one CS input in target mode.

In dw_spi_update_config(), return after setting the CTRLR0 register as
the other registers are only relevant in host mode and are read-only
in target mode. This function is called as part of the transfer_one()
callback, which is identical in both the host and target mode.

Move the code implementing the handle_err() callback to a new function
named dw_spi_abort(), and use it to implement both the handle_err()
and the target_abort() callbacks.

Finally, drop the error path on the spi-slave property in
dw_spi_mmio_probe(), as it is now a valid configuration.

Signed-off-by: Benoît Monin <benoit.monin@...tlin.com>
---
 drivers/spi/spi-dw-core.c | 82 ++++++++++++++++++++++++++++++++---------------
 drivers/spi/spi-dw-mmio.c |  5 ---
 2 files changed, 57 insertions(+), 30 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 90dea6f9b3dab773204c667cb12f3ecaef1d7108..9ebf244294f89db1c5f26471d18eb298ae804cd9 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -332,6 +332,9 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
 
 	dw_writel(dws, DW_SPI_CTRLR0, cr0);
 
+	if (spi_controller_is_target(dws->ctlr))
+		return;
+
 	if (cfg->tmode == DW_SPI_CTRLR0_TMOD_EPROMREAD ||
 	    cfg->tmode == DW_SPI_CTRLR0_TMOD_RO)
 		dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
@@ -462,8 +465,7 @@ static int dw_spi_transfer_one(struct spi_controller *ctlr,
 	return 1;
 }
 
-static void dw_spi_handle_err(struct spi_controller *ctlr,
-			      struct spi_message *msg)
+static inline void dw_spi_abort(struct spi_controller *ctlr)
 {
 	struct dw_spi *dws = spi_controller_get_devdata(ctlr);
 
@@ -473,6 +475,19 @@ static void dw_spi_handle_err(struct spi_controller *ctlr,
 	dw_spi_reset_chip(dws);
 }
 
+static void dw_spi_handle_err(struct spi_controller *ctlr,
+			      struct spi_message *msg)
+{
+	dw_spi_abort(ctlr);
+}
+
+static int dw_spi_target_abort(struct spi_controller *ctlr)
+{
+	dw_spi_abort(ctlr);
+
+	return 0;
+}
+
 static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
 {
 	if (op->data.dir == SPI_MEM_DATA_IN)
@@ -834,18 +849,23 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
 			DW_SPI_GET_BYTE(dws->ver, 1));
 	}
 
-	/*
-	 * Try to detect the number of native chip-selects if the platform
-	 * driver didn't set it up. There can be up to 16 lines configured.
-	 */
-	if (!dws->num_cs) {
-		u32 ser;
+	if (spi_controller_is_target(dws->ctlr)) {
+		/* There is only one CS input signal in target mode */
+		dws->num_cs = 1;
+	} else {
+		/*
+		 * Try to detect the number of native chip-selects if the platform
+		 * driver didn't set it up. There can be up to 16 lines configured.
+		 */
+		if (!dws->num_cs) {
+			u32 ser;
 
-		dw_writel(dws, DW_SPI_SER, 0xffff);
-		ser = dw_readl(dws, DW_SPI_SER);
-		dw_writel(dws, DW_SPI_SER, 0);
+			dw_writel(dws, DW_SPI_SER, 0xffff);
+			ser = dw_readl(dws, DW_SPI_SER);
+			dw_writel(dws, DW_SPI_SER, 0);
 
-		dws->num_cs = hweight16(ser);
+			dws->num_cs = hweight16(ser);
+		}
 	}
 
 	/*
@@ -901,12 +921,18 @@ static const struct spi_controller_mem_caps dw_spi_mem_caps = {
 int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
 {
 	struct spi_controller *ctlr;
+	bool target;
 	int ret;
 
 	if (!dws)
 		return -EINVAL;
 
-	ctlr = spi_alloc_host(dev, 0);
+	target = device_property_read_bool(dev, "spi-slave");
+	if (target)
+		ctlr = spi_alloc_target(dev, 0);
+	else
+		ctlr = spi_alloc_host(dev, 0);
+
 	if (!ctlr)
 		return -ENOMEM;
 
@@ -929,8 +955,7 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
 
 	dw_spi_init_mem_ops(dws);
 
-	ctlr->use_gpio_descriptors = true;
-	ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
+	ctlr->mode_bits = SPI_CPOL | SPI_CPHA;
 	if (dws->caps & DW_SPI_CAP_DFS32)
 		ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
 	else
@@ -939,20 +964,27 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
 	ctlr->num_chipselect = dws->num_cs;
 	ctlr->setup = dw_spi_setup;
 	ctlr->cleanup = dw_spi_cleanup;
-	if (dws->set_cs)
-		ctlr->set_cs = dws->set_cs;
-	else
-		ctlr->set_cs = dw_spi_set_cs;
 	ctlr->transfer_one = dw_spi_transfer_one;
 	ctlr->handle_err = dw_spi_handle_err;
-	if (dws->mem_ops.exec_op) {
-		ctlr->mem_ops = &dws->mem_ops;
-		ctlr->mem_caps = &dw_spi_mem_caps;
-	}
-	ctlr->max_speed_hz = dws->max_freq;
-	ctlr->flags = SPI_CONTROLLER_GPIO_SS;
 	ctlr->auto_runtime_pm = true;
 
+	if (!target) {
+		ctlr->use_gpio_descriptors = true;
+		ctlr->mode_bits |= SPI_LOOP;
+		if (dws->set_cs)
+			ctlr->set_cs = dws->set_cs;
+		else
+			ctlr->set_cs = dw_spi_set_cs;
+		if (dws->mem_ops.exec_op) {
+			ctlr->mem_ops = &dws->mem_ops;
+			ctlr->mem_caps = &dw_spi_mem_caps;
+		}
+		ctlr->max_speed_hz = dws->max_freq;
+		ctlr->flags = SPI_CONTROLLER_GPIO_SS;
+	} else {
+		ctlr->target_abort = dw_spi_target_abort;
+	}
+
 	/* Get default rx sample delay */
 	device_property_read_u32(dev, "rx-sample-delay-ns",
 				 &dws->def_rx_sample_dly_ns);
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index cc16139e121bf2dae29a16e362db56ea8ad3a18b..f2cd675a9a1980fba447e13e356bb81a0395256e 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -321,11 +321,6 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
 	struct dw_spi *dws;
 	int ret;
 
-	if (device_property_read_bool(&pdev->dev, "spi-slave")) {
-		dev_warn(&pdev->dev, "spi-slave is not yet supported\n");
-		return -ENODEV;
-	}
-
 	dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio),
 			GFP_KERNEL);
 	if (!dwsmmio)

-- 
2.51.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ