All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] fpga: xilinx-spi: extract a common driver core
@ 2024-01-29 22:56 Charles Perry
  2024-01-29 22:56 ` [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema Charles Perry
                   ` (2 more replies)
  0 siblings, 3 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-29 22:56 UTC (permalink / raw)
  To: mdf
  Cc: hao.wu, yilun.xu, trix, krzysztof.kozlowski+dt, bcody, avandiver,
	linux-fpga, devicetree, linux-kernel, Charles Perry

Factor out the gpio handshaking (using PROGRAM_B, INIT_B and DONE)
protocol in xilinx-core so that it can be reused for another driver.
This commit does not change anything functionally to xilinx-spi.

xilinx-core expects drivers to provide two operations:

 * ->write(const char* buf, size_t count): write to the device
 * ->write_one_dummy_byte(): write 0xFF to the device

Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
---
 drivers/fpga/Kconfig       |   4 +
 drivers/fpga/Makefile      |   1 +
 drivers/fpga/xilinx-core.c | 210 +++++++++++++++++++++++++++++++++++++
 drivers/fpga/xilinx-core.h |  27 +++++
 drivers/fpga/xilinx-spi.c  | 202 +++--------------------------------
 5 files changed, 256 insertions(+), 188 deletions(-)
 create mode 100644 drivers/fpga/xilinx-core.c
 create mode 100644 drivers/fpga/xilinx-core.h

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 2f689ac4ba3a3..d27a1ebf40838 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -64,9 +64,13 @@ config FPGA_MGR_STRATIX10_SOC
 	help
 	  FPGA manager driver support for the Intel Stratix10 SoC.
 
+config FPGA_MGR_XILINX_CORE
+	tristate
+
 config FPGA_MGR_XILINX_SPI
 	tristate "Xilinx Configuration over Slave Serial (SPI)"
 	depends on SPI
+	select FPGA_MGR_XILINX_CORE
 	help
 	  FPGA manager driver support for Xilinx FPGA configuration
 	  over slave serial interface.
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 352a2612623e0..7ec795b6a5a70 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
 obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
 obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
 obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
+obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
 obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
new file mode 100644
index 0000000000000..47839b5541ddd
--- /dev/null
+++ b/drivers/fpga/xilinx-core.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common parts of the Xilinx Spartan6 and 7 Series FPGA manager drivers.
+ *
+ * Copyright (C) 2017 DENX Software Engineering
+ *
+ * Anatolij Gustschin <agust@denx.de>
+ */
+
+#include "xilinx-core.h"
+
+#include <linux/delay.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+
+static int get_done_gpio(struct fpga_manager *mgr)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	int ret;
+
+	ret = gpiod_get_value(core->done);
+
+	if (ret < 0)
+		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
+
+	return ret;
+}
+
+static enum fpga_mgr_states xilinx_core_state(struct fpga_manager *mgr)
+{
+	if (!get_done_gpio(mgr))
+		return FPGA_MGR_STATE_RESET;
+
+	return FPGA_MGR_STATE_UNKNOWN;
+}
+
+/**
+ * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
+ * a given delay if the pin is unavailable
+ *
+ * @mgr:        The FPGA manager object
+ * @value:      Value INIT_B to wait for (1 = asserted = low)
+ * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
+ *
+ * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
+ * too much time passed waiting for that. If no INIT_B GPIO is available
+ * then always return 0.
+ */
+static int wait_for_init_b(struct fpga_manager *mgr, int value,
+			   unsigned long alt_udelay)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+	if (core->init_b) {
+		while (time_before(jiffies, timeout)) {
+			int ret = gpiod_get_value(core->init_b);
+
+			if (ret == value)
+				return 0;
+
+			if (ret < 0) {
+				dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
+				return ret;
+			}
+
+			usleep_range(100, 400);
+		}
+
+		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
+			value ? "assert" : "deassert");
+		return -ETIMEDOUT;
+	}
+
+	udelay(alt_udelay);
+
+	return 0;
+}
+
+static int xilinx_core_write_init(struct fpga_manager *mgr,
+				 struct fpga_image_info *info,
+				 const char *buf, size_t count)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	int err;
+
+	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
+		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
+		return -EINVAL;
+	}
+
+	gpiod_set_value(core->prog_b, 1);
+
+	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
+	if (err) {
+		gpiod_set_value(core->prog_b, 0);
+		return err;
+	}
+
+	gpiod_set_value(core->prog_b, 0);
+
+	err = wait_for_init_b(mgr, 0, 0);
+	if (err)
+		return err;
+
+	if (get_done_gpio(mgr)) {
+		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
+		return -EIO;
+	}
+
+	/* program latency */
+	usleep_range(7500, 7600);
+	return 0;
+}
+
+static int xilinx_core_write(struct fpga_manager *mgr, const char *buf,
+			    size_t count)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+
+	return core->write(core, buf, count);
+}
+
+static int xilinx_core_write_complete(struct fpga_manager *mgr,
+				     struct fpga_image_info *info)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	unsigned long timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
+	bool expired = false;
+	int done;
+	int ret;
+
+	/*
+	 * This loop is carefully written such that if the driver is
+	 * scheduled out for more than 'timeout', we still check for DONE
+	 * before giving up and we apply 8 extra CCLK cycles in all cases.
+	 */
+	while (!expired) {
+		expired = time_after(jiffies, timeout);
+
+		done = get_done_gpio(mgr);
+		if (done < 0)
+			return done;
+
+		ret = core->write_one_dummy_byte(core);
+		if (ret)
+			return ret;
+
+		if (done)
+			return 0;
+	}
+
+	if (core->init_b) {
+		ret = gpiod_get_value(core->init_b);
+
+		if (ret < 0) {
+			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
+			return ret;
+		}
+
+		dev_err(&mgr->dev,
+			ret ? "CRC error or invalid device\n"
+			: "Missing sync word or incomplete bitstream\n");
+	} else {
+		dev_err(&mgr->dev, "Timeout after config data transfer\n");
+	}
+
+	return -ETIMEDOUT;
+}
+
+static const struct fpga_manager_ops xilinx_core_ops = {
+	.state = xilinx_core_state,
+	.write_init = xilinx_core_write_init,
+	.write = xilinx_core_write,
+	.write_complete = xilinx_core_write_complete,
+};
+
+int xilinx_core_probe(struct xilinx_fpga_core *core,
+					  struct device *dev,
+					  xilinx_write_func write,
+					  xilinx_write_one_dummy_byte_func write_one_dummy_byte)
+{
+	struct fpga_manager *mgr;
+
+	core->dev = dev;
+	core->write = write;
+	core->write_one_dummy_byte = write_one_dummy_byte;
+
+	/* PROGRAM_B is active low */
+	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
+	if (IS_ERR(core->prog_b))
+		return dev_err_probe(dev, PTR_ERR(core->prog_b),
+				     "Failed to get PROGRAM_B gpio\n");
+
+	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
+	if (IS_ERR(core->init_b))
+		return dev_err_probe(dev, PTR_ERR(core->init_b),
+				     "Failed to get INIT_B gpio\n");
+
+	core->done = devm_gpiod_get(dev, "done", GPIOD_IN);
+	if (IS_ERR(core->done))
+		return dev_err_probe(dev, PTR_ERR(core->done),
+				     "Failed to get DONE gpio\n");
+
+	mgr = devm_fpga_mgr_register(dev,
+				     "Xilinx Slave Serial FPGA Manager",
+				     &xilinx_core_ops, core);
+	return PTR_ERR_OR_ZERO(mgr);
+}
diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
new file mode 100644
index 0000000000000..2e6ce2235531f
--- /dev/null
+++ b/drivers/fpga/xilinx-core.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef	__XILINX_CORE_H
+#define	__XILINX_CORE_H
+
+#include <linux/device.h>
+
+struct xilinx_fpga_core;
+
+typedef int (*xilinx_write_func)(struct xilinx_fpga_core *core, const char *buf,
+			    size_t count);
+typedef int (*xilinx_write_one_dummy_byte_func)(struct xilinx_fpga_core *core);
+
+struct xilinx_fpga_core {
+	struct device *dev;
+	xilinx_write_func write;
+	xilinx_write_one_dummy_byte_func write_one_dummy_byte;
+	struct gpio_desc *prog_b;
+	struct gpio_desc *init_b;
+	struct gpio_desc *done;
+};
+
+int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
+					xilinx_write_func write,
+					xilinx_write_one_dummy_byte_func write_one_dummy_byte);
+
+#endif /* __XILINX_CORE_H */
diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
index e1a227e7ff2ae..71d8d421f3c63 100644
--- a/drivers/fpga/xilinx-spi.c
+++ b/drivers/fpga/xilinx-spi.c
@@ -10,127 +10,25 @@
  * the slave serial configuration interface.
  */
 
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/fpga/fpga-mgr.h>
-#include <linux/gpio/consumer.h>
+#include "xilinx-core.h"
+
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/of.h>
 #include <linux/spi/spi.h>
-#include <linux/sizes.h>
 
 struct xilinx_spi_conf {
+	struct xilinx_fpga_core core;
 	struct spi_device *spi;
-	struct gpio_desc *prog_b;
-	struct gpio_desc *init_b;
-	struct gpio_desc *done;
 };
 
-static int get_done_gpio(struct fpga_manager *mgr)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	int ret;
-
-	ret = gpiod_get_value(conf->done);
-
-	if (ret < 0)
-		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
-
-	return ret;
-}
-
-static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
-{
-	if (!get_done_gpio(mgr))
-		return FPGA_MGR_STATE_RESET;
-
-	return FPGA_MGR_STATE_UNKNOWN;
-}
-
-/**
- * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
- * a given delay if the pin is unavailable
- *
- * @mgr:        The FPGA manager object
- * @value:      Value INIT_B to wait for (1 = asserted = low)
- * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
- *
- * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
- * too much time passed waiting for that. If no INIT_B GPIO is available
- * then always return 0.
- */
-static int wait_for_init_b(struct fpga_manager *mgr, int value,
-			   unsigned long alt_udelay)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-	if (conf->init_b) {
-		while (time_before(jiffies, timeout)) {
-			int ret = gpiod_get_value(conf->init_b);
-
-			if (ret == value)
-				return 0;
-
-			if (ret < 0) {
-				dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
-				return ret;
-			}
-
-			usleep_range(100, 400);
-		}
-
-		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
-			value ? "assert" : "deassert");
-		return -ETIMEDOUT;
-	}
-
-	udelay(alt_udelay);
-
-	return 0;
-}
-
-static int xilinx_spi_write_init(struct fpga_manager *mgr,
-				 struct fpga_image_info *info,
-				 const char *buf, size_t count)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	int err;
-
-	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
-		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
-		return -EINVAL;
-	}
-
-	gpiod_set_value(conf->prog_b, 1);
-
-	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
-	if (err) {
-		gpiod_set_value(conf->prog_b, 0);
-		return err;
-	}
-
-	gpiod_set_value(conf->prog_b, 0);
-
-	err = wait_for_init_b(mgr, 0, 0);
-	if (err)
-		return err;
-
-	if (get_done_gpio(mgr)) {
-		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
-		return -EIO;
-	}
-
-	/* program latency */
-	usleep_range(7500, 7600);
-	return 0;
-}
+#define to_xilinx_spi_conf(obj) \
+	container_of(obj, struct xilinx_spi_conf, core)
 
-static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
+static int xilinx_spi_write(struct xilinx_fpga_core *core, const char *buf,
 			    size_t count)
 {
-	struct xilinx_spi_conf *conf = mgr->priv;
+	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
 	const char *fw_data = buf;
 	const char *fw_data_end = fw_data + count;
 
@@ -143,7 +41,7 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
 
 		ret = spi_write(conf->spi, fw_data, stride);
 		if (ret) {
-			dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
+			dev_err(core->dev, "SPI error in firmware write: %d\n",
 				ret);
 			return ret;
 		}
@@ -153,77 +51,22 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
 	return 0;
 }
 
-static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf)
+static int xilinx_spi_apply_cclk_cycles(struct xilinx_fpga_core *core)
 {
-	struct spi_device *spi = conf->spi;
+	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
 	const u8 din_data[1] = { 0xff };
 	int ret;
 
 	ret = spi_write(conf->spi, din_data, sizeof(din_data));
 	if (ret)
-		dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret);
+		dev_err(core->dev, "applying CCLK cycles failed: %d\n", ret);
 
 	return ret;
 }
 
-static int xilinx_spi_write_complete(struct fpga_manager *mgr,
-				     struct fpga_image_info *info)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	unsigned long timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
-	bool expired = false;
-	int done;
-	int ret;
-
-	/*
-	 * This loop is carefully written such that if the driver is
-	 * scheduled out for more than 'timeout', we still check for DONE
-	 * before giving up and we apply 8 extra CCLK cycles in all cases.
-	 */
-	while (!expired) {
-		expired = time_after(jiffies, timeout);
-
-		done = get_done_gpio(mgr);
-		if (done < 0)
-			return done;
-
-		ret = xilinx_spi_apply_cclk_cycles(conf);
-		if (ret)
-			return ret;
-
-		if (done)
-			return 0;
-	}
-
-	if (conf->init_b) {
-		ret = gpiod_get_value(conf->init_b);
-
-		if (ret < 0) {
-			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
-			return ret;
-		}
-
-		dev_err(&mgr->dev,
-			ret ? "CRC error or invalid device\n"
-			: "Missing sync word or incomplete bitstream\n");
-	} else {
-		dev_err(&mgr->dev, "Timeout after config data transfer\n");
-	}
-
-	return -ETIMEDOUT;
-}
-
-static const struct fpga_manager_ops xilinx_spi_ops = {
-	.state = xilinx_spi_state,
-	.write_init = xilinx_spi_write_init,
-	.write = xilinx_spi_write,
-	.write_complete = xilinx_spi_write_complete,
-};
-
 static int xilinx_spi_probe(struct spi_device *spi)
 {
 	struct xilinx_spi_conf *conf;
-	struct fpga_manager *mgr;
 
 	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
 	if (!conf)
@@ -231,26 +74,9 @@ static int xilinx_spi_probe(struct spi_device *spi)
 
 	conf->spi = spi;
 
-	/* PROGRAM_B is active low */
-	conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW);
-	if (IS_ERR(conf->prog_b))
-		return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b),
-				     "Failed to get PROGRAM_B gpio\n");
-
-	conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN);
-	if (IS_ERR(conf->init_b))
-		return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b),
-				     "Failed to get INIT_B gpio\n");
-
-	conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
-	if (IS_ERR(conf->done))
-		return dev_err_probe(&spi->dev, PTR_ERR(conf->done),
-				     "Failed to get DONE gpio\n");
-
-	mgr = devm_fpga_mgr_register(&spi->dev,
-				     "Xilinx Slave Serial FPGA Manager",
-				     &xilinx_spi_ops, conf);
-	return PTR_ERR_OR_ZERO(mgr);
+	return xilinx_core_probe(&conf->core, &spi->dev,
+							&xilinx_spi_write,
+							&xilinx_spi_apply_cclk_cycles);
 }
 
 #ifdef CONFIG_OF
-- 
2.43.0


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

* [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-29 22:56 [PATCH 1/3] fpga: xilinx-spi: extract a common driver core Charles Perry
@ 2024-01-29 22:56 ` Charles Perry
  2024-01-30  0:21   ` Rob Herring
                     ` (2 more replies)
  2024-01-29 22:56 ` [PATCH 3/3] fpga: xilinx-selectmap: add new driver Charles Perry
  2024-01-31 23:05   ` Charles Perry
  2 siblings, 3 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-29 22:56 UTC (permalink / raw)
  To: mdf
  Cc: hao.wu, yilun.xu, trix, krzysztof.kozlowski+dt, bcody, avandiver,
	linux-fpga, devicetree, linux-kernel, Charles Perry

Document the slave SelectMAP interface of Xilinx 7 series FPGA.

Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
---
 .../fpga/xlnx,fpga-slave-selectmap.yaml       | 85 +++++++++++++++++++
 1 file changed, 85 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml

diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml b/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
new file mode 100644
index 0000000000000..20cea24e3e39a
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/xlnx,fpga-slave-selectmap.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Xilinx Slave SelectMAP FPGA
+
+description: |
+  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
+  parallel port named the slave SelectMAP interface in the documentation. Only
+  the x8 mode is supported where data is loaded at one byte per rising edge of
+  the clock, with the MSB of each byte presented to the D0 pin.
+
+  Datasheets:
+    https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
+
+properties:
+  compatible:
+    enum:
+      - xlnx,fpga-slave-selectmap
+
+  reg:
+    description:
+      At least 1 byte of memory mapped IO
+    maxItems: 1
+
+  prog_b-gpios:
+    description:
+      config pin (referred to as PROGRAM_B in the manual)
+    maxItems: 1
+
+  done-gpios:
+    description:
+      config status pin (referred to as DONE in the manual)
+    maxItems: 1
+
+  init-b-gpios:
+    description:
+      initialization status and configuration error pin
+      (referred to as INIT_B in the manual)
+    maxItems: 1
+
+  csi-b-gpios:
+    description:
+      chip select pin (referred to as CSI_B in the manual)
+      Optional gpio for if the bus controller does not provide a chip select.
+    maxItems: 1
+
+  rdwr-b-gpios:
+    description:
+      read/write select pin (referred to as RDWR_B in the manual)
+      Optional gpio for if the bus controller does not provide this pin.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - prog_b-gpios
+  - done-gpios
+  - init-b-gpios
+
+additionalProperties: true
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    &weim {
+      status = "okay";
+      ranges = <0 0 0x08000000 0x04000000>;
+
+      fpga_mgr: fpga_programmer@0,0 {
+        compatible = "xlnx,fpga-slave-selectmap";
+        reg = <0 0 0x4000000>;
+        fsl,weim-cs-timing = <0x00070031 0x00000142
+              0x00020000 0x00000000
+              0x0c000645 0x00000000>;
+        prog_b-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>;
+        init-b-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
+        done-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
+        csi-b-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+        rdwr-b-gpios = <&gpio3 10 GPIO_ACTIVE_LOW>;
+      };
+    };
+...
-- 
2.43.0


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

* [PATCH 3/3] fpga: xilinx-selectmap: add new driver
  2024-01-29 22:56 [PATCH 1/3] fpga: xilinx-spi: extract a common driver core Charles Perry
  2024-01-29 22:56 ` [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema Charles Perry
@ 2024-01-29 22:56 ` Charles Perry
  2024-01-30  7:56   ` Krzysztof Kozlowski
  2024-01-31 23:05   ` Charles Perry
  2 siblings, 1 reply; 44+ messages in thread
From: Charles Perry @ 2024-01-29 22:56 UTC (permalink / raw)
  To: mdf
  Cc: hao.wu, yilun.xu, trix, krzysztof.kozlowski+dt, bcody, avandiver,
	linux-fpga, devicetree, linux-kernel, Charles Perry

Xilinx 7 series FPGA can be programmed using a slave parallel port named
the SelectMAP interface in the datasheet. This slave interface is
compatible with the i.MX6 EIM bus controller but other types of external
memory mapped parallel bus might work.

xilinx-selectmap currently only supports the x8 mode where data is loaded
at one byte per rising edge of the clock, with the MSb of each byte
presented to the D0 pin.

The following DT fragment shows a valid configuration on a custom i.MX6
board (pinctrl not shown for readability):

&weim {
    status = "okay";
    ranges = <0 0 0x08000000 0x04000000>;

    fpga_mgr: fpga_programmer@0,0 {
        compatible = "xlnx,fpga-slave-selectmap";
        reg = <0 0 0x4000000>;
        fsl,weim-cs-timing = <0x00070031 0x00000142
                              0x00020000 0x00000000
                              0x0c000645 0x00000000>;
        prog_b-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>;
        init-b-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
        done-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
        csi-b-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
        rdwr-b-gpios = <&gpio3 10 GPIO_ACTIVE_LOW>;
    };
};

Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
---
 drivers/fpga/Kconfig            |   8 +++
 drivers/fpga/Makefile           |   1 +
 drivers/fpga/xilinx-selectmap.c | 100 ++++++++++++++++++++++++++++++++
 3 files changed, 109 insertions(+)
 create mode 100644 drivers/fpga/xilinx-selectmap.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index d27a1ebf40838..37b35f58f0dfb 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -67,6 +67,14 @@ config FPGA_MGR_STRATIX10_SOC
 config FPGA_MGR_XILINX_CORE
 	tristate
 
+config FPGA_MGR_XILINX_SELECTMAP
+	tristate "Xilinx Configuration over SelectMAP"
+	depends on HAS_IOMEM
+	select FPGA_MGR_XILINX_CORE
+	help
+	  FPGA manager driver support for Xilinx FPGA configuration
+	  over SelectMAP interface.
+
 config FPGA_MGR_XILINX_SPI
 	tristate "Xilinx Configuration over Slave Serial (SPI)"
 	depends on SPI
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 7ec795b6a5a70..aeb89bb13517e 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
 obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
 obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
 obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
+obj-$(CONFIG_FPGA_MGR_XILINX_SELECTMAP)	+= xilinx-selectmap.o
 obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c
new file mode 100644
index 0000000000000..e9e522e9952bb
--- /dev/null
+++ b/drivers/fpga/xilinx-selectmap.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Xilinx Spartan6 and 7 Series Slave SelectMAP Driver
+ *
+ * (C) 2024 Charles Perry <charles.perry@savoirfairelinux.com>
+ *
+ * Manage Xilinx FPGA firmware loaded over the SelectMAP configuration
+ * interface.
+ */
+
+#include "xilinx-core.h"
+
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/io.h>
+
+struct xilinx_selectmap_conf {
+	struct xilinx_fpga_core core;
+	void __iomem *base;
+	struct gpio_desc *csi_b;
+	struct gpio_desc *rdwr_b;
+};
+
+#define to_xilinx_selectmap_conf(obj) \
+	container_of(obj, struct xilinx_selectmap_conf, core)
+
+static int xilinx_selectmap_write(struct xilinx_fpga_core *core, const char *buf,
+			    size_t count)
+{
+	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
+	u32 i;
+
+	for (i = 0; i < count; ++i)
+		writeb(buf[i], conf->base);
+
+	return 0;
+}
+
+static int xilinx_selectmap_apply_padding(struct xilinx_fpga_core *core)
+{
+	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
+
+	writeb(0xFF, conf->base);
+	return 0;
+}
+
+static int xilinx_selectmap_probe(struct platform_device *pdev)
+{
+	struct xilinx_selectmap_conf *conf;
+	struct resource *r;
+	void __iomem *base;
+
+	conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
+	if (!conf)
+		return -ENOMEM;
+
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
+	if (IS_ERR(base))
+		return dev_err_probe(&pdev->dev, PTR_ERR(base), "ioremap error\n");
+	conf->base = base;
+
+	/* CSI_B is active low */
+	conf->csi_b = devm_gpiod_get_optional(&pdev->dev, "csi-b", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->csi_b))
+		return dev_err_probe(&pdev->dev, PTR_ERR(conf->csi_b),
+				     "Failed to get CSI_B gpio\n");
+
+	/* RDWR_B is active low */
+	conf->rdwr_b = devm_gpiod_get_optional(&pdev->dev, "rdwr-b", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->rdwr_b))
+		return dev_err_probe(&pdev->dev, PTR_ERR(conf->rdwr_b),
+				     "Failed to get RDWR_B gpio\n");
+
+	return xilinx_core_probe(&conf->core, &pdev->dev,
+							xilinx_selectmap_write,
+							xilinx_selectmap_apply_padding);
+}
+
+static const struct of_device_id xlnx_selectmap_of_match[] = {
+		{ .compatible = "xlnx,fpga-slave-selectmap", },
+		{}
+};
+MODULE_DEVICE_TABLE(of, xlnx_selectmap_of_match);
+
+static struct platform_driver xilinx_slave_selectmap_driver = {
+	.driver = {
+		.name = "xilinx-slave-selectmap",
+		.of_match_table = of_match_ptr(xlnx_selectmap_of_match),
+	},
+	.probe  = xilinx_selectmap_probe,
+};
+
+module_platform_driver(xilinx_slave_selectmap_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Charles Perry <charles.perry@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SelectMap");
-- 
2.43.0


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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-29 22:56 ` [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema Charles Perry
@ 2024-01-30  0:21   ` Rob Herring
  2024-01-30  7:52   ` Krzysztof Kozlowski
  2024-01-30 16:09   ` Krzysztof Kozlowski
  2 siblings, 0 replies; 44+ messages in thread
From: Rob Herring @ 2024-01-30  0:21 UTC (permalink / raw)
  To: Charles Perry
  Cc: bcody, yilun.xu, trix, avandiver, linux-fpga, devicetree,
	linux-kernel, krzysztof.kozlowski+dt, hao.wu, mdf


On Mon, 29 Jan 2024 17:56:01 -0500, Charles Perry wrote:
> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---
>  .../fpga/xlnx,fpga-slave-selectmap.yaml       | 85 +++++++++++++++++++
>  1 file changed, 85 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml: 'maintainers' is a required property
	hint: Metaschema for devicetree binding documentation
	from schema $id: http://devicetree.org/meta-schemas/base.yaml#
Error: Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.example.dts:19.9-14 syntax error
FATAL ERROR: Unable to parse input tree
make[2]: *** [scripts/Makefile.lib:419: Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.example.dtb] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1428: dt_binding_check] Error 2
make: *** [Makefile:240: __sub-make] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20240129225602.3832449-2-charles.perry@savoirfairelinux.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-29 22:56 ` [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema Charles Perry
  2024-01-30  0:21   ` Rob Herring
@ 2024-01-30  7:52   ` Krzysztof Kozlowski
  2024-01-30  7:53     ` Krzysztof Kozlowski
  2024-01-30 15:45     ` Charles Perry
  2024-01-30 16:09   ` Krzysztof Kozlowski
  2 siblings, 2 replies; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-01-30  7:52 UTC (permalink / raw)
  To: Charles Perry, mdf
  Cc: hao.wu, yilun.xu, trix, krzysztof.kozlowski+dt, bcody, avandiver,
	linux-fpga, devicetree, linux-kernel

On 29/01/2024 23:56, Charles Perry wrote:
> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---
>  .../fpga/xlnx,fpga-slave-selectmap.yaml       | 85 +++++++++++++++++++
>  1 file changed, 85 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
> 
> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml b/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
> new file mode 100644
> index 0000000000000..20cea24e3e39a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
> @@ -0,0 +1,85 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-slave-selectmap.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Xilinx Slave SelectMAP FPGA
> +
> +description: |
> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
> +  parallel port named the slave SelectMAP interface in the documentation. Only
> +  the x8 mode is supported where data is loaded at one byte per rising edge of
> +  the clock, with the MSB of each byte presented to the D0 pin.
> +
> +  Datasheets:
> +    https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
> +
> +properties:
> +  compatible:
> +    enum:
> +      - xlnx,fpga-slave-selectmap

You did not test bindings, so only limited review.

> +
> +  reg:
> +    description:
> +      At least 1 byte of memory mapped IO
> +    maxItems: 1
> +
> +  prog_b-gpios:


No underscores in names.


> +    description:
> +      config pin (referred to as PROGRAM_B in the manual)
> +    maxItems: 1
> +
> +  done-gpios:
> +    description:
> +      config status pin (referred to as DONE in the manual)
> +    maxItems: 1
> +
> +  init-b-gpios:

Is there init-a? Open other bindings and look how these are called there.


> +    description:
> +      initialization status and configuration error pin
> +      (referred to as INIT_B in the manual)
> +    maxItems: 1
> +
> +  csi-b-gpios:

Where is csi-a?

> +    description:
> +      chip select pin (referred to as CSI_B in the manual)
> +      Optional gpio for if the bus controller does not provide a chip select.
> +    maxItems: 1
> +
> +  rdwr-b-gpios:
> +    description:
> +      read/write select pin (referred to as RDWR_B in the manual)
> +      Optional gpio for if the bus controller does not provide this pin.
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - prog_b-gpios
> +  - done-gpios
> +  - init-b-gpios
> +
> +additionalProperties: true

Nope, this cannot bue true.

> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    &weim {

Drop or use some generic soc

> +      status = "okay";

Drop

> +      ranges = <0 0 0x08000000 0x04000000>;

Drop

> +
> +      fpga_mgr: fpga_programmer@0,0 {

No underscores in names, drop label.

Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation


> +        compatible = "xlnx,fpga-slave-selectmap";
> +        reg = <0 0 0x4000000>;
> +        fsl,weim-cs-timing = <0x00070031 0x00000142
> +              0x00020000 0x00000000
> +              0x0c000645 0x00000000>;

NAK.

Please run your patch through Xilinx folks before sending.

Best regards,
Krzysztof


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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-30  7:52   ` Krzysztof Kozlowski
@ 2024-01-30  7:53     ` Krzysztof Kozlowski
  2024-01-30 15:45     ` Charles Perry
  1 sibling, 0 replies; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-01-30  7:53 UTC (permalink / raw)
  To: Charles Perry, mdf
  Cc: hao.wu, yilun.xu, trix, krzysztof.kozlowski+dt, bcody, avandiver,
	linux-fpga, devicetree, linux-kernel

On 30/01/2024 08:52, Krzysztof Kozlowski wrote:
> Please run your patch through Xilinx folks before sending.

Uh, you are not Xilinx folk, so disregard that. Yet still amount of
trivial issues here point that you need to start from scratch from
existing schema or example-schema.

Best regards,
Krzysztof


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

* Re: [PATCH 3/3] fpga: xilinx-selectmap: add new driver
  2024-01-29 22:56 ` [PATCH 3/3] fpga: xilinx-selectmap: add new driver Charles Perry
@ 2024-01-30  7:56   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-01-30  7:56 UTC (permalink / raw)
  To: Charles Perry, mdf
  Cc: hao.wu, yilun.xu, trix, krzysztof.kozlowski+dt, bcody, avandiver,
	linux-fpga, devicetree, linux-kernel

On 29/01/2024 23:56, Charles Perry wrote:
> Xilinx 7 series FPGA can be programmed using a slave parallel port named
> the SelectMAP interface in the datasheet. This slave interface is
> compatible with the i.MX6 EIM bus controller but other types of external
> memory mapped parallel bus might work.
> 
> xilinx-selectmap currently only supports the x8 mode where data is loaded
> at one byte per rising edge of the clock, with the MSb of each byte
> presented to the D0 pin.
> 
> The following DT fragment shows a valid configuration on a custom i.MX6
> board (pinctrl not shown for readability):
> 
> &weim {
>     status = "okay";
>     ranges = <0 0 0x08000000 0x04000000>;
> 
>     fpga_mgr: fpga_programmer@0,0 {
>         compatible = "xlnx,fpga-slave-selectmap";
>         reg = <0 0 0x4000000>;
>         fsl,weim-cs-timing = <0x00070031 0x00000142
>                               0x00020000 0x00000000
>                               0x0c000645 0x00000000>;
>         prog_b-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>;
>         init-b-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
>         done-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
>         csi-b-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
>         rdwr-b-gpios = <&gpio3 10 GPIO_ACTIVE_LOW>;
>     };
> };

Drop that example. First, it is not correct. Second, a correct one in
bindings is enough.

> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---

...

> +static int xilinx_selectmap_probe(struct platform_device *pdev)
> +{
> +	struct xilinx_selectmap_conf *conf;
> +	struct resource *r;
> +	void __iomem *base;
> +
> +	conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
> +	if (!conf)
> +		return -ENOMEM;
> +
> +	base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
> +	if (IS_ERR(base))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(base), "ioremap error\n");
> +	conf->base = base;
> +
> +	/* CSI_B is active low */
> +	conf->csi_b = devm_gpiod_get_optional(&pdev->dev, "csi-b", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->csi_b))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->csi_b),
> +				     "Failed to get CSI_B gpio\n");
> +
> +	/* RDWR_B is active low */
> +	conf->rdwr_b = devm_gpiod_get_optional(&pdev->dev, "rdwr-b", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->rdwr_b))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->rdwr_b),
> +				     "Failed to get RDWR_B gpio\n");
> +
> +	return xilinx_core_probe(&conf->core, &pdev->dev,
> +							xilinx_selectmap_write,
> +							xilinx_selectmap_apply_padding);

Totally messed indentation. Please run scripts/checkpatch.pl and fix
reported warnings. Some warnings can be ignored, but the code here looks
like it needs a fix. Feel free to get in touch if the warning is not clear.

> +}
> +
> +static const struct of_device_id xlnx_selectmap_of_match[] = {
> +		{ .compatible = "xlnx,fpga-slave-selectmap", },
> +		{}
> +};
> +MODULE_DEVICE_TABLE(of, xlnx_selectmap_of_match);
> +
> +static struct platform_driver xilinx_slave_selectmap_driver = {
> +	.driver = {
> +		.name = "xilinx-slave-selectmap",
> +		.of_match_table = of_match_ptr(xlnx_selectmap_of_match),

Drop of_match_ptr, it leads to warnings.

> +	},
> +	.probe  = xilinx_selectmap_probe,
> +};

Best regards,
Krzysztof


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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-30  7:52   ` Krzysztof Kozlowski
  2024-01-30  7:53     ` Krzysztof Kozlowski
@ 2024-01-30 15:45     ` Charles Perry
  2024-01-30 16:05       ` Krzysztof Kozlowski
  1 sibling, 1 reply; 44+ messages in thread
From: Charles Perry @ 2024-01-30 15:45 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: mdf, hao wu, yilun xu, trix, krzysztof kozlowski+dt, Brian CODY,
	Allen VANDIVER, linux-fpga, devicetree, linux-kernel

----- On Jan 30, 2024, at 2:52 AM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:

> On 29/01/2024 23:56, Charles Perry wrote:
>> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
>> 
>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>> ---
>>  .../fpga/xlnx,fpga-slave-selectmap.yaml       | 85 +++++++++++++++++++
>>  1 file changed, 85 insertions(+)
>>  create mode 100644
>>  Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
>> 
>> diff --git
>> a/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
>> b/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
>> new file mode 100644
>> index 0000000000000..20cea24e3e39a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
>> @@ -0,0 +1,85 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-slave-selectmap.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Xilinx Slave SelectMAP FPGA
>> +
>> +description: |
>> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
>> +  parallel port named the slave SelectMAP interface in the documentation. Only
>> +  the x8 mode is supported where data is loaded at one byte per rising edge of
>> +  the clock, with the MSB of each byte presented to the D0 pin.
>> +
>> +  Datasheets:
>> +
>> https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
>> +
>> +properties:
>> +  compatible:
>> +    enum:
>> +      - xlnx,fpga-slave-selectmap
> 
> You did not test bindings, so only limited review.
> 

I had issues installing pylibfdt but that's fixed now, will do.

>> +
>> +  reg:
>> +    description:
>> +      At least 1 byte of memory mapped IO
>> +    maxItems: 1
>> +
>> +  prog_b-gpios:
> 
> 
> No underscores in names.
> 

This is heavily based on "xlnx,fpga-slave-serial.yaml" which uses an underscore.
I can use a dash instead but that would make things inconsistent across the two schemas. 

> 
>> +    description:
>> +      config pin (referred to as PROGRAM_B in the manual)
>> +    maxItems: 1
>> +
>> +  done-gpios:
>> +    description:
>> +      config status pin (referred to as DONE in the manual)
>> +    maxItems: 1
>> +
>> +  init-b-gpios:
> 
> Is there init-a? Open other bindings and look how these are called there.
> 

No, the "-b" is there to denote that the signal is active low. I think its shorthand
for "bar" which is the overline (‾) that electronic engineer put on top of the name of the
signal on schematics. It comes from the datasheet.

> 
>> +    description:
>> +      initialization status and configuration error pin
>> +      (referred to as INIT_B in the manual)
>> +    maxItems: 1
>> +
>> +  csi-b-gpios:
> 
> Where is csi-a?
> 

No "csi-a", this is the CSI signal which is active low.

>> +    description:
>> +      chip select pin (referred to as CSI_B in the manual)
>> +      Optional gpio for if the bus controller does not provide a chip select.
>> +    maxItems: 1
>> +
>> +  rdwr-b-gpios:
>> +    description:
>> +      read/write select pin (referred to as RDWR_B in the manual)
>> +      Optional gpio for if the bus controller does not provide this pin.
>> +    maxItems: 1
>> +
>> +required:
>> +  - compatible
>> +  - reg
>> +  - prog_b-gpios
>> +  - done-gpios
>> +  - init-b-gpios
>> +
>> +additionalProperties: true
> 
> Nope, this cannot bue true.
> 

Ok, I'll put this to false but I'm not quite sure I understand the implications.

My reasoning behind assigning this to true was that the FPGA is an external
device on a bus that needs to be configured by a bus controller. The bus controller
would be the parent of the fpga DT node and the later would contain properties
parsed by the bus controller driver.

>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/gpio/gpio.h>
>> +    &weim {
> 
> Drop or use some generic soc
> 

Ok

>> +      status = "okay";
> 
> Drop
> 

Ok

>> +      ranges = <0 0 0x08000000 0x04000000>;
> 
> Drop
> 

Ok

>> +
>> +      fpga_mgr: fpga_programmer@0,0 {
> 
> No underscores in names, drop label.
> 
> Node names should be generic. See also an explanation and list of
> examples (not exhaustive) in DT specification:
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> 
> 

Ok, will use "fpga-mgr" as this seems to be the most common one for fpga managers.

>> +        compatible = "xlnx,fpga-slave-selectmap";
>> +        reg = <0 0 0x4000000>;
>> +        fsl,weim-cs-timing = <0x00070031 0x00000142
>> +              0x00020000 0x00000000
>> +              0x0c000645 0x00000000>;
> 
> NAK.
> 
> Please run your patch through Xilinx folks before sending.
> 
> Best regards,
> Krzysztof

Thank you,
Charles

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-30 15:45     ` Charles Perry
@ 2024-01-30 16:05       ` Krzysztof Kozlowski
  2024-01-30 17:05         ` Charles Perry
  0 siblings, 1 reply; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-01-30 16:05 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, hao wu, yilun xu, trix, krzysztof kozlowski+dt, Brian CODY,
	Allen VANDIVER, linux-fpga, devicetree, linux-kernel

On 30/01/2024 16:45, Charles Perry wrote:
> 
>>> +
>>> +  reg:
>>> +    description:
>>> +      At least 1 byte of memory mapped IO
>>> +    maxItems: 1
>>> +
>>> +  prog_b-gpios:
>>
>>
>> No underscores in names.
>>
> 
> This is heavily based on "xlnx,fpga-slave-serial.yaml" which uses an underscore.
> I can use a dash instead but that would make things inconsistent across the two schemas. 

Inconsistency is not a problem. Duplicating technical debt is.

> 
>>
>>> +    description:
>>> +      config pin (referred to as PROGRAM_B in the manual)
>>> +    maxItems: 1
>>> +
>>> +  done-gpios:
>>> +    description:
>>> +      config status pin (referred to as DONE in the manual)
>>> +    maxItems: 1
>>> +
>>> +  init-b-gpios:
>>
>> Is there init-a? Open other bindings and look how these are called there.
>>
> 
> No, the "-b" is there to denote that the signal is active low. I think its shorthand
> for "bar" which is the overline (‾) that electronic engineer put on top of the name of the
> signal on schematics. It comes from the datasheet.

Then just "init-gpios"

...

>>> +required:
>>> +  - compatible
>>> +  - reg
>>> +  - prog_b-gpios
>>> +  - done-gpios
>>> +  - init-b-gpios
>>> +
>>> +additionalProperties: true
>>
>> Nope, this cannot bue true.
>>
> 
> Ok, I'll put this to false but I'm not quite sure I understand the implications.
> 
> My reasoning behind assigning this to true was that the FPGA is an external
> device on a bus that needs to be configured by a bus controller. The bus controller
> would be the parent of the fpga DT node and the later would contain properties
> parsed by the bus controller driver.

Which bus controller? MMIO bus does not parse children properties.
Anyway, if that's the case you miss $ref to respective
peripheral-props.yaml matching your bus and then "unevaluatedProperties:
false".

Best regards,
Krzysztof


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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-29 22:56 ` [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema Charles Perry
  2024-01-30  0:21   ` Rob Herring
  2024-01-30  7:52   ` Krzysztof Kozlowski
@ 2024-01-30 16:09   ` Krzysztof Kozlowski
  2024-01-31 11:03     ` Kris Chaplin
  2 siblings, 1 reply; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-01-30 16:09 UTC (permalink / raw)
  To: Charles Perry, mdf, michal.simek
  Cc: hao.wu, yilun.xu, trix, krzysztof.kozlowski+dt, bcody, avandiver,
	linux-fpga, devicetree, linux-kernel

On 29/01/2024 23:56, Charles Perry wrote:
> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---
>  .../fpga/xlnx,fpga-slave-selectmap.yaml       | 85 +++++++++++++++++++
>  1 file changed, 85 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
> 
> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml b/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
> new file mode 100644
> index 0000000000000..20cea24e3e39a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-slave-selectmap.yaml
> @@ -0,0 +1,85 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-slave-selectmap.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Xilinx Slave SelectMAP FPGA

https://elixir.bootlin.com/linux/v6.8-rc2/source/Documentation/process/coding-style.rst#L338

Everywhere: compatible, title, filename, descriptions.

> +
> +description: |
> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
> +  parallel port named the slave SelectMAP interface in the documentation. Only
> +  the x8 mode is supported where data is loaded at one byte per rising edge of
> +  the clock, with the MSB of each byte presented to the D0 pin.
> +
> +  Datasheets:
> +    https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf

I am surprised that AMD/Xilinx still did not update the document to
modern naming (slave->secondary).

+Cc Michal,
Maybe that's something you could push it.

Best regards,
Krzysztof


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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-30 16:05       ` Krzysztof Kozlowski
@ 2024-01-30 17:05         ` Charles Perry
  2024-01-30 17:58           ` Krzysztof Kozlowski
  0 siblings, 1 reply; 44+ messages in thread
From: Charles Perry @ 2024-01-30 17:05 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: mdf, hao wu, yilun xu, trix, krzysztof kozlowski+dt, Brian CODY,
	Allen VANDIVER, linux-fpga, devicetree, linux-kernel



----- On Jan 30, 2024, at 11:05 AM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:

> On 30/01/2024 16:45, Charles Perry wrote:
>> 
>>>> +
>>>> +  reg:
>>>> +    description:
>>>> +      At least 1 byte of memory mapped IO
>>>> +    maxItems: 1
>>>> +
>>>> +  prog_b-gpios:
>>>
>>>
>>> No underscores in names.
>>>
>> 
>> This is heavily based on "xlnx,fpga-slave-serial.yaml" which uses an underscore.
>> I can use a dash instead but that would make things inconsistent across the two
>> schemas.
> 
> Inconsistency is not a problem. Duplicating technical debt is.
> 
>> 
>>>
>>>> +    description:
>>>> +      config pin (referred to as PROGRAM_B in the manual)
>>>> +    maxItems: 1
>>>> +
>>>> +  done-gpios:
>>>> +    description:
>>>> +      config status pin (referred to as DONE in the manual)
>>>> +    maxItems: 1
>>>> +
>>>> +  init-b-gpios:
>>>
>>> Is there init-a? Open other bindings and look how these are called there.
>>>
>> 
>> No, the "-b" is there to denote that the signal is active low. I think its
>> shorthand
>> for "bar" which is the overline (‾) that electronic engineer put on top of the
>> name of the
>> signal on schematics. It comes from the datasheet.
> 
> Then just "init-gpios"
> 
> ...
> 
>>>> +required:
>>>> +  - compatible
>>>> +  - reg
>>>> +  - prog_b-gpios
>>>> +  - done-gpios
>>>> +  - init-b-gpios
>>>> +
>>>> +additionalProperties: true
>>>
>>> Nope, this cannot bue true.
>>>
>> 
>> Ok, I'll put this to false but I'm not quite sure I understand the implications.
>> 
>> My reasoning behind assigning this to true was that the FPGA is an external
>> device on a bus that needs to be configured by a bus controller. The bus
>> controller
>> would be the parent of the fpga DT node and the later would contain properties
>> parsed by the bus controller driver.
> 
> Which bus controller? MMIO bus does not parse children properties.
> Anyway, if that's the case you miss $ref to respective
> peripheral-props.yaml matching your bus and then "unevaluatedProperties:
> false".

This one: https://elixir.bootlin.com/linux/v6.8-rc2/source/Documentation/devicetree/bindings/bus/imx-weim.txt#L56

> 
> Best regards,
> Krzysztof

Regards,
Charles

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-30 17:05         ` Charles Perry
@ 2024-01-30 17:58           ` Krzysztof Kozlowski
  2024-01-30 23:32             ` Charles Perry
  0 siblings, 1 reply; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-01-30 17:58 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, hao wu, yilun xu, trix, krzysztof kozlowski+dt, Brian CODY,
	Allen VANDIVER, linux-fpga, devicetree, linux-kernel

On 30/01/2024 18:05, Charles Perry wrote:
> 
> 
> ----- On Jan 30, 2024, at 11:05 AM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:
> 
>> On 30/01/2024 16:45, Charles Perry wrote:
>>>
>>>>> +
>>>>> +  reg:
>>>>> +    description:
>>>>> +      At least 1 byte of memory mapped IO
>>>>> +    maxItems: 1
>>>>> +
>>>>> +  prog_b-gpios:
>>>>
>>>>
>>>> No underscores in names.
>>>>
>>>
>>> This is heavily based on "xlnx,fpga-slave-serial.yaml" which uses an underscore.
>>> I can use a dash instead but that would make things inconsistent across the two
>>> schemas.
>>
>> Inconsistency is not a problem. Duplicating technical debt is.
>>
>>>
>>>>
>>>>> +    description:
>>>>> +      config pin (referred to as PROGRAM_B in the manual)
>>>>> +    maxItems: 1
>>>>> +
>>>>> +  done-gpios:
>>>>> +    description:
>>>>> +      config status pin (referred to as DONE in the manual)
>>>>> +    maxItems: 1
>>>>> +
>>>>> +  init-b-gpios:
>>>>
>>>> Is there init-a? Open other bindings and look how these are called there.
>>>>
>>>
>>> No, the "-b" is there to denote that the signal is active low. I think its
>>> shorthand
>>> for "bar" which is the overline (‾) that electronic engineer put on top of the
>>> name of the
>>> signal on schematics. It comes from the datasheet.
>>
>> Then just "init-gpios"
>>
>> ...
>>
>>>>> +required:
>>>>> +  - compatible
>>>>> +  - reg
>>>>> +  - prog_b-gpios
>>>>> +  - done-gpios
>>>>> +  - init-b-gpios
>>>>> +
>>>>> +additionalProperties: true
>>>>
>>>> Nope, this cannot bue true.
>>>>
>>>
>>> Ok, I'll put this to false but I'm not quite sure I understand the implications.
>>>
>>> My reasoning behind assigning this to true was that the FPGA is an external
>>> device on a bus that needs to be configured by a bus controller. The bus
>>> controller
>>> would be the parent of the fpga DT node and the later would contain properties
>>> parsed by the bus controller driver.
>>
>> Which bus controller? MMIO bus does not parse children properties.
>> Anyway, if that's the case you miss $ref to respective
>> peripheral-props.yaml matching your bus and then "unevaluatedProperties:
>> false".
> 
> This one: https://elixir.bootlin.com/linux/v6.8-rc2/source/Documentation/devicetree/bindings/bus/imx-weim.txt#L56

Eh, ok, so after fast check WEIM looks like some memory interface bus,
so the bus bindings should be moved to memory-controllers and converted
to YAML. Then you add child node properties to own schema and reference
in mc-peripheral-props, which is then referenced in your binding here,
as I mentioned.

Best regards,
Krzysztof


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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-30 17:58           ` Krzysztof Kozlowski
@ 2024-01-30 23:32             ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-30 23:32 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: mdf, hao wu, yilun xu, trix, krzysztof kozlowski+dt, Brian CODY,
	Allen VANDIVER, linux-fpga, devicetree, linux-kernel


----- On Jan 30, 2024, at 12:58 PM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:

> On 30/01/2024 18:05, Charles Perry wrote:
>> 
>> 
>> ----- On Jan 30, 2024, at 11:05 AM, Krzysztof Kozlowski
>> krzysztof.kozlowski@linaro.org wrote:
>> 
>>> On 30/01/2024 16:45, Charles Perry wrote:
>>>>
>>>>>> +
>>>>>> +  reg:
>>>>>> +    description:
>>>>>> +      At least 1 byte of memory mapped IO
>>>>>> +    maxItems: 1
>>>>>> +
>>>>>> +  prog_b-gpios:
>>>>>
>>>>>
>>>>> No underscores in names.
>>>>>
>>>>
>>>> This is heavily based on "xlnx,fpga-slave-serial.yaml" which uses an underscore.
>>>> I can use a dash instead but that would make things inconsistent across the two
>>>> schemas.
>>>
>>> Inconsistency is not a problem. Duplicating technical debt is.
>>>
>>>>
>>>>>
>>>>>> +    description:
>>>>>> +      config pin (referred to as PROGRAM_B in the manual)
>>>>>> +    maxItems: 1
>>>>>> +
>>>>>> +  done-gpios:
>>>>>> +    description:
>>>>>> +      config status pin (referred to as DONE in the manual)
>>>>>> +    maxItems: 1
>>>>>> +
>>>>>> +  init-b-gpios:
>>>>>
>>>>> Is there init-a? Open other bindings and look how these are called there.
>>>>>
>>>>
>>>> No, the "-b" is there to denote that the signal is active low. I think its
>>>> shorthand
>>>> for "bar" which is the overline (‾) that electronic engineer put on top of the
>>>> name of the
>>>> signal on schematics. It comes from the datasheet.
>>>
>>> Then just "init-gpios"
>>>
>>> ...
>>>
>>>>>> +required:
>>>>>> +  - compatible
>>>>>> +  - reg
>>>>>> +  - prog_b-gpios
>>>>>> +  - done-gpios
>>>>>> +  - init-b-gpios
>>>>>> +
>>>>>> +additionalProperties: true
>>>>>
>>>>> Nope, this cannot bue true.
>>>>>
>>>>
>>>> Ok, I'll put this to false but I'm not quite sure I understand the implications.
>>>>
>>>> My reasoning behind assigning this to true was that the FPGA is an external
>>>> device on a bus that needs to be configured by a bus controller. The bus
>>>> controller
>>>> would be the parent of the fpga DT node and the later would contain properties
>>>> parsed by the bus controller driver.
>>>
>>> Which bus controller? MMIO bus does not parse children properties.
>>> Anyway, if that's the case you miss $ref to respective
>>> peripheral-props.yaml matching your bus and then "unevaluatedProperties:
>>> false".
>> 
>> This one:
>> https://elixir.bootlin.com/linux/v6.8-rc2/source/Documentation/devicetree/bindings/bus/imx-weim.txt#L56
> 
> Eh, ok, so after fast check WEIM looks like some memory interface bus,
> so the bus bindings should be moved to memory-controllers and converted
> to YAML. Then you add child node properties to own schema and reference
> in mc-peripheral-props, which is then referenced in your binding here,
> as I mentioned.
> 
> Best regards,
> Krzysztof

Thank you for pointing that out, mc-peripheral-props.yaml seems to be
exactly what I was looking for.

Regards,
Charles

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-30 16:09   ` Krzysztof Kozlowski
@ 2024-01-31 11:03     ` Kris Chaplin
  2024-02-04  8:30       ` Xu Yilun
  0 siblings, 1 reply; 44+ messages in thread
From: Kris Chaplin @ 2024-01-31 11:03 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Charles Perry, mdf, michal.simek
  Cc: hao.wu, yilun.xu, trix, krzysztof.kozlowski+dt, bcody, avandiver,
	linux-fpga, devicetree, linux-kernel

Hello Krzysztof,

On 30/01/2024 16:09, Krzysztof Kozlowski wrote:

>> +
>> +description: |
>> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
>> +  parallel port named the slave SelectMAP interface in the documentation. Only
>> +  the x8 mode is supported where data is loaded at one byte per rising edge of
>> +  the clock, with the MSB of each byte presented to the D0 pin.
>> +
>> +  Datasheets:
>> +    https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
> 
> I am surprised that AMD/Xilinx still did not update the document to
> modern naming (slave->secondary).

Thank you for bringing this up.

We are moving away from using non-inclusive technical terminology and 
are removing non-inclusive language from our products and related 
collateral.  You will for some time find examples of non-inclusive 
language, especially in our older products as we work to make these 
changes and align with industry standards.  For new IP we're ensuring 
that we switch and stick to inclusive terminology, as you may have seen 
with my recent w1 driver submission.

SelectMAP is a decades-old interface and as such it is unlikely that we 
will update this in all documentation dating back this time.  I shall 
however look to understand what is planned here for active documentation 
and new driver submissions.

regards
Kris

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

* [PATCH 0/3] fpga: xilinx-selectmap: add new driver
  2024-01-29 22:56 [PATCH 1/3] fpga: xilinx-spi: extract a common driver core Charles Perry
@ 2024-01-31 23:05   ` Charles Perry
  2024-01-29 22:56 ` [PATCH 3/3] fpga: xilinx-selectmap: add new driver Charles Perry
  2024-01-31 23:05   ` Charles Perry
  2 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-31 23:05 UTC (permalink / raw)
  To: mdf
  Cc: avandiver, bcody, Charles Perry, Wu Hao, Xu Yilun, Tom Rix,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

Hello,

This patchset adds a new driver for the 7 series FPGA's SelectMAP
interface.

The SelectMAP interface shares a common GPIO protocol with the SPI
interface which is already in the kernel (drivers/fpga/xilinx-spi.c).
The approach proposed in this patchset is to refactor xilinx-spi.c into
xilinx-core.c which would handle the common GPIO protocol. This is then
used to build two drivers, the already existing xilinx-spi.c driver and
a newly added xilinx-selectmap.c driver.

The SelectMAP driver proposed only supports 8 bit mode. This is because
the 16 and 32 bits mode have limitations with regards to compressed
bitstream support as well as introducing endianness considerations.

I'm testing xilinx-selectmap.c on a custom i.MX6 board connected to an
Artix 7 FPGA. Flashing a 913K bitstream takes 0.44 seconds.

v2: From Krzysztof Kozlowski review's:
  * Use more conventional names for gpio DT bindings
  * fix example in DT bindings
  * add mc-peripheral-props.yaml to DT bindings
  * fix various formatting mistakes
  * Remove all occurences of the "slave" word.

Charles Perry (3):
  fpga: xilinx-spi: extract a common driver core
  dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  fpga: xilinx-selectmap: add new driver

 .../bindings/fpga/xlnx,fpga-selectmap.yaml    |  83 +++++++
 drivers/fpga/Kconfig                          |  12 +
 drivers/fpga/Makefile                         |   2 +
 drivers/fpga/xilinx-core.c                    | 215 ++++++++++++++++++
 drivers/fpga/xilinx-core.h                    |  28 +++
 drivers/fpga/xilinx-selectmap.c               | 106 +++++++++
 drivers/fpga/xilinx-spi.c                     | 205 ++---------------
 7 files changed, 462 insertions(+), 189 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
 create mode 100644 drivers/fpga/xilinx-core.c
 create mode 100644 drivers/fpga/xilinx-core.h
 create mode 100644 drivers/fpga/xilinx-selectmap.c

--
2.43.0

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

* [PATCH 0/3] fpga: xilinx-selectmap: add new driver
@ 2024-01-31 23:05   ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-31 23:05 UTC (permalink / raw)
  To: mdf
  Cc: avandiver, bcody, Charles Perry, Wu Hao, Xu Yilun, Tom Rix,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

Hello,

This patchset adds a new driver for the 7 series FPGA's SelectMAP
interface.

The SelectMAP interface shares a common GPIO protocol with the SPI
interface which is already in the kernel (drivers/fpga/xilinx-spi.c).
The approach proposed in this patchset is to refactor xilinx-spi.c into
xilinx-core.c which would handle the common GPIO protocol. This is then
used to build two drivers, the already existing xilinx-spi.c driver and
a newly added xilinx-selectmap.c driver.

The SelectMAP driver proposed only supports 8 bit mode. This is because
the 16 and 32 bits mode have limitations with regards to compressed
bitstream support as well as introducing endianness considerations.

I'm testing xilinx-selectmap.c on a custom i.MX6 board connected to an
Artix 7 FPGA. Flashing a 913K bitstream takes 0.44 seconds.

v2: From Krzysztof Kozlowski review's:
  * Use more conventional names for gpio DT bindings
  * fix example in DT bindings
  * add mc-peripheral-props.yaml to DT bindings
  * fix various formatting mistakes
  * Remove all occurences of the "slave" word.

Charles Perry (3):
  fpga: xilinx-spi: extract a common driver core
  dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  fpga: xilinx-selectmap: add new driver

 .../bindings/fpga/xlnx,fpga-selectmap.yaml    |  83 +++++++
 drivers/fpga/Kconfig                          |  12 +
 drivers/fpga/Makefile                         |   2 +
 drivers/fpga/xilinx-core.c                    | 215 ++++++++++++++++++
 drivers/fpga/xilinx-core.h                    |  28 +++
 drivers/fpga/xilinx-selectmap.c               | 106 +++++++++
 drivers/fpga/xilinx-spi.c                     | 205 ++---------------
 7 files changed, 462 insertions(+), 189 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
 create mode 100644 drivers/fpga/xilinx-core.c
 create mode 100644 drivers/fpga/xilinx-core.h
 create mode 100644 drivers/fpga/xilinx-selectmap.c

--
2.43.0

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 1/3] fpga: xilinx-spi: extract a common driver core
  2024-01-31 23:05   ` Charles Perry
@ 2024-01-31 23:05     ` Charles Perry
  -1 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-31 23:05 UTC (permalink / raw)
  To: mdf
  Cc: avandiver, bcody, Charles Perry, Wu Hao, Xu Yilun, Tom Rix,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

Factor out the gpio handshaking (using PROGRAM_B, INIT_B and DONE)
protocol in xilinx-core so that it can be reused for another driver.
This commit does not change anything functionally to xilinx-spi.

xilinx-core expects drivers to provide two operations:

 * ->write(const char* buf, size_t count): write to the device
 * ->write_one_dummy_byte(): write 0xFF to the device

Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
---
 drivers/fpga/Kconfig       |   4 +
 drivers/fpga/Makefile      |   1 +
 drivers/fpga/xilinx-core.c | 210 +++++++++++++++++++++++++++++++++++++
 drivers/fpga/xilinx-core.h |  27 +++++
 drivers/fpga/xilinx-spi.c  | 204 +++--------------------------------
 5 files changed, 257 insertions(+), 189 deletions(-)
 create mode 100644 drivers/fpga/xilinx-core.c
 create mode 100644 drivers/fpga/xilinx-core.h

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 2f689ac4ba3a3..d27a1ebf40838 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -64,9 +64,13 @@ config FPGA_MGR_STRATIX10_SOC
 	help
 	  FPGA manager driver support for the Intel Stratix10 SoC.
 
+config FPGA_MGR_XILINX_CORE
+	tristate
+
 config FPGA_MGR_XILINX_SPI
 	tristate "Xilinx Configuration over Slave Serial (SPI)"
 	depends on SPI
+	select FPGA_MGR_XILINX_CORE
 	help
 	  FPGA manager driver support for Xilinx FPGA configuration
 	  over slave serial interface.
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 352a2612623e0..7ec795b6a5a70 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
 obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
 obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
 obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
+obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
 obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
new file mode 100644
index 0000000000000..aff40e9394085
--- /dev/null
+++ b/drivers/fpga/xilinx-core.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common parts of the Xilinx Spartan6 and 7 Series FPGA manager drivers.
+ *
+ * Copyright (C) 2017 DENX Software Engineering
+ *
+ * Anatolij Gustschin <agust@denx.de>
+ */
+
+#include "xilinx-core.h"
+
+#include <linux/delay.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+
+static int get_done_gpio(struct fpga_manager *mgr)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	int ret;
+
+	ret = gpiod_get_value(core->done);
+
+	if (ret < 0)
+		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
+
+	return ret;
+}
+
+static enum fpga_mgr_states xilinx_core_state(struct fpga_manager *mgr)
+{
+	if (!get_done_gpio(mgr))
+		return FPGA_MGR_STATE_RESET;
+
+	return FPGA_MGR_STATE_UNKNOWN;
+}
+
+/**
+ * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
+ * a given delay if the pin is unavailable
+ *
+ * @mgr:        The FPGA manager object
+ * @value:      Value INIT_B to wait for (1 = asserted = low)
+ * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
+ *
+ * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
+ * too much time passed waiting for that. If no INIT_B GPIO is available
+ * then always return 0.
+ */
+static int wait_for_init_b(struct fpga_manager *mgr, int value,
+			   unsigned long alt_udelay)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+	if (core->init_b) {
+		while (time_before(jiffies, timeout)) {
+			int ret = gpiod_get_value(core->init_b);
+
+			if (ret == value)
+				return 0;
+
+			if (ret < 0) {
+				dev_err(&mgr->dev,
+					"Error reading INIT_B (%d)\n", ret);
+				return ret;
+			}
+
+			usleep_range(100, 400);
+		}
+
+		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
+			value ? "assert" : "deassert");
+		return -ETIMEDOUT;
+	}
+
+	udelay(alt_udelay);
+
+	return 0;
+}
+
+static int xilinx_core_write_init(struct fpga_manager *mgr,
+				  struct fpga_image_info *info, const char *buf,
+				  size_t count)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	int err;
+
+	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
+		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
+		return -EINVAL;
+	}
+
+	gpiod_set_value(core->prog_b, 1);
+
+	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
+	if (err) {
+		gpiod_set_value(core->prog_b, 0);
+		return err;
+	}
+
+	gpiod_set_value(core->prog_b, 0);
+
+	err = wait_for_init_b(mgr, 0, 0);
+	if (err)
+		return err;
+
+	if (get_done_gpio(mgr)) {
+		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
+		return -EIO;
+	}
+
+	/* program latency */
+	usleep_range(7500, 7600);
+	return 0;
+}
+
+static int xilinx_core_write(struct fpga_manager *mgr, const char *buf,
+			     size_t count)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+
+	return core->write(core, buf, count);
+}
+
+static int xilinx_core_write_complete(struct fpga_manager *mgr,
+				      struct fpga_image_info *info)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	unsigned long timeout =
+		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
+	bool expired = false;
+	int done;
+	int ret;
+
+	/*
+	 * This loop is carefully written such that if the driver is
+	 * scheduled out for more than 'timeout', we still check for DONE
+	 * before giving up and we apply 8 extra CCLK cycles in all cases.
+	 */
+	while (!expired) {
+		expired = time_after(jiffies, timeout);
+
+		done = get_done_gpio(mgr);
+		if (done < 0)
+			return done;
+
+		ret = core->write_one_dummy_byte(core);
+		if (ret)
+			return ret;
+
+		if (done)
+			return 0;
+	}
+
+	if (core->init_b) {
+		ret = gpiod_get_value(core->init_b);
+
+		if (ret < 0) {
+			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
+			return ret;
+		}
+
+		dev_err(&mgr->dev,
+			ret ? "CRC error or invalid device\n" :
+			      "Missing sync word or incomplete bitstream\n");
+	} else {
+		dev_err(&mgr->dev, "Timeout after config data transfer\n");
+	}
+
+	return -ETIMEDOUT;
+}
+
+static const struct fpga_manager_ops xilinx_core_ops = {
+	.state = xilinx_core_state,
+	.write_init = xilinx_core_write_init,
+	.write = xilinx_core_write,
+	.write_complete = xilinx_core_write_complete,
+};
+
+int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
+		      xilinx_write_func write,
+		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
+{
+	struct fpga_manager *mgr;
+
+	core->dev = dev;
+	core->write = write;
+	core->write_one_dummy_byte = write_one_dummy_byte;
+
+	/* PROGRAM_B is active low */
+	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
+	if (IS_ERR(core->prog_b))
+		return dev_err_probe(dev, PTR_ERR(core->prog_b),
+				     "Failed to get PROGRAM_B gpio\n");
+
+	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
+	if (IS_ERR(core->init_b))
+		return dev_err_probe(dev, PTR_ERR(core->init_b),
+				     "Failed to get INIT_B gpio\n");
+
+	core->done = devm_gpiod_get(dev, "done", GPIOD_IN);
+	if (IS_ERR(core->done))
+		return dev_err_probe(dev, PTR_ERR(core->done),
+				     "Failed to get DONE gpio\n");
+
+	mgr = devm_fpga_mgr_register(dev, "Xilinx Slave Serial FPGA Manager",
+				     &xilinx_core_ops, core);
+	return PTR_ERR_OR_ZERO(mgr);
+}
diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
new file mode 100644
index 0000000000000..40e120945ba70
--- /dev/null
+++ b/drivers/fpga/xilinx-core.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __XILINX_CORE_H
+#define __XILINX_CORE_H
+
+#include <linux/device.h>
+
+struct xilinx_fpga_core;
+
+typedef int (*xilinx_write_func)(struct xilinx_fpga_core *core, const char *buf,
+				 size_t count);
+typedef int (*xilinx_write_one_dummy_byte_func)(struct xilinx_fpga_core *core);
+
+struct xilinx_fpga_core {
+	struct device *dev;
+	xilinx_write_func write;
+	xilinx_write_one_dummy_byte_func write_one_dummy_byte;
+	struct gpio_desc *prog_b;
+	struct gpio_desc *init_b;
+	struct gpio_desc *done;
+};
+
+int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
+		      xilinx_write_func write,
+		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
+
+#endif /* __XILINX_CORE_H */
diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
index e1a227e7ff2ae..ec128dee97312 100644
--- a/drivers/fpga/xilinx-spi.c
+++ b/drivers/fpga/xilinx-spi.c
@@ -10,127 +10,24 @@
  * the slave serial configuration interface.
  */
 
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/fpga/fpga-mgr.h>
-#include <linux/gpio/consumer.h>
+#include "xilinx-core.h"
+
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/of.h>
 #include <linux/spi/spi.h>
-#include <linux/sizes.h>
 
 struct xilinx_spi_conf {
+	struct xilinx_fpga_core core;
 	struct spi_device *spi;
-	struct gpio_desc *prog_b;
-	struct gpio_desc *init_b;
-	struct gpio_desc *done;
 };
 
-static int get_done_gpio(struct fpga_manager *mgr)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	int ret;
-
-	ret = gpiod_get_value(conf->done);
-
-	if (ret < 0)
-		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
-
-	return ret;
-}
-
-static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
-{
-	if (!get_done_gpio(mgr))
-		return FPGA_MGR_STATE_RESET;
-
-	return FPGA_MGR_STATE_UNKNOWN;
-}
-
-/**
- * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
- * a given delay if the pin is unavailable
- *
- * @mgr:        The FPGA manager object
- * @value:      Value INIT_B to wait for (1 = asserted = low)
- * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
- *
- * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
- * too much time passed waiting for that. If no INIT_B GPIO is available
- * then always return 0.
- */
-static int wait_for_init_b(struct fpga_manager *mgr, int value,
-			   unsigned long alt_udelay)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-	if (conf->init_b) {
-		while (time_before(jiffies, timeout)) {
-			int ret = gpiod_get_value(conf->init_b);
-
-			if (ret == value)
-				return 0;
-
-			if (ret < 0) {
-				dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
-				return ret;
-			}
-
-			usleep_range(100, 400);
-		}
-
-		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
-			value ? "assert" : "deassert");
-		return -ETIMEDOUT;
-	}
-
-	udelay(alt_udelay);
-
-	return 0;
-}
-
-static int xilinx_spi_write_init(struct fpga_manager *mgr,
-				 struct fpga_image_info *info,
-				 const char *buf, size_t count)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	int err;
-
-	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
-		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
-		return -EINVAL;
-	}
-
-	gpiod_set_value(conf->prog_b, 1);
+#define to_xilinx_spi_conf(obj) container_of(obj, struct xilinx_spi_conf, core)
 
-	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
-	if (err) {
-		gpiod_set_value(conf->prog_b, 0);
-		return err;
-	}
-
-	gpiod_set_value(conf->prog_b, 0);
-
-	err = wait_for_init_b(mgr, 0, 0);
-	if (err)
-		return err;
-
-	if (get_done_gpio(mgr)) {
-		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
-		return -EIO;
-	}
-
-	/* program latency */
-	usleep_range(7500, 7600);
-	return 0;
-}
-
-static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
+static int xilinx_spi_write(struct xilinx_fpga_core *core, const char *buf,
 			    size_t count)
 {
-	struct xilinx_spi_conf *conf = mgr->priv;
+	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
 	const char *fw_data = buf;
 	const char *fw_data_end = fw_data + count;
 
@@ -143,7 +40,7 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
 
 		ret = spi_write(conf->spi, fw_data, stride);
 		if (ret) {
-			dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
+			dev_err(core->dev, "SPI error in firmware write: %d\n",
 				ret);
 			return ret;
 		}
@@ -153,77 +50,22 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
 	return 0;
 }
 
-static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf)
+static int xilinx_spi_apply_cclk_cycles(struct xilinx_fpga_core *core)
 {
-	struct spi_device *spi = conf->spi;
+	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
 	const u8 din_data[1] = { 0xff };
 	int ret;
 
 	ret = spi_write(conf->spi, din_data, sizeof(din_data));
 	if (ret)
-		dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret);
+		dev_err(core->dev, "applying CCLK cycles failed: %d\n", ret);
 
 	return ret;
 }
 
-static int xilinx_spi_write_complete(struct fpga_manager *mgr,
-				     struct fpga_image_info *info)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	unsigned long timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
-	bool expired = false;
-	int done;
-	int ret;
-
-	/*
-	 * This loop is carefully written such that if the driver is
-	 * scheduled out for more than 'timeout', we still check for DONE
-	 * before giving up and we apply 8 extra CCLK cycles in all cases.
-	 */
-	while (!expired) {
-		expired = time_after(jiffies, timeout);
-
-		done = get_done_gpio(mgr);
-		if (done < 0)
-			return done;
-
-		ret = xilinx_spi_apply_cclk_cycles(conf);
-		if (ret)
-			return ret;
-
-		if (done)
-			return 0;
-	}
-
-	if (conf->init_b) {
-		ret = gpiod_get_value(conf->init_b);
-
-		if (ret < 0) {
-			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
-			return ret;
-		}
-
-		dev_err(&mgr->dev,
-			ret ? "CRC error or invalid device\n"
-			: "Missing sync word or incomplete bitstream\n");
-	} else {
-		dev_err(&mgr->dev, "Timeout after config data transfer\n");
-	}
-
-	return -ETIMEDOUT;
-}
-
-static const struct fpga_manager_ops xilinx_spi_ops = {
-	.state = xilinx_spi_state,
-	.write_init = xilinx_spi_write_init,
-	.write = xilinx_spi_write,
-	.write_complete = xilinx_spi_write_complete,
-};
-
 static int xilinx_spi_probe(struct spi_device *spi)
 {
 	struct xilinx_spi_conf *conf;
-	struct fpga_manager *mgr;
 
 	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
 	if (!conf)
@@ -231,31 +73,15 @@ static int xilinx_spi_probe(struct spi_device *spi)
 
 	conf->spi = spi;
 
-	/* PROGRAM_B is active low */
-	conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW);
-	if (IS_ERR(conf->prog_b))
-		return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b),
-				     "Failed to get PROGRAM_B gpio\n");
-
-	conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN);
-	if (IS_ERR(conf->init_b))
-		return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b),
-				     "Failed to get INIT_B gpio\n");
-
-	conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
-	if (IS_ERR(conf->done))
-		return dev_err_probe(&spi->dev, PTR_ERR(conf->done),
-				     "Failed to get DONE gpio\n");
-
-	mgr = devm_fpga_mgr_register(&spi->dev,
-				     "Xilinx Slave Serial FPGA Manager",
-				     &xilinx_spi_ops, conf);
-	return PTR_ERR_OR_ZERO(mgr);
+	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
+				 xilinx_spi_apply_cclk_cycles);
 }
 
 #ifdef CONFIG_OF
 static const struct of_device_id xlnx_spi_of_match[] = {
-	{ .compatible = "xlnx,fpga-slave-serial", },
+	{
+		.compatible = "xlnx,fpga-slave-serial",
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, xlnx_spi_of_match);
-- 
2.43.0


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

* [PATCH 1/3] fpga: xilinx-spi: extract a common driver core
@ 2024-01-31 23:05     ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-31 23:05 UTC (permalink / raw)
  To: mdf
  Cc: avandiver, bcody, Charles Perry, Wu Hao, Xu Yilun, Tom Rix,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

Factor out the gpio handshaking (using PROGRAM_B, INIT_B and DONE)
protocol in xilinx-core so that it can be reused for another driver.
This commit does not change anything functionally to xilinx-spi.

xilinx-core expects drivers to provide two operations:

 * ->write(const char* buf, size_t count): write to the device
 * ->write_one_dummy_byte(): write 0xFF to the device

Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
---
 drivers/fpga/Kconfig       |   4 +
 drivers/fpga/Makefile      |   1 +
 drivers/fpga/xilinx-core.c | 210 +++++++++++++++++++++++++++++++++++++
 drivers/fpga/xilinx-core.h |  27 +++++
 drivers/fpga/xilinx-spi.c  | 204 +++--------------------------------
 5 files changed, 257 insertions(+), 189 deletions(-)
 create mode 100644 drivers/fpga/xilinx-core.c
 create mode 100644 drivers/fpga/xilinx-core.h

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 2f689ac4ba3a3..d27a1ebf40838 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -64,9 +64,13 @@ config FPGA_MGR_STRATIX10_SOC
 	help
 	  FPGA manager driver support for the Intel Stratix10 SoC.
 
+config FPGA_MGR_XILINX_CORE
+	tristate
+
 config FPGA_MGR_XILINX_SPI
 	tristate "Xilinx Configuration over Slave Serial (SPI)"
 	depends on SPI
+	select FPGA_MGR_XILINX_CORE
 	help
 	  FPGA manager driver support for Xilinx FPGA configuration
 	  over slave serial interface.
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 352a2612623e0..7ec795b6a5a70 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
 obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
 obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
 obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
+obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
 obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
new file mode 100644
index 0000000000000..aff40e9394085
--- /dev/null
+++ b/drivers/fpga/xilinx-core.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common parts of the Xilinx Spartan6 and 7 Series FPGA manager drivers.
+ *
+ * Copyright (C) 2017 DENX Software Engineering
+ *
+ * Anatolij Gustschin <agust@denx.de>
+ */
+
+#include "xilinx-core.h"
+
+#include <linux/delay.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
+
+static int get_done_gpio(struct fpga_manager *mgr)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	int ret;
+
+	ret = gpiod_get_value(core->done);
+
+	if (ret < 0)
+		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
+
+	return ret;
+}
+
+static enum fpga_mgr_states xilinx_core_state(struct fpga_manager *mgr)
+{
+	if (!get_done_gpio(mgr))
+		return FPGA_MGR_STATE_RESET;
+
+	return FPGA_MGR_STATE_UNKNOWN;
+}
+
+/**
+ * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
+ * a given delay if the pin is unavailable
+ *
+ * @mgr:        The FPGA manager object
+ * @value:      Value INIT_B to wait for (1 = asserted = low)
+ * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
+ *
+ * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
+ * too much time passed waiting for that. If no INIT_B GPIO is available
+ * then always return 0.
+ */
+static int wait_for_init_b(struct fpga_manager *mgr, int value,
+			   unsigned long alt_udelay)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+	if (core->init_b) {
+		while (time_before(jiffies, timeout)) {
+			int ret = gpiod_get_value(core->init_b);
+
+			if (ret == value)
+				return 0;
+
+			if (ret < 0) {
+				dev_err(&mgr->dev,
+					"Error reading INIT_B (%d)\n", ret);
+				return ret;
+			}
+
+			usleep_range(100, 400);
+		}
+
+		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
+			value ? "assert" : "deassert");
+		return -ETIMEDOUT;
+	}
+
+	udelay(alt_udelay);
+
+	return 0;
+}
+
+static int xilinx_core_write_init(struct fpga_manager *mgr,
+				  struct fpga_image_info *info, const char *buf,
+				  size_t count)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	int err;
+
+	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
+		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
+		return -EINVAL;
+	}
+
+	gpiod_set_value(core->prog_b, 1);
+
+	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
+	if (err) {
+		gpiod_set_value(core->prog_b, 0);
+		return err;
+	}
+
+	gpiod_set_value(core->prog_b, 0);
+
+	err = wait_for_init_b(mgr, 0, 0);
+	if (err)
+		return err;
+
+	if (get_done_gpio(mgr)) {
+		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
+		return -EIO;
+	}
+
+	/* program latency */
+	usleep_range(7500, 7600);
+	return 0;
+}
+
+static int xilinx_core_write(struct fpga_manager *mgr, const char *buf,
+			     size_t count)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+
+	return core->write(core, buf, count);
+}
+
+static int xilinx_core_write_complete(struct fpga_manager *mgr,
+				      struct fpga_image_info *info)
+{
+	struct xilinx_fpga_core *core = mgr->priv;
+	unsigned long timeout =
+		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
+	bool expired = false;
+	int done;
+	int ret;
+
+	/*
+	 * This loop is carefully written such that if the driver is
+	 * scheduled out for more than 'timeout', we still check for DONE
+	 * before giving up and we apply 8 extra CCLK cycles in all cases.
+	 */
+	while (!expired) {
+		expired = time_after(jiffies, timeout);
+
+		done = get_done_gpio(mgr);
+		if (done < 0)
+			return done;
+
+		ret = core->write_one_dummy_byte(core);
+		if (ret)
+			return ret;
+
+		if (done)
+			return 0;
+	}
+
+	if (core->init_b) {
+		ret = gpiod_get_value(core->init_b);
+
+		if (ret < 0) {
+			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
+			return ret;
+		}
+
+		dev_err(&mgr->dev,
+			ret ? "CRC error or invalid device\n" :
+			      "Missing sync word or incomplete bitstream\n");
+	} else {
+		dev_err(&mgr->dev, "Timeout after config data transfer\n");
+	}
+
+	return -ETIMEDOUT;
+}
+
+static const struct fpga_manager_ops xilinx_core_ops = {
+	.state = xilinx_core_state,
+	.write_init = xilinx_core_write_init,
+	.write = xilinx_core_write,
+	.write_complete = xilinx_core_write_complete,
+};
+
+int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
+		      xilinx_write_func write,
+		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
+{
+	struct fpga_manager *mgr;
+
+	core->dev = dev;
+	core->write = write;
+	core->write_one_dummy_byte = write_one_dummy_byte;
+
+	/* PROGRAM_B is active low */
+	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
+	if (IS_ERR(core->prog_b))
+		return dev_err_probe(dev, PTR_ERR(core->prog_b),
+				     "Failed to get PROGRAM_B gpio\n");
+
+	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
+	if (IS_ERR(core->init_b))
+		return dev_err_probe(dev, PTR_ERR(core->init_b),
+				     "Failed to get INIT_B gpio\n");
+
+	core->done = devm_gpiod_get(dev, "done", GPIOD_IN);
+	if (IS_ERR(core->done))
+		return dev_err_probe(dev, PTR_ERR(core->done),
+				     "Failed to get DONE gpio\n");
+
+	mgr = devm_fpga_mgr_register(dev, "Xilinx Slave Serial FPGA Manager",
+				     &xilinx_core_ops, core);
+	return PTR_ERR_OR_ZERO(mgr);
+}
diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
new file mode 100644
index 0000000000000..40e120945ba70
--- /dev/null
+++ b/drivers/fpga/xilinx-core.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __XILINX_CORE_H
+#define __XILINX_CORE_H
+
+#include <linux/device.h>
+
+struct xilinx_fpga_core;
+
+typedef int (*xilinx_write_func)(struct xilinx_fpga_core *core, const char *buf,
+				 size_t count);
+typedef int (*xilinx_write_one_dummy_byte_func)(struct xilinx_fpga_core *core);
+
+struct xilinx_fpga_core {
+	struct device *dev;
+	xilinx_write_func write;
+	xilinx_write_one_dummy_byte_func write_one_dummy_byte;
+	struct gpio_desc *prog_b;
+	struct gpio_desc *init_b;
+	struct gpio_desc *done;
+};
+
+int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
+		      xilinx_write_func write,
+		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
+
+#endif /* __XILINX_CORE_H */
diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
index e1a227e7ff2ae..ec128dee97312 100644
--- a/drivers/fpga/xilinx-spi.c
+++ b/drivers/fpga/xilinx-spi.c
@@ -10,127 +10,24 @@
  * the slave serial configuration interface.
  */
 
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/fpga/fpga-mgr.h>
-#include <linux/gpio/consumer.h>
+#include "xilinx-core.h"
+
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/of.h>
 #include <linux/spi/spi.h>
-#include <linux/sizes.h>
 
 struct xilinx_spi_conf {
+	struct xilinx_fpga_core core;
 	struct spi_device *spi;
-	struct gpio_desc *prog_b;
-	struct gpio_desc *init_b;
-	struct gpio_desc *done;
 };
 
-static int get_done_gpio(struct fpga_manager *mgr)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	int ret;
-
-	ret = gpiod_get_value(conf->done);
-
-	if (ret < 0)
-		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
-
-	return ret;
-}
-
-static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
-{
-	if (!get_done_gpio(mgr))
-		return FPGA_MGR_STATE_RESET;
-
-	return FPGA_MGR_STATE_UNKNOWN;
-}
-
-/**
- * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
- * a given delay if the pin is unavailable
- *
- * @mgr:        The FPGA manager object
- * @value:      Value INIT_B to wait for (1 = asserted = low)
- * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
- *
- * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
- * too much time passed waiting for that. If no INIT_B GPIO is available
- * then always return 0.
- */
-static int wait_for_init_b(struct fpga_manager *mgr, int value,
-			   unsigned long alt_udelay)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-	if (conf->init_b) {
-		while (time_before(jiffies, timeout)) {
-			int ret = gpiod_get_value(conf->init_b);
-
-			if (ret == value)
-				return 0;
-
-			if (ret < 0) {
-				dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
-				return ret;
-			}
-
-			usleep_range(100, 400);
-		}
-
-		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
-			value ? "assert" : "deassert");
-		return -ETIMEDOUT;
-	}
-
-	udelay(alt_udelay);
-
-	return 0;
-}
-
-static int xilinx_spi_write_init(struct fpga_manager *mgr,
-				 struct fpga_image_info *info,
-				 const char *buf, size_t count)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	int err;
-
-	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
-		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
-		return -EINVAL;
-	}
-
-	gpiod_set_value(conf->prog_b, 1);
+#define to_xilinx_spi_conf(obj) container_of(obj, struct xilinx_spi_conf, core)
 
-	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
-	if (err) {
-		gpiod_set_value(conf->prog_b, 0);
-		return err;
-	}
-
-	gpiod_set_value(conf->prog_b, 0);
-
-	err = wait_for_init_b(mgr, 0, 0);
-	if (err)
-		return err;
-
-	if (get_done_gpio(mgr)) {
-		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
-		return -EIO;
-	}
-
-	/* program latency */
-	usleep_range(7500, 7600);
-	return 0;
-}
-
-static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
+static int xilinx_spi_write(struct xilinx_fpga_core *core, const char *buf,
 			    size_t count)
 {
-	struct xilinx_spi_conf *conf = mgr->priv;
+	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
 	const char *fw_data = buf;
 	const char *fw_data_end = fw_data + count;
 
@@ -143,7 +40,7 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
 
 		ret = spi_write(conf->spi, fw_data, stride);
 		if (ret) {
-			dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
+			dev_err(core->dev, "SPI error in firmware write: %d\n",
 				ret);
 			return ret;
 		}
@@ -153,77 +50,22 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
 	return 0;
 }
 
-static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf)
+static int xilinx_spi_apply_cclk_cycles(struct xilinx_fpga_core *core)
 {
-	struct spi_device *spi = conf->spi;
+	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
 	const u8 din_data[1] = { 0xff };
 	int ret;
 
 	ret = spi_write(conf->spi, din_data, sizeof(din_data));
 	if (ret)
-		dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret);
+		dev_err(core->dev, "applying CCLK cycles failed: %d\n", ret);
 
 	return ret;
 }
 
-static int xilinx_spi_write_complete(struct fpga_manager *mgr,
-				     struct fpga_image_info *info)
-{
-	struct xilinx_spi_conf *conf = mgr->priv;
-	unsigned long timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
-	bool expired = false;
-	int done;
-	int ret;
-
-	/*
-	 * This loop is carefully written such that if the driver is
-	 * scheduled out for more than 'timeout', we still check for DONE
-	 * before giving up and we apply 8 extra CCLK cycles in all cases.
-	 */
-	while (!expired) {
-		expired = time_after(jiffies, timeout);
-
-		done = get_done_gpio(mgr);
-		if (done < 0)
-			return done;
-
-		ret = xilinx_spi_apply_cclk_cycles(conf);
-		if (ret)
-			return ret;
-
-		if (done)
-			return 0;
-	}
-
-	if (conf->init_b) {
-		ret = gpiod_get_value(conf->init_b);
-
-		if (ret < 0) {
-			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
-			return ret;
-		}
-
-		dev_err(&mgr->dev,
-			ret ? "CRC error or invalid device\n"
-			: "Missing sync word or incomplete bitstream\n");
-	} else {
-		dev_err(&mgr->dev, "Timeout after config data transfer\n");
-	}
-
-	return -ETIMEDOUT;
-}
-
-static const struct fpga_manager_ops xilinx_spi_ops = {
-	.state = xilinx_spi_state,
-	.write_init = xilinx_spi_write_init,
-	.write = xilinx_spi_write,
-	.write_complete = xilinx_spi_write_complete,
-};
-
 static int xilinx_spi_probe(struct spi_device *spi)
 {
 	struct xilinx_spi_conf *conf;
-	struct fpga_manager *mgr;
 
 	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
 	if (!conf)
@@ -231,31 +73,15 @@ static int xilinx_spi_probe(struct spi_device *spi)
 
 	conf->spi = spi;
 
-	/* PROGRAM_B is active low */
-	conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW);
-	if (IS_ERR(conf->prog_b))
-		return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b),
-				     "Failed to get PROGRAM_B gpio\n");
-
-	conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN);
-	if (IS_ERR(conf->init_b))
-		return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b),
-				     "Failed to get INIT_B gpio\n");
-
-	conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
-	if (IS_ERR(conf->done))
-		return dev_err_probe(&spi->dev, PTR_ERR(conf->done),
-				     "Failed to get DONE gpio\n");
-
-	mgr = devm_fpga_mgr_register(&spi->dev,
-				     "Xilinx Slave Serial FPGA Manager",
-				     &xilinx_spi_ops, conf);
-	return PTR_ERR_OR_ZERO(mgr);
+	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
+				 xilinx_spi_apply_cclk_cycles);
 }
 
 #ifdef CONFIG_OF
 static const struct of_device_id xlnx_spi_of_match[] = {
-	{ .compatible = "xlnx,fpga-slave-serial", },
+	{
+		.compatible = "xlnx,fpga-slave-serial",
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, xlnx_spi_of_match);
-- 
2.43.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-31 23:05   ` Charles Perry
@ 2024-01-31 23:05     ` Charles Perry
  -1 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-31 23:05 UTC (permalink / raw)
  To: mdf
  Cc: avandiver, bcody, Charles Perry, Wu Hao, Xu Yilun, Tom Rix,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

Document the slave SelectMAP interface of Xilinx 7 series FPGA.

Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
---
 .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml

diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
new file mode 100644
index 0000000000000..c9a446b43cdd9
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Xilinx SelectMAP FPGA interface
+
+maintainers:
+  - Charles Perry <charles.perry@savoirfairelinux.com>
+
+description: |
+  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
+  parallel port named the SelectMAP interface in the documentation. Only
+  the x8 mode is supported where data is loaded at one byte per rising edge of
+  the clock, with the MSB of each byte presented to the D0 pin.
+
+  Datasheets:
+    https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
+
+allOf:
+  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
+
+properties:
+  compatible:
+    enum:
+      - xlnx,fpga-selectmap
+
+  reg:
+    description:
+      At least 1 byte of memory mapped IO
+    maxItems: 1
+
+  prog-gpios:
+    description:
+      config pin (referred to as PROGRAM_B in the manual)
+    maxItems: 1
+
+  done-gpios:
+    description:
+      config status pin (referred to as DONE in the manual)
+    maxItems: 1
+
+  init-gpios:
+    description:
+      initialization status and configuration error pin
+      (referred to as INIT_B in the manual)
+    maxItems: 1
+
+  csi-gpios:
+    description:
+      chip select pin (referred to as CSI_B in the manual)
+      Optional gpio for if the bus controller does not provide a chip select.
+    maxItems: 1
+
+  rdwr-gpios:
+    description:
+      read/write select pin (referred to as RDWR_B in the manual)
+      Optional gpio for if the bus controller does not provide this pin.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - prog-gpios
+  - done-gpios
+  - init-gpios
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    fpga-mgr@8000000 {
+      compatible = "xlnx,fpga-selectmap";
+      reg = <0x8000000 0x4>;
+      prog-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>;
+      init-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
+      done-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
+      csi-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+      rdwr-gpios = <&gpio3 10 GPIO_ACTIVE_LOW>;
+    };
+...
-- 
2.43.0


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

* [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
@ 2024-01-31 23:05     ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-31 23:05 UTC (permalink / raw)
  To: mdf
  Cc: avandiver, bcody, Charles Perry, Wu Hao, Xu Yilun, Tom Rix,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

Document the slave SelectMAP interface of Xilinx 7 series FPGA.

Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
---
 .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
 1 file changed, 83 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml

diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
new file mode 100644
index 0000000000000..c9a446b43cdd9
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Xilinx SelectMAP FPGA interface
+
+maintainers:
+  - Charles Perry <charles.perry@savoirfairelinux.com>
+
+description: |
+  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
+  parallel port named the SelectMAP interface in the documentation. Only
+  the x8 mode is supported where data is loaded at one byte per rising edge of
+  the clock, with the MSB of each byte presented to the D0 pin.
+
+  Datasheets:
+    https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
+
+allOf:
+  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
+
+properties:
+  compatible:
+    enum:
+      - xlnx,fpga-selectmap
+
+  reg:
+    description:
+      At least 1 byte of memory mapped IO
+    maxItems: 1
+
+  prog-gpios:
+    description:
+      config pin (referred to as PROGRAM_B in the manual)
+    maxItems: 1
+
+  done-gpios:
+    description:
+      config status pin (referred to as DONE in the manual)
+    maxItems: 1
+
+  init-gpios:
+    description:
+      initialization status and configuration error pin
+      (referred to as INIT_B in the manual)
+    maxItems: 1
+
+  csi-gpios:
+    description:
+      chip select pin (referred to as CSI_B in the manual)
+      Optional gpio for if the bus controller does not provide a chip select.
+    maxItems: 1
+
+  rdwr-gpios:
+    description:
+      read/write select pin (referred to as RDWR_B in the manual)
+      Optional gpio for if the bus controller does not provide this pin.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - prog-gpios
+  - done-gpios
+  - init-gpios
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    fpga-mgr@8000000 {
+      compatible = "xlnx,fpga-selectmap";
+      reg = <0x8000000 0x4>;
+      prog-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>;
+      init-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
+      done-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
+      csi-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+      rdwr-gpios = <&gpio3 10 GPIO_ACTIVE_LOW>;
+    };
+...
-- 
2.43.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 3/3] fpga: xilinx-selectmap: add new driver
  2024-01-31 23:05   ` Charles Perry
@ 2024-01-31 23:05     ` Charles Perry
  -1 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-31 23:05 UTC (permalink / raw)
  To: mdf
  Cc: avandiver, bcody, Charles Perry, Wu Hao, Xu Yilun, Tom Rix,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

Xilinx 7 series FPGA can be programmed using a slave parallel port named
the SelectMAP interface in the datasheet. This slave interface is
compatible with the i.MX6 EIM bus controller but other types of external
memory mapped parallel bus might work.

xilinx-selectmap currently only supports the x8 mode where data is loaded
at one byte per rising edge of the clock, with the MSb of each byte
presented to the D0 pin.

Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
---
 drivers/fpga/Kconfig            |   8 +++
 drivers/fpga/Makefile           |   1 +
 drivers/fpga/xilinx-core.c      |  11 +++-
 drivers/fpga/xilinx-core.h      |   3 +-
 drivers/fpga/xilinx-selectmap.c | 106 ++++++++++++++++++++++++++++++++
 drivers/fpga/xilinx-spi.c       |   3 +-
 6 files changed, 127 insertions(+), 5 deletions(-)
 create mode 100644 drivers/fpga/xilinx-selectmap.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index d27a1ebf40838..37b35f58f0dfb 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -67,6 +67,14 @@ config FPGA_MGR_STRATIX10_SOC
 config FPGA_MGR_XILINX_CORE
 	tristate
 
+config FPGA_MGR_XILINX_SELECTMAP
+	tristate "Xilinx Configuration over SelectMAP"
+	depends on HAS_IOMEM
+	select FPGA_MGR_XILINX_CORE
+	help
+	  FPGA manager driver support for Xilinx FPGA configuration
+	  over SelectMAP interface.
+
 config FPGA_MGR_XILINX_SPI
 	tristate "Xilinx Configuration over Slave Serial (SPI)"
 	depends on SPI
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 7ec795b6a5a70..aeb89bb13517e 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
 obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
 obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
 obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
+obj-$(CONFIG_FPGA_MGR_XILINX_SELECTMAP)	+= xilinx-selectmap.o
 obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
index aff40e9394085..64117759be100 100644
--- a/drivers/fpga/xilinx-core.c
+++ b/drivers/fpga/xilinx-core.c
@@ -180,21 +180,26 @@ static const struct fpga_manager_ops xilinx_core_ops = {
 
 int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
 		      xilinx_write_func write,
-		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
+		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
+		      const char *prog_con_id, const char *init_con_id)
 {
 	struct fpga_manager *mgr;
 
+	if (!core || !dev || !write || !write_one_dummy_byte || !prog_con_id ||
+	    !init_con_id)
+		return -EINVAL;
+
 	core->dev = dev;
 	core->write = write;
 	core->write_one_dummy_byte = write_one_dummy_byte;
 
 	/* PROGRAM_B is active low */
-	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
+	core->prog_b = devm_gpiod_get(dev, prog_con_id, GPIOD_OUT_LOW);
 	if (IS_ERR(core->prog_b))
 		return dev_err_probe(dev, PTR_ERR(core->prog_b),
 				     "Failed to get PROGRAM_B gpio\n");
 
-	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
+	core->init_b = devm_gpiod_get_optional(dev, init_con_id, GPIOD_IN);
 	if (IS_ERR(core->init_b))
 		return dev_err_probe(dev, PTR_ERR(core->init_b),
 				     "Failed to get INIT_B gpio\n");
diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
index 40e120945ba70..817f0e551d093 100644
--- a/drivers/fpga/xilinx-core.h
+++ b/drivers/fpga/xilinx-core.h
@@ -22,6 +22,7 @@ struct xilinx_fpga_core {
 
 int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
 		      xilinx_write_func write,
-		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
+		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
+		      const char *prog_con_id, const char *init_con_id);
 
 #endif /* __XILINX_CORE_H */
diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c
new file mode 100644
index 0000000000000..08054e19bb498
--- /dev/null
+++ b/drivers/fpga/xilinx-selectmap.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Xilinx Spartan6 and 7 Series SelectMAP interface driver
+ *
+ * (C) 2024 Charles Perry <charles.perry@savoirfairelinux.com>
+ *
+ * Manage Xilinx FPGA firmware loaded over the SelectMAP configuration
+ * interface.
+ */
+
+#include "xilinx-core.h"
+
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/io.h>
+
+struct xilinx_selectmap_conf {
+	struct xilinx_fpga_core core;
+	void __iomem *base;
+	struct gpio_desc *csi_b;
+	struct gpio_desc *rdwr_b;
+};
+
+#define to_xilinx_selectmap_conf(obj) \
+	container_of(obj, struct xilinx_selectmap_conf, core)
+
+static int xilinx_selectmap_write(struct xilinx_fpga_core *core,
+				  const char *buf, size_t count)
+{
+	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
+	u32 i;
+
+	for (i = 0; i < count; ++i)
+		writeb(buf[i], conf->base);
+
+	return 0;
+}
+
+static int xilinx_selectmap_apply_padding(struct xilinx_fpga_core *core)
+{
+	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
+
+	writeb(0xFF, conf->base);
+	return 0;
+}
+
+static int xilinx_selectmap_probe(struct platform_device *pdev)
+{
+	struct xilinx_selectmap_conf *conf;
+	struct resource *r;
+	void __iomem *base;
+
+	conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
+	if (!conf)
+		return -ENOMEM;
+
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
+	if (IS_ERR(base))
+		return dev_err_probe(&pdev->dev, PTR_ERR(base),
+				     "ioremap error\n");
+	conf->base = base;
+
+	/* CSI_B is active low */
+	conf->csi_b =
+		devm_gpiod_get_optional(&pdev->dev, "csi", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->csi_b))
+		return dev_err_probe(&pdev->dev, PTR_ERR(conf->csi_b),
+				     "Failed to get CSI_B gpio\n");
+
+	/* RDWR_B is active low */
+	conf->rdwr_b =
+		devm_gpiod_get_optional(&pdev->dev, "rdwr", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->rdwr_b))
+		return dev_err_probe(&pdev->dev, PTR_ERR(conf->rdwr_b),
+				     "Failed to get RDWR_B gpio\n");
+
+	return xilinx_core_probe(&conf->core, &pdev->dev,
+				 xilinx_selectmap_write,
+				 xilinx_selectmap_apply_padding, "prog",
+				 "init");
+}
+
+static const struct of_device_id xlnx_selectmap_of_match[] = {
+	{
+		.compatible = "xlnx,fpga-selectmap",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, xlnx_selectmap_of_match);
+
+static struct platform_driver xilinx_selectmap_driver = {
+	.driver = {
+		.name = "xilinx-selectmap",
+		.of_match_table = xlnx_selectmap_of_match,
+	},
+	.probe  = xilinx_selectmap_probe,
+};
+
+module_platform_driver(xilinx_selectmap_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Charles Perry <charles.perry@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SelectMap");
diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
index ec128dee97312..b9ab3d5da004c 100644
--- a/drivers/fpga/xilinx-spi.c
+++ b/drivers/fpga/xilinx-spi.c
@@ -74,7 +74,8 @@ static int xilinx_spi_probe(struct spi_device *spi)
 	conf->spi = spi;
 
 	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
-				 xilinx_spi_apply_cclk_cycles);
+				 xilinx_spi_apply_cclk_cycles, "prog_b",
+				 "init-b");
 }
 
 #ifdef CONFIG_OF
-- 
2.43.0


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

* [PATCH 3/3] fpga: xilinx-selectmap: add new driver
@ 2024-01-31 23:05     ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-01-31 23:05 UTC (permalink / raw)
  To: mdf
  Cc: avandiver, bcody, Charles Perry, Wu Hao, Xu Yilun, Tom Rix,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

Xilinx 7 series FPGA can be programmed using a slave parallel port named
the SelectMAP interface in the datasheet. This slave interface is
compatible with the i.MX6 EIM bus controller but other types of external
memory mapped parallel bus might work.

xilinx-selectmap currently only supports the x8 mode where data is loaded
at one byte per rising edge of the clock, with the MSb of each byte
presented to the D0 pin.

Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
---
 drivers/fpga/Kconfig            |   8 +++
 drivers/fpga/Makefile           |   1 +
 drivers/fpga/xilinx-core.c      |  11 +++-
 drivers/fpga/xilinx-core.h      |   3 +-
 drivers/fpga/xilinx-selectmap.c | 106 ++++++++++++++++++++++++++++++++
 drivers/fpga/xilinx-spi.c       |   3 +-
 6 files changed, 127 insertions(+), 5 deletions(-)
 create mode 100644 drivers/fpga/xilinx-selectmap.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index d27a1ebf40838..37b35f58f0dfb 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -67,6 +67,14 @@ config FPGA_MGR_STRATIX10_SOC
 config FPGA_MGR_XILINX_CORE
 	tristate
 
+config FPGA_MGR_XILINX_SELECTMAP
+	tristate "Xilinx Configuration over SelectMAP"
+	depends on HAS_IOMEM
+	select FPGA_MGR_XILINX_CORE
+	help
+	  FPGA manager driver support for Xilinx FPGA configuration
+	  over SelectMAP interface.
+
 config FPGA_MGR_XILINX_SPI
 	tristate "Xilinx Configuration over Slave Serial (SPI)"
 	depends on SPI
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 7ec795b6a5a70..aeb89bb13517e 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
 obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
 obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
 obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
+obj-$(CONFIG_FPGA_MGR_XILINX_SELECTMAP)	+= xilinx-selectmap.o
 obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
index aff40e9394085..64117759be100 100644
--- a/drivers/fpga/xilinx-core.c
+++ b/drivers/fpga/xilinx-core.c
@@ -180,21 +180,26 @@ static const struct fpga_manager_ops xilinx_core_ops = {
 
 int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
 		      xilinx_write_func write,
-		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
+		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
+		      const char *prog_con_id, const char *init_con_id)
 {
 	struct fpga_manager *mgr;
 
+	if (!core || !dev || !write || !write_one_dummy_byte || !prog_con_id ||
+	    !init_con_id)
+		return -EINVAL;
+
 	core->dev = dev;
 	core->write = write;
 	core->write_one_dummy_byte = write_one_dummy_byte;
 
 	/* PROGRAM_B is active low */
-	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
+	core->prog_b = devm_gpiod_get(dev, prog_con_id, GPIOD_OUT_LOW);
 	if (IS_ERR(core->prog_b))
 		return dev_err_probe(dev, PTR_ERR(core->prog_b),
 				     "Failed to get PROGRAM_B gpio\n");
 
-	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
+	core->init_b = devm_gpiod_get_optional(dev, init_con_id, GPIOD_IN);
 	if (IS_ERR(core->init_b))
 		return dev_err_probe(dev, PTR_ERR(core->init_b),
 				     "Failed to get INIT_B gpio\n");
diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
index 40e120945ba70..817f0e551d093 100644
--- a/drivers/fpga/xilinx-core.h
+++ b/drivers/fpga/xilinx-core.h
@@ -22,6 +22,7 @@ struct xilinx_fpga_core {
 
 int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
 		      xilinx_write_func write,
-		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
+		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
+		      const char *prog_con_id, const char *init_con_id);
 
 #endif /* __XILINX_CORE_H */
diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c
new file mode 100644
index 0000000000000..08054e19bb498
--- /dev/null
+++ b/drivers/fpga/xilinx-selectmap.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Xilinx Spartan6 and 7 Series SelectMAP interface driver
+ *
+ * (C) 2024 Charles Perry <charles.perry@savoirfairelinux.com>
+ *
+ * Manage Xilinx FPGA firmware loaded over the SelectMAP configuration
+ * interface.
+ */
+
+#include "xilinx-core.h"
+
+#include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/io.h>
+
+struct xilinx_selectmap_conf {
+	struct xilinx_fpga_core core;
+	void __iomem *base;
+	struct gpio_desc *csi_b;
+	struct gpio_desc *rdwr_b;
+};
+
+#define to_xilinx_selectmap_conf(obj) \
+	container_of(obj, struct xilinx_selectmap_conf, core)
+
+static int xilinx_selectmap_write(struct xilinx_fpga_core *core,
+				  const char *buf, size_t count)
+{
+	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
+	u32 i;
+
+	for (i = 0; i < count; ++i)
+		writeb(buf[i], conf->base);
+
+	return 0;
+}
+
+static int xilinx_selectmap_apply_padding(struct xilinx_fpga_core *core)
+{
+	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
+
+	writeb(0xFF, conf->base);
+	return 0;
+}
+
+static int xilinx_selectmap_probe(struct platform_device *pdev)
+{
+	struct xilinx_selectmap_conf *conf;
+	struct resource *r;
+	void __iomem *base;
+
+	conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
+	if (!conf)
+		return -ENOMEM;
+
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
+	if (IS_ERR(base))
+		return dev_err_probe(&pdev->dev, PTR_ERR(base),
+				     "ioremap error\n");
+	conf->base = base;
+
+	/* CSI_B is active low */
+	conf->csi_b =
+		devm_gpiod_get_optional(&pdev->dev, "csi", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->csi_b))
+		return dev_err_probe(&pdev->dev, PTR_ERR(conf->csi_b),
+				     "Failed to get CSI_B gpio\n");
+
+	/* RDWR_B is active low */
+	conf->rdwr_b =
+		devm_gpiod_get_optional(&pdev->dev, "rdwr", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->rdwr_b))
+		return dev_err_probe(&pdev->dev, PTR_ERR(conf->rdwr_b),
+				     "Failed to get RDWR_B gpio\n");
+
+	return xilinx_core_probe(&conf->core, &pdev->dev,
+				 xilinx_selectmap_write,
+				 xilinx_selectmap_apply_padding, "prog",
+				 "init");
+}
+
+static const struct of_device_id xlnx_selectmap_of_match[] = {
+	{
+		.compatible = "xlnx,fpga-selectmap",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, xlnx_selectmap_of_match);
+
+static struct platform_driver xilinx_selectmap_driver = {
+	.driver = {
+		.name = "xilinx-selectmap",
+		.of_match_table = xlnx_selectmap_of_match,
+	},
+	.probe  = xilinx_selectmap_probe,
+};
+
+module_platform_driver(xilinx_selectmap_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Charles Perry <charles.perry@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SelectMap");
diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
index ec128dee97312..b9ab3d5da004c 100644
--- a/drivers/fpga/xilinx-spi.c
+++ b/drivers/fpga/xilinx-spi.c
@@ -74,7 +74,8 @@ static int xilinx_spi_probe(struct spi_device *spi)
 	conf->spi = spi;
 
 	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
-				 xilinx_spi_apply_cclk_cycles);
+				 xilinx_spi_apply_cclk_cycles, "prog_b",
+				 "init-b");
 }
 
 #ifdef CONFIG_OF
-- 
2.43.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-31 23:05     ` Charles Perry
@ 2024-02-01  8:07       ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-02-01  8:07 UTC (permalink / raw)
  To: Charles Perry, mdf
  Cc: avandiver, bcody, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On 01/02/2024 00:05, Charles Perry wrote:
> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---
>  .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
>  1 file changed, 83 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
> 
> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
> new file mode 100644
> index 0000000000000..c9a446b43cdd9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
> @@ -0,0 +1,83 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Xilinx SelectMAP FPGA interface
> +
> +maintainers:
> +  - Charles Perry <charles.perry@savoirfairelinux.com>
> +
> +description: |
> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
> +  parallel port named the SelectMAP interface in the documentation. Only
> +  the x8 mode is supported where data is loaded at one byte per rising edge of
> +  the clock, with the MSB of each byte presented to the D0 pin.
> +
> +  Datasheets:
> +    https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
> +
> +allOf:
> +  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - xlnx,fpga-selectmap

Your description mentions "7 Series" which is not present in compatible
and title. What is exactly the product here? Interface usually is not
the final binding, so is this specific to some particular FPGA or SoC?


Best regards,
Krzysztof


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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
@ 2024-02-01  8:07       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-02-01  8:07 UTC (permalink / raw)
  To: Charles Perry, mdf
  Cc: avandiver, bcody, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On 01/02/2024 00:05, Charles Perry wrote:
> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---
>  .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
>  1 file changed, 83 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
> 
> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
> new file mode 100644
> index 0000000000000..c9a446b43cdd9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
> @@ -0,0 +1,83 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Xilinx SelectMAP FPGA interface
> +
> +maintainers:
> +  - Charles Perry <charles.perry@savoirfairelinux.com>
> +
> +description: |
> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
> +  parallel port named the SelectMAP interface in the documentation. Only
> +  the x8 mode is supported where data is loaded at one byte per rising edge of
> +  the clock, with the MSB of each byte presented to the D0 pin.
> +
> +  Datasheets:
> +    https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
> +
> +allOf:
> +  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - xlnx,fpga-selectmap

Your description mentions "7 Series" which is not present in compatible
and title. What is exactly the product here? Interface usually is not
the final binding, so is this specific to some particular FPGA or SoC?


Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-02-01  8:07       ` Krzysztof Kozlowski
@ 2024-02-01 18:24         ` Charles Perry
  -1 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-01 18:24 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, krzysztof kozlowski+dt, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel



----- On Feb 1, 2024, at 3:07 AM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:

> On 01/02/2024 00:05, Charles Perry wrote:
>> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
>> 
>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>> ---
>>  .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
>>  1 file changed, 83 insertions(+)
>>  create mode 100644
>>  Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>> 
>> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>> b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>> new file mode 100644
>> index 0000000000000..c9a446b43cdd9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>> @@ -0,0 +1,83 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Xilinx SelectMAP FPGA interface
>> +
>> +maintainers:
>> +  - Charles Perry <charles.perry@savoirfairelinux.com>
>> +
>> +description: |
>> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
>> +  parallel port named the SelectMAP interface in the documentation. Only
>> +  the x8 mode is supported where data is loaded at one byte per rising edge of
>> +  the clock, with the MSB of each byte presented to the D0 pin.
>> +
>> +  Datasheets:
>> +
>> https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
>> +
>> +allOf:
>> +  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
>> +
>> +properties:
>> +  compatible:
>> +    enum:
>> +      - xlnx,fpga-selectmap
> 
> Your description mentions "7 Series" which is not present in compatible
> and title. What is exactly the product here? Interface usually is not
> the final binding, so is this specific to some particular FPGA or SoC?
> 
> 
> Best regards,
> Krzysztof

This is specific to the FPGA, the 7 series encompass the following part
family:
 * Spartan-7 (XC7S6, XC7S15, ... XC7S100)
 * Artix-7 (XC7A12T, XC7A15T, ... XC7A200T)
 * Kintex-7 (XC7K70T, XC7K160T, ... XC7K480T)
 * Virtex-7 (XC7V585T, XC7V2000T, 
             XC7VX330T, XC7VX415T, ... XC7VX1140T,
             XC7VH580T, XC7VH870T)


The configuration guide of Xilinx [1] tells us that all those devices
share a common programming scheme.

I do agree that having a mention of "7 series" in the compatible name
would be beneficial as Xilinx has more FPGA than just the 7 series.
The name was inspired from "xlnx,fpga-slave-serial" which is the compatible
for the serial interface.

What about "xlnx,fpga-xc7-selectmap" ?

I'm also seeing that I missed some mention of the "slave" word in the
commit message, will fix.

Regards,
Charles

[1] https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
@ 2024-02-01 18:24         ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-01 18:24 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, krzysztof kozlowski+dt, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel



----- On Feb 1, 2024, at 3:07 AM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:

> On 01/02/2024 00:05, Charles Perry wrote:
>> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
>> 
>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>> ---
>>  .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
>>  1 file changed, 83 insertions(+)
>>  create mode 100644
>>  Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>> 
>> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>> b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>> new file mode 100644
>> index 0000000000000..c9a446b43cdd9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>> @@ -0,0 +1,83 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Xilinx SelectMAP FPGA interface
>> +
>> +maintainers:
>> +  - Charles Perry <charles.perry@savoirfairelinux.com>
>> +
>> +description: |
>> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
>> +  parallel port named the SelectMAP interface in the documentation. Only
>> +  the x8 mode is supported where data is loaded at one byte per rising edge of
>> +  the clock, with the MSB of each byte presented to the D0 pin.
>> +
>> +  Datasheets:
>> +
>> https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
>> +
>> +allOf:
>> +  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
>> +
>> +properties:
>> +  compatible:
>> +    enum:
>> +      - xlnx,fpga-selectmap
> 
> Your description mentions "7 Series" which is not present in compatible
> and title. What is exactly the product here? Interface usually is not
> the final binding, so is this specific to some particular FPGA or SoC?
> 
> 
> Best regards,
> Krzysztof

This is specific to the FPGA, the 7 series encompass the following part
family:
 * Spartan-7 (XC7S6, XC7S15, ... XC7S100)
 * Artix-7 (XC7A12T, XC7A15T, ... XC7A200T)
 * Kintex-7 (XC7K70T, XC7K160T, ... XC7K480T)
 * Virtex-7 (XC7V585T, XC7V2000T, 
             XC7VX330T, XC7VX415T, ... XC7VX1140T,
             XC7VH580T, XC7VH870T)


The configuration guide of Xilinx [1] tells us that all those devices
share a common programming scheme.

I do agree that having a mention of "7 series" in the compatible name
would be beneficial as Xilinx has more FPGA than just the 7 series.
The name was inspired from "xlnx,fpga-slave-serial" which is the compatible
for the serial interface.

What about "xlnx,fpga-xc7-selectmap" ?

I'm also seeing that I missed some mention of the "slave" word in the
commit message, will fix.

Regards,
Charles

[1] https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf



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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-02-01 18:24         ` Charles Perry
@ 2024-02-02 10:49           ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-02-02 10:49 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, krzysztof kozlowski+dt, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

On 01/02/2024 19:24, Charles Perry wrote:
> 
> 
> ----- On Feb 1, 2024, at 3:07 AM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:
> 
>> On 01/02/2024 00:05, Charles Perry wrote:
>>> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
>>>
>>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>>> ---
>>>  .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
>>>  1 file changed, 83 insertions(+)
>>>  create mode 100644
>>>  Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>> b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>> new file mode 100644
>>> index 0000000000000..c9a446b43cdd9
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>> @@ -0,0 +1,83 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Xilinx SelectMAP FPGA interface
>>> +
>>> +maintainers:
>>> +  - Charles Perry <charles.perry@savoirfairelinux.com>
>>> +
>>> +description: |
>>> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
>>> +  parallel port named the SelectMAP interface in the documentation. Only
>>> +  the x8 mode is supported where data is loaded at one byte per rising edge of
>>> +  the clock, with the MSB of each byte presented to the D0 pin.
>>> +
>>> +  Datasheets:
>>> +
>>> https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
>>> +
>>> +allOf:
>>> +  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
>>> +
>>> +properties:
>>> +  compatible:
>>> +    enum:
>>> +      - xlnx,fpga-selectmap
>>
>> Your description mentions "7 Series" which is not present in compatible
>> and title. What is exactly the product here? Interface usually is not
>> the final binding, so is this specific to some particular FPGA or SoC?
>>
>>
>> Best regards,
>> Krzysztof
> 
> This is specific to the FPGA, the 7 series encompass the following part
> family:
>  * Spartan-7 (XC7S6, XC7S15, ... XC7S100)
>  * Artix-7 (XC7A12T, XC7A15T, ... XC7A200T)
>  * Kintex-7 (XC7K70T, XC7K160T, ... XC7K480T)
>  * Virtex-7 (XC7V585T, XC7V2000T, 
>              XC7VX330T, XC7VX415T, ... XC7VX1140T,
>              XC7VH580T, XC7VH870T)
> 
> 
> The configuration guide of Xilinx [1] tells us that all those devices
> share a common programming scheme.
> 
> I do agree that having a mention of "7 series" in the compatible name
> would be beneficial as Xilinx has more FPGA than just the 7 series.
> The name was inspired from "xlnx,fpga-slave-serial" which is the compatible
> for the serial interface.
> 
> What about "xlnx,fpga-xc7-selectmap" ?
> 

I am not sure what xc7 is and how Xilinx numbers it products, but
compatibles are supposed to be device specific, not family. Common
programming model could be denoted with generic fallback, but then the
fallback could be device-specific as well, which usually we recommend.

Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
@ 2024-02-02 10:49           ` Krzysztof Kozlowski
  0 siblings, 0 replies; 44+ messages in thread
From: Krzysztof Kozlowski @ 2024-02-02 10:49 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, krzysztof kozlowski+dt, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

On 01/02/2024 19:24, Charles Perry wrote:
> 
> 
> ----- On Feb 1, 2024, at 3:07 AM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:
> 
>> On 01/02/2024 00:05, Charles Perry wrote:
>>> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
>>>
>>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>>> ---
>>>  .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
>>>  1 file changed, 83 insertions(+)
>>>  create mode 100644
>>>  Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>> b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>> new file mode 100644
>>> index 0000000000000..c9a446b43cdd9
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>> @@ -0,0 +1,83 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Xilinx SelectMAP FPGA interface
>>> +
>>> +maintainers:
>>> +  - Charles Perry <charles.perry@savoirfairelinux.com>
>>> +
>>> +description: |
>>> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
>>> +  parallel port named the SelectMAP interface in the documentation. Only
>>> +  the x8 mode is supported where data is loaded at one byte per rising edge of
>>> +  the clock, with the MSB of each byte presented to the D0 pin.
>>> +
>>> +  Datasheets:
>>> +
>>> https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
>>> +
>>> +allOf:
>>> +  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
>>> +
>>> +properties:
>>> +  compatible:
>>> +    enum:
>>> +      - xlnx,fpga-selectmap
>>
>> Your description mentions "7 Series" which is not present in compatible
>> and title. What is exactly the product here? Interface usually is not
>> the final binding, so is this specific to some particular FPGA or SoC?
>>
>>
>> Best regards,
>> Krzysztof
> 
> This is specific to the FPGA, the 7 series encompass the following part
> family:
>  * Spartan-7 (XC7S6, XC7S15, ... XC7S100)
>  * Artix-7 (XC7A12T, XC7A15T, ... XC7A200T)
>  * Kintex-7 (XC7K70T, XC7K160T, ... XC7K480T)
>  * Virtex-7 (XC7V585T, XC7V2000T, 
>              XC7VX330T, XC7VX415T, ... XC7VX1140T,
>              XC7VH580T, XC7VH870T)
> 
> 
> The configuration guide of Xilinx [1] tells us that all those devices
> share a common programming scheme.
> 
> I do agree that having a mention of "7 series" in the compatible name
> would be beneficial as Xilinx has more FPGA than just the 7 series.
> The name was inspired from "xlnx,fpga-slave-serial" which is the compatible
> for the serial interface.
> 
> What about "xlnx,fpga-xc7-selectmap" ?
> 

I am not sure what xc7 is and how Xilinx numbers it products, but
compatibles are supposed to be device specific, not family. Common
programming model could be denoted with generic fallback, but then the
fallback could be device-specific as well, which usually we recommend.

Best regards,
Krzysztof


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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-02-02 10:49           ` Krzysztof Kozlowski
@ 2024-02-02 19:52             ` Charles Perry
  -1 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-02 19:52 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, krzysztof kozlowski+dt, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel


----- On Feb 2, 2024, at 5:49 AM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:

> On 01/02/2024 19:24, Charles Perry wrote:
>> 
>> 
>> ----- On Feb 1, 2024, at 3:07 AM, Krzysztof Kozlowski
>> krzysztof.kozlowski@linaro.org wrote:
>> 
>>> On 01/02/2024 00:05, Charles Perry wrote:
>>>> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
>>>>
>>>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>>>> ---
>>>>  .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
>>>>  1 file changed, 83 insertions(+)
>>>>  create mode 100644
>>>>  Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>> b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>> new file mode 100644
>>>> index 0000000000000..c9a446b43cdd9
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>> @@ -0,0 +1,83 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Xilinx SelectMAP FPGA interface
>>>> +
>>>> +maintainers:
>>>> +  - Charles Perry <charles.perry@savoirfairelinux.com>
>>>> +
>>>> +description: |
>>>> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
>>>> +  parallel port named the SelectMAP interface in the documentation. Only
>>>> +  the x8 mode is supported where data is loaded at one byte per rising edge of
>>>> +  the clock, with the MSB of each byte presented to the D0 pin.
>>>> +
>>>> +  Datasheets:
>>>> +
>>>> https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
>>>> +
>>>> +allOf:
>>>> +  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
>>>> +
>>>> +properties:
>>>> +  compatible:
>>>> +    enum:
>>>> +      - xlnx,fpga-selectmap
>>>
>>> Your description mentions "7 Series" which is not present in compatible
>>> and title. What is exactly the product here? Interface usually is not
>>> the final binding, so is this specific to some particular FPGA or SoC?
>>>
>>>
>>> Best regards,
>>> Krzysztof
>> 
>> This is specific to the FPGA, the 7 series encompass the following part
>> family:
>>  * Spartan-7 (XC7S6, XC7S15, ... XC7S100)
>>  * Artix-7 (XC7A12T, XC7A15T, ... XC7A200T)
>>  * Kintex-7 (XC7K70T, XC7K160T, ... XC7K480T)
>>  * Virtex-7 (XC7V585T, XC7V2000T,
>>              XC7VX330T, XC7VX415T, ... XC7VX1140T,
>>              XC7VH580T, XC7VH870T)
>> 
>> 
>> The configuration guide of Xilinx [1] tells us that all those devices
>> share a common programming scheme.
>> 
>> I do agree that having a mention of "7 series" in the compatible name
>> would be beneficial as Xilinx has more FPGA than just the 7 series.
>> The name was inspired from "xlnx,fpga-slave-serial" which is the compatible
>> for the serial interface.
>> 
>> What about "xlnx,fpga-xc7-selectmap" ?
>> 
> 
> I am not sure what xc7 is and how Xilinx numbers it products, but
> compatibles are supposed to be device specific, not family. Common
> programming model could be denoted with generic fallback, but then the
> fallback could be device-specific as well, which usually we recommend.
> 
> Best regards,
> Krzysztof

XC7 is the common prefix for all 4 families of the 7 series.

Then we have XC7S, XC7A, XC7K and XC7V as the prefixes of those 4 family.

Following that is a number denoting the number of logic element, e.g.
XC7S6, XC7S15, XC7S100, ... I don't think that should be part of the
compatible.

Finally there will be another set of letters and numbers for the
temperature grade and physical package, but those are usually not part
of a compatible string.

I'll change it to four compatibles: "xlnx,fpga-xc7[sakv]-selectmap" so
that the driver can do device specific things if anomalies are found in
one of them.

Thanks again for the review!

Regards,
Charles

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
@ 2024-02-02 19:52             ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-02 19:52 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, krzysztof kozlowski+dt, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel


----- On Feb 2, 2024, at 5:49 AM, Krzysztof Kozlowski krzysztof.kozlowski@linaro.org wrote:

> On 01/02/2024 19:24, Charles Perry wrote:
>> 
>> 
>> ----- On Feb 1, 2024, at 3:07 AM, Krzysztof Kozlowski
>> krzysztof.kozlowski@linaro.org wrote:
>> 
>>> On 01/02/2024 00:05, Charles Perry wrote:
>>>> Document the slave SelectMAP interface of Xilinx 7 series FPGA.
>>>>
>>>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>>>> ---
>>>>  .../bindings/fpga/xlnx,fpga-selectmap.yaml    | 83 +++++++++++++++++++
>>>>  1 file changed, 83 insertions(+)
>>>>  create mode 100644
>>>>  Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>> b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>> new file mode 100644
>>>> index 0000000000000..c9a446b43cdd9
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/fpga/xlnx,fpga-selectmap.yaml
>>>> @@ -0,0 +1,83 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/fpga/xlnx,fpga-selectmap.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: Xilinx SelectMAP FPGA interface
>>>> +
>>>> +maintainers:
>>>> +  - Charles Perry <charles.perry@savoirfairelinux.com>
>>>> +
>>>> +description: |
>>>> +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
>>>> +  parallel port named the SelectMAP interface in the documentation. Only
>>>> +  the x8 mode is supported where data is loaded at one byte per rising edge of
>>>> +  the clock, with the MSB of each byte presented to the D0 pin.
>>>> +
>>>> +  Datasheets:
>>>> +
>>>> https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
>>>> +
>>>> +allOf:
>>>> +  - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
>>>> +
>>>> +properties:
>>>> +  compatible:
>>>> +    enum:
>>>> +      - xlnx,fpga-selectmap
>>>
>>> Your description mentions "7 Series" which is not present in compatible
>>> and title. What is exactly the product here? Interface usually is not
>>> the final binding, so is this specific to some particular FPGA or SoC?
>>>
>>>
>>> Best regards,
>>> Krzysztof
>> 
>> This is specific to the FPGA, the 7 series encompass the following part
>> family:
>>  * Spartan-7 (XC7S6, XC7S15, ... XC7S100)
>>  * Artix-7 (XC7A12T, XC7A15T, ... XC7A200T)
>>  * Kintex-7 (XC7K70T, XC7K160T, ... XC7K480T)
>>  * Virtex-7 (XC7V585T, XC7V2000T,
>>              XC7VX330T, XC7VX415T, ... XC7VX1140T,
>>              XC7VH580T, XC7VH870T)
>> 
>> 
>> The configuration guide of Xilinx [1] tells us that all those devices
>> share a common programming scheme.
>> 
>> I do agree that having a mention of "7 series" in the compatible name
>> would be beneficial as Xilinx has more FPGA than just the 7 series.
>> The name was inspired from "xlnx,fpga-slave-serial" which is the compatible
>> for the serial interface.
>> 
>> What about "xlnx,fpga-xc7-selectmap" ?
>> 
> 
> I am not sure what xc7 is and how Xilinx numbers it products, but
> compatibles are supposed to be device specific, not family. Common
> programming model could be denoted with generic fallback, but then the
> fallback could be device-specific as well, which usually we recommend.
> 
> Best regards,
> Krzysztof

XC7 is the common prefix for all 4 families of the 7 series.

Then we have XC7S, XC7A, XC7K and XC7V as the prefixes of those 4 family.

Following that is a number denoting the number of logic element, e.g.
XC7S6, XC7S15, XC7S100, ... I don't think that should be part of the
compatible.

Finally there will be another set of letters and numbers for the
temperature grade and physical package, but those are usually not part
of a compatible string.

I'll change it to four compatibles: "xlnx,fpga-xc7[sakv]-selectmap" so
that the driver can do device specific things if anomalies are found in
one of them.

Thanks again for the review!

Regards,
Charles

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 0/3] fpga: xilinx-selectmap: add new driver
  2024-01-31 23:05   ` Charles Perry
@ 2024-02-02 20:16     ` Rob Herring
  -1 siblings, 0 replies; 44+ messages in thread
From: Rob Herring @ 2024-02-02 20:16 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, avandiver, bcody, Wu Hao, Xu Yilun, Tom Rix,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On Wed, Jan 31, 2024 at 06:05:30PM -0500, Charles Perry wrote:
> Hello,
> 
> This patchset adds a new driver for the 7 series FPGA's SelectMAP
> interface.
> 
> The SelectMAP interface shares a common GPIO protocol with the SPI
> interface which is already in the kernel (drivers/fpga/xilinx-spi.c).
> The approach proposed in this patchset is to refactor xilinx-spi.c into
> xilinx-core.c which would handle the common GPIO protocol. This is then
> used to build two drivers, the already existing xilinx-spi.c driver and
> a newly added xilinx-selectmap.c driver.
> 
> The SelectMAP driver proposed only supports 8 bit mode. This is because
> the 16 and 32 bits mode have limitations with regards to compressed
> bitstream support as well as introducing endianness considerations.
> 
> I'm testing xilinx-selectmap.c on a custom i.MX6 board connected to an
> Artix 7 FPGA. Flashing a 913K bitstream takes 0.44 seconds.
> 
> v2: From Krzysztof Kozlowski review's:
>   * Use more conventional names for gpio DT bindings
>   * fix example in DT bindings
>   * add mc-peripheral-props.yaml to DT bindings
>   * fix various formatting mistakes
>   * Remove all occurences of the "slave" word.

Please label the series with the version number and don't send new 
versions as replies to the previous version.

Rob

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

* Re: [PATCH 0/3] fpga: xilinx-selectmap: add new driver
@ 2024-02-02 20:16     ` Rob Herring
  0 siblings, 0 replies; 44+ messages in thread
From: Rob Herring @ 2024-02-02 20:16 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, avandiver, bcody, Wu Hao, Xu Yilun, Tom Rix,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On Wed, Jan 31, 2024 at 06:05:30PM -0500, Charles Perry wrote:
> Hello,
> 
> This patchset adds a new driver for the 7 series FPGA's SelectMAP
> interface.
> 
> The SelectMAP interface shares a common GPIO protocol with the SPI
> interface which is already in the kernel (drivers/fpga/xilinx-spi.c).
> The approach proposed in this patchset is to refactor xilinx-spi.c into
> xilinx-core.c which would handle the common GPIO protocol. This is then
> used to build two drivers, the already existing xilinx-spi.c driver and
> a newly added xilinx-selectmap.c driver.
> 
> The SelectMAP driver proposed only supports 8 bit mode. This is because
> the 16 and 32 bits mode have limitations with regards to compressed
> bitstream support as well as introducing endianness considerations.
> 
> I'm testing xilinx-selectmap.c on a custom i.MX6 board connected to an
> Artix 7 FPGA. Flashing a 913K bitstream takes 0.44 seconds.
> 
> v2: From Krzysztof Kozlowski review's:
>   * Use more conventional names for gpio DT bindings
>   * fix example in DT bindings
>   * add mc-peripheral-props.yaml to DT bindings
>   * fix various formatting mistakes
>   * Remove all occurences of the "slave" word.

Please label the series with the version number and don't send new 
versions as replies to the previous version.

Rob

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 0/3] fpga: xilinx-selectmap: add new driver
  2024-02-02 20:16     ` Rob Herring
@ 2024-02-02 20:53       ` Charles Perry
  -1 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-02 20:53 UTC (permalink / raw)
  To: Rob Herring
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	krzysztof kozlowski+dt, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On Feb 2, 2024, at 3:16 PM, Rob Herring robh@kernel.org wrote:
> On Wed, Jan 31, 2024 at 06:05:30PM -0500, Charles Perry wrote:
>> Hello,
>> 
>> This patchset adds a new driver for the 7 series FPGA's SelectMAP
>> interface.
>> 
>> The SelectMAP interface shares a common GPIO protocol with the SPI
>> interface which is already in the kernel (drivers/fpga/xilinx-spi.c).
>> The approach proposed in this patchset is to refactor xilinx-spi.c into
>> xilinx-core.c which would handle the common GPIO protocol. This is then
>> used to build two drivers, the already existing xilinx-spi.c driver and
>> a newly added xilinx-selectmap.c driver.
>> 
>> The SelectMAP driver proposed only supports 8 bit mode. This is because
>> the 16 and 32 bits mode have limitations with regards to compressed
>> bitstream support as well as introducing endianness considerations.
>> 
>> I'm testing xilinx-selectmap.c on a custom i.MX6 board connected to an
>> Artix 7 FPGA. Flashing a 913K bitstream takes 0.44 seconds.
>> 
>> v2: From Krzysztof Kozlowski review's:
>>   * Use more conventional names for gpio DT bindings
>>   * fix example in DT bindings
>>   * add mc-peripheral-props.yaml to DT bindings
>>   * fix various formatting mistakes
>>   * Remove all occurences of the "slave" word.
> 
> Please label the series with the version number and don't send new
> versions as replies to the previous version.
> 
> Rob

Ok, will do.

Regards,
Charles

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

* Re: [PATCH 0/3] fpga: xilinx-selectmap: add new driver
@ 2024-02-02 20:53       ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-02 20:53 UTC (permalink / raw)
  To: Rob Herring
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	krzysztof kozlowski+dt, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On Feb 2, 2024, at 3:16 PM, Rob Herring robh@kernel.org wrote:
> On Wed, Jan 31, 2024 at 06:05:30PM -0500, Charles Perry wrote:
>> Hello,
>> 
>> This patchset adds a new driver for the 7 series FPGA's SelectMAP
>> interface.
>> 
>> The SelectMAP interface shares a common GPIO protocol with the SPI
>> interface which is already in the kernel (drivers/fpga/xilinx-spi.c).
>> The approach proposed in this patchset is to refactor xilinx-spi.c into
>> xilinx-core.c which would handle the common GPIO protocol. This is then
>> used to build two drivers, the already existing xilinx-spi.c driver and
>> a newly added xilinx-selectmap.c driver.
>> 
>> The SelectMAP driver proposed only supports 8 bit mode. This is because
>> the 16 and 32 bits mode have limitations with regards to compressed
>> bitstream support as well as introducing endianness considerations.
>> 
>> I'm testing xilinx-selectmap.c on a custom i.MX6 board connected to an
>> Artix 7 FPGA. Flashing a 913K bitstream takes 0.44 seconds.
>> 
>> v2: From Krzysztof Kozlowski review's:
>>   * Use more conventional names for gpio DT bindings
>>   * fix example in DT bindings
>>   * add mc-peripheral-props.yaml to DT bindings
>>   * fix various formatting mistakes
>>   * Remove all occurences of the "slave" word.
> 
> Please label the series with the version number and don't send new
> versions as replies to the previous version.
> 
> Rob

Ok, will do.

Regards,
Charles

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 3/3] fpga: xilinx-selectmap: add new driver
  2024-01-31 23:05     ` Charles Perry
@ 2024-02-04  8:10       ` Xu Yilun
  -1 siblings, 0 replies; 44+ messages in thread
From: Xu Yilun @ 2024-02-04  8:10 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, avandiver, bcody, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On Wed, Jan 31, 2024 at 06:05:33PM -0500, Charles Perry wrote:
> Xilinx 7 series FPGA can be programmed using a slave parallel port named
> the SelectMAP interface in the datasheet. This slave interface is
> compatible with the i.MX6 EIM bus controller but other types of external
> memory mapped parallel bus might work.
> 
> xilinx-selectmap currently only supports the x8 mode where data is loaded
> at one byte per rising edge of the clock, with the MSb of each byte
> presented to the D0 pin.
> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---
>  drivers/fpga/Kconfig            |   8 +++
>  drivers/fpga/Makefile           |   1 +
>  drivers/fpga/xilinx-core.c      |  11 +++-
>  drivers/fpga/xilinx-core.h      |   3 +-
>  drivers/fpga/xilinx-selectmap.c | 106 ++++++++++++++++++++++++++++++++
>  drivers/fpga/xilinx-spi.c       |   3 +-
>  6 files changed, 127 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/fpga/xilinx-selectmap.c
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index d27a1ebf40838..37b35f58f0dfb 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -67,6 +67,14 @@ config FPGA_MGR_STRATIX10_SOC
>  config FPGA_MGR_XILINX_CORE
>  	tristate
>  
> +config FPGA_MGR_XILINX_SELECTMAP
> +	tristate "Xilinx Configuration over SelectMAP"
> +	depends on HAS_IOMEM
> +	select FPGA_MGR_XILINX_CORE
> +	help
> +	  FPGA manager driver support for Xilinx FPGA configuration
> +	  over SelectMAP interface.
> +
>  config FPGA_MGR_XILINX_SPI
>  	tristate "Xilinx Configuration over Slave Serial (SPI)"
>  	depends on SPI
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index 7ec795b6a5a70..aeb89bb13517e 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
>  obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
>  obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
>  obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
> +obj-$(CONFIG_FPGA_MGR_XILINX_SELECTMAP)	+= xilinx-selectmap.o
>  obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
> diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
> index aff40e9394085..64117759be100 100644
> --- a/drivers/fpga/xilinx-core.c
> +++ b/drivers/fpga/xilinx-core.c
> @@ -180,21 +180,26 @@ static const struct fpga_manager_ops xilinx_core_ops = {
>  
>  int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>  		      xilinx_write_func write,
> -		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
> +		      const char *prog_con_id, const char *init_con_id)

These gpio name inputs are not necessary except for DTS format concern.
Is it possible we don't change the names?

>  {
>  	struct fpga_manager *mgr;
>  
> +	if (!core || !dev || !write || !write_one_dummy_byte || !prog_con_id ||
> +	    !init_con_id)
> +		return -EINVAL;

These checks belong to Patch #1.

> +
>  	core->dev = dev;
>  	core->write = write;
>  	core->write_one_dummy_byte = write_one_dummy_byte;
>  
>  	/* PROGRAM_B is active low */
> -	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
> +	core->prog_b = devm_gpiod_get(dev, prog_con_id, GPIOD_OUT_LOW);
>  	if (IS_ERR(core->prog_b))
>  		return dev_err_probe(dev, PTR_ERR(core->prog_b),
>  				     "Failed to get PROGRAM_B gpio\n");
>  
> -	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
> +	core->init_b = devm_gpiod_get_optional(dev, init_con_id, GPIOD_IN);
>  	if (IS_ERR(core->init_b))
>  		return dev_err_probe(dev, PTR_ERR(core->init_b),
>  				     "Failed to get INIT_B gpio\n");
> diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
> index 40e120945ba70..817f0e551d093 100644
> --- a/drivers/fpga/xilinx-core.h
> +++ b/drivers/fpga/xilinx-core.h
> @@ -22,6 +22,7 @@ struct xilinx_fpga_core {
>  
>  int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>  		      xilinx_write_func write,
> -		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
> +		      const char *prog_con_id, const char *init_con_id);
>  
>  #endif /* __XILINX_CORE_H */
> diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c
> new file mode 100644
> index 0000000000000..08054e19bb498
> --- /dev/null
> +++ b/drivers/fpga/xilinx-selectmap.c
> @@ -0,0 +1,106 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Xilinx Spartan6 and 7 Series SelectMAP interface driver
> + *
> + * (C) 2024 Charles Perry <charles.perry@savoirfairelinux.com>
> + *
> + * Manage Xilinx FPGA firmware loaded over the SelectMAP configuration
> + * interface.
> + */
> +
> +#include "xilinx-core.h"
> +
> +#include <linux/platform_device.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/of.h>
> +#include <linux/io.h>
> +
> +struct xilinx_selectmap_conf {
> +	struct xilinx_fpga_core core;
> +	void __iomem *base;
> +	struct gpio_desc *csi_b;
> +	struct gpio_desc *rdwr_b;

These 2 gpio_desc are not used globally, maybe remove them here.

> +};
> +
> +#define to_xilinx_selectmap_conf(obj) \
> +	container_of(obj, struct xilinx_selectmap_conf, core)
> +
> +static int xilinx_selectmap_write(struct xilinx_fpga_core *core,
> +				  const char *buf, size_t count)
> +{
> +	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
> +	u32 i;
> +
> +	for (i = 0; i < count; ++i)
> +		writeb(buf[i], conf->base);
> +
> +	return 0;
> +}
> +
> +static int xilinx_selectmap_apply_padding(struct xilinx_fpga_core *core)
> +{
> +	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
> +
> +	writeb(0xFF, conf->base);

Seems only one callback needed. Just use write() to xfer 1 byte?

Thanks,
Yilun

> +	return 0;
> +}
> +
> +static int xilinx_selectmap_probe(struct platform_device *pdev)
> +{
> +	struct xilinx_selectmap_conf *conf;
> +	struct resource *r;
> +	void __iomem *base;
> +
> +	conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
> +	if (!conf)
> +		return -ENOMEM;
> +
> +	base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
> +	if (IS_ERR(base))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(base),
> +				     "ioremap error\n");
> +	conf->base = base;
> +
> +	/* CSI_B is active low */
> +	conf->csi_b =
> +		devm_gpiod_get_optional(&pdev->dev, "csi", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->csi_b))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->csi_b),
> +				     "Failed to get CSI_B gpio\n");
> +
> +	/* RDWR_B is active low */
> +	conf->rdwr_b =
> +		devm_gpiod_get_optional(&pdev->dev, "rdwr", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->rdwr_b))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->rdwr_b),
> +				     "Failed to get RDWR_B gpio\n");
> +
> +	return xilinx_core_probe(&conf->core, &pdev->dev,
> +				 xilinx_selectmap_write,
> +				 xilinx_selectmap_apply_padding, "prog",
> +				 "init");
> +}
> +
> +static const struct of_device_id xlnx_selectmap_of_match[] = {
> +	{
> +		.compatible = "xlnx,fpga-selectmap",
> +	},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, xlnx_selectmap_of_match);
> +
> +static struct platform_driver xilinx_selectmap_driver = {
> +	.driver = {
> +		.name = "xilinx-selectmap",
> +		.of_match_table = xlnx_selectmap_of_match,
> +	},
> +	.probe  = xilinx_selectmap_probe,
> +};
> +
> +module_platform_driver(xilinx_selectmap_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Charles Perry <charles.perry@savoirfairelinux.com>");
> +MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SelectMap");
> diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
> index ec128dee97312..b9ab3d5da004c 100644
> --- a/drivers/fpga/xilinx-spi.c
> +++ b/drivers/fpga/xilinx-spi.c
> @@ -74,7 +74,8 @@ static int xilinx_spi_probe(struct spi_device *spi)
>  	conf->spi = spi;
>  
>  	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
> -				 xilinx_spi_apply_cclk_cycles);
> +				 xilinx_spi_apply_cclk_cycles, "prog_b",
> +				 "init-b");
>  }
>  
>  #ifdef CONFIG_OF
> -- 
> 2.43.0
> 
> 

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

* Re: [PATCH 3/3] fpga: xilinx-selectmap: add new driver
@ 2024-02-04  8:10       ` Xu Yilun
  0 siblings, 0 replies; 44+ messages in thread
From: Xu Yilun @ 2024-02-04  8:10 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, avandiver, bcody, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On Wed, Jan 31, 2024 at 06:05:33PM -0500, Charles Perry wrote:
> Xilinx 7 series FPGA can be programmed using a slave parallel port named
> the SelectMAP interface in the datasheet. This slave interface is
> compatible with the i.MX6 EIM bus controller but other types of external
> memory mapped parallel bus might work.
> 
> xilinx-selectmap currently only supports the x8 mode where data is loaded
> at one byte per rising edge of the clock, with the MSb of each byte
> presented to the D0 pin.
> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---
>  drivers/fpga/Kconfig            |   8 +++
>  drivers/fpga/Makefile           |   1 +
>  drivers/fpga/xilinx-core.c      |  11 +++-
>  drivers/fpga/xilinx-core.h      |   3 +-
>  drivers/fpga/xilinx-selectmap.c | 106 ++++++++++++++++++++++++++++++++
>  drivers/fpga/xilinx-spi.c       |   3 +-
>  6 files changed, 127 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/fpga/xilinx-selectmap.c
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index d27a1ebf40838..37b35f58f0dfb 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -67,6 +67,14 @@ config FPGA_MGR_STRATIX10_SOC
>  config FPGA_MGR_XILINX_CORE
>  	tristate
>  
> +config FPGA_MGR_XILINX_SELECTMAP
> +	tristate "Xilinx Configuration over SelectMAP"
> +	depends on HAS_IOMEM
> +	select FPGA_MGR_XILINX_CORE
> +	help
> +	  FPGA manager driver support for Xilinx FPGA configuration
> +	  over SelectMAP interface.
> +
>  config FPGA_MGR_XILINX_SPI
>  	tristate "Xilinx Configuration over Slave Serial (SPI)"
>  	depends on SPI
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index 7ec795b6a5a70..aeb89bb13517e 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
>  obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
>  obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
>  obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
> +obj-$(CONFIG_FPGA_MGR_XILINX_SELECTMAP)	+= xilinx-selectmap.o
>  obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
> diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
> index aff40e9394085..64117759be100 100644
> --- a/drivers/fpga/xilinx-core.c
> +++ b/drivers/fpga/xilinx-core.c
> @@ -180,21 +180,26 @@ static const struct fpga_manager_ops xilinx_core_ops = {
>  
>  int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>  		      xilinx_write_func write,
> -		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
> +		      const char *prog_con_id, const char *init_con_id)

These gpio name inputs are not necessary except for DTS format concern.
Is it possible we don't change the names?

>  {
>  	struct fpga_manager *mgr;
>  
> +	if (!core || !dev || !write || !write_one_dummy_byte || !prog_con_id ||
> +	    !init_con_id)
> +		return -EINVAL;

These checks belong to Patch #1.

> +
>  	core->dev = dev;
>  	core->write = write;
>  	core->write_one_dummy_byte = write_one_dummy_byte;
>  
>  	/* PROGRAM_B is active low */
> -	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
> +	core->prog_b = devm_gpiod_get(dev, prog_con_id, GPIOD_OUT_LOW);
>  	if (IS_ERR(core->prog_b))
>  		return dev_err_probe(dev, PTR_ERR(core->prog_b),
>  				     "Failed to get PROGRAM_B gpio\n");
>  
> -	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
> +	core->init_b = devm_gpiod_get_optional(dev, init_con_id, GPIOD_IN);
>  	if (IS_ERR(core->init_b))
>  		return dev_err_probe(dev, PTR_ERR(core->init_b),
>  				     "Failed to get INIT_B gpio\n");
> diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
> index 40e120945ba70..817f0e551d093 100644
> --- a/drivers/fpga/xilinx-core.h
> +++ b/drivers/fpga/xilinx-core.h
> @@ -22,6 +22,7 @@ struct xilinx_fpga_core {
>  
>  int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>  		      xilinx_write_func write,
> -		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
> +		      const char *prog_con_id, const char *init_con_id);
>  
>  #endif /* __XILINX_CORE_H */
> diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c
> new file mode 100644
> index 0000000000000..08054e19bb498
> --- /dev/null
> +++ b/drivers/fpga/xilinx-selectmap.c
> @@ -0,0 +1,106 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Xilinx Spartan6 and 7 Series SelectMAP interface driver
> + *
> + * (C) 2024 Charles Perry <charles.perry@savoirfairelinux.com>
> + *
> + * Manage Xilinx FPGA firmware loaded over the SelectMAP configuration
> + * interface.
> + */
> +
> +#include "xilinx-core.h"
> +
> +#include <linux/platform_device.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/of.h>
> +#include <linux/io.h>
> +
> +struct xilinx_selectmap_conf {
> +	struct xilinx_fpga_core core;
> +	void __iomem *base;
> +	struct gpio_desc *csi_b;
> +	struct gpio_desc *rdwr_b;

These 2 gpio_desc are not used globally, maybe remove them here.

> +};
> +
> +#define to_xilinx_selectmap_conf(obj) \
> +	container_of(obj, struct xilinx_selectmap_conf, core)
> +
> +static int xilinx_selectmap_write(struct xilinx_fpga_core *core,
> +				  const char *buf, size_t count)
> +{
> +	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
> +	u32 i;
> +
> +	for (i = 0; i < count; ++i)
> +		writeb(buf[i], conf->base);
> +
> +	return 0;
> +}
> +
> +static int xilinx_selectmap_apply_padding(struct xilinx_fpga_core *core)
> +{
> +	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
> +
> +	writeb(0xFF, conf->base);

Seems only one callback needed. Just use write() to xfer 1 byte?

Thanks,
Yilun

> +	return 0;
> +}
> +
> +static int xilinx_selectmap_probe(struct platform_device *pdev)
> +{
> +	struct xilinx_selectmap_conf *conf;
> +	struct resource *r;
> +	void __iomem *base;
> +
> +	conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
> +	if (!conf)
> +		return -ENOMEM;
> +
> +	base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
> +	if (IS_ERR(base))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(base),
> +				     "ioremap error\n");
> +	conf->base = base;
> +
> +	/* CSI_B is active low */
> +	conf->csi_b =
> +		devm_gpiod_get_optional(&pdev->dev, "csi", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->csi_b))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->csi_b),
> +				     "Failed to get CSI_B gpio\n");
> +
> +	/* RDWR_B is active low */
> +	conf->rdwr_b =
> +		devm_gpiod_get_optional(&pdev->dev, "rdwr", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->rdwr_b))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->rdwr_b),
> +				     "Failed to get RDWR_B gpio\n");
> +
> +	return xilinx_core_probe(&conf->core, &pdev->dev,
> +				 xilinx_selectmap_write,
> +				 xilinx_selectmap_apply_padding, "prog",
> +				 "init");
> +}
> +
> +static const struct of_device_id xlnx_selectmap_of_match[] = {
> +	{
> +		.compatible = "xlnx,fpga-selectmap",
> +	},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, xlnx_selectmap_of_match);
> +
> +static struct platform_driver xilinx_selectmap_driver = {
> +	.driver = {
> +		.name = "xilinx-selectmap",
> +		.of_match_table = xlnx_selectmap_of_match,
> +	},
> +	.probe  = xilinx_selectmap_probe,
> +};
> +
> +module_platform_driver(xilinx_selectmap_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Charles Perry <charles.perry@savoirfairelinux.com>");
> +MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SelectMap");
> diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
> index ec128dee97312..b9ab3d5da004c 100644
> --- a/drivers/fpga/xilinx-spi.c
> +++ b/drivers/fpga/xilinx-spi.c
> @@ -74,7 +74,8 @@ static int xilinx_spi_probe(struct spi_device *spi)
>  	conf->spi = spi;
>  
>  	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
> -				 xilinx_spi_apply_cclk_cycles);
> +				 xilinx_spi_apply_cclk_cycles, "prog_b",
> +				 "init-b");
>  }
>  
>  #ifdef CONFIG_OF
> -- 
> 2.43.0
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/3] fpga: xilinx-spi: extract a common driver core
  2024-01-31 23:05     ` Charles Perry
@ 2024-02-04  8:22       ` Xu Yilun
  -1 siblings, 0 replies; 44+ messages in thread
From: Xu Yilun @ 2024-02-04  8:22 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, avandiver, bcody, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On Wed, Jan 31, 2024 at 06:05:31PM -0500, Charles Perry wrote:
> Factor out the gpio handshaking (using PROGRAM_B, INIT_B and DONE)
> protocol in xilinx-core so that it can be reused for another driver.
> This commit does not change anything functionally to xilinx-spi.
> 
> xilinx-core expects drivers to provide two operations:
> 
>  * ->write(const char* buf, size_t count): write to the device
>  * ->write_one_dummy_byte(): write 0xFF to the device
> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---
>  drivers/fpga/Kconfig       |   4 +
>  drivers/fpga/Makefile      |   1 +
>  drivers/fpga/xilinx-core.c | 210 +++++++++++++++++++++++++++++++++++++
>  drivers/fpga/xilinx-core.h |  27 +++++
>  drivers/fpga/xilinx-spi.c  | 204 +++--------------------------------
>  5 files changed, 257 insertions(+), 189 deletions(-)
>  create mode 100644 drivers/fpga/xilinx-core.c
>  create mode 100644 drivers/fpga/xilinx-core.h
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 2f689ac4ba3a3..d27a1ebf40838 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -64,9 +64,13 @@ config FPGA_MGR_STRATIX10_SOC
>  	help
>  	  FPGA manager driver support for the Intel Stratix10 SoC.
>  
> +config FPGA_MGR_XILINX_CORE
> +	tristate
> +
>  config FPGA_MGR_XILINX_SPI
>  	tristate "Xilinx Configuration over Slave Serial (SPI)"
>  	depends on SPI
> +	select FPGA_MGR_XILINX_CORE
>  	help
>  	  FPGA manager driver support for Xilinx FPGA configuration
>  	  over slave serial interface.
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index 352a2612623e0..7ec795b6a5a70 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
>  obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
>  obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
>  obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
> +obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
>  obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
> diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
> new file mode 100644
> index 0000000000000..aff40e9394085
> --- /dev/null
> +++ b/drivers/fpga/xilinx-core.c
> @@ -0,0 +1,210 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Common parts of the Xilinx Spartan6 and 7 Series FPGA manager drivers.
> + *
> + * Copyright (C) 2017 DENX Software Engineering
> + *
> + * Anatolij Gustschin <agust@denx.de>
> + */
> +
> +#include "xilinx-core.h"
> +
> +#include <linux/delay.h>
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/of.h>
> +
> +static int get_done_gpio(struct fpga_manager *mgr)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +	int ret;
> +
> +	ret = gpiod_get_value(core->done);
> +

remove the line.

> +	if (ret < 0)
> +		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
> +
> +	return ret;
> +}
> +
> +static enum fpga_mgr_states xilinx_core_state(struct fpga_manager *mgr)
> +{
> +	if (!get_done_gpio(mgr))
> +		return FPGA_MGR_STATE_RESET;
> +
> +	return FPGA_MGR_STATE_UNKNOWN;
> +}
> +
> +/**
> + * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
> + * a given delay if the pin is unavailable
> + *
> + * @mgr:        The FPGA manager object
> + * @value:      Value INIT_B to wait for (1 = asserted = low)
> + * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
> + *
> + * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
> + * too much time passed waiting for that. If no INIT_B GPIO is available
> + * then always return 0.
> + */
> +static int wait_for_init_b(struct fpga_manager *mgr, int value,
> +			   unsigned long alt_udelay)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
> +
> +	if (core->init_b) {
> +		while (time_before(jiffies, timeout)) {
> +			int ret = gpiod_get_value(core->init_b);
> +
> +			if (ret == value)
> +				return 0;
> +
> +			if (ret < 0) {
> +				dev_err(&mgr->dev,
> +					"Error reading INIT_B (%d)\n", ret);
> +				return ret;
> +			}
> +
> +			usleep_range(100, 400);
> +		}
> +
> +		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
> +			value ? "assert" : "deassert");
> +		return -ETIMEDOUT;
> +	}
> +
> +	udelay(alt_udelay);
> +
> +	return 0;
> +}
> +
> +static int xilinx_core_write_init(struct fpga_manager *mgr,
> +				  struct fpga_image_info *info, const char *buf,
> +				  size_t count)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +	int err;
> +
> +	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> +		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> +		return -EINVAL;
> +	}
> +
> +	gpiod_set_value(core->prog_b, 1);
> +
> +	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
> +	if (err) {
> +		gpiod_set_value(core->prog_b, 0);
> +		return err;
> +	}
> +
> +	gpiod_set_value(core->prog_b, 0);
> +
> +	err = wait_for_init_b(mgr, 0, 0);
> +	if (err)
> +		return err;
> +
> +	if (get_done_gpio(mgr)) {
> +		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
> +		return -EIO;
> +	}
> +
> +	/* program latency */
> +	usleep_range(7500, 7600);
> +	return 0;
> +}
> +
> +static int xilinx_core_write(struct fpga_manager *mgr, const char *buf,
> +			     size_t count)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +
> +	return core->write(core, buf, count);
> +}
> +
> +static int xilinx_core_write_complete(struct fpga_manager *mgr,
> +				      struct fpga_image_info *info)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +	unsigned long timeout =
> +		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
> +	bool expired = false;
> +	int done;
> +	int ret;
> +
> +	/*
> +	 * This loop is carefully written such that if the driver is
> +	 * scheduled out for more than 'timeout', we still check for DONE
> +	 * before giving up and we apply 8 extra CCLK cycles in all cases.
> +	 */
> +	while (!expired) {
> +		expired = time_after(jiffies, timeout);
> +
> +		done = get_done_gpio(mgr);
> +		if (done < 0)
> +			return done;
> +
> +		ret = core->write_one_dummy_byte(core);
> +		if (ret)
> +			return ret;
> +
> +		if (done)
> +			return 0;
> +	}
> +
> +	if (core->init_b) {
> +		ret = gpiod_get_value(core->init_b);
> +
> +		if (ret < 0) {
> +			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
> +			return ret;
> +		}
> +
> +		dev_err(&mgr->dev,
> +			ret ? "CRC error or invalid device\n" :
> +			      "Missing sync word or incomplete bitstream\n");
> +	} else {
> +		dev_err(&mgr->dev, "Timeout after config data transfer\n");
> +	}
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static const struct fpga_manager_ops xilinx_core_ops = {
> +	.state = xilinx_core_state,
> +	.write_init = xilinx_core_write_init,
> +	.write = xilinx_core_write,
> +	.write_complete = xilinx_core_write_complete,
> +};
> +
> +int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
> +		      xilinx_write_func write,
> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)

I prefer to move these parameters in xilinx_fpga_core structure. I don't
want the param list becomes longer and longer when we have more inputs.

> +{
> +	struct fpga_manager *mgr;
> +
> +	core->dev = dev;
> +	core->write = write;
> +	core->write_one_dummy_byte = write_one_dummy_byte;

Could the write() writes one dummy byte? Maybe one write callback is enough.

> +
> +	/* PROGRAM_B is active low */
> +	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
> +	if (IS_ERR(core->prog_b))
> +		return dev_err_probe(dev, PTR_ERR(core->prog_b),
> +				     "Failed to get PROGRAM_B gpio\n");
> +
> +	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
> +	if (IS_ERR(core->init_b))
> +		return dev_err_probe(dev, PTR_ERR(core->init_b),
> +				     "Failed to get INIT_B gpio\n");
> +
> +	core->done = devm_gpiod_get(dev, "done", GPIOD_IN);
> +	if (IS_ERR(core->done))
> +		return dev_err_probe(dev, PTR_ERR(core->done),
> +				     "Failed to get DONE gpio\n");
> +
> +	mgr = devm_fpga_mgr_register(dev, "Xilinx Slave Serial FPGA Manager",
> +				     &xilinx_core_ops, core);
> +	return PTR_ERR_OR_ZERO(mgr);
> +}
> diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
> new file mode 100644
> index 0000000000000..40e120945ba70
> --- /dev/null
> +++ b/drivers/fpga/xilinx-core.h
> @@ -0,0 +1,27 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef __XILINX_CORE_H
> +#define __XILINX_CORE_H
> +
> +#include <linux/device.h>
> +
> +struct xilinx_fpga_core;
> +
> +typedef int (*xilinx_write_func)(struct xilinx_fpga_core *core, const char *buf,
> +				 size_t count);
> +typedef int (*xilinx_write_one_dummy_byte_func)(struct xilinx_fpga_core *core);

No need to typedef.

Thanks,
Yilun

> +
> +struct xilinx_fpga_core {
> +	struct device *dev;
> +	xilinx_write_func write;
> +	xilinx_write_one_dummy_byte_func write_one_dummy_byte;
> +	struct gpio_desc *prog_b;
> +	struct gpio_desc *init_b;
> +	struct gpio_desc *done;
> +};
> +
> +int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
> +		      xilinx_write_func write,
> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
> +
> +#endif /* __XILINX_CORE_H */
> diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
> index e1a227e7ff2ae..ec128dee97312 100644
> --- a/drivers/fpga/xilinx-spi.c
> +++ b/drivers/fpga/xilinx-spi.c
> @@ -10,127 +10,24 @@
>   * the slave serial configuration interface.
>   */
>  
> -#include <linux/delay.h>
> -#include <linux/device.h>
> -#include <linux/fpga/fpga-mgr.h>
> -#include <linux/gpio/consumer.h>
> +#include "xilinx-core.h"
> +
>  #include <linux/module.h>
>  #include <linux/mod_devicetable.h>
>  #include <linux/of.h>
>  #include <linux/spi/spi.h>
> -#include <linux/sizes.h>
>  
>  struct xilinx_spi_conf {
> +	struct xilinx_fpga_core core;
>  	struct spi_device *spi;
> -	struct gpio_desc *prog_b;
> -	struct gpio_desc *init_b;
> -	struct gpio_desc *done;
>  };
>  
> -static int get_done_gpio(struct fpga_manager *mgr)
> -{
> -	struct xilinx_spi_conf *conf = mgr->priv;
> -	int ret;
> -
> -	ret = gpiod_get_value(conf->done);
> -
> -	if (ret < 0)
> -		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
> -
> -	return ret;
> -}
> -
> -static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
> -{
> -	if (!get_done_gpio(mgr))
> -		return FPGA_MGR_STATE_RESET;
> -
> -	return FPGA_MGR_STATE_UNKNOWN;
> -}
> -
> -/**
> - * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
> - * a given delay if the pin is unavailable
> - *
> - * @mgr:        The FPGA manager object
> - * @value:      Value INIT_B to wait for (1 = asserted = low)
> - * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
> - *
> - * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
> - * too much time passed waiting for that. If no INIT_B GPIO is available
> - * then always return 0.
> - */
> -static int wait_for_init_b(struct fpga_manager *mgr, int value,
> -			   unsigned long alt_udelay)
> -{
> -	struct xilinx_spi_conf *conf = mgr->priv;
> -	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
> -
> -	if (conf->init_b) {
> -		while (time_before(jiffies, timeout)) {
> -			int ret = gpiod_get_value(conf->init_b);
> -
> -			if (ret == value)
> -				return 0;
> -
> -			if (ret < 0) {
> -				dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
> -				return ret;
> -			}
> -
> -			usleep_range(100, 400);
> -		}
> -
> -		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
> -			value ? "assert" : "deassert");
> -		return -ETIMEDOUT;
> -	}
> -
> -	udelay(alt_udelay);
> -
> -	return 0;
> -}
> -
> -static int xilinx_spi_write_init(struct fpga_manager *mgr,
> -				 struct fpga_image_info *info,
> -				 const char *buf, size_t count)
> -{
> -	struct xilinx_spi_conf *conf = mgr->priv;
> -	int err;
> -
> -	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> -		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> -		return -EINVAL;
> -	}
> -
> -	gpiod_set_value(conf->prog_b, 1);
> +#define to_xilinx_spi_conf(obj) container_of(obj, struct xilinx_spi_conf, core)
>  
> -	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
> -	if (err) {
> -		gpiod_set_value(conf->prog_b, 0);
> -		return err;
> -	}
> -
> -	gpiod_set_value(conf->prog_b, 0);
> -
> -	err = wait_for_init_b(mgr, 0, 0);
> -	if (err)
> -		return err;
> -
> -	if (get_done_gpio(mgr)) {
> -		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
> -		return -EIO;
> -	}
> -
> -	/* program latency */
> -	usleep_range(7500, 7600);
> -	return 0;
> -}
> -
> -static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
> +static int xilinx_spi_write(struct xilinx_fpga_core *core, const char *buf,
>  			    size_t count)
>  {
> -	struct xilinx_spi_conf *conf = mgr->priv;
> +	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
>  	const char *fw_data = buf;
>  	const char *fw_data_end = fw_data + count;
>  
> @@ -143,7 +40,7 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
>  
>  		ret = spi_write(conf->spi, fw_data, stride);
>  		if (ret) {
> -			dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
> +			dev_err(core->dev, "SPI error in firmware write: %d\n",
>  				ret);
>  			return ret;
>  		}
> @@ -153,77 +50,22 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
>  	return 0;
>  }
>  
> -static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf)
> +static int xilinx_spi_apply_cclk_cycles(struct xilinx_fpga_core *core)
>  {
> -	struct spi_device *spi = conf->spi;
> +	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
>  	const u8 din_data[1] = { 0xff };
>  	int ret;
>  
>  	ret = spi_write(conf->spi, din_data, sizeof(din_data));
>  	if (ret)
> -		dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret);
> +		dev_err(core->dev, "applying CCLK cycles failed: %d\n", ret);
>  
>  	return ret;
>  }
>  
> -static int xilinx_spi_write_complete(struct fpga_manager *mgr,
> -				     struct fpga_image_info *info)
> -{
> -	struct xilinx_spi_conf *conf = mgr->priv;
> -	unsigned long timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
> -	bool expired = false;
> -	int done;
> -	int ret;
> -
> -	/*
> -	 * This loop is carefully written such that if the driver is
> -	 * scheduled out for more than 'timeout', we still check for DONE
> -	 * before giving up and we apply 8 extra CCLK cycles in all cases.
> -	 */
> -	while (!expired) {
> -		expired = time_after(jiffies, timeout);
> -
> -		done = get_done_gpio(mgr);
> -		if (done < 0)
> -			return done;
> -
> -		ret = xilinx_spi_apply_cclk_cycles(conf);
> -		if (ret)
> -			return ret;
> -
> -		if (done)
> -			return 0;
> -	}
> -
> -	if (conf->init_b) {
> -		ret = gpiod_get_value(conf->init_b);
> -
> -		if (ret < 0) {
> -			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
> -			return ret;
> -		}
> -
> -		dev_err(&mgr->dev,
> -			ret ? "CRC error or invalid device\n"
> -			: "Missing sync word or incomplete bitstream\n");
> -	} else {
> -		dev_err(&mgr->dev, "Timeout after config data transfer\n");
> -	}
> -
> -	return -ETIMEDOUT;
> -}
> -
> -static const struct fpga_manager_ops xilinx_spi_ops = {
> -	.state = xilinx_spi_state,
> -	.write_init = xilinx_spi_write_init,
> -	.write = xilinx_spi_write,
> -	.write_complete = xilinx_spi_write_complete,
> -};
> -
>  static int xilinx_spi_probe(struct spi_device *spi)
>  {
>  	struct xilinx_spi_conf *conf;
> -	struct fpga_manager *mgr;
>  
>  	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
>  	if (!conf)
> @@ -231,31 +73,15 @@ static int xilinx_spi_probe(struct spi_device *spi)
>  
>  	conf->spi = spi;
>  
> -	/* PROGRAM_B is active low */
> -	conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW);
> -	if (IS_ERR(conf->prog_b))
> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b),
> -				     "Failed to get PROGRAM_B gpio\n");
> -
> -	conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN);
> -	if (IS_ERR(conf->init_b))
> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b),
> -				     "Failed to get INIT_B gpio\n");
> -
> -	conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
> -	if (IS_ERR(conf->done))
> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->done),
> -				     "Failed to get DONE gpio\n");
> -
> -	mgr = devm_fpga_mgr_register(&spi->dev,
> -				     "Xilinx Slave Serial FPGA Manager",
> -				     &xilinx_spi_ops, conf);
> -	return PTR_ERR_OR_ZERO(mgr);
> +	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
> +				 xilinx_spi_apply_cclk_cycles);
>  }
>  
>  #ifdef CONFIG_OF
>  static const struct of_device_id xlnx_spi_of_match[] = {
> -	{ .compatible = "xlnx,fpga-slave-serial", },
> +	{
> +		.compatible = "xlnx,fpga-slave-serial",
> +	},
>  	{}
>  };
>  MODULE_DEVICE_TABLE(of, xlnx_spi_of_match);
> -- 
> 2.43.0
> 
> 

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

* Re: [PATCH 1/3] fpga: xilinx-spi: extract a common driver core
@ 2024-02-04  8:22       ` Xu Yilun
  0 siblings, 0 replies; 44+ messages in thread
From: Xu Yilun @ 2024-02-04  8:22 UTC (permalink / raw)
  To: Charles Perry
  Cc: mdf, avandiver, bcody, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Michal Simek, linux-fpga,
	devicetree, linux-kernel, linux-arm-kernel

On Wed, Jan 31, 2024 at 06:05:31PM -0500, Charles Perry wrote:
> Factor out the gpio handshaking (using PROGRAM_B, INIT_B and DONE)
> protocol in xilinx-core so that it can be reused for another driver.
> This commit does not change anything functionally to xilinx-spi.
> 
> xilinx-core expects drivers to provide two operations:
> 
>  * ->write(const char* buf, size_t count): write to the device
>  * ->write_one_dummy_byte(): write 0xFF to the device
> 
> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
> ---
>  drivers/fpga/Kconfig       |   4 +
>  drivers/fpga/Makefile      |   1 +
>  drivers/fpga/xilinx-core.c | 210 +++++++++++++++++++++++++++++++++++++
>  drivers/fpga/xilinx-core.h |  27 +++++
>  drivers/fpga/xilinx-spi.c  | 204 +++--------------------------------
>  5 files changed, 257 insertions(+), 189 deletions(-)
>  create mode 100644 drivers/fpga/xilinx-core.c
>  create mode 100644 drivers/fpga/xilinx-core.h
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 2f689ac4ba3a3..d27a1ebf40838 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -64,9 +64,13 @@ config FPGA_MGR_STRATIX10_SOC
>  	help
>  	  FPGA manager driver support for the Intel Stratix10 SoC.
>  
> +config FPGA_MGR_XILINX_CORE
> +	tristate
> +
>  config FPGA_MGR_XILINX_SPI
>  	tristate "Xilinx Configuration over Slave Serial (SPI)"
>  	depends on SPI
> +	select FPGA_MGR_XILINX_CORE
>  	help
>  	  FPGA manager driver support for Xilinx FPGA configuration
>  	  over slave serial interface.
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index 352a2612623e0..7ec795b6a5a70 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
>  obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
>  obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
>  obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
> +obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
>  obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
> diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
> new file mode 100644
> index 0000000000000..aff40e9394085
> --- /dev/null
> +++ b/drivers/fpga/xilinx-core.c
> @@ -0,0 +1,210 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Common parts of the Xilinx Spartan6 and 7 Series FPGA manager drivers.
> + *
> + * Copyright (C) 2017 DENX Software Engineering
> + *
> + * Anatolij Gustschin <agust@denx.de>
> + */
> +
> +#include "xilinx-core.h"
> +
> +#include <linux/delay.h>
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/of.h>
> +
> +static int get_done_gpio(struct fpga_manager *mgr)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +	int ret;
> +
> +	ret = gpiod_get_value(core->done);
> +

remove the line.

> +	if (ret < 0)
> +		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
> +
> +	return ret;
> +}
> +
> +static enum fpga_mgr_states xilinx_core_state(struct fpga_manager *mgr)
> +{
> +	if (!get_done_gpio(mgr))
> +		return FPGA_MGR_STATE_RESET;
> +
> +	return FPGA_MGR_STATE_UNKNOWN;
> +}
> +
> +/**
> + * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
> + * a given delay if the pin is unavailable
> + *
> + * @mgr:        The FPGA manager object
> + * @value:      Value INIT_B to wait for (1 = asserted = low)
> + * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
> + *
> + * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
> + * too much time passed waiting for that. If no INIT_B GPIO is available
> + * then always return 0.
> + */
> +static int wait_for_init_b(struct fpga_manager *mgr, int value,
> +			   unsigned long alt_udelay)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
> +
> +	if (core->init_b) {
> +		while (time_before(jiffies, timeout)) {
> +			int ret = gpiod_get_value(core->init_b);
> +
> +			if (ret == value)
> +				return 0;
> +
> +			if (ret < 0) {
> +				dev_err(&mgr->dev,
> +					"Error reading INIT_B (%d)\n", ret);
> +				return ret;
> +			}
> +
> +			usleep_range(100, 400);
> +		}
> +
> +		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
> +			value ? "assert" : "deassert");
> +		return -ETIMEDOUT;
> +	}
> +
> +	udelay(alt_udelay);
> +
> +	return 0;
> +}
> +
> +static int xilinx_core_write_init(struct fpga_manager *mgr,
> +				  struct fpga_image_info *info, const char *buf,
> +				  size_t count)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +	int err;
> +
> +	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> +		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> +		return -EINVAL;
> +	}
> +
> +	gpiod_set_value(core->prog_b, 1);
> +
> +	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
> +	if (err) {
> +		gpiod_set_value(core->prog_b, 0);
> +		return err;
> +	}
> +
> +	gpiod_set_value(core->prog_b, 0);
> +
> +	err = wait_for_init_b(mgr, 0, 0);
> +	if (err)
> +		return err;
> +
> +	if (get_done_gpio(mgr)) {
> +		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
> +		return -EIO;
> +	}
> +
> +	/* program latency */
> +	usleep_range(7500, 7600);
> +	return 0;
> +}
> +
> +static int xilinx_core_write(struct fpga_manager *mgr, const char *buf,
> +			     size_t count)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +
> +	return core->write(core, buf, count);
> +}
> +
> +static int xilinx_core_write_complete(struct fpga_manager *mgr,
> +				      struct fpga_image_info *info)
> +{
> +	struct xilinx_fpga_core *core = mgr->priv;
> +	unsigned long timeout =
> +		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
> +	bool expired = false;
> +	int done;
> +	int ret;
> +
> +	/*
> +	 * This loop is carefully written such that if the driver is
> +	 * scheduled out for more than 'timeout', we still check for DONE
> +	 * before giving up and we apply 8 extra CCLK cycles in all cases.
> +	 */
> +	while (!expired) {
> +		expired = time_after(jiffies, timeout);
> +
> +		done = get_done_gpio(mgr);
> +		if (done < 0)
> +			return done;
> +
> +		ret = core->write_one_dummy_byte(core);
> +		if (ret)
> +			return ret;
> +
> +		if (done)
> +			return 0;
> +	}
> +
> +	if (core->init_b) {
> +		ret = gpiod_get_value(core->init_b);
> +
> +		if (ret < 0) {
> +			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
> +			return ret;
> +		}
> +
> +		dev_err(&mgr->dev,
> +			ret ? "CRC error or invalid device\n" :
> +			      "Missing sync word or incomplete bitstream\n");
> +	} else {
> +		dev_err(&mgr->dev, "Timeout after config data transfer\n");
> +	}
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static const struct fpga_manager_ops xilinx_core_ops = {
> +	.state = xilinx_core_state,
> +	.write_init = xilinx_core_write_init,
> +	.write = xilinx_core_write,
> +	.write_complete = xilinx_core_write_complete,
> +};
> +
> +int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
> +		      xilinx_write_func write,
> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)

I prefer to move these parameters in xilinx_fpga_core structure. I don't
want the param list becomes longer and longer when we have more inputs.

> +{
> +	struct fpga_manager *mgr;
> +
> +	core->dev = dev;
> +	core->write = write;
> +	core->write_one_dummy_byte = write_one_dummy_byte;

Could the write() writes one dummy byte? Maybe one write callback is enough.

> +
> +	/* PROGRAM_B is active low */
> +	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
> +	if (IS_ERR(core->prog_b))
> +		return dev_err_probe(dev, PTR_ERR(core->prog_b),
> +				     "Failed to get PROGRAM_B gpio\n");
> +
> +	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
> +	if (IS_ERR(core->init_b))
> +		return dev_err_probe(dev, PTR_ERR(core->init_b),
> +				     "Failed to get INIT_B gpio\n");
> +
> +	core->done = devm_gpiod_get(dev, "done", GPIOD_IN);
> +	if (IS_ERR(core->done))
> +		return dev_err_probe(dev, PTR_ERR(core->done),
> +				     "Failed to get DONE gpio\n");
> +
> +	mgr = devm_fpga_mgr_register(dev, "Xilinx Slave Serial FPGA Manager",
> +				     &xilinx_core_ops, core);
> +	return PTR_ERR_OR_ZERO(mgr);
> +}
> diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
> new file mode 100644
> index 0000000000000..40e120945ba70
> --- /dev/null
> +++ b/drivers/fpga/xilinx-core.h
> @@ -0,0 +1,27 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef __XILINX_CORE_H
> +#define __XILINX_CORE_H
> +
> +#include <linux/device.h>
> +
> +struct xilinx_fpga_core;
> +
> +typedef int (*xilinx_write_func)(struct xilinx_fpga_core *core, const char *buf,
> +				 size_t count);
> +typedef int (*xilinx_write_one_dummy_byte_func)(struct xilinx_fpga_core *core);

No need to typedef.

Thanks,
Yilun

> +
> +struct xilinx_fpga_core {
> +	struct device *dev;
> +	xilinx_write_func write;
> +	xilinx_write_one_dummy_byte_func write_one_dummy_byte;
> +	struct gpio_desc *prog_b;
> +	struct gpio_desc *init_b;
> +	struct gpio_desc *done;
> +};
> +
> +int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
> +		      xilinx_write_func write,
> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
> +
> +#endif /* __XILINX_CORE_H */
> diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
> index e1a227e7ff2ae..ec128dee97312 100644
> --- a/drivers/fpga/xilinx-spi.c
> +++ b/drivers/fpga/xilinx-spi.c
> @@ -10,127 +10,24 @@
>   * the slave serial configuration interface.
>   */
>  
> -#include <linux/delay.h>
> -#include <linux/device.h>
> -#include <linux/fpga/fpga-mgr.h>
> -#include <linux/gpio/consumer.h>
> +#include "xilinx-core.h"
> +
>  #include <linux/module.h>
>  #include <linux/mod_devicetable.h>
>  #include <linux/of.h>
>  #include <linux/spi/spi.h>
> -#include <linux/sizes.h>
>  
>  struct xilinx_spi_conf {
> +	struct xilinx_fpga_core core;
>  	struct spi_device *spi;
> -	struct gpio_desc *prog_b;
> -	struct gpio_desc *init_b;
> -	struct gpio_desc *done;
>  };
>  
> -static int get_done_gpio(struct fpga_manager *mgr)
> -{
> -	struct xilinx_spi_conf *conf = mgr->priv;
> -	int ret;
> -
> -	ret = gpiod_get_value(conf->done);
> -
> -	if (ret < 0)
> -		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
> -
> -	return ret;
> -}
> -
> -static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
> -{
> -	if (!get_done_gpio(mgr))
> -		return FPGA_MGR_STATE_RESET;
> -
> -	return FPGA_MGR_STATE_UNKNOWN;
> -}
> -
> -/**
> - * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
> - * a given delay if the pin is unavailable
> - *
> - * @mgr:        The FPGA manager object
> - * @value:      Value INIT_B to wait for (1 = asserted = low)
> - * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
> - *
> - * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
> - * too much time passed waiting for that. If no INIT_B GPIO is available
> - * then always return 0.
> - */
> -static int wait_for_init_b(struct fpga_manager *mgr, int value,
> -			   unsigned long alt_udelay)
> -{
> -	struct xilinx_spi_conf *conf = mgr->priv;
> -	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
> -
> -	if (conf->init_b) {
> -		while (time_before(jiffies, timeout)) {
> -			int ret = gpiod_get_value(conf->init_b);
> -
> -			if (ret == value)
> -				return 0;
> -
> -			if (ret < 0) {
> -				dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
> -				return ret;
> -			}
> -
> -			usleep_range(100, 400);
> -		}
> -
> -		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
> -			value ? "assert" : "deassert");
> -		return -ETIMEDOUT;
> -	}
> -
> -	udelay(alt_udelay);
> -
> -	return 0;
> -}
> -
> -static int xilinx_spi_write_init(struct fpga_manager *mgr,
> -				 struct fpga_image_info *info,
> -				 const char *buf, size_t count)
> -{
> -	struct xilinx_spi_conf *conf = mgr->priv;
> -	int err;
> -
> -	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> -		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> -		return -EINVAL;
> -	}
> -
> -	gpiod_set_value(conf->prog_b, 1);
> +#define to_xilinx_spi_conf(obj) container_of(obj, struct xilinx_spi_conf, core)
>  
> -	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
> -	if (err) {
> -		gpiod_set_value(conf->prog_b, 0);
> -		return err;
> -	}
> -
> -	gpiod_set_value(conf->prog_b, 0);
> -
> -	err = wait_for_init_b(mgr, 0, 0);
> -	if (err)
> -		return err;
> -
> -	if (get_done_gpio(mgr)) {
> -		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
> -		return -EIO;
> -	}
> -
> -	/* program latency */
> -	usleep_range(7500, 7600);
> -	return 0;
> -}
> -
> -static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
> +static int xilinx_spi_write(struct xilinx_fpga_core *core, const char *buf,
>  			    size_t count)
>  {
> -	struct xilinx_spi_conf *conf = mgr->priv;
> +	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
>  	const char *fw_data = buf;
>  	const char *fw_data_end = fw_data + count;
>  
> @@ -143,7 +40,7 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
>  
>  		ret = spi_write(conf->spi, fw_data, stride);
>  		if (ret) {
> -			dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
> +			dev_err(core->dev, "SPI error in firmware write: %d\n",
>  				ret);
>  			return ret;
>  		}
> @@ -153,77 +50,22 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
>  	return 0;
>  }
>  
> -static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf)
> +static int xilinx_spi_apply_cclk_cycles(struct xilinx_fpga_core *core)
>  {
> -	struct spi_device *spi = conf->spi;
> +	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
>  	const u8 din_data[1] = { 0xff };
>  	int ret;
>  
>  	ret = spi_write(conf->spi, din_data, sizeof(din_data));
>  	if (ret)
> -		dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret);
> +		dev_err(core->dev, "applying CCLK cycles failed: %d\n", ret);
>  
>  	return ret;
>  }
>  
> -static int xilinx_spi_write_complete(struct fpga_manager *mgr,
> -				     struct fpga_image_info *info)
> -{
> -	struct xilinx_spi_conf *conf = mgr->priv;
> -	unsigned long timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
> -	bool expired = false;
> -	int done;
> -	int ret;
> -
> -	/*
> -	 * This loop is carefully written such that if the driver is
> -	 * scheduled out for more than 'timeout', we still check for DONE
> -	 * before giving up and we apply 8 extra CCLK cycles in all cases.
> -	 */
> -	while (!expired) {
> -		expired = time_after(jiffies, timeout);
> -
> -		done = get_done_gpio(mgr);
> -		if (done < 0)
> -			return done;
> -
> -		ret = xilinx_spi_apply_cclk_cycles(conf);
> -		if (ret)
> -			return ret;
> -
> -		if (done)
> -			return 0;
> -	}
> -
> -	if (conf->init_b) {
> -		ret = gpiod_get_value(conf->init_b);
> -
> -		if (ret < 0) {
> -			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
> -			return ret;
> -		}
> -
> -		dev_err(&mgr->dev,
> -			ret ? "CRC error or invalid device\n"
> -			: "Missing sync word or incomplete bitstream\n");
> -	} else {
> -		dev_err(&mgr->dev, "Timeout after config data transfer\n");
> -	}
> -
> -	return -ETIMEDOUT;
> -}
> -
> -static const struct fpga_manager_ops xilinx_spi_ops = {
> -	.state = xilinx_spi_state,
> -	.write_init = xilinx_spi_write_init,
> -	.write = xilinx_spi_write,
> -	.write_complete = xilinx_spi_write_complete,
> -};
> -
>  static int xilinx_spi_probe(struct spi_device *spi)
>  {
>  	struct xilinx_spi_conf *conf;
> -	struct fpga_manager *mgr;
>  
>  	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
>  	if (!conf)
> @@ -231,31 +73,15 @@ static int xilinx_spi_probe(struct spi_device *spi)
>  
>  	conf->spi = spi;
>  
> -	/* PROGRAM_B is active low */
> -	conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW);
> -	if (IS_ERR(conf->prog_b))
> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b),
> -				     "Failed to get PROGRAM_B gpio\n");
> -
> -	conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN);
> -	if (IS_ERR(conf->init_b))
> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b),
> -				     "Failed to get INIT_B gpio\n");
> -
> -	conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
> -	if (IS_ERR(conf->done))
> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->done),
> -				     "Failed to get DONE gpio\n");
> -
> -	mgr = devm_fpga_mgr_register(&spi->dev,
> -				     "Xilinx Slave Serial FPGA Manager",
> -				     &xilinx_spi_ops, conf);
> -	return PTR_ERR_OR_ZERO(mgr);
> +	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
> +				 xilinx_spi_apply_cclk_cycles);
>  }
>  
>  #ifdef CONFIG_OF
>  static const struct of_device_id xlnx_spi_of_match[] = {
> -	{ .compatible = "xlnx,fpga-slave-serial", },
> +	{
> +		.compatible = "xlnx,fpga-slave-serial",
> +	},
>  	{}
>  };
>  MODULE_DEVICE_TABLE(of, xlnx_spi_of_match);
> -- 
> 2.43.0
> 
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-01-31 11:03     ` Kris Chaplin
@ 2024-02-04  8:30       ` Xu Yilun
  2024-02-13 21:54         ` Charles Perry
  0 siblings, 1 reply; 44+ messages in thread
From: Xu Yilun @ 2024-02-04  8:30 UTC (permalink / raw)
  To: Kris Chaplin
  Cc: Krzysztof Kozlowski, Charles Perry, mdf, michal.simek, hao.wu,
	yilun.xu, trix, krzysztof.kozlowski+dt, bcody, avandiver,
	linux-fpga, devicetree, linux-kernel

On Wed, Jan 31, 2024 at 11:03:25AM +0000, Kris Chaplin wrote:
> Hello Krzysztof,
> 
> On 30/01/2024 16:09, Krzysztof Kozlowski wrote:
> 
> > > +
> > > +description: |
> > > +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
> > > +  parallel port named the slave SelectMAP interface in the documentation. Only
> > > +  the x8 mode is supported where data is loaded at one byte per rising edge of
> > > +  the clock, with the MSB of each byte presented to the D0 pin.
> > > +
> > > +  Datasheets:
> > > +    https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
> > 
> > I am surprised that AMD/Xilinx still did not update the document to
> > modern naming (slave->secondary).
> 
> Thank you for bringing this up.
> 
> We are moving away from using non-inclusive technical terminology and are
> removing non-inclusive language from our products and related collateral.
> You will for some time find examples of non-inclusive language, especially
> in our older products as we work to make these changes and align with
> industry standards.  For new IP we're ensuring that we switch and stick to
> inclusive terminology, as you may have seen with my recent w1 driver
> submission.
> 
> SelectMAP is a decades-old interface and as such it is unlikely that we will
> update this in all documentation dating back this time.  I shall however
> look to understand what is planned here for active documentation and new
> driver submissions.

Yes, I need review from AMD/Xilinx side. Especially the HW parts, and
some namings of variables, e.g. if xilinx-core is proper for what products
it supports, and won't be an issue in future.

Thanks,
Yilun

> 
> regards
> Kris
> 

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

* Re: [PATCH 1/3] fpga: xilinx-spi: extract a common driver core
  2024-02-04  8:22       ` Xu Yilun
@ 2024-02-06 15:39         ` Charles Perry
  -1 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-06 15:39 UTC (permalink / raw)
  To: Xu Yilun
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, krzysztof kozlowski+dt, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

On Feb 4, 2024, at 3:22 AM, Xu Yilun yilun.xu@linux.intel.com wrote:
> On Wed, Jan 31, 2024 at 06:05:31PM -0500, Charles Perry wrote:
>> Factor out the gpio handshaking (using PROGRAM_B, INIT_B and DONE)
>> protocol in xilinx-core so that it can be reused for another driver.
>> This commit does not change anything functionally to xilinx-spi.
>> 
>> xilinx-core expects drivers to provide two operations:
>> 
>>  * ->write(const char* buf, size_t count): write to the device
>>  * ->write_one_dummy_byte(): write 0xFF to the device
>> 
>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>> ---
>>  drivers/fpga/Kconfig       |   4 +
>>  drivers/fpga/Makefile      |   1 +
>>  drivers/fpga/xilinx-core.c | 210 +++++++++++++++++++++++++++++++++++++
>>  drivers/fpga/xilinx-core.h |  27 +++++
>>  drivers/fpga/xilinx-spi.c  | 204 +++--------------------------------
>>  5 files changed, 257 insertions(+), 189 deletions(-)
>>  create mode 100644 drivers/fpga/xilinx-core.c
>>  create mode 100644 drivers/fpga/xilinx-core.h
>> 
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index 2f689ac4ba3a3..d27a1ebf40838 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -64,9 +64,13 @@ config FPGA_MGR_STRATIX10_SOC
>>  	help
>>  	  FPGA manager driver support for the Intel Stratix10 SoC.
>>  
>> +config FPGA_MGR_XILINX_CORE
>> +	tristate
>> +
>>  config FPGA_MGR_XILINX_SPI
>>  	tristate "Xilinx Configuration over Slave Serial (SPI)"
>>  	depends on SPI
>> +	select FPGA_MGR_XILINX_CORE
>>  	help
>>  	  FPGA manager driver support for Xilinx FPGA configuration
>>  	  over slave serial interface.
>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>> index 352a2612623e0..7ec795b6a5a70 100644
>> --- a/drivers/fpga/Makefile
>> +++ b/drivers/fpga/Makefile
>> @@ -15,6 +15,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
>>  obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
>>  obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
>>  obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
>> +obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
>>  obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
>>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
>> diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
>> new file mode 100644
>> index 0000000000000..aff40e9394085
>> --- /dev/null
>> +++ b/drivers/fpga/xilinx-core.c
>> @@ -0,0 +1,210 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Common parts of the Xilinx Spartan6 and 7 Series FPGA manager drivers.
>> + *
>> + * Copyright (C) 2017 DENX Software Engineering
>> + *
>> + * Anatolij Gustschin <agust@denx.de>
>> + */
>> +
>> +#include "xilinx-core.h"
>> +
>> +#include <linux/delay.h>
>> +#include <linux/fpga/fpga-mgr.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/of.h>
>> +
>> +static int get_done_gpio(struct fpga_manager *mgr)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +	int ret;
>> +
>> +	ret = gpiod_get_value(core->done);
>> +
> 
> remove the line.
> 

Ok

>> +	if (ret < 0)
>> +		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static enum fpga_mgr_states xilinx_core_state(struct fpga_manager *mgr)
>> +{
>> +	if (!get_done_gpio(mgr))
>> +		return FPGA_MGR_STATE_RESET;
>> +
>> +	return FPGA_MGR_STATE_UNKNOWN;
>> +}
>> +
>> +/**
>> + * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
>> + * a given delay if the pin is unavailable
>> + *
>> + * @mgr:        The FPGA manager object
>> + * @value:      Value INIT_B to wait for (1 = asserted = low)
>> + * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
>> + *
>> + * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
>> + * too much time passed waiting for that. If no INIT_B GPIO is available
>> + * then always return 0.
>> + */
>> +static int wait_for_init_b(struct fpga_manager *mgr, int value,
>> +			   unsigned long alt_udelay)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
>> +
>> +	if (core->init_b) {
>> +		while (time_before(jiffies, timeout)) {
>> +			int ret = gpiod_get_value(core->init_b);
>> +
>> +			if (ret == value)
>> +				return 0;
>> +
>> +			if (ret < 0) {
>> +				dev_err(&mgr->dev,
>> +					"Error reading INIT_B (%d)\n", ret);
>> +				return ret;
>> +			}
>> +
>> +			usleep_range(100, 400);
>> +		}
>> +
>> +		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
>> +			value ? "assert" : "deassert");
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	udelay(alt_udelay);
>> +
>> +	return 0;
>> +}
>> +
>> +static int xilinx_core_write_init(struct fpga_manager *mgr,
>> +				  struct fpga_image_info *info, const char *buf,
>> +				  size_t count)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +	int err;
>> +
>> +	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
>> +		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	gpiod_set_value(core->prog_b, 1);
>> +
>> +	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
>> +	if (err) {
>> +		gpiod_set_value(core->prog_b, 0);
>> +		return err;
>> +	}
>> +
>> +	gpiod_set_value(core->prog_b, 0);
>> +
>> +	err = wait_for_init_b(mgr, 0, 0);
>> +	if (err)
>> +		return err;
>> +
>> +	if (get_done_gpio(mgr)) {
>> +		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
>> +		return -EIO;
>> +	}
>> +
>> +	/* program latency */
>> +	usleep_range(7500, 7600);
>> +	return 0;
>> +}
>> +
>> +static int xilinx_core_write(struct fpga_manager *mgr, const char *buf,
>> +			     size_t count)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +
>> +	return core->write(core, buf, count);
>> +}
>> +
>> +static int xilinx_core_write_complete(struct fpga_manager *mgr,
>> +				      struct fpga_image_info *info)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +	unsigned long timeout =
>> +		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
>> +	bool expired = false;
>> +	int done;
>> +	int ret;
>> +
>> +	/*
>> +	 * This loop is carefully written such that if the driver is
>> +	 * scheduled out for more than 'timeout', we still check for DONE
>> +	 * before giving up and we apply 8 extra CCLK cycles in all cases.
>> +	 */
>> +	while (!expired) {
>> +		expired = time_after(jiffies, timeout);
>> +
>> +		done = get_done_gpio(mgr);
>> +		if (done < 0)
>> +			return done;
>> +
>> +		ret = core->write_one_dummy_byte(core);
>> +		if (ret)
>> +			return ret;
>> +
>> +		if (done)
>> +			return 0;
>> +	}
>> +
>> +	if (core->init_b) {
>> +		ret = gpiod_get_value(core->init_b);
>> +
>> +		if (ret < 0) {
>> +			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
>> +			return ret;
>> +		}
>> +
>> +		dev_err(&mgr->dev,
>> +			ret ? "CRC error or invalid device\n" :
>> +			      "Missing sync word or incomplete bitstream\n");
>> +	} else {
>> +		dev_err(&mgr->dev, "Timeout after config data transfer\n");
>> +	}
>> +
>> +	return -ETIMEDOUT;
>> +}
>> +
>> +static const struct fpga_manager_ops xilinx_core_ops = {
>> +	.state = xilinx_core_state,
>> +	.write_init = xilinx_core_write_init,
>> +	.write = xilinx_core_write,
>> +	.write_complete = xilinx_core_write_complete,
>> +};
>> +
>> +int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>> +		      xilinx_write_func write,
>> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
> 
> I prefer to move these parameters in xilinx_fpga_core structure. I don't
> want the param list becomes longer and longer when we have more inputs.
> 

Ok

>> +{
>> +	struct fpga_manager *mgr;
>> +
>> +	core->dev = dev;
>> +	core->write = write;
>> +	core->write_one_dummy_byte = write_one_dummy_byte;
> 
> Could the write() writes one dummy byte? Maybe one write callback is enough.
> 

Yes, good idea.

>> +
>> +	/* PROGRAM_B is active low */
>> +	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
>> +	if (IS_ERR(core->prog_b))
>> +		return dev_err_probe(dev, PTR_ERR(core->prog_b),
>> +				     "Failed to get PROGRAM_B gpio\n");
>> +
>> +	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
>> +	if (IS_ERR(core->init_b))
>> +		return dev_err_probe(dev, PTR_ERR(core->init_b),
>> +				     "Failed to get INIT_B gpio\n");
>> +
>> +	core->done = devm_gpiod_get(dev, "done", GPIOD_IN);
>> +	if (IS_ERR(core->done))
>> +		return dev_err_probe(dev, PTR_ERR(core->done),
>> +				     "Failed to get DONE gpio\n");
>> +
>> +	mgr = devm_fpga_mgr_register(dev, "Xilinx Slave Serial FPGA Manager",
>> +				     &xilinx_core_ops, core);
>> +	return PTR_ERR_OR_ZERO(mgr);
>> +}
>> diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
>> new file mode 100644
>> index 0000000000000..40e120945ba70
>> --- /dev/null
>> +++ b/drivers/fpga/xilinx-core.h
>> @@ -0,0 +1,27 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +
>> +#ifndef __XILINX_CORE_H
>> +#define __XILINX_CORE_H
>> +
>> +#include <linux/device.h>
>> +
>> +struct xilinx_fpga_core;
>> +
>> +typedef int (*xilinx_write_func)(struct xilinx_fpga_core *core, const char
>> *buf,
>> +				 size_t count);
>> +typedef int (*xilinx_write_one_dummy_byte_func)(struct xilinx_fpga_core *core);
> 
> No need to typedef.
> 
> Thanks,
> Yilun
> 

Ok

Thank you for the review,
Charles

>> +
>> +struct xilinx_fpga_core {
>> +	struct device *dev;
>> +	xilinx_write_func write;
>> +	xilinx_write_one_dummy_byte_func write_one_dummy_byte;
>> +	struct gpio_desc *prog_b;
>> +	struct gpio_desc *init_b;
>> +	struct gpio_desc *done;
>> +};
>> +
>> +int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>> +		      xilinx_write_func write,
>> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
>> +
>> +#endif /* __XILINX_CORE_H */
>> diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
>> index e1a227e7ff2ae..ec128dee97312 100644
>> --- a/drivers/fpga/xilinx-spi.c
>> +++ b/drivers/fpga/xilinx-spi.c
>> @@ -10,127 +10,24 @@
>>   * the slave serial configuration interface.
>>   */
>>  
>> -#include <linux/delay.h>
>> -#include <linux/device.h>
>> -#include <linux/fpga/fpga-mgr.h>
>> -#include <linux/gpio/consumer.h>
>> +#include "xilinx-core.h"
>> +
>>  #include <linux/module.h>
>>  #include <linux/mod_devicetable.h>
>>  #include <linux/of.h>
>>  #include <linux/spi/spi.h>
>> -#include <linux/sizes.h>
>>  
>>  struct xilinx_spi_conf {
>> +	struct xilinx_fpga_core core;
>>  	struct spi_device *spi;
>> -	struct gpio_desc *prog_b;
>> -	struct gpio_desc *init_b;
>> -	struct gpio_desc *done;
>>  };
>>  
>> -static int get_done_gpio(struct fpga_manager *mgr)
>> -{
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> -	int ret;
>> -
>> -	ret = gpiod_get_value(conf->done);
>> -
>> -	if (ret < 0)
>> -		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
>> -
>> -	return ret;
>> -}
>> -
>> -static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
>> -{
>> -	if (!get_done_gpio(mgr))
>> -		return FPGA_MGR_STATE_RESET;
>> -
>> -	return FPGA_MGR_STATE_UNKNOWN;
>> -}
>> -
>> -/**
>> - * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
>> - * a given delay if the pin is unavailable
>> - *
>> - * @mgr:        The FPGA manager object
>> - * @value:      Value INIT_B to wait for (1 = asserted = low)
>> - * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
>> - *
>> - * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
>> - * too much time passed waiting for that. If no INIT_B GPIO is available
>> - * then always return 0.
>> - */
>> -static int wait_for_init_b(struct fpga_manager *mgr, int value,
>> -			   unsigned long alt_udelay)
>> -{
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> -	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
>> -
>> -	if (conf->init_b) {
>> -		while (time_before(jiffies, timeout)) {
>> -			int ret = gpiod_get_value(conf->init_b);
>> -
>> -			if (ret == value)
>> -				return 0;
>> -
>> -			if (ret < 0) {
>> -				dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
>> -				return ret;
>> -			}
>> -
>> -			usleep_range(100, 400);
>> -		}
>> -
>> -		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
>> -			value ? "assert" : "deassert");
>> -		return -ETIMEDOUT;
>> -	}
>> -
>> -	udelay(alt_udelay);
>> -
>> -	return 0;
>> -}
>> -
>> -static int xilinx_spi_write_init(struct fpga_manager *mgr,
>> -				 struct fpga_image_info *info,
>> -				 const char *buf, size_t count)
>> -{
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> -	int err;
>> -
>> -	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
>> -		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
>> -		return -EINVAL;
>> -	}
>> -
>> -	gpiod_set_value(conf->prog_b, 1);
>> +#define to_xilinx_spi_conf(obj) container_of(obj, struct xilinx_spi_conf, core)
>>  
>> -	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
>> -	if (err) {
>> -		gpiod_set_value(conf->prog_b, 0);
>> -		return err;
>> -	}
>> -
>> -	gpiod_set_value(conf->prog_b, 0);
>> -
>> -	err = wait_for_init_b(mgr, 0, 0);
>> -	if (err)
>> -		return err;
>> -
>> -	if (get_done_gpio(mgr)) {
>> -		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
>> -		return -EIO;
>> -	}
>> -
>> -	/* program latency */
>> -	usleep_range(7500, 7600);
>> -	return 0;
>> -}
>> -
>> -static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
>> +static int xilinx_spi_write(struct xilinx_fpga_core *core, const char *buf,
>>  			    size_t count)
>>  {
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> +	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
>>  	const char *fw_data = buf;
>>  	const char *fw_data_end = fw_data + count;
>>  
>> @@ -143,7 +40,7 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const
>> char *buf,
>>  
>>  		ret = spi_write(conf->spi, fw_data, stride);
>>  		if (ret) {
>> -			dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
>> +			dev_err(core->dev, "SPI error in firmware write: %d\n",
>>  				ret);
>>  			return ret;
>>  		}
>> @@ -153,77 +50,22 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const
>> char *buf,
>>  	return 0;
>>  }
>>  
>> -static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf)
>> +static int xilinx_spi_apply_cclk_cycles(struct xilinx_fpga_core *core)
>>  {
>> -	struct spi_device *spi = conf->spi;
>> +	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
>>  	const u8 din_data[1] = { 0xff };
>>  	int ret;
>>  
>>  	ret = spi_write(conf->spi, din_data, sizeof(din_data));
>>  	if (ret)
>> -		dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret);
>> +		dev_err(core->dev, "applying CCLK cycles failed: %d\n", ret);
>>  
>>  	return ret;
>>  }
>>  
>> -static int xilinx_spi_write_complete(struct fpga_manager *mgr,
>> -				     struct fpga_image_info *info)
>> -{
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> -	unsigned long timeout = jiffies +
>> usecs_to_jiffies(info->config_complete_timeout_us);
>> -	bool expired = false;
>> -	int done;
>> -	int ret;
>> -
>> -	/*
>> -	 * This loop is carefully written such that if the driver is
>> -	 * scheduled out for more than 'timeout', we still check for DONE
>> -	 * before giving up and we apply 8 extra CCLK cycles in all cases.
>> -	 */
>> -	while (!expired) {
>> -		expired = time_after(jiffies, timeout);
>> -
>> -		done = get_done_gpio(mgr);
>> -		if (done < 0)
>> -			return done;
>> -
>> -		ret = xilinx_spi_apply_cclk_cycles(conf);
>> -		if (ret)
>> -			return ret;
>> -
>> -		if (done)
>> -			return 0;
>> -	}
>> -
>> -	if (conf->init_b) {
>> -		ret = gpiod_get_value(conf->init_b);
>> -
>> -		if (ret < 0) {
>> -			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
>> -			return ret;
>> -		}
>> -
>> -		dev_err(&mgr->dev,
>> -			ret ? "CRC error or invalid device\n"
>> -			: "Missing sync word or incomplete bitstream\n");
>> -	} else {
>> -		dev_err(&mgr->dev, "Timeout after config data transfer\n");
>> -	}
>> -
>> -	return -ETIMEDOUT;
>> -}
>> -
>> -static const struct fpga_manager_ops xilinx_spi_ops = {
>> -	.state = xilinx_spi_state,
>> -	.write_init = xilinx_spi_write_init,
>> -	.write = xilinx_spi_write,
>> -	.write_complete = xilinx_spi_write_complete,
>> -};
>> -
>>  static int xilinx_spi_probe(struct spi_device *spi)
>>  {
>>  	struct xilinx_spi_conf *conf;
>> -	struct fpga_manager *mgr;
>>  
>>  	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
>>  	if (!conf)
>> @@ -231,31 +73,15 @@ static int xilinx_spi_probe(struct spi_device *spi)
>>  
>>  	conf->spi = spi;
>>  
>> -	/* PROGRAM_B is active low */
>> -	conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW);
>> -	if (IS_ERR(conf->prog_b))
>> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b),
>> -				     "Failed to get PROGRAM_B gpio\n");
>> -
>> -	conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN);
>> -	if (IS_ERR(conf->init_b))
>> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b),
>> -				     "Failed to get INIT_B gpio\n");
>> -
>> -	conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
>> -	if (IS_ERR(conf->done))
>> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->done),
>> -				     "Failed to get DONE gpio\n");
>> -
>> -	mgr = devm_fpga_mgr_register(&spi->dev,
>> -				     "Xilinx Slave Serial FPGA Manager",
>> -				     &xilinx_spi_ops, conf);
>> -	return PTR_ERR_OR_ZERO(mgr);
>> +	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
>> +				 xilinx_spi_apply_cclk_cycles);
>>  }
>>  
>>  #ifdef CONFIG_OF
>>  static const struct of_device_id xlnx_spi_of_match[] = {
>> -	{ .compatible = "xlnx,fpga-slave-serial", },
>> +	{
>> +		.compatible = "xlnx,fpga-slave-serial",
>> +	},
>>  	{}
>>  };
>>  MODULE_DEVICE_TABLE(of, xlnx_spi_of_match);
>> --
>> 2.43.0
>> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/3] fpga: xilinx-spi: extract a common driver core
@ 2024-02-06 15:39         ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-06 15:39 UTC (permalink / raw)
  To: Xu Yilun
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, krzysztof kozlowski+dt, Conor Dooley, Michal Simek,
	linux-fpga, devicetree, linux-kernel, linux-arm-kernel

On Feb 4, 2024, at 3:22 AM, Xu Yilun yilun.xu@linux.intel.com wrote:
> On Wed, Jan 31, 2024 at 06:05:31PM -0500, Charles Perry wrote:
>> Factor out the gpio handshaking (using PROGRAM_B, INIT_B and DONE)
>> protocol in xilinx-core so that it can be reused for another driver.
>> This commit does not change anything functionally to xilinx-spi.
>> 
>> xilinx-core expects drivers to provide two operations:
>> 
>>  * ->write(const char* buf, size_t count): write to the device
>>  * ->write_one_dummy_byte(): write 0xFF to the device
>> 
>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>> ---
>>  drivers/fpga/Kconfig       |   4 +
>>  drivers/fpga/Makefile      |   1 +
>>  drivers/fpga/xilinx-core.c | 210 +++++++++++++++++++++++++++++++++++++
>>  drivers/fpga/xilinx-core.h |  27 +++++
>>  drivers/fpga/xilinx-spi.c  | 204 +++--------------------------------
>>  5 files changed, 257 insertions(+), 189 deletions(-)
>>  create mode 100644 drivers/fpga/xilinx-core.c
>>  create mode 100644 drivers/fpga/xilinx-core.h
>> 
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index 2f689ac4ba3a3..d27a1ebf40838 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -64,9 +64,13 @@ config FPGA_MGR_STRATIX10_SOC
>>  	help
>>  	  FPGA manager driver support for the Intel Stratix10 SoC.
>>  
>> +config FPGA_MGR_XILINX_CORE
>> +	tristate
>> +
>>  config FPGA_MGR_XILINX_SPI
>>  	tristate "Xilinx Configuration over Slave Serial (SPI)"
>>  	depends on SPI
>> +	select FPGA_MGR_XILINX_CORE
>>  	help
>>  	  FPGA manager driver support for Xilinx FPGA configuration
>>  	  over slave serial interface.
>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>> index 352a2612623e0..7ec795b6a5a70 100644
>> --- a/drivers/fpga/Makefile
>> +++ b/drivers/fpga/Makefile
>> @@ -15,6 +15,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
>>  obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
>>  obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
>>  obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
>> +obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
>>  obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
>>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
>> diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
>> new file mode 100644
>> index 0000000000000..aff40e9394085
>> --- /dev/null
>> +++ b/drivers/fpga/xilinx-core.c
>> @@ -0,0 +1,210 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Common parts of the Xilinx Spartan6 and 7 Series FPGA manager drivers.
>> + *
>> + * Copyright (C) 2017 DENX Software Engineering
>> + *
>> + * Anatolij Gustschin <agust@denx.de>
>> + */
>> +
>> +#include "xilinx-core.h"
>> +
>> +#include <linux/delay.h>
>> +#include <linux/fpga/fpga-mgr.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/of.h>
>> +
>> +static int get_done_gpio(struct fpga_manager *mgr)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +	int ret;
>> +
>> +	ret = gpiod_get_value(core->done);
>> +
> 
> remove the line.
> 

Ok

>> +	if (ret < 0)
>> +		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
>> +
>> +	return ret;
>> +}
>> +
>> +static enum fpga_mgr_states xilinx_core_state(struct fpga_manager *mgr)
>> +{
>> +	if (!get_done_gpio(mgr))
>> +		return FPGA_MGR_STATE_RESET;
>> +
>> +	return FPGA_MGR_STATE_UNKNOWN;
>> +}
>> +
>> +/**
>> + * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
>> + * a given delay if the pin is unavailable
>> + *
>> + * @mgr:        The FPGA manager object
>> + * @value:      Value INIT_B to wait for (1 = asserted = low)
>> + * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
>> + *
>> + * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
>> + * too much time passed waiting for that. If no INIT_B GPIO is available
>> + * then always return 0.
>> + */
>> +static int wait_for_init_b(struct fpga_manager *mgr, int value,
>> +			   unsigned long alt_udelay)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
>> +
>> +	if (core->init_b) {
>> +		while (time_before(jiffies, timeout)) {
>> +			int ret = gpiod_get_value(core->init_b);
>> +
>> +			if (ret == value)
>> +				return 0;
>> +
>> +			if (ret < 0) {
>> +				dev_err(&mgr->dev,
>> +					"Error reading INIT_B (%d)\n", ret);
>> +				return ret;
>> +			}
>> +
>> +			usleep_range(100, 400);
>> +		}
>> +
>> +		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
>> +			value ? "assert" : "deassert");
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	udelay(alt_udelay);
>> +
>> +	return 0;
>> +}
>> +
>> +static int xilinx_core_write_init(struct fpga_manager *mgr,
>> +				  struct fpga_image_info *info, const char *buf,
>> +				  size_t count)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +	int err;
>> +
>> +	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
>> +		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	gpiod_set_value(core->prog_b, 1);
>> +
>> +	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
>> +	if (err) {
>> +		gpiod_set_value(core->prog_b, 0);
>> +		return err;
>> +	}
>> +
>> +	gpiod_set_value(core->prog_b, 0);
>> +
>> +	err = wait_for_init_b(mgr, 0, 0);
>> +	if (err)
>> +		return err;
>> +
>> +	if (get_done_gpio(mgr)) {
>> +		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
>> +		return -EIO;
>> +	}
>> +
>> +	/* program latency */
>> +	usleep_range(7500, 7600);
>> +	return 0;
>> +}
>> +
>> +static int xilinx_core_write(struct fpga_manager *mgr, const char *buf,
>> +			     size_t count)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +
>> +	return core->write(core, buf, count);
>> +}
>> +
>> +static int xilinx_core_write_complete(struct fpga_manager *mgr,
>> +				      struct fpga_image_info *info)
>> +{
>> +	struct xilinx_fpga_core *core = mgr->priv;
>> +	unsigned long timeout =
>> +		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
>> +	bool expired = false;
>> +	int done;
>> +	int ret;
>> +
>> +	/*
>> +	 * This loop is carefully written such that if the driver is
>> +	 * scheduled out for more than 'timeout', we still check for DONE
>> +	 * before giving up and we apply 8 extra CCLK cycles in all cases.
>> +	 */
>> +	while (!expired) {
>> +		expired = time_after(jiffies, timeout);
>> +
>> +		done = get_done_gpio(mgr);
>> +		if (done < 0)
>> +			return done;
>> +
>> +		ret = core->write_one_dummy_byte(core);
>> +		if (ret)
>> +			return ret;
>> +
>> +		if (done)
>> +			return 0;
>> +	}
>> +
>> +	if (core->init_b) {
>> +		ret = gpiod_get_value(core->init_b);
>> +
>> +		if (ret < 0) {
>> +			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
>> +			return ret;
>> +		}
>> +
>> +		dev_err(&mgr->dev,
>> +			ret ? "CRC error or invalid device\n" :
>> +			      "Missing sync word or incomplete bitstream\n");
>> +	} else {
>> +		dev_err(&mgr->dev, "Timeout after config data transfer\n");
>> +	}
>> +
>> +	return -ETIMEDOUT;
>> +}
>> +
>> +static const struct fpga_manager_ops xilinx_core_ops = {
>> +	.state = xilinx_core_state,
>> +	.write_init = xilinx_core_write_init,
>> +	.write = xilinx_core_write,
>> +	.write_complete = xilinx_core_write_complete,
>> +};
>> +
>> +int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>> +		      xilinx_write_func write,
>> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
> 
> I prefer to move these parameters in xilinx_fpga_core structure. I don't
> want the param list becomes longer and longer when we have more inputs.
> 

Ok

>> +{
>> +	struct fpga_manager *mgr;
>> +
>> +	core->dev = dev;
>> +	core->write = write;
>> +	core->write_one_dummy_byte = write_one_dummy_byte;
> 
> Could the write() writes one dummy byte? Maybe one write callback is enough.
> 

Yes, good idea.

>> +
>> +	/* PROGRAM_B is active low */
>> +	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
>> +	if (IS_ERR(core->prog_b))
>> +		return dev_err_probe(dev, PTR_ERR(core->prog_b),
>> +				     "Failed to get PROGRAM_B gpio\n");
>> +
>> +	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
>> +	if (IS_ERR(core->init_b))
>> +		return dev_err_probe(dev, PTR_ERR(core->init_b),
>> +				     "Failed to get INIT_B gpio\n");
>> +
>> +	core->done = devm_gpiod_get(dev, "done", GPIOD_IN);
>> +	if (IS_ERR(core->done))
>> +		return dev_err_probe(dev, PTR_ERR(core->done),
>> +				     "Failed to get DONE gpio\n");
>> +
>> +	mgr = devm_fpga_mgr_register(dev, "Xilinx Slave Serial FPGA Manager",
>> +				     &xilinx_core_ops, core);
>> +	return PTR_ERR_OR_ZERO(mgr);
>> +}
>> diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
>> new file mode 100644
>> index 0000000000000..40e120945ba70
>> --- /dev/null
>> +++ b/drivers/fpga/xilinx-core.h
>> @@ -0,0 +1,27 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +
>> +#ifndef __XILINX_CORE_H
>> +#define __XILINX_CORE_H
>> +
>> +#include <linux/device.h>
>> +
>> +struct xilinx_fpga_core;
>> +
>> +typedef int (*xilinx_write_func)(struct xilinx_fpga_core *core, const char
>> *buf,
>> +				 size_t count);
>> +typedef int (*xilinx_write_one_dummy_byte_func)(struct xilinx_fpga_core *core);
> 
> No need to typedef.
> 
> Thanks,
> Yilun
> 

Ok

Thank you for the review,
Charles

>> +
>> +struct xilinx_fpga_core {
>> +	struct device *dev;
>> +	xilinx_write_func write;
>> +	xilinx_write_one_dummy_byte_func write_one_dummy_byte;
>> +	struct gpio_desc *prog_b;
>> +	struct gpio_desc *init_b;
>> +	struct gpio_desc *done;
>> +};
>> +
>> +int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>> +		      xilinx_write_func write,
>> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
>> +
>> +#endif /* __XILINX_CORE_H */
>> diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
>> index e1a227e7ff2ae..ec128dee97312 100644
>> --- a/drivers/fpga/xilinx-spi.c
>> +++ b/drivers/fpga/xilinx-spi.c
>> @@ -10,127 +10,24 @@
>>   * the slave serial configuration interface.
>>   */
>>  
>> -#include <linux/delay.h>
>> -#include <linux/device.h>
>> -#include <linux/fpga/fpga-mgr.h>
>> -#include <linux/gpio/consumer.h>
>> +#include "xilinx-core.h"
>> +
>>  #include <linux/module.h>
>>  #include <linux/mod_devicetable.h>
>>  #include <linux/of.h>
>>  #include <linux/spi/spi.h>
>> -#include <linux/sizes.h>
>>  
>>  struct xilinx_spi_conf {
>> +	struct xilinx_fpga_core core;
>>  	struct spi_device *spi;
>> -	struct gpio_desc *prog_b;
>> -	struct gpio_desc *init_b;
>> -	struct gpio_desc *done;
>>  };
>>  
>> -static int get_done_gpio(struct fpga_manager *mgr)
>> -{
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> -	int ret;
>> -
>> -	ret = gpiod_get_value(conf->done);
>> -
>> -	if (ret < 0)
>> -		dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
>> -
>> -	return ret;
>> -}
>> -
>> -static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
>> -{
>> -	if (!get_done_gpio(mgr))
>> -		return FPGA_MGR_STATE_RESET;
>> -
>> -	return FPGA_MGR_STATE_UNKNOWN;
>> -}
>> -
>> -/**
>> - * wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
>> - * a given delay if the pin is unavailable
>> - *
>> - * @mgr:        The FPGA manager object
>> - * @value:      Value INIT_B to wait for (1 = asserted = low)
>> - * @alt_udelay: Delay to wait if the INIT_B GPIO is not available
>> - *
>> - * Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
>> - * too much time passed waiting for that. If no INIT_B GPIO is available
>> - * then always return 0.
>> - */
>> -static int wait_for_init_b(struct fpga_manager *mgr, int value,
>> -			   unsigned long alt_udelay)
>> -{
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> -	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
>> -
>> -	if (conf->init_b) {
>> -		while (time_before(jiffies, timeout)) {
>> -			int ret = gpiod_get_value(conf->init_b);
>> -
>> -			if (ret == value)
>> -				return 0;
>> -
>> -			if (ret < 0) {
>> -				dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
>> -				return ret;
>> -			}
>> -
>> -			usleep_range(100, 400);
>> -		}
>> -
>> -		dev_err(&mgr->dev, "Timeout waiting for INIT_B to %s\n",
>> -			value ? "assert" : "deassert");
>> -		return -ETIMEDOUT;
>> -	}
>> -
>> -	udelay(alt_udelay);
>> -
>> -	return 0;
>> -}
>> -
>> -static int xilinx_spi_write_init(struct fpga_manager *mgr,
>> -				 struct fpga_image_info *info,
>> -				 const char *buf, size_t count)
>> -{
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> -	int err;
>> -
>> -	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
>> -		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
>> -		return -EINVAL;
>> -	}
>> -
>> -	gpiod_set_value(conf->prog_b, 1);
>> +#define to_xilinx_spi_conf(obj) container_of(obj, struct xilinx_spi_conf, core)
>>  
>> -	err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
>> -	if (err) {
>> -		gpiod_set_value(conf->prog_b, 0);
>> -		return err;
>> -	}
>> -
>> -	gpiod_set_value(conf->prog_b, 0);
>> -
>> -	err = wait_for_init_b(mgr, 0, 0);
>> -	if (err)
>> -		return err;
>> -
>> -	if (get_done_gpio(mgr)) {
>> -		dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
>> -		return -EIO;
>> -	}
>> -
>> -	/* program latency */
>> -	usleep_range(7500, 7600);
>> -	return 0;
>> -}
>> -
>> -static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf,
>> +static int xilinx_spi_write(struct xilinx_fpga_core *core, const char *buf,
>>  			    size_t count)
>>  {
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> +	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
>>  	const char *fw_data = buf;
>>  	const char *fw_data_end = fw_data + count;
>>  
>> @@ -143,7 +40,7 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const
>> char *buf,
>>  
>>  		ret = spi_write(conf->spi, fw_data, stride);
>>  		if (ret) {
>> -			dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
>> +			dev_err(core->dev, "SPI error in firmware write: %d\n",
>>  				ret);
>>  			return ret;
>>  		}
>> @@ -153,77 +50,22 @@ static int xilinx_spi_write(struct fpga_manager *mgr, const
>> char *buf,
>>  	return 0;
>>  }
>>  
>> -static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf)
>> +static int xilinx_spi_apply_cclk_cycles(struct xilinx_fpga_core *core)
>>  {
>> -	struct spi_device *spi = conf->spi;
>> +	struct xilinx_spi_conf *conf = to_xilinx_spi_conf(core);
>>  	const u8 din_data[1] = { 0xff };
>>  	int ret;
>>  
>>  	ret = spi_write(conf->spi, din_data, sizeof(din_data));
>>  	if (ret)
>> -		dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret);
>> +		dev_err(core->dev, "applying CCLK cycles failed: %d\n", ret);
>>  
>>  	return ret;
>>  }
>>  
>> -static int xilinx_spi_write_complete(struct fpga_manager *mgr,
>> -				     struct fpga_image_info *info)
>> -{
>> -	struct xilinx_spi_conf *conf = mgr->priv;
>> -	unsigned long timeout = jiffies +
>> usecs_to_jiffies(info->config_complete_timeout_us);
>> -	bool expired = false;
>> -	int done;
>> -	int ret;
>> -
>> -	/*
>> -	 * This loop is carefully written such that if the driver is
>> -	 * scheduled out for more than 'timeout', we still check for DONE
>> -	 * before giving up and we apply 8 extra CCLK cycles in all cases.
>> -	 */
>> -	while (!expired) {
>> -		expired = time_after(jiffies, timeout);
>> -
>> -		done = get_done_gpio(mgr);
>> -		if (done < 0)
>> -			return done;
>> -
>> -		ret = xilinx_spi_apply_cclk_cycles(conf);
>> -		if (ret)
>> -			return ret;
>> -
>> -		if (done)
>> -			return 0;
>> -	}
>> -
>> -	if (conf->init_b) {
>> -		ret = gpiod_get_value(conf->init_b);
>> -
>> -		if (ret < 0) {
>> -			dev_err(&mgr->dev, "Error reading INIT_B (%d)\n", ret);
>> -			return ret;
>> -		}
>> -
>> -		dev_err(&mgr->dev,
>> -			ret ? "CRC error or invalid device\n"
>> -			: "Missing sync word or incomplete bitstream\n");
>> -	} else {
>> -		dev_err(&mgr->dev, "Timeout after config data transfer\n");
>> -	}
>> -
>> -	return -ETIMEDOUT;
>> -}
>> -
>> -static const struct fpga_manager_ops xilinx_spi_ops = {
>> -	.state = xilinx_spi_state,
>> -	.write_init = xilinx_spi_write_init,
>> -	.write = xilinx_spi_write,
>> -	.write_complete = xilinx_spi_write_complete,
>> -};
>> -
>>  static int xilinx_spi_probe(struct spi_device *spi)
>>  {
>>  	struct xilinx_spi_conf *conf;
>> -	struct fpga_manager *mgr;
>>  
>>  	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
>>  	if (!conf)
>> @@ -231,31 +73,15 @@ static int xilinx_spi_probe(struct spi_device *spi)
>>  
>>  	conf->spi = spi;
>>  
>> -	/* PROGRAM_B is active low */
>> -	conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW);
>> -	if (IS_ERR(conf->prog_b))
>> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->prog_b),
>> -				     "Failed to get PROGRAM_B gpio\n");
>> -
>> -	conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN);
>> -	if (IS_ERR(conf->init_b))
>> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->init_b),
>> -				     "Failed to get INIT_B gpio\n");
>> -
>> -	conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
>> -	if (IS_ERR(conf->done))
>> -		return dev_err_probe(&spi->dev, PTR_ERR(conf->done),
>> -				     "Failed to get DONE gpio\n");
>> -
>> -	mgr = devm_fpga_mgr_register(&spi->dev,
>> -				     "Xilinx Slave Serial FPGA Manager",
>> -				     &xilinx_spi_ops, conf);
>> -	return PTR_ERR_OR_ZERO(mgr);
>> +	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
>> +				 xilinx_spi_apply_cclk_cycles);
>>  }
>>  
>>  #ifdef CONFIG_OF
>>  static const struct of_device_id xlnx_spi_of_match[] = {
>> -	{ .compatible = "xlnx,fpga-slave-serial", },
>> +	{
>> +		.compatible = "xlnx,fpga-slave-serial",
>> +	},
>>  	{}
>>  };
>>  MODULE_DEVICE_TABLE(of, xlnx_spi_of_match);
>> --
>> 2.43.0
>> 

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

* Re: [PATCH 3/3] fpga: xilinx-selectmap: add new driver
  2024-02-04  8:10       ` Xu Yilun
@ 2024-02-06 15:48         ` Charles Perry
  -1 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-06 15:48 UTC (permalink / raw)
  To: Xu Yilun, krzysztof kozlowski+dt
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, Conor Dooley, Michal Simek, linux-fpga, devicetree,
	linux-kernel, linux-arm-kernel

On Feb 4, 2024, at 3:10 AM, Xu Yilun yilun.xu@linux.intel.com wrote:
> On Wed, Jan 31, 2024 at 06:05:33PM -0500, Charles Perry wrote:
>> Xilinx 7 series FPGA can be programmed using a slave parallel port named
>> the SelectMAP interface in the datasheet. This slave interface is
>> compatible with the i.MX6 EIM bus controller but other types of external
>> memory mapped parallel bus might work.
>> 
>> xilinx-selectmap currently only supports the x8 mode where data is loaded
>> at one byte per rising edge of the clock, with the MSb of each byte
>> presented to the D0 pin.
>> 
>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>> ---
>>  drivers/fpga/Kconfig            |   8 +++
>>  drivers/fpga/Makefile           |   1 +
>>  drivers/fpga/xilinx-core.c      |  11 +++-
>>  drivers/fpga/xilinx-core.h      |   3 +-
>>  drivers/fpga/xilinx-selectmap.c | 106 ++++++++++++++++++++++++++++++++
>>  drivers/fpga/xilinx-spi.c       |   3 +-
>>  6 files changed, 127 insertions(+), 5 deletions(-)
>>  create mode 100644 drivers/fpga/xilinx-selectmap.c
>> 
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index d27a1ebf40838..37b35f58f0dfb 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -67,6 +67,14 @@ config FPGA_MGR_STRATIX10_SOC
>>  config FPGA_MGR_XILINX_CORE
>>  	tristate
>>  
>> +config FPGA_MGR_XILINX_SELECTMAP
>> +	tristate "Xilinx Configuration over SelectMAP"
>> +	depends on HAS_IOMEM
>> +	select FPGA_MGR_XILINX_CORE
>> +	help
>> +	  FPGA manager driver support for Xilinx FPGA configuration
>> +	  over SelectMAP interface.
>> +
>>  config FPGA_MGR_XILINX_SPI
>>  	tristate "Xilinx Configuration over Slave Serial (SPI)"
>>  	depends on SPI
>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>> index 7ec795b6a5a70..aeb89bb13517e 100644
>> --- a/drivers/fpga/Makefile
>> +++ b/drivers/fpga/Makefile
>> @@ -16,6 +16,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
>>  obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
>>  obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
>>  obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
>> +obj-$(CONFIG_FPGA_MGR_XILINX_SELECTMAP)	+= xilinx-selectmap.o
>>  obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
>>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
>> diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
>> index aff40e9394085..64117759be100 100644
>> --- a/drivers/fpga/xilinx-core.c
>> +++ b/drivers/fpga/xilinx-core.c
>> @@ -180,21 +180,26 @@ static const struct fpga_manager_ops xilinx_core_ops = {
>>  
>>  int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>>  		      xilinx_write_func write,
>> -		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
>> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
>> +		      const char *prog_con_id, const char *init_con_id)
> 
> These gpio name inputs are not necessary except for DTS format concern.
> Is it possible we don't change the names?
> 

Krzysztof won't accept the old names as they are non standard (contain a 
prohibited char "_" and use a "-b" prefix for active low). I agree that it
is cumbersome to have different gpio names injected in the core by the top 
level driver.

Can I change the GPIO names of xlnx,fpga-slave-serial? i.e.:

 * "prog_b" -> "prog"
 * "init-b" -> "init"

and keep a fallback in the driver so that current users of this driver keep
working without adaptation in the DT.

>>  {
>>  	struct fpga_manager *mgr;
>>  
>> +	if (!core || !dev || !write || !write_one_dummy_byte || !prog_con_id ||
>> +	    !init_con_id)
>> +		return -EINVAL;
> 
> These checks belong to Patch #1.
> 

Ok

>> +
>>  	core->dev = dev;
>>  	core->write = write;
>>  	core->write_one_dummy_byte = write_one_dummy_byte;
>>  
>>  	/* PROGRAM_B is active low */
>> -	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
>> +	core->prog_b = devm_gpiod_get(dev, prog_con_id, GPIOD_OUT_LOW);
>>  	if (IS_ERR(core->prog_b))
>>  		return dev_err_probe(dev, PTR_ERR(core->prog_b),
>>  				     "Failed to get PROGRAM_B gpio\n");
>>  
>> -	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
>> +	core->init_b = devm_gpiod_get_optional(dev, init_con_id, GPIOD_IN);
>>  	if (IS_ERR(core->init_b))
>>  		return dev_err_probe(dev, PTR_ERR(core->init_b),
>>  				     "Failed to get INIT_B gpio\n");
>> diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
>> index 40e120945ba70..817f0e551d093 100644
>> --- a/drivers/fpga/xilinx-core.h
>> +++ b/drivers/fpga/xilinx-core.h
>> @@ -22,6 +22,7 @@ struct xilinx_fpga_core {
>>  
>>  int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>>  		      xilinx_write_func write,
>> -		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
>> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
>> +		      const char *prog_con_id, const char *init_con_id);
>>  
>>  #endif /* __XILINX_CORE_H */
>> diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c
>> new file mode 100644
>> index 0000000000000..08054e19bb498
>> --- /dev/null
>> +++ b/drivers/fpga/xilinx-selectmap.c
>> @@ -0,0 +1,106 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Xilinx Spartan6 and 7 Series SelectMAP interface driver
>> + *
>> + * (C) 2024 Charles Perry <charles.perry@savoirfairelinux.com>
>> + *
>> + * Manage Xilinx FPGA firmware loaded over the SelectMAP configuration
>> + * interface.
>> + */
>> +
>> +#include "xilinx-core.h"
>> +
>> +#include <linux/platform_device.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/module.h>
>> +#include <linux/mod_devicetable.h>
>> +#include <linux/of.h>
>> +#include <linux/io.h>
>> +
>> +struct xilinx_selectmap_conf {
>> +	struct xilinx_fpga_core core;
>> +	void __iomem *base;
>> +	struct gpio_desc *csi_b;
>> +	struct gpio_desc *rdwr_b;
> 
> These 2 gpio_desc are not used globally, maybe remove them here.
> 

Ok

>> +};
>> +
>> +#define to_xilinx_selectmap_conf(obj) \
>> +	container_of(obj, struct xilinx_selectmap_conf, core)
>> +
>> +static int xilinx_selectmap_write(struct xilinx_fpga_core *core,
>> +				  const char *buf, size_t count)
>> +{
>> +	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
>> +	u32 i;
>> +
>> +	for (i = 0; i < count; ++i)
>> +		writeb(buf[i], conf->base);
>> +
>> +	return 0;
>> +}
>> +
>> +static int xilinx_selectmap_apply_padding(struct xilinx_fpga_core *core)
>> +{
>> +	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
>> +
>> +	writeb(0xFF, conf->base);
> 
> Seems only one callback needed. Just use write() to xfer 1 byte?
> 
> Thanks,
> Yilun
> 

Yes, will be changed.

Thank you,
Charles

>> +	return 0;
>> +}
>> +
>> +static int xilinx_selectmap_probe(struct platform_device *pdev)
>> +{
>> +	struct xilinx_selectmap_conf *conf;
>> +	struct resource *r;
>> +	void __iomem *base;
>> +
>> +	conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
>> +	if (!conf)
>> +		return -ENOMEM;
>> +
>> +	base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
>> +	if (IS_ERR(base))
>> +		return dev_err_probe(&pdev->dev, PTR_ERR(base),
>> +				     "ioremap error\n");
>> +	conf->base = base;
>> +
>> +	/* CSI_B is active low */
>> +	conf->csi_b =
>> +		devm_gpiod_get_optional(&pdev->dev, "csi", GPIOD_OUT_HIGH);
>> +	if (IS_ERR(conf->csi_b))
>> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->csi_b),
>> +				     "Failed to get CSI_B gpio\n");
>> +
>> +	/* RDWR_B is active low */
>> +	conf->rdwr_b =
>> +		devm_gpiod_get_optional(&pdev->dev, "rdwr", GPIOD_OUT_HIGH);
>> +	if (IS_ERR(conf->rdwr_b))
>> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->rdwr_b),
>> +				     "Failed to get RDWR_B gpio\n");
>> +
>> +	return xilinx_core_probe(&conf->core, &pdev->dev,
>> +				 xilinx_selectmap_write,
>> +				 xilinx_selectmap_apply_padding, "prog",
>> +				 "init");
>> +}
>> +
>> +static const struct of_device_id xlnx_selectmap_of_match[] = {
>> +	{
>> +		.compatible = "xlnx,fpga-selectmap",
>> +	},
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(of, xlnx_selectmap_of_match);
>> +
>> +static struct platform_driver xilinx_selectmap_driver = {
>> +	.driver = {
>> +		.name = "xilinx-selectmap",
>> +		.of_match_table = xlnx_selectmap_of_match,
>> +	},
>> +	.probe  = xilinx_selectmap_probe,
>> +};
>> +
>> +module_platform_driver(xilinx_selectmap_driver);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Charles Perry <charles.perry@savoirfairelinux.com>");
>> +MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SelectMap");
>> diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
>> index ec128dee97312..b9ab3d5da004c 100644
>> --- a/drivers/fpga/xilinx-spi.c
>> +++ b/drivers/fpga/xilinx-spi.c
>> @@ -74,7 +74,8 @@ static int xilinx_spi_probe(struct spi_device *spi)
>>  	conf->spi = spi;
>>  
>>  	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
>> -				 xilinx_spi_apply_cclk_cycles);
>> +				 xilinx_spi_apply_cclk_cycles, "prog_b",
>> +				 "init-b");
>>  }
>>  
>>  #ifdef CONFIG_OF
>> --
>> 2.43.0
>> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 3/3] fpga: xilinx-selectmap: add new driver
@ 2024-02-06 15:48         ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-06 15:48 UTC (permalink / raw)
  To: Xu Yilun, krzysztof kozlowski+dt
  Cc: mdf, Allen VANDIVER, Brian CODY, hao wu, yilun xu, Tom Rix,
	Rob Herring, Conor Dooley, Michal Simek, linux-fpga, devicetree,
	linux-kernel, linux-arm-kernel

On Feb 4, 2024, at 3:10 AM, Xu Yilun yilun.xu@linux.intel.com wrote:
> On Wed, Jan 31, 2024 at 06:05:33PM -0500, Charles Perry wrote:
>> Xilinx 7 series FPGA can be programmed using a slave parallel port named
>> the SelectMAP interface in the datasheet. This slave interface is
>> compatible with the i.MX6 EIM bus controller but other types of external
>> memory mapped parallel bus might work.
>> 
>> xilinx-selectmap currently only supports the x8 mode where data is loaded
>> at one byte per rising edge of the clock, with the MSb of each byte
>> presented to the D0 pin.
>> 
>> Signed-off-by: Charles Perry <charles.perry@savoirfairelinux.com>
>> ---
>>  drivers/fpga/Kconfig            |   8 +++
>>  drivers/fpga/Makefile           |   1 +
>>  drivers/fpga/xilinx-core.c      |  11 +++-
>>  drivers/fpga/xilinx-core.h      |   3 +-
>>  drivers/fpga/xilinx-selectmap.c | 106 ++++++++++++++++++++++++++++++++
>>  drivers/fpga/xilinx-spi.c       |   3 +-
>>  6 files changed, 127 insertions(+), 5 deletions(-)
>>  create mode 100644 drivers/fpga/xilinx-selectmap.c
>> 
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index d27a1ebf40838..37b35f58f0dfb 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -67,6 +67,14 @@ config FPGA_MGR_STRATIX10_SOC
>>  config FPGA_MGR_XILINX_CORE
>>  	tristate
>>  
>> +config FPGA_MGR_XILINX_SELECTMAP
>> +	tristate "Xilinx Configuration over SelectMAP"
>> +	depends on HAS_IOMEM
>> +	select FPGA_MGR_XILINX_CORE
>> +	help
>> +	  FPGA manager driver support for Xilinx FPGA configuration
>> +	  over SelectMAP interface.
>> +
>>  config FPGA_MGR_XILINX_SPI
>>  	tristate "Xilinx Configuration over Slave Serial (SPI)"
>>  	depends on SPI
>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>> index 7ec795b6a5a70..aeb89bb13517e 100644
>> --- a/drivers/fpga/Makefile
>> +++ b/drivers/fpga/Makefile
>> @@ -16,6 +16,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
>>  obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
>>  obj-$(CONFIG_FPGA_MGR_TS73XX)		+= ts73xx-fpga.o
>>  obj-$(CONFIG_FPGA_MGR_XILINX_CORE)	+= xilinx-core.o
>> +obj-$(CONFIG_FPGA_MGR_XILINX_SELECTMAP)	+= xilinx-selectmap.o
>>  obj-$(CONFIG_FPGA_MGR_XILINX_SPI)	+= xilinx-spi.o
>>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
>> diff --git a/drivers/fpga/xilinx-core.c b/drivers/fpga/xilinx-core.c
>> index aff40e9394085..64117759be100 100644
>> --- a/drivers/fpga/xilinx-core.c
>> +++ b/drivers/fpga/xilinx-core.c
>> @@ -180,21 +180,26 @@ static const struct fpga_manager_ops xilinx_core_ops = {
>>  
>>  int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>>  		      xilinx_write_func write,
>> -		      xilinx_write_one_dummy_byte_func write_one_dummy_byte)
>> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
>> +		      const char *prog_con_id, const char *init_con_id)
> 
> These gpio name inputs are not necessary except for DTS format concern.
> Is it possible we don't change the names?
> 

Krzysztof won't accept the old names as they are non standard (contain a 
prohibited char "_" and use a "-b" prefix for active low). I agree that it
is cumbersome to have different gpio names injected in the core by the top 
level driver.

Can I change the GPIO names of xlnx,fpga-slave-serial? i.e.:

 * "prog_b" -> "prog"
 * "init-b" -> "init"

and keep a fallback in the driver so that current users of this driver keep
working without adaptation in the DT.

>>  {
>>  	struct fpga_manager *mgr;
>>  
>> +	if (!core || !dev || !write || !write_one_dummy_byte || !prog_con_id ||
>> +	    !init_con_id)
>> +		return -EINVAL;
> 
> These checks belong to Patch #1.
> 

Ok

>> +
>>  	core->dev = dev;
>>  	core->write = write;
>>  	core->write_one_dummy_byte = write_one_dummy_byte;
>>  
>>  	/* PROGRAM_B is active low */
>> -	core->prog_b = devm_gpiod_get(dev, "prog_b", GPIOD_OUT_LOW);
>> +	core->prog_b = devm_gpiod_get(dev, prog_con_id, GPIOD_OUT_LOW);
>>  	if (IS_ERR(core->prog_b))
>>  		return dev_err_probe(dev, PTR_ERR(core->prog_b),
>>  				     "Failed to get PROGRAM_B gpio\n");
>>  
>> -	core->init_b = devm_gpiod_get_optional(dev, "init-b", GPIOD_IN);
>> +	core->init_b = devm_gpiod_get_optional(dev, init_con_id, GPIOD_IN);
>>  	if (IS_ERR(core->init_b))
>>  		return dev_err_probe(dev, PTR_ERR(core->init_b),
>>  				     "Failed to get INIT_B gpio\n");
>> diff --git a/drivers/fpga/xilinx-core.h b/drivers/fpga/xilinx-core.h
>> index 40e120945ba70..817f0e551d093 100644
>> --- a/drivers/fpga/xilinx-core.h
>> +++ b/drivers/fpga/xilinx-core.h
>> @@ -22,6 +22,7 @@ struct xilinx_fpga_core {
>>  
>>  int xilinx_core_probe(struct xilinx_fpga_core *core, struct device *dev,
>>  		      xilinx_write_func write,
>> -		      xilinx_write_one_dummy_byte_func write_one_dummy_byte);
>> +		      xilinx_write_one_dummy_byte_func write_one_dummy_byte,
>> +		      const char *prog_con_id, const char *init_con_id);
>>  
>>  #endif /* __XILINX_CORE_H */
>> diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c
>> new file mode 100644
>> index 0000000000000..08054e19bb498
>> --- /dev/null
>> +++ b/drivers/fpga/xilinx-selectmap.c
>> @@ -0,0 +1,106 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Xilinx Spartan6 and 7 Series SelectMAP interface driver
>> + *
>> + * (C) 2024 Charles Perry <charles.perry@savoirfairelinux.com>
>> + *
>> + * Manage Xilinx FPGA firmware loaded over the SelectMAP configuration
>> + * interface.
>> + */
>> +
>> +#include "xilinx-core.h"
>> +
>> +#include <linux/platform_device.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/module.h>
>> +#include <linux/mod_devicetable.h>
>> +#include <linux/of.h>
>> +#include <linux/io.h>
>> +
>> +struct xilinx_selectmap_conf {
>> +	struct xilinx_fpga_core core;
>> +	void __iomem *base;
>> +	struct gpio_desc *csi_b;
>> +	struct gpio_desc *rdwr_b;
> 
> These 2 gpio_desc are not used globally, maybe remove them here.
> 

Ok

>> +};
>> +
>> +#define to_xilinx_selectmap_conf(obj) \
>> +	container_of(obj, struct xilinx_selectmap_conf, core)
>> +
>> +static int xilinx_selectmap_write(struct xilinx_fpga_core *core,
>> +				  const char *buf, size_t count)
>> +{
>> +	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
>> +	u32 i;
>> +
>> +	for (i = 0; i < count; ++i)
>> +		writeb(buf[i], conf->base);
>> +
>> +	return 0;
>> +}
>> +
>> +static int xilinx_selectmap_apply_padding(struct xilinx_fpga_core *core)
>> +{
>> +	struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core);
>> +
>> +	writeb(0xFF, conf->base);
> 
> Seems only one callback needed. Just use write() to xfer 1 byte?
> 
> Thanks,
> Yilun
> 

Yes, will be changed.

Thank you,
Charles

>> +	return 0;
>> +}
>> +
>> +static int xilinx_selectmap_probe(struct platform_device *pdev)
>> +{
>> +	struct xilinx_selectmap_conf *conf;
>> +	struct resource *r;
>> +	void __iomem *base;
>> +
>> +	conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
>> +	if (!conf)
>> +		return -ENOMEM;
>> +
>> +	base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
>> +	if (IS_ERR(base))
>> +		return dev_err_probe(&pdev->dev, PTR_ERR(base),
>> +				     "ioremap error\n");
>> +	conf->base = base;
>> +
>> +	/* CSI_B is active low */
>> +	conf->csi_b =
>> +		devm_gpiod_get_optional(&pdev->dev, "csi", GPIOD_OUT_HIGH);
>> +	if (IS_ERR(conf->csi_b))
>> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->csi_b),
>> +				     "Failed to get CSI_B gpio\n");
>> +
>> +	/* RDWR_B is active low */
>> +	conf->rdwr_b =
>> +		devm_gpiod_get_optional(&pdev->dev, "rdwr", GPIOD_OUT_HIGH);
>> +	if (IS_ERR(conf->rdwr_b))
>> +		return dev_err_probe(&pdev->dev, PTR_ERR(conf->rdwr_b),
>> +				     "Failed to get RDWR_B gpio\n");
>> +
>> +	return xilinx_core_probe(&conf->core, &pdev->dev,
>> +				 xilinx_selectmap_write,
>> +				 xilinx_selectmap_apply_padding, "prog",
>> +				 "init");
>> +}
>> +
>> +static const struct of_device_id xlnx_selectmap_of_match[] = {
>> +	{
>> +		.compatible = "xlnx,fpga-selectmap",
>> +	},
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(of, xlnx_selectmap_of_match);
>> +
>> +static struct platform_driver xilinx_selectmap_driver = {
>> +	.driver = {
>> +		.name = "xilinx-selectmap",
>> +		.of_match_table = xlnx_selectmap_of_match,
>> +	},
>> +	.probe  = xilinx_selectmap_probe,
>> +};
>> +
>> +module_platform_driver(xilinx_selectmap_driver);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Charles Perry <charles.perry@savoirfairelinux.com>");
>> +MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SelectMap");
>> diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c
>> index ec128dee97312..b9ab3d5da004c 100644
>> --- a/drivers/fpga/xilinx-spi.c
>> +++ b/drivers/fpga/xilinx-spi.c
>> @@ -74,7 +74,8 @@ static int xilinx_spi_probe(struct spi_device *spi)
>>  	conf->spi = spi;
>>  
>>  	return xilinx_core_probe(&conf->core, &spi->dev, xilinx_spi_write,
>> -				 xilinx_spi_apply_cclk_cycles);
>> +				 xilinx_spi_apply_cclk_cycles, "prog_b",
>> +				 "init-b");
>>  }
>>  
>>  #ifdef CONFIG_OF
>> --
>> 2.43.0
>> 

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

* Re: [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema
  2024-02-04  8:30       ` Xu Yilun
@ 2024-02-13 21:54         ` Charles Perry
  0 siblings, 0 replies; 44+ messages in thread
From: Charles Perry @ 2024-02-13 21:54 UTC (permalink / raw)
  To: Xu Yilun, Kris Chaplin
  Cc: Krzysztof Kozlowski, mdf, Michal Simek, hao wu, yilun xu, trix,
	krzysztof kozlowski+dt, Brian CODY, Allen VANDIVER, linux-fpga,
	devicetree, linux-kernel

On Feb 4, 2024, at 3:30 AM, Xu Yilun yilun.xu@linux.intel.com wrote:
> On Wed, Jan 31, 2024 at 11:03:25AM +0000, Kris Chaplin wrote:
>> Hello Krzysztof,
>> 
>> On 30/01/2024 16:09, Krzysztof Kozlowski wrote:
>> 
>> > > +
>> > > +description: |
>> > > +  Xilinx 7 Series FPGAs support a method of loading the bitstream over a
>> > > +  parallel port named the slave SelectMAP interface in the documentation. Only
>> > > +  the x8 mode is supported where data is loaded at one byte per rising edge of
>> > > +  the clock, with the MSB of each byte presented to the D0 pin.
>> > > +
>> > > +  Datasheets:
>> > > +
>> > > https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
>> > 
>> > I am surprised that AMD/Xilinx still did not update the document to
>> > modern naming (slave->secondary).
>> 
>> Thank you for bringing this up.
>> 
>> We are moving away from using non-inclusive technical terminology and are
>> removing non-inclusive language from our products and related collateral.
>> You will for some time find examples of non-inclusive language, especially
>> in our older products as we work to make these changes and align with
>> industry standards.  For new IP we're ensuring that we switch and stick to
>> inclusive terminology, as you may have seen with my recent w1 driver
>> submission.
>> 
>> SelectMAP is a decades-old interface and as such it is unlikely that we will
>> update this in all documentation dating back this time.  I shall however
>> look to understand what is planned here for active documentation and new
>> driver submissions.
> 
> Yes, I need review from AMD/Xilinx side. Especially the HW parts, and
> some namings of variables, e.g. if xilinx-core is proper for what products
> it supports, and won't be an issue in future.
> 
> Thanks,
> Yilun
> 
>> 
>> regards
>> Kris

Hello,

I chose the "-core" suffix as it seems widely used for core logic of device 
drivers for chips that comes in an i2c and spi flavour. It seems like "-common"
is also widespread, let me know if you prefer that suffix.

As for the HW parts, here's the compatibles used in the v3 patchset for 
convenience:
- xlnx,fpga-xc7s-selectmap
- xlnx,fpga-xc7a-selectmap
- xlnx,fpga-xc7k-selectmap
- xlnx,fpga-xc7v-selectmap

We're trying to be a bit more specific than the spi interface which uses
"xlnx,fpga-slave-serial"

Regards,
Charles

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

end of thread, other threads:[~2024-02-13 21:54 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-29 22:56 [PATCH 1/3] fpga: xilinx-spi: extract a common driver core Charles Perry
2024-01-29 22:56 ` [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema Charles Perry
2024-01-30  0:21   ` Rob Herring
2024-01-30  7:52   ` Krzysztof Kozlowski
2024-01-30  7:53     ` Krzysztof Kozlowski
2024-01-30 15:45     ` Charles Perry
2024-01-30 16:05       ` Krzysztof Kozlowski
2024-01-30 17:05         ` Charles Perry
2024-01-30 17:58           ` Krzysztof Kozlowski
2024-01-30 23:32             ` Charles Perry
2024-01-30 16:09   ` Krzysztof Kozlowski
2024-01-31 11:03     ` Kris Chaplin
2024-02-04  8:30       ` Xu Yilun
2024-02-13 21:54         ` Charles Perry
2024-01-29 22:56 ` [PATCH 3/3] fpga: xilinx-selectmap: add new driver Charles Perry
2024-01-30  7:56   ` Krzysztof Kozlowski
2024-01-31 23:05 ` [PATCH 0/3] " Charles Perry
2024-01-31 23:05   ` Charles Perry
2024-01-31 23:05   ` [PATCH 1/3] fpga: xilinx-spi: extract a common driver core Charles Perry
2024-01-31 23:05     ` Charles Perry
2024-02-04  8:22     ` Xu Yilun
2024-02-04  8:22       ` Xu Yilun
2024-02-06 15:39       ` Charles Perry
2024-02-06 15:39         ` Charles Perry
2024-01-31 23:05   ` [PATCH 2/3] dt-bindings: fpga: xlnx,fpga-slave-selectmap: add DT schema Charles Perry
2024-01-31 23:05     ` Charles Perry
2024-02-01  8:07     ` Krzysztof Kozlowski
2024-02-01  8:07       ` Krzysztof Kozlowski
2024-02-01 18:24       ` Charles Perry
2024-02-01 18:24         ` Charles Perry
2024-02-02 10:49         ` Krzysztof Kozlowski
2024-02-02 10:49           ` Krzysztof Kozlowski
2024-02-02 19:52           ` Charles Perry
2024-02-02 19:52             ` Charles Perry
2024-01-31 23:05   ` [PATCH 3/3] fpga: xilinx-selectmap: add new driver Charles Perry
2024-01-31 23:05     ` Charles Perry
2024-02-04  8:10     ` Xu Yilun
2024-02-04  8:10       ` Xu Yilun
2024-02-06 15:48       ` Charles Perry
2024-02-06 15:48         ` Charles Perry
2024-02-02 20:16   ` [PATCH 0/3] " Rob Herring
2024-02-02 20:16     ` Rob Herring
2024-02-02 20:53     ` Charles Perry
2024-02-02 20:53       ` Charles Perry

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.