linux-fpga.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
@ 2024-06-20 14:42 iansdannapel
  2024-06-20 18:05 ` Marco Pagani
  2024-06-28 15:23 ` [PATCH v2 0/3] Summary of changes iansdannapel
  0 siblings, 2 replies; 24+ messages in thread
From: iansdannapel @ 2024-06-20 14:42 UTC (permalink / raw)
  To: mdf, hao.wu, yilun.xu, trix, linux-kernel, linux-fpga; +Cc: Ian Dannapel

From: Ian Dannapel <iansdannapel@gmail.com>

Add a new driver for loading binary firmware using "SPI passive
programming" on Efinix FPGAs.

Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
---
 drivers/fpga/Kconfig      |   8 ++
 drivers/fpga/Makefile     |   1 +
 drivers/fpga/efinix-spi.c | 219 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 228 insertions(+)
 create mode 100644 drivers/fpga/efinix-spi.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 37b35f58f0df..cb3a6628fa71 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -83,6 +83,14 @@ config FPGA_MGR_XILINX_SPI
 	  FPGA manager driver support for Xilinx FPGA configuration
 	  over slave serial interface.
 
+config FPGA_MGR_EFINIX_SPI
+	tristate "Efinix FPGA configuration over SPI passive"
+	depends on SPI
+	help
+	  This option enables support for the FPGA manager driver to configure
+	  Efinix Trion and Titanium Series FPGAs over SPI using passive serial
+	  mode.
+
 config FPGA_MGR_ICE40_SPI
 	tristate "Lattice iCE40 SPI"
 	depends on OF && SPI
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index aeb89bb13517..adbd51d2cd1e 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -18,6 +18,7 @@ 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_EFINIX_SPI)	+= efinix-spi.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
 obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)	+= versal-fpga.o
diff --git a/drivers/fpga/efinix-spi.c b/drivers/fpga/efinix-spi.c
new file mode 100644
index 000000000000..7f7d7e6714ae
--- /dev/null
+++ b/drivers/fpga/efinix-spi.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Trion and Titanium Series FPGA SPI Passive Programming Driver
+ *
+ * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
+ *
+ * Ian Dannapel <iansdannapel@gmail.com>
+ *
+ * Manage Efinix FPGA firmware that is loaded over SPI using
+ * the serial configuration interface.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+#include <linux/sizes.h>
+
+struct efinix_spi_conf {
+	struct spi_device *spi;
+	struct gpio_desc *done;
+	struct gpio_desc *reset;
+	struct gpio_desc *cs;
+	enum fpga_mgr_states state;
+};
+
+static int get_done_gpio(struct fpga_manager *mgr)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	int ret = 0;
+
+	if (conf->done) {
+		ret = gpiod_get_value(conf->done);
+		if (ret < 0)
+			dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
+	}
+
+	return ret;
+}
+
+static void reset(struct fpga_manager *mgr)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+
+	gpiod_set_value(conf->reset, 1);
+	/* wait tCRESET_N */
+	usleep_range(5, 15);
+	gpiod_set_value(conf->reset, 0);
+	conf->state = FPGA_MGR_STATE_RESET;
+}
+
+static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+
+	return conf->state;
+}
+
+static int efinix_spi_apply_clk_cycles(struct fpga_manager *mgr)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	char data[13] = {0};
+
+	return spi_write(conf->spi, data, sizeof(data));
+}
+
+static int efinix_spi_write_init(struct fpga_manager *mgr,
+				 struct fpga_image_info *info,
+				 const char *buf, size_t count)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+
+	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
+		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
+		return -EINVAL;
+	}
+
+	/* reset with chip select active */
+	gpiod_set_value(conf->cs, 1);
+	usleep_range(5, 15);
+	reset(mgr);
+
+	/* wait tDMIN */
+	usleep_range(100, 150);
+
+	return 0;
+}
+
+static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
+			    size_t count)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	int ret;
+
+	ret = spi_write(conf->spi, buf, count);
+	if (ret) {
+		dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
+			ret);
+		return ret;
+	}
+
+	/* append at least 100 clock cycles */
+	efinix_spi_apply_clk_cycles(mgr);
+
+	/* release chip select */
+	gpiod_set_value(conf->cs, 0);
+
+	return 0;
+}
+
+static int efinix_spi_write_complete(struct fpga_manager *mgr,
+				     struct fpga_image_info *info)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	unsigned long timeout =
+		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
+	bool expired = false;
+	int done;
+
+	if (conf->done) {
+		while (!expired) {
+			expired = time_after(jiffies, timeout);
+
+			done = get_done_gpio(mgr);
+			if (done < 0)
+				return done;
+
+			if (done)
+				break;
+		}
+	}
+
+	if (expired)
+		return -ETIMEDOUT;
+
+	/* wait tUSER */
+	usleep_range(75, 125);
+
+	return 0;
+}
+
+static const struct fpga_manager_ops efinix_spi_ops = {
+	.state = efinix_spi_state,
+	.write_init = efinix_spi_write_init,
+	.write = efinix_spi_write,
+	.write_complete = efinix_spi_write_complete,
+};
+
+static int efinix_spi_probe(struct spi_device *spi)
+{
+	struct efinix_spi_conf *conf;
+	struct fpga_manager *mgr;
+
+	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
+	if (!conf)
+		return -ENOMEM;
+
+	conf->spi = spi;
+	conf->state = FPGA_MGR_STATE_UNKNOWN;
+
+	conf->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->reset))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->reset),
+				"Failed to get RESET gpio\n");
+
+	conf->cs = devm_gpiod_get(&spi->dev, "cs", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->cs))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
+				"Failed to get CHIP_SELECT gpio\n");
+
+	if (!(spi->mode & SPI_CPHA) || !(spi->mode & SPI_CPOL))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
+				"Unsupported SPI mode, set CPHA and CPOL\n");
+
+	conf->done = devm_gpiod_get_optional(&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,
+				"Efinix SPI Passive Programming FPGA Manager",
+					&efinix_spi_ops, conf);
+
+	return PTR_ERR_OR_ZERO(mgr);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id efnx_spi_of_match[] = {
+	{ .compatible = "efnx,fpga-spi-passive", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, efnx_spi_of_match);
+#endif
+
+static const struct spi_device_id efinix_ids[] = {
+	{ "fpga-spi-passive", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, efinix_ids);
+
+
+static struct spi_driver efinix_spi_passive_driver = {
+	.driver = {
+		.name = "efnx-fpga-spi-passive",
+		.of_match_table = of_match_ptr(efnx_spi_of_match),
+	},
+	.probe = efinix_spi_probe,
+	.id_table = efinix_ids,
+};
+
+module_spi_driver(efinix_spi_passive_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ian Dannapel <iansdannapel@gmail.com>");
+MODULE_DESCRIPTION("Load Efinix FPGA firmware over SPI passive");
-- 
2.34.1


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

* Re: [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-06-20 14:42 [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
@ 2024-06-20 18:05 ` Marco Pagani
  2024-06-28 15:23 ` [PATCH v2 0/3] Summary of changes iansdannapel
  1 sibling, 0 replies; 24+ messages in thread
From: Marco Pagani @ 2024-06-20 18:05 UTC (permalink / raw)
  To: iansdannapel; +Cc: mdf, hao.wu, yilun.xu, trix, linux-kernel, linux-fpga



On 2024-06-20 16:42, iansdannapel@gmail.com wrote:
> From: Ian Dannapel <iansdannapel@gmail.com>
> 
> Add a new driver for loading binary firmware using "SPI passive
> programming" on Efinix FPGAs.
> 
> Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> ---
>  drivers/fpga/Kconfig      |   8 ++
>  drivers/fpga/Makefile     |   1 +
>  drivers/fpga/efinix-spi.c | 219 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 228 insertions(+)
>  create mode 100644 drivers/fpga/efinix-spi.c
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 37b35f58f0df..cb3a6628fa71 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -83,6 +83,14 @@ config FPGA_MGR_XILINX_SPI
>  	  FPGA manager driver support for Xilinx FPGA configuration
>  	  over slave serial interface.
>  
> +config FPGA_MGR_EFINIX_SPI
> +	tristate "Efinix FPGA configuration over SPI passive"
> +	depends on SPI
> +	help
> +	  This option enables support for the FPGA manager driver to configure
> +	  Efinix Trion and Titanium Series FPGAs over SPI using passive serial
> +	  mode.
> +
>  config FPGA_MGR_ICE40_SPI
>  	tristate "Lattice iCE40 SPI"
>  	depends on OF && SPI
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index aeb89bb13517..adbd51d2cd1e 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -18,6 +18,7 @@ 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_EFINIX_SPI)	+= efinix-spi.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
>  obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)	+= versal-fpga.o
> diff --git a/drivers/fpga/efinix-spi.c b/drivers/fpga/efinix-spi.c
> new file mode 100644
> index 000000000000..7f7d7e6714ae
> --- /dev/null
> +++ b/drivers/fpga/efinix-spi.c
> @@ -0,0 +1,219 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Trion and Titanium Series FPGA SPI Passive Programming Driver
> + *
> + * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
> + *
> + * Ian Dannapel <iansdannapel@gmail.com>
> + *
> + * Manage Efinix FPGA firmware that is loaded over SPI using
> + * the serial configuration interface.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/of.h>
> +#include <linux/spi/spi.h>
> +#include <linux/sizes.h>
> +
> +struct efinix_spi_conf {
> +	struct spi_device *spi;
> +	struct gpio_desc *done;
> +	struct gpio_desc *reset;
> +	struct gpio_desc *cs;
> +	enum fpga_mgr_states state;

This is a bit confusing. I wouldn't use an fpga_mgr_states enum in the
context struct of the low-level module since they define the state of
the fpga manager core. If possible, I would have read the physical
state of the device in the state op to determine if the fpga is
already programmed or in an unknown or error state, since the op is
called only during device registration to set the initial state.

Also, a quick check with checkpatch.pl returned a couple of style
issues.

> +};
> +
> +static int get_done_gpio(struct fpga_manager *mgr)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	int ret = 0;
> +
> +	if (conf->done) {
> +		ret = gpiod_get_value(conf->done);
> +		if (ret < 0)
> +			dev_err(&mgr->dev, "Error reading DONE (%d)\n", ret);
> +	}
> +
> +	return ret;
> +}
> +
> +static void reset(struct fpga_manager *mgr)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +
> +	gpiod_set_value(conf->reset, 1);
> +	/* wait tCRESET_N */
> +	usleep_range(5, 15);
> +	gpiod_set_value(conf->reset, 0);
> +	conf->state = FPGA_MGR_STATE_RESET;
> +}
> +
> +static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +
> +	return conf->state;
> +}
> +
> +static int efinix_spi_apply_clk_cycles(struct fpga_manager *mgr)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	char data[13] = {0};
> +
> +	return spi_write(conf->spi, data, sizeof(data));
> +}
> +
> +static int efinix_spi_write_init(struct fpga_manager *mgr,
> +				 struct fpga_image_info *info,
> +				 const char *buf, size_t count)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +
> +	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> +		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> +		return -EINVAL;
> +	}
> +
> +	/* reset with chip select active */
> +	gpiod_set_value(conf->cs, 1);
> +	usleep_range(5, 15);
> +	reset(mgr);
> +
> +	/* wait tDMIN */
> +	usleep_range(100, 150);
> +
> +	return 0;
> +}
> +
> +static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
> +			    size_t count)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	int ret;
> +
> +	ret = spi_write(conf->spi, buf, count);
> +	if (ret) {
> +		dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	/* append at least 100 clock cycles */
> +	efinix_spi_apply_clk_cycles(mgr);
> +
> +	/* release chip select */
> +	gpiod_set_value(conf->cs, 0);
> +
> +	return 0;
> +}
> +
> +static int efinix_spi_write_complete(struct fpga_manager *mgr,
> +				     struct fpga_image_info *info)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	unsigned long timeout =
> +		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
> +	bool expired = false;
> +	int done;
> +
> +	if (conf->done) {
> +		while (!expired) {
> +			expired = time_after(jiffies, timeout);
> +
> +			done = get_done_gpio(mgr);
> +			if (done < 0)
> +				return done;
> +
> +			if (done)
> +				break;
> +		}
> +	}
> +
> +	if (expired)
> +		return -ETIMEDOUT;
> +
> +	/* wait tUSER */
> +	usleep_range(75, 125);
> +
> +	return 0;
> +}
> +
> +static const struct fpga_manager_ops efinix_spi_ops = {
> +	.state = efinix_spi_state,
> +	.write_init = efinix_spi_write_init,
> +	.write = efinix_spi_write,
> +	.write_complete = efinix_spi_write_complete,
> +};
> +
> +static int efinix_spi_probe(struct spi_device *spi)
> +{
> +	struct efinix_spi_conf *conf;
> +	struct fpga_manager *mgr;
> +
> +	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
> +	if (!conf)
> +		return -ENOMEM;
> +
> +	conf->spi = spi;
> +	conf->state = FPGA_MGR_STATE_UNKNOWN;
> +
> +	conf->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->reset))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->reset),
> +				"Failed to get RESET gpio\n");
> +
> +	conf->cs = devm_gpiod_get(&spi->dev, "cs", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->cs))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
> +				"Failed to get CHIP_SELECT gpio\n");
> +
> +	if (!(spi->mode & SPI_CPHA) || !(spi->mode & SPI_CPOL))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
> +				"Unsupported SPI mode, set CPHA and CPOL\n");
> +
> +	conf->done = devm_gpiod_get_optional(&spi->dev, "done", GPIOD_IN);

I'm not familiar with this FPGA, but from the code, it seems to me that
you also want to support the case where a "done" line is not available.
In such a case, what happens if you start a new programming cycle before
waiting for the previous one to complete? Also, checking if (conf->done)
in get_done_gpio() seems to be redundant since the function is called only
in efinix_spi_write_complete() after checking if (conf->done).


> +	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,
> +				"Efinix SPI Passive Programming FPGA Manager",
> +					&efinix_spi_ops, conf);
> +
> +	return PTR_ERR_OR_ZERO(mgr);
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id efnx_spi_of_match[] = {
> +	{ .compatible = "efnx,fpga-spi-passive", },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, efnx_spi_of_match);
> +#endif
> +
> +static const struct spi_device_id efinix_ids[] = {
> +	{ "fpga-spi-passive", 0 },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(spi, efinix_ids);
> +
> +
> +static struct spi_driver efinix_spi_passive_driver = {
> +	.driver = {
> +		.name = "efnx-fpga-spi-passive",
> +		.of_match_table = of_match_ptr(efnx_spi_of_match),
> +	},
> +	.probe = efinix_spi_probe,
> +	.id_table = efinix_ids,
> +};
> +
> +module_spi_driver(efinix_spi_passive_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Ian Dannapel <iansdannapel@gmail.com>");
> +MODULE_DESCRIPTION("Load Efinix FPGA firmware over SPI passive");

Thanks,
Marco


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

* [PATCH v2 0/3] Summary of changes
  2024-06-20 14:42 [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
  2024-06-20 18:05 ` Marco Pagani
@ 2024-06-28 15:23 ` iansdannapel
  2024-06-28 15:23   ` [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
                     ` (2 more replies)
  1 sibling, 3 replies; 24+ messages in thread
From: iansdannapel @ 2024-06-28 15:23 UTC (permalink / raw)
  To: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel
  Cc: Ian Dannapel

Patch 1:
- Add trion/titanium specific compatibles
- done gpio renamed to cdone, as referred in the datasheet
- reset gpio renamed to creset, as referred in the datasheet
- removed fpga_mgr_states from the context struct of the low-level module
[attached: v2-0001-fpga-Add-Efinix-Trion-Titanium-serial-SPI-program.patch]

Patch 2:
- corrected examples compatible/reg/others order
- fixed 'make dt_binding_check'
[attached: v2-0002-dt-bindings-fpga-Add-Efinix-serial-SPI-programmin.patch]

Patch 3:
- renamed prefix to "efinix"
[attached: v2-0003-dt-bindings-vendor-prefix-Add-prefix-for-Efinix-I.patch]

Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>

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

* [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-06-28 15:23 ` [PATCH v2 0/3] Summary of changes iansdannapel
@ 2024-06-28 15:23   ` iansdannapel
  2024-07-02 21:27     ` Dan Carpenter
  2024-07-12  6:53     ` Xu Yilun
  2024-06-28 15:23   ` [PATCH v2 2/3] dt-bindings: fpga: Add Efinix serial SPI programming bindings iansdannapel
  2024-06-28 15:23   ` [PATCH v2 3/3] dt-bindings: vendor-prefix: Add prefix for Efinix, Inc iansdannapel
  2 siblings, 2 replies; 24+ messages in thread
From: iansdannapel @ 2024-06-28 15:23 UTC (permalink / raw)
  To: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel
  Cc: Ian Dannapel

From: Ian Dannapel <iansdannapel@gmail.com>

Add a new driver for loading binary firmware using "SPI passive
programming" on Efinix FPGAs.

Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
---
 drivers/fpga/Kconfig                    |   8 +
 drivers/fpga/Makefile                   |   1 +
 drivers/fpga/efinix-trion-spi-passive.c | 219 ++++++++++++++++++++++++
 3 files changed, 228 insertions(+)
 create mode 100644 drivers/fpga/efinix-trion-spi-passive.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 37b35f58f0df..25579510e49e 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -83,6 +83,14 @@ config FPGA_MGR_XILINX_SPI
 	  FPGA manager driver support for Xilinx FPGA configuration
 	  over slave serial interface.
 
+config FPGA_MGR_EFINIX_SPI
+	tristate "Efinix FPGA configuration over SPI passive"
+	depends on SPI
+	help
+	  This option enables support for the FPGA manager driver to
+	  configure Efinix Trion and Titanium Series FPGAs over SPI
+	  using passive serial mode.
+
 config FPGA_MGR_ICE40_SPI
 	tristate "Lattice iCE40 SPI"
 	depends on OF && SPI
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index aeb89bb13517..1a95124ff847 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -18,6 +18,7 @@ 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_EFINIX_SPI)	+= efinix-trion-spi-passive.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
 obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)	+= versal-fpga.o
diff --git a/drivers/fpga/efinix-trion-spi-passive.c b/drivers/fpga/efinix-trion-spi-passive.c
new file mode 100644
index 000000000000..eb2592e788b9
--- /dev/null
+++ b/drivers/fpga/efinix-trion-spi-passive.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Trion and Titanium Series FPGA SPI Passive Programming Driver
+ *
+ * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
+ *
+ * Ian Dannapel <iansdannapel@gmail.com>
+ *
+ * Manage Efinix FPGA firmware that is loaded over SPI using
+ * the serial configuration interface.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+#include <linux/sizes.h>
+
+struct efinix_spi_conf {
+	struct spi_device *spi;
+	struct gpio_desc *cdone;
+	struct gpio_desc *creset;
+	struct gpio_desc *cs;
+};
+
+static int get_cdone_gpio(struct fpga_manager *mgr)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	int ret;
+
+	ret = gpiod_get_value(conf->cdone);
+	if (ret < 0)
+		dev_err(&mgr->dev, "Error reading CDONE (%d)\n", ret);
+
+	return ret;
+}
+
+static void reset(struct fpga_manager *mgr)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+
+	gpiod_set_value(conf->creset, 1);
+	/* wait tCRESET_N */
+	usleep_range(5, 15);
+	gpiod_set_value(conf->creset, 0);
+}
+
+static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+
+	if (conf->cdone && get_cdone_gpio(mgr) == 1)
+		return FPGA_MGR_STATE_OPERATING;
+
+	return FPGA_MGR_STATE_UNKNOWN;
+}
+
+static int efinix_spi_apply_clk_cycles(struct fpga_manager *mgr)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	char data[13] = {0};
+
+	return spi_write(conf->spi, data, sizeof(data));
+}
+
+static int efinix_spi_write_init(struct fpga_manager *mgr,
+				 struct fpga_image_info *info,
+				 const char *buf, size_t count)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+
+	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
+		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
+		return -EINVAL;
+	}
+
+	/* reset with chip select active */
+	gpiod_set_value(conf->cs, 1);
+	usleep_range(5, 15);
+	reset(mgr);
+
+	/* wait tDMIN */
+	usleep_range(100, 150);
+
+	return 0;
+}
+
+static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
+			    size_t count)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	int ret;
+
+	ret = spi_write(conf->spi, buf, count);
+	if (ret) {
+		dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
+			ret);
+		return ret;
+	}
+
+	/* append at least 100 clock cycles */
+	efinix_spi_apply_clk_cycles(mgr);
+
+	/* release chip select */
+	gpiod_set_value(conf->cs, 0);
+
+	return 0;
+}
+
+static int efinix_spi_write_complete(struct fpga_manager *mgr,
+				     struct fpga_image_info *info)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	unsigned long timeout =
+		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
+	bool expired = false;
+	int done;
+
+	if (conf->cdone) {
+		while (!expired) {
+			expired = time_after(jiffies, timeout);
+
+			done = get_cdone_gpio(mgr);
+			if (done < 0)
+				return done;
+
+			if (done)
+				break;
+		}
+	}
+
+	if (expired)
+		return -ETIMEDOUT;
+
+	/* wait tUSER */
+	usleep_range(75, 125);
+
+	return 0;
+}
+
+static const struct fpga_manager_ops efinix_spi_ops = {
+	.state = efinix_spi_state,
+	.write_init = efinix_spi_write_init,
+	.write = efinix_spi_write,
+	.write_complete = efinix_spi_write_complete,
+};
+
+static int efinix_spi_probe(struct spi_device *spi)
+{
+	struct efinix_spi_conf *conf;
+	struct fpga_manager *mgr;
+
+	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
+	if (!conf)
+		return -ENOMEM;
+
+	conf->spi = spi;
+
+	conf->creset = devm_gpiod_get(&spi->dev, "creset", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->creset))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->creset),
+				"Failed to get RESET gpio\n");
+
+	conf->cs = devm_gpiod_get(&spi->dev, "cs", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->cs))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
+				"Failed to get CHIP_SELECT gpio\n");
+
+	if (!(spi->mode & SPI_CPHA) || !(spi->mode & SPI_CPOL))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
+				"Unsupported SPI mode, set CPHA and CPOL\n");
+
+	conf->cdone = devm_gpiod_get_optional(&spi->dev, "cdone", GPIOD_IN);
+	if (IS_ERR(conf->cdone))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->cdone),
+				"Failed to get CDONE gpio\n");
+
+	mgr = devm_fpga_mgr_register(&spi->dev,
+				"Efinix SPI Passive Programming FPGA Manager",
+					&efinix_spi_ops, conf);
+
+	return PTR_ERR_OR_ZERO(mgr);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id efnx_spi_of_match[] = {
+	{ .compatible = "efinix,trion-spi-passive", },
+	{ .compatible = "efinix,titanium-spi-passive", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, efnx_spi_of_match);
+#endif
+
+static const struct spi_device_id efinix_ids[] = {
+	{ "trion-spi-passive", 0 },
+	{ "titanium-spi-passive", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(spi, efinix_ids);
+
+
+static struct spi_driver efinix_spi_passive_driver = {
+	.driver = {
+		.name = "efinix-fpga-spi-passive",
+		.of_match_table = of_match_ptr(efnx_spi_of_match),
+	},
+	.probe = efinix_spi_probe,
+	.id_table = efinix_ids,
+};
+
+module_spi_driver(efinix_spi_passive_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ian Dannapel <iansdannapel@gmail.com>");
+MODULE_DESCRIPTION("Load Efinix FPGA firmware over SPI passive");
-- 
2.34.1


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

* [PATCH v2 2/3] dt-bindings: fpga: Add Efinix serial SPI programming bindings
  2024-06-28 15:23 ` [PATCH v2 0/3] Summary of changes iansdannapel
  2024-06-28 15:23   ` [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
@ 2024-06-28 15:23   ` iansdannapel
  2024-06-28 16:07     ` Conor Dooley
  2024-06-28 15:23   ` [PATCH v2 3/3] dt-bindings: vendor-prefix: Add prefix for Efinix, Inc iansdannapel
  2 siblings, 1 reply; 24+ messages in thread
From: iansdannapel @ 2024-06-28 15:23 UTC (permalink / raw)
  To: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel
  Cc: Ian Dannapel

From: Ian Dannapel <iansdannapel@gmail.com>

Add device tree binding documentation for configuring Efinix FPGA
using serial SPI passive programming mode.

Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
---
 .../fpga/efinix,trion-spi-passive.yaml        | 81 +++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fpga/efinix,trion-spi-passive.yaml

diff --git a/Documentation/devicetree/bindings/fpga/efinix,trion-spi-passive.yaml b/Documentation/devicetree/bindings/fpga/efinix,trion-spi-passive.yaml
new file mode 100644
index 000000000000..d44a9d0627b6
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/efinix,trion-spi-passive.yaml
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/efinix,trion-spi-passive.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Efinix SPI FPGA Manager
+
+maintainers:
+  - Ian Dannapel <iansdannapel@gmail.com>
+
+description: |
+  Efinix Trion and Titanium Series FPGAs support a method of loading the
+  bitstream over what is referred to as "SPI Passive Programming".
+  Only serial (1x bus width) is supported, setting the programming mode
+  is not in the scope the this manager and must be done elsewhere.
+
+  References:
+  - https://www.efinixinc.com/docs/an033-configuring-titanium-fpgas-v2.6.pdf
+  - https://www.efinixinc.com/docs/an006-configuring-trion-fpgas-v6.0.pdf
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+  compatible:
+    enum:
+      - efinix,trion-spi-passive
+      - efinix,titanium-spi-passive
+
+  spi-cpha: true
+
+  spi-cpol: true
+
+  spi-max-frequency:
+    maximum: 25000000
+
+  reg:
+    maxItems: 1
+
+  creset-gpios:
+    description:
+      reset and re-configuration trigger pin (low active)
+    maxItems: 1
+
+  cs-gpios:
+    description:
+      chip-select pin (low active)
+    maxItems: 1
+
+  cdone-gpios:
+    description:
+      optional configuration done status pin (high active)
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - creset-gpios
+  - cs-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      fpga_mgr_spi: fpga-mgr@0 {
+        compatible = "efinix,trion-spi-passive";
+        reg = <0>;
+        spi-max-frequency = <25000000>;
+        spi-cpha;
+        spi-cpol;
+        creset-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>;
+        cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+        cdone-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
+      };
+    };
+...
-- 
2.34.1


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

* [PATCH v2 3/3] dt-bindings: vendor-prefix: Add prefix for Efinix, Inc.
  2024-06-28 15:23 ` [PATCH v2 0/3] Summary of changes iansdannapel
  2024-06-28 15:23   ` [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
  2024-06-28 15:23   ` [PATCH v2 2/3] dt-bindings: fpga: Add Efinix serial SPI programming bindings iansdannapel
@ 2024-06-28 15:23   ` iansdannapel
  2024-06-28 16:00     ` Conor Dooley
  2024-07-02  8:57     ` Alexander Dahl
  2 siblings, 2 replies; 24+ messages in thread
From: iansdannapel @ 2024-06-28 15:23 UTC (permalink / raw)
  To: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel
  Cc: Ian Dannapel

From: Ian Dannapel <iansdannapel@gmail.com>

Add entry for Efinix, Inc. (https://www.efinixinc.com/)

Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index fbf47f0bacf1..6175719c1fb6 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -422,6 +422,8 @@ patternProperties:
     description: Emtop Embedded Solutions
   "^eeti,.*":
     description: eGalax_eMPIA Technology Inc
+  "^efinix,.*":
+    description: Efinix, Inc.
   "^einfochips,.*":
     description: Einfochips
   "^eink,.*":
-- 
2.34.1


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

* Re: [PATCH v2 3/3] dt-bindings: vendor-prefix: Add prefix for Efinix, Inc.
  2024-06-28 15:23   ` [PATCH v2 3/3] dt-bindings: vendor-prefix: Add prefix for Efinix, Inc iansdannapel
@ 2024-06-28 16:00     ` Conor Dooley
  2024-07-02  8:57     ` Alexander Dahl
  1 sibling, 0 replies; 24+ messages in thread
From: Conor Dooley @ 2024-06-28 16:00 UTC (permalink / raw)
  To: iansdannapel
  Cc: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 298 bytes --]

On Fri, Jun 28, 2024 at 05:23:48PM +0200, iansdannapel@gmail.com wrote:
> From: Ian Dannapel <iansdannapel@gmail.com>
> 
> Add entry for Efinix, Inc. (https://www.efinixinc.com/)
> 
> Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>

Acked-by: Conor Dooley <conor.dooley@microchip.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 2/3] dt-bindings: fpga: Add Efinix serial SPI programming bindings
  2024-06-28 15:23   ` [PATCH v2 2/3] dt-bindings: fpga: Add Efinix serial SPI programming bindings iansdannapel
@ 2024-06-28 16:07     ` Conor Dooley
  0 siblings, 0 replies; 24+ messages in thread
From: Conor Dooley @ 2024-06-28 16:07 UTC (permalink / raw)
  To: iansdannapel
  Cc: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 328 bytes --]

> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    spi {
> +      #address-cells = <1>;
> +      #size-cells = <0>;
> +      fpga_mgr_spi: fpga-mgr@0 {

nit: the label here isn't used and can be dropped.
Otherwise this looks okay to me,
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>

Thanks,
Conor.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v2 3/3] dt-bindings: vendor-prefix: Add prefix for Efinix, Inc.
  2024-06-28 15:23   ` [PATCH v2 3/3] dt-bindings: vendor-prefix: Add prefix for Efinix, Inc iansdannapel
  2024-06-28 16:00     ` Conor Dooley
@ 2024-07-02  8:57     ` Alexander Dahl
  1 sibling, 0 replies; 24+ messages in thread
From: Alexander Dahl @ 2024-07-02  8:57 UTC (permalink / raw)
  To: iansdannapel
  Cc: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel

Hei hei,

Am Fri, Jun 28, 2024 at 05:23:48PM +0200 schrieb iansdannapel@gmail.com:
> From: Ian Dannapel <iansdannapel@gmail.com>
> 
> Add entry for Efinix, Inc. (https://www.efinixinc.com/)
> 
> Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> index fbf47f0bacf1..6175719c1fb6 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> @@ -422,6 +422,8 @@ patternProperties:
>      description: Emtop Embedded Solutions
>    "^eeti,.*":
>      description: eGalax_eMPIA Technology Inc
> +  "^efinix,.*":
> +    description: Efinix, Inc.
>    "^einfochips,.*":
>      description: Einfochips
>    "^eink,.*":

Acked-by: Alexander Dahl <ada@thorsis.com>

Greets
Alex

> -- 
> 2.34.1
> 
> 

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

* Re: [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-06-28 15:23   ` [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
@ 2024-07-02 21:27     ` Dan Carpenter
  2024-07-12  6:53     ` Xu Yilun
  1 sibling, 0 replies; 24+ messages in thread
From: Dan Carpenter @ 2024-07-02 21:27 UTC (permalink / raw)
  To: oe-kbuild, iansdannapel, Moritz Fischer, Wu Hao, Xu Yilun,
	Tom Rix, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Heiko Stuebner, Neil Armstrong, Sebastian Reichel, Chris Morgan,
	Michael Riesch, Rafał Miłecki, Andre Przywara,
	Linus Walleij, linux-fpga, devicetree, linux-kernel
  Cc: lkp, oe-kbuild-all, Ian Dannapel

Hi,

kernel test robot noticed the following build warnings:

https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/iansdannapel-gmail-com/fpga-Add-Efinix-Trion-Titanium-serial-SPI-programming-driver/20240630-044745
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20240628152348.61133-2-iansdannapel%40gmail.com
patch subject: [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
config: powerpc-randconfig-r081-20240701 (https://download.01.org/0day-ci/archive/20240703/202407030525.VHF3He6K-lkp@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202407030525.VHF3He6K-lkp@intel.com/

smatch warnings:
drivers/fpga/efinix-trion-spi-passive.c:174 efinix_spi_probe() warn: passing zero to 'PTR_ERR'

vim +/PTR_ERR +174 drivers/fpga/efinix-trion-spi-passive.c

4c272ecc14b70f Ian Dannapel 2024-06-28  152  static int efinix_spi_probe(struct spi_device *spi)
4c272ecc14b70f Ian Dannapel 2024-06-28  153  {
4c272ecc14b70f Ian Dannapel 2024-06-28  154  	struct efinix_spi_conf *conf;
4c272ecc14b70f Ian Dannapel 2024-06-28  155  	struct fpga_manager *mgr;
4c272ecc14b70f Ian Dannapel 2024-06-28  156  
4c272ecc14b70f Ian Dannapel 2024-06-28  157  	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
4c272ecc14b70f Ian Dannapel 2024-06-28  158  	if (!conf)
4c272ecc14b70f Ian Dannapel 2024-06-28  159  		return -ENOMEM;
4c272ecc14b70f Ian Dannapel 2024-06-28  160  
4c272ecc14b70f Ian Dannapel 2024-06-28  161  	conf->spi = spi;
4c272ecc14b70f Ian Dannapel 2024-06-28  162  
4c272ecc14b70f Ian Dannapel 2024-06-28  163  	conf->creset = devm_gpiod_get(&spi->dev, "creset", GPIOD_OUT_HIGH);
4c272ecc14b70f Ian Dannapel 2024-06-28  164  	if (IS_ERR(conf->creset))
4c272ecc14b70f Ian Dannapel 2024-06-28  165  		return dev_err_probe(&spi->dev, PTR_ERR(conf->creset),
4c272ecc14b70f Ian Dannapel 2024-06-28  166  				"Failed to get RESET gpio\n");
4c272ecc14b70f Ian Dannapel 2024-06-28  167  
4c272ecc14b70f Ian Dannapel 2024-06-28  168  	conf->cs = devm_gpiod_get(&spi->dev, "cs", GPIOD_OUT_HIGH);
4c272ecc14b70f Ian Dannapel 2024-06-28  169  	if (IS_ERR(conf->cs))
4c272ecc14b70f Ian Dannapel 2024-06-28  170  		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
4c272ecc14b70f Ian Dannapel 2024-06-28  171  				"Failed to get CHIP_SELECT gpio\n");
4c272ecc14b70f Ian Dannapel 2024-06-28  172  
4c272ecc14b70f Ian Dannapel 2024-06-28  173  	if (!(spi->mode & SPI_CPHA) || !(spi->mode & SPI_CPOL))
4c272ecc14b70f Ian Dannapel 2024-06-28 @174  		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),

s/conf->cs/-EINVAL/

4c272ecc14b70f Ian Dannapel 2024-06-28  175  				"Unsupported SPI mode, set CPHA and CPOL\n");
4c272ecc14b70f Ian Dannapel 2024-06-28  176  
4c272ecc14b70f Ian Dannapel 2024-06-28  177  	conf->cdone = devm_gpiod_get_optional(&spi->dev, "cdone", GPIOD_IN);
4c272ecc14b70f Ian Dannapel 2024-06-28  178  	if (IS_ERR(conf->cdone))
4c272ecc14b70f Ian Dannapel 2024-06-28  179  		return dev_err_probe(&spi->dev, PTR_ERR(conf->cdone),
4c272ecc14b70f Ian Dannapel 2024-06-28  180  				"Failed to get CDONE gpio\n");
4c272ecc14b70f Ian Dannapel 2024-06-28  181  
4c272ecc14b70f Ian Dannapel 2024-06-28  182  	mgr = devm_fpga_mgr_register(&spi->dev,
4c272ecc14b70f Ian Dannapel 2024-06-28  183  				"Efinix SPI Passive Programming FPGA Manager",
4c272ecc14b70f Ian Dannapel 2024-06-28  184  					&efinix_spi_ops, conf);
4c272ecc14b70f Ian Dannapel 2024-06-28  185  
4c272ecc14b70f Ian Dannapel 2024-06-28  186  	return PTR_ERR_OR_ZERO(mgr);
4c272ecc14b70f Ian Dannapel 2024-06-28  187  }

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


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

* Re: [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-06-28 15:23   ` [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
  2024-07-02 21:27     ` Dan Carpenter
@ 2024-07-12  6:53     ` Xu Yilun
  2024-07-25 13:44       ` Ian Dannapel
  1 sibling, 1 reply; 24+ messages in thread
From: Xu Yilun @ 2024-07-12  6:53 UTC (permalink / raw)
  To: iansdannapel
  Cc: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel

On Fri, Jun 28, 2024 at 05:23:46PM +0200, iansdannapel@gmail.com wrote:
> From: Ian Dannapel <iansdannapel@gmail.com>
> 

Please don't reply to the previous series when you post a new version.

> Add a new driver for loading binary firmware using "SPI passive

Loading to some nvram or reporgraming to FPGA logic blocks.

> programming" on Efinix FPGAs.
> 
> Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> ---
>  drivers/fpga/Kconfig                    |   8 +
>  drivers/fpga/Makefile                   |   1 +
>  drivers/fpga/efinix-trion-spi-passive.c | 219 ++++++++++++++++++++++++
>  3 files changed, 228 insertions(+)
>  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 37b35f58f0df..25579510e49e 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -83,6 +83,14 @@ config FPGA_MGR_XILINX_SPI
>  	  FPGA manager driver support for Xilinx FPGA configuration
>  	  over slave serial interface.
>  
> +config FPGA_MGR_EFINIX_SPI
> +	tristate "Efinix FPGA configuration over SPI passive"
> +	depends on SPI
> +	help
> +	  This option enables support for the FPGA manager driver to
> +	  configure Efinix Trion and Titanium Series FPGAs over SPI
> +	  using passive serial mode.
> +
>  config FPGA_MGR_ICE40_SPI
>  	tristate "Lattice iCE40 SPI"
>  	depends on OF && SPI
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index aeb89bb13517..1a95124ff847 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -18,6 +18,7 @@ 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_EFINIX_SPI)	+= efinix-trion-spi-passive.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
>  obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)	+= versal-fpga.o
> diff --git a/drivers/fpga/efinix-trion-spi-passive.c b/drivers/fpga/efinix-trion-spi-passive.c
> new file mode 100644
> index 000000000000..eb2592e788b9
> --- /dev/null
> +++ b/drivers/fpga/efinix-trion-spi-passive.c
> @@ -0,0 +1,219 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Trion and Titanium Series FPGA SPI Passive Programming Driver
> + *
> + * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
> + *
> + * Ian Dannapel <iansdannapel@gmail.com>
> + *
> + * Manage Efinix FPGA firmware that is loaded over SPI using
> + * the serial configuration interface.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/of.h>
> +#include <linux/spi/spi.h>
> +#include <linux/sizes.h>
> +
> +struct efinix_spi_conf {
> +	struct spi_device *spi;
> +	struct gpio_desc *cdone;
> +	struct gpio_desc *creset;
> +	struct gpio_desc *cs;
> +};
> +
> +static int get_cdone_gpio(struct fpga_manager *mgr)

Is it better use 'struct efinix_spi_conf *conf' as parameter?

Same for the following functions.

> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	int ret;
> +
> +	ret = gpiod_get_value(conf->cdone);
> +	if (ret < 0)
> +		dev_err(&mgr->dev, "Error reading CDONE (%d)\n", ret);
> +
> +	return ret;
> +}
> +
> +static void reset(struct fpga_manager *mgr)

Please unify the naming of the internal functions. You use
'efinix_spi_apply_clk_cycles()' below.

> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +
> +	gpiod_set_value(conf->creset, 1);
> +	/* wait tCRESET_N */
> +	usleep_range(5, 15);
> +	gpiod_set_value(conf->creset, 0);
> +}
> +
> +static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +
> +	if (conf->cdone && get_cdone_gpio(mgr) == 1)
> +		return FPGA_MGR_STATE_OPERATING;
> +
> +	return FPGA_MGR_STATE_UNKNOWN;
> +}
> +
> +static int efinix_spi_apply_clk_cycles(struct fpga_manager *mgr)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	char data[13] = {0};
> +
> +	return spi_write(conf->spi, data, sizeof(data));
> +}
> +
> +static int efinix_spi_write_init(struct fpga_manager *mgr,
> +				 struct fpga_image_info *info,
> +				 const char *buf, size_t count)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +
> +	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> +		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> +		return -EINVAL;
> +	}
> +
> +	/* reset with chip select active */
> +	gpiod_set_value(conf->cs, 1);

Why operating chip selective at SPI client driver? Isn't it the job for SPI
controller?

> +	usleep_range(5, 15);
> +	reset(mgr);
> +
> +	/* wait tDMIN */
> +	usleep_range(100, 150);
> +
> +	return 0;
> +}
> +
> +static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
> +			    size_t count)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	int ret;
> +
> +	ret = spi_write(conf->spi, buf, count);
> +	if (ret) {
> +		dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	/* append at least 100 clock cycles */
> +	efinix_spi_apply_clk_cycles(mgr);
> +
> +	/* release chip select */
> +	gpiod_set_value(conf->cs, 0);

Is it correct? What if there is remaining data to write?

> +
> +	return 0;
> +}
> +
> +static int efinix_spi_write_complete(struct fpga_manager *mgr,
> +				     struct fpga_image_info *info)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	unsigned long timeout =
> +		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
> +	bool expired = false;
> +	int done;
> +
> +	if (conf->cdone) {
> +		while (!expired) {
> +			expired = time_after(jiffies, timeout);
> +
> +			done = get_cdone_gpio(mgr);
> +			if (done < 0)
> +				return done;
> +
> +			if (done)
> +				break;
> +		}
> +	}
> +
> +	if (expired)
> +		return -ETIMEDOUT;
> +
> +	/* wait tUSER */
> +	usleep_range(75, 125);
> +
> +	return 0;
> +}
> +
> +static const struct fpga_manager_ops efinix_spi_ops = {
> +	.state = efinix_spi_state,
> +	.write_init = efinix_spi_write_init,
> +	.write = efinix_spi_write,
> +	.write_complete = efinix_spi_write_complete,
> +};
> +
> +static int efinix_spi_probe(struct spi_device *spi)
> +{
> +	struct efinix_spi_conf *conf;
> +	struct fpga_manager *mgr;
> +
> +	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
> +	if (!conf)
> +		return -ENOMEM;
> +
> +	conf->spi = spi;
> +
> +	conf->creset = devm_gpiod_get(&spi->dev, "creset", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->creset))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->creset),
> +				"Failed to get RESET gpio\n");
> +
> +	conf->cs = devm_gpiod_get(&spi->dev, "cs", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->cs))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
> +				"Failed to get CHIP_SELECT gpio\n");
> +
> +	if (!(spi->mode & SPI_CPHA) || !(spi->mode & SPI_CPOL))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
> +				"Unsupported SPI mode, set CPHA and CPOL\n");
> +
> +	conf->cdone = devm_gpiod_get_optional(&spi->dev, "cdone", GPIOD_IN);
> +	if (IS_ERR(conf->cdone))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->cdone),
> +				"Failed to get CDONE gpio\n");
> +
> +	mgr = devm_fpga_mgr_register(&spi->dev,
> +				"Efinix SPI Passive Programming FPGA Manager",
> +					&efinix_spi_ops, conf);
> +
> +	return PTR_ERR_OR_ZERO(mgr);
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id efnx_spi_of_match[] = {
> +	{ .compatible = "efinix,trion-spi-passive", },
> +	{ .compatible = "efinix,titanium-spi-passive", },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, efnx_spi_of_match);
> +#endif
> +
> +static const struct spi_device_id efinix_ids[] = {
> +	{ "trion-spi-passive", 0 },
> +	{ "titanium-spi-passive", 0 },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(spi, efinix_ids);
> +
> +

remove the extra blank line.

> +static struct spi_driver efinix_spi_passive_driver = {
> +	.driver = {
> +		.name = "efinix-fpga-spi-passive",
> +		.of_match_table = of_match_ptr(efnx_spi_of_match),

Is it OK remove CONFIG_OF & of_match_ptr()?

Thanks,
Yilun

> +	},
> +	.probe = efinix_spi_probe,
> +	.id_table = efinix_ids,
> +};
> +
> +module_spi_driver(efinix_spi_passive_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Ian Dannapel <iansdannapel@gmail.com>");
> +MODULE_DESCRIPTION("Load Efinix FPGA firmware over SPI passive");
> -- 
> 2.34.1
> 
> 

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

* Re: [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-07-12  6:53     ` Xu Yilun
@ 2024-07-25 13:44       ` Ian Dannapel
  2024-07-27 15:58         ` Xu Yilun
  0 siblings, 1 reply; 24+ messages in thread
From: Ian Dannapel @ 2024-07-25 13:44 UTC (permalink / raw)
  To: Xu Yilun
  Cc: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel

Hi Yilun, thanks for the review.

Am Fr., 12. Juli 2024 um 09:00 Uhr schrieb Xu Yilun <yilun.xu@linux.intel.com>:
>
> On Fri, Jun 28, 2024 at 05:23:46PM +0200, iansdannapel@gmail.com wrote:
> > From: Ian Dannapel <iansdannapel@gmail.com>
> >
>
> Please don't reply to the previous series when you post a new version.
sure
>
> > Add a new driver for loading binary firmware using "SPI passive
>
> Loading to some nvram or reporgraming to FPGA logic blocks.
>
> > programming" on Efinix FPGAs.
> >
> > Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> > ---
> >  drivers/fpga/Kconfig                    |   8 +
> >  drivers/fpga/Makefile                   |   1 +
> >  drivers/fpga/efinix-trion-spi-passive.c | 219 ++++++++++++++++++++++++
> >  3 files changed, 228 insertions(+)
> >  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> >
> > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > index 37b35f58f0df..25579510e49e 100644
> > --- a/drivers/fpga/Kconfig
> > +++ b/drivers/fpga/Kconfig
> > @@ -83,6 +83,14 @@ config FPGA_MGR_XILINX_SPI
> >         FPGA manager driver support for Xilinx FPGA configuration
> >         over slave serial interface.
> >
> > +config FPGA_MGR_EFINIX_SPI
> > +     tristate "Efinix FPGA configuration over SPI passive"
> > +     depends on SPI
> > +     help
> > +       This option enables support for the FPGA manager driver to
> > +       configure Efinix Trion and Titanium Series FPGAs over SPI
> > +       using passive serial mode.
> > +
> >  config FPGA_MGR_ICE40_SPI
> >       tristate "Lattice iCE40 SPI"
> >       depends on OF && SPI
> > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> > index aeb89bb13517..1a95124ff847 100644
> > --- a/drivers/fpga/Makefile
> > +++ b/drivers/fpga/Makefile
> > @@ -18,6 +18,7 @@ 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_EFINIX_SPI)    += efinix-trion-spi-passive.o
> >  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)     += zynq-fpga.o
> >  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)   += zynqmp-fpga.o
> >  obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)   += versal-fpga.o
> > diff --git a/drivers/fpga/efinix-trion-spi-passive.c b/drivers/fpga/efinix-trion-spi-passive.c
> > new file mode 100644
> > index 000000000000..eb2592e788b9
> > --- /dev/null
> > +++ b/drivers/fpga/efinix-trion-spi-passive.c
> > @@ -0,0 +1,219 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Trion and Titanium Series FPGA SPI Passive Programming Driver
> > + *
> > + * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
> > + *
> > + * Ian Dannapel <iansdannapel@gmail.com>
> > + *
> > + * Manage Efinix FPGA firmware that is loaded over SPI using
> > + * the serial configuration interface.
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/device.h>
> > +#include <linux/fpga/fpga-mgr.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/module.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/of.h>
> > +#include <linux/spi/spi.h>
> > +#include <linux/sizes.h>
> > +
> > +struct efinix_spi_conf {
> > +     struct spi_device *spi;
> > +     struct gpio_desc *cdone;
> > +     struct gpio_desc *creset;
> > +     struct gpio_desc *cs;
> > +};
> > +
> > +static int get_cdone_gpio(struct fpga_manager *mgr)
>
> Is it better use 'struct efinix_spi_conf *conf' as parameter?
>
> Same for the following functions.
>
> > +{
> > +     struct efinix_spi_conf *conf = mgr->priv;
> > +     int ret;
> > +
> > +     ret = gpiod_get_value(conf->cdone);
> > +     if (ret < 0)
> > +             dev_err(&mgr->dev, "Error reading CDONE (%d)\n", ret);
> > +
> > +     return ret;
> > +}
> > +
> > +static void reset(struct fpga_manager *mgr)
>
> Please unify the naming of the internal functions. You use
> 'efinix_spi_apply_clk_cycles()' below.
>
> > +{
> > +     struct efinix_spi_conf *conf = mgr->priv;
> > +
> > +     gpiod_set_value(conf->creset, 1);
> > +     /* wait tCRESET_N */
> > +     usleep_range(5, 15);
> > +     gpiod_set_value(conf->creset, 0);
> > +}
> > +
> > +static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
> > +{
> > +     struct efinix_spi_conf *conf = mgr->priv;
> > +
> > +     if (conf->cdone && get_cdone_gpio(mgr) == 1)
> > +             return FPGA_MGR_STATE_OPERATING;
> > +
> > +     return FPGA_MGR_STATE_UNKNOWN;
> > +}
> > +
> > +static int efinix_spi_apply_clk_cycles(struct fpga_manager *mgr)
> > +{
> > +     struct efinix_spi_conf *conf = mgr->priv;
> > +     char data[13] = {0};
> > +
> > +     return spi_write(conf->spi, data, sizeof(data));
> > +}
> > +
> > +static int efinix_spi_write_init(struct fpga_manager *mgr,
> > +                              struct fpga_image_info *info,
> > +                              const char *buf, size_t count)
> > +{
> > +     struct efinix_spi_conf *conf = mgr->priv;
> > +
> > +     if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> > +             dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> > +             return -EINVAL;
> > +     }
> > +
> > +     /* reset with chip select active */
> > +     gpiod_set_value(conf->cs, 1);
>
> Why operating chip selective at SPI client driver? Isn't it the job for SPI
> controller?
to enter the passive programming mode, a reset must be executed while
the chip select is active.
The is controlling the chip select from here, since I expect that the
SPI controller to only activate
the CS when communicating.
>
> > +     usleep_range(5, 15);
> > +     reset(mgr);
> > +
> > +     /* wait tDMIN */
> > +     usleep_range(100, 150);
> > +
> > +     return 0;
> > +}
> > +
> > +static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
> > +                         size_t count)
> > +{
> > +     struct efinix_spi_conf *conf = mgr->priv;
> > +     int ret;
> > +
> > +     ret = spi_write(conf->spi, buf, count);
> > +     if (ret) {
> > +             dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
> > +                     ret);
> > +             return ret;
> > +     }
> > +
> > +     /* append at least 100 clock cycles */
> > +     efinix_spi_apply_clk_cycles(mgr);
> > +
> > +     /* release chip select */
> > +     gpiod_set_value(conf->cs, 0);
>
> Is it correct? What if there is remaining data to write?
I assumed that the spi controller should write complete buffer and
decide on the transfer block size,
so there shouldn't be any remaining data. Can someone confirm?
>
> > +
> > +     return 0;
> > +}
> > +
> > +static int efinix_spi_write_complete(struct fpga_manager *mgr,
> > +                                  struct fpga_image_info *info)
> > +{
> > +     struct efinix_spi_conf *conf = mgr->priv;
> > +     unsigned long timeout =
> > +             jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
> > +     bool expired = false;
> > +     int done;
> > +
> > +     if (conf->cdone) {
> > +             while (!expired) {
> > +                     expired = time_after(jiffies, timeout);
> > +
> > +                     done = get_cdone_gpio(mgr);
> > +                     if (done < 0)
> > +                             return done;
> > +
> > +                     if (done)
> > +                             break;
> > +             }
> > +     }
> > +
> > +     if (expired)
> > +             return -ETIMEDOUT;
> > +
> > +     /* wait tUSER */
> > +     usleep_range(75, 125);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct fpga_manager_ops efinix_spi_ops = {
> > +     .state = efinix_spi_state,
> > +     .write_init = efinix_spi_write_init,
> > +     .write = efinix_spi_write,
> > +     .write_complete = efinix_spi_write_complete,
> > +};
> > +
> > +static int efinix_spi_probe(struct spi_device *spi)
> > +{
> > +     struct efinix_spi_conf *conf;
> > +     struct fpga_manager *mgr;
> > +
> > +     conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
> > +     if (!conf)
> > +             return -ENOMEM;
> > +
> > +     conf->spi = spi;
> > +
> > +     conf->creset = devm_gpiod_get(&spi->dev, "creset", GPIOD_OUT_HIGH);
> > +     if (IS_ERR(conf->creset))
> > +             return dev_err_probe(&spi->dev, PTR_ERR(conf->creset),
> > +                             "Failed to get RESET gpio\n");
> > +
> > +     conf->cs = devm_gpiod_get(&spi->dev, "cs", GPIOD_OUT_HIGH);
> > +     if (IS_ERR(conf->cs))
> > +             return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
> > +                             "Failed to get CHIP_SELECT gpio\n");
> > +
> > +     if (!(spi->mode & SPI_CPHA) || !(spi->mode & SPI_CPOL))
> > +             return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
> > +                             "Unsupported SPI mode, set CPHA and CPOL\n");
> > +
> > +     conf->cdone = devm_gpiod_get_optional(&spi->dev, "cdone", GPIOD_IN);
> > +     if (IS_ERR(conf->cdone))
> > +             return dev_err_probe(&spi->dev, PTR_ERR(conf->cdone),
> > +                             "Failed to get CDONE gpio\n");
> > +
> > +     mgr = devm_fpga_mgr_register(&spi->dev,
> > +                             "Efinix SPI Passive Programming FPGA Manager",
> > +                                     &efinix_spi_ops, conf);
> > +
> > +     return PTR_ERR_OR_ZERO(mgr);
> > +}
> > +
> > +#ifdef CONFIG_OF
> > +static const struct of_device_id efnx_spi_of_match[] = {
> > +     { .compatible = "efinix,trion-spi-passive", },
> > +     { .compatible = "efinix,titanium-spi-passive", },
> > +     {}
> > +};
> > +MODULE_DEVICE_TABLE(of, efnx_spi_of_match);
> > +#endif
> > +
> > +static const struct spi_device_id efinix_ids[] = {
> > +     { "trion-spi-passive", 0 },
> > +     { "titanium-spi-passive", 0 },
> > +     {},
> > +};
> > +MODULE_DEVICE_TABLE(spi, efinix_ids);
> > +
> > +
>
> remove the extra blank line.
>
> > +static struct spi_driver efinix_spi_passive_driver = {
> > +     .driver = {
> > +             .name = "efinix-fpga-spi-passive",
> > +             .of_match_table = of_match_ptr(efnx_spi_of_match),
>
> Is it OK remove CONFIG_OF & of_match_ptr()?
I don't think it could work without device tree support
>
> Thanks,
> Yilun
>
> > +     },
> > +     .probe = efinix_spi_probe,
> > +     .id_table = efinix_ids,
> > +};
> > +
> > +module_spi_driver(efinix_spi_passive_driver);
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_AUTHOR("Ian Dannapel <iansdannapel@gmail.com>");
> > +MODULE_DESCRIPTION("Load Efinix FPGA firmware over SPI passive");
> > --
> > 2.34.1
> >
> >

I will soon prepare a v3 for the rest.

Thanks
Ian

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

* Re: [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-07-25 13:44       ` Ian Dannapel
@ 2024-07-27 15:58         ` Xu Yilun
  2024-07-28 11:44           ` Ian Dannapel
  0 siblings, 1 reply; 24+ messages in thread
From: Xu Yilun @ 2024-07-27 15:58 UTC (permalink / raw)
  To: Ian Dannapel
  Cc: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel

On Thu, Jul 25, 2024 at 03:44:54PM +0200, Ian Dannapel wrote:
> Hi Yilun, thanks for the review.
> 
> Am Fr., 12. Juli 2024 um 09:00 Uhr schrieb Xu Yilun <yilun.xu@linux.intel.com>:
> >
> > On Fri, Jun 28, 2024 at 05:23:46PM +0200, iansdannapel@gmail.com wrote:
> > > From: Ian Dannapel <iansdannapel@gmail.com>
> > >
> >
> > Please don't reply to the previous series when you post a new version.
> sure
> >
> > > Add a new driver for loading binary firmware using "SPI passive
> >
> > Loading to some nvram or reporgraming to FPGA logic blocks.

Sorry for typo, this is a question:

  Loading to some nvram or reporgraming to FPGA logic blocks?

> >
> > > programming" on Efinix FPGAs.
> > >
> > > Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> > > ---
> > >  drivers/fpga/Kconfig                    |   8 +
> > >  drivers/fpga/Makefile                   |   1 +
> > >  drivers/fpga/efinix-trion-spi-passive.c | 219 ++++++++++++++++++++++++
> > >  3 files changed, 228 insertions(+)
> > >  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> > >
> > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > > index 37b35f58f0df..25579510e49e 100644
> > > --- a/drivers/fpga/Kconfig
> > > +++ b/drivers/fpga/Kconfig
> > > @@ -83,6 +83,14 @@ config FPGA_MGR_XILINX_SPI
> > >         FPGA manager driver support for Xilinx FPGA configuration
> > >         over slave serial interface.
> > >
> > > +config FPGA_MGR_EFINIX_SPI
> > > +     tristate "Efinix FPGA configuration over SPI passive"
> > > +     depends on SPI
> > > +     help
> > > +       This option enables support for the FPGA manager driver to
> > > +       configure Efinix Trion and Titanium Series FPGAs over SPI
> > > +       using passive serial mode.
> > > +
> > >  config FPGA_MGR_ICE40_SPI
> > >       tristate "Lattice iCE40 SPI"
> > >       depends on OF && SPI
> > > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> > > index aeb89bb13517..1a95124ff847 100644
> > > --- a/drivers/fpga/Makefile
> > > +++ b/drivers/fpga/Makefile
> > > @@ -18,6 +18,7 @@ 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_EFINIX_SPI)    += efinix-trion-spi-passive.o
> > >  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)     += zynq-fpga.o
> > >  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)   += zynqmp-fpga.o
> > >  obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)   += versal-fpga.o
> > > diff --git a/drivers/fpga/efinix-trion-spi-passive.c b/drivers/fpga/efinix-trion-spi-passive.c
> > > new file mode 100644
> > > index 000000000000..eb2592e788b9
> > > --- /dev/null
> > > +++ b/drivers/fpga/efinix-trion-spi-passive.c
> > > @@ -0,0 +1,219 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * Trion and Titanium Series FPGA SPI Passive Programming Driver
> > > + *
> > > + * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
> > > + *
> > > + * Ian Dannapel <iansdannapel@gmail.com>
> > > + *
> > > + * Manage Efinix FPGA firmware that is loaded over SPI using
> > > + * the serial configuration interface.
> > > + */
> > > +
> > > +#include <linux/delay.h>
> > > +#include <linux/device.h>
> > > +#include <linux/fpga/fpga-mgr.h>
> > > +#include <linux/gpio/consumer.h>
> > > +#include <linux/module.h>
> > > +#include <linux/mod_devicetable.h>
> > > +#include <linux/of.h>
> > > +#include <linux/spi/spi.h>
> > > +#include <linux/sizes.h>
> > > +
> > > +struct efinix_spi_conf {
> > > +     struct spi_device *spi;
> > > +     struct gpio_desc *cdone;
> > > +     struct gpio_desc *creset;
> > > +     struct gpio_desc *cs;
> > > +};
> > > +
> > > +static int get_cdone_gpio(struct fpga_manager *mgr)
> >
> > Is it better use 'struct efinix_spi_conf *conf' as parameter?
> >
> > Same for the following functions.
> >
> > > +{
> > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > +     int ret;
> > > +
> > > +     ret = gpiod_get_value(conf->cdone);
> > > +     if (ret < 0)
> > > +             dev_err(&mgr->dev, "Error reading CDONE (%d)\n", ret);
> > > +
> > > +     return ret;
> > > +}
> > > +
> > > +static void reset(struct fpga_manager *mgr)
> >
> > Please unify the naming of the internal functions. You use
> > 'efinix_spi_apply_clk_cycles()' below.
> >
> > > +{
> > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > +
> > > +     gpiod_set_value(conf->creset, 1);
> > > +     /* wait tCRESET_N */
> > > +     usleep_range(5, 15);
> > > +     gpiod_set_value(conf->creset, 0);
> > > +}
> > > +
> > > +static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
> > > +{
> > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > +
> > > +     if (conf->cdone && get_cdone_gpio(mgr) == 1)
> > > +             return FPGA_MGR_STATE_OPERATING;
> > > +
> > > +     return FPGA_MGR_STATE_UNKNOWN;
> > > +}
> > > +
> > > +static int efinix_spi_apply_clk_cycles(struct fpga_manager *mgr)
> > > +{
> > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > +     char data[13] = {0};
> > > +
> > > +     return spi_write(conf->spi, data, sizeof(data));
> > > +}
> > > +
> > > +static int efinix_spi_write_init(struct fpga_manager *mgr,
> > > +                              struct fpga_image_info *info,
> > > +                              const char *buf, size_t count)
> > > +{
> > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > +
> > > +     if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> > > +             dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     /* reset with chip select active */
> > > +     gpiod_set_value(conf->cs, 1);
> >
> > Why operating chip selective at SPI client driver? Isn't it the job for SPI
> > controller?
> to enter the passive programming mode, a reset must be executed while
> the chip select is active.
> The is controlling the chip select from here, since I expect that the
> SPI controller to only activate
> the CS when communicating.

The concern is, it may conflict with the underlying cs control in spi
controller.

There are several control flags in struct spi_transfter to affect cs. Is
there any chance using them, or try to improve if they doesn't meet your
request?

> >
> > > +     usleep_range(5, 15);
> > > +     reset(mgr);
> > > +
> > > +     /* wait tDMIN */
> > > +     usleep_range(100, 150);

And these ones, or you could use some delay controls in struct spi_transfer.

> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
> > > +                         size_t count)
> > > +{
> > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > +     int ret;
> > > +
> > > +     ret = spi_write(conf->spi, buf, count);
> > > +     if (ret) {
> > > +             dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
> > > +                     ret);
> > > +             return ret;
> > > +     }
> > > +
> > > +     /* append at least 100 clock cycles */
> > > +     efinix_spi_apply_clk_cycles(mgr);
> > > +
> > > +     /* release chip select */
> > > +     gpiod_set_value(conf->cs, 0);
> >
> > Is it correct? What if there is remaining data to write?
> I assumed that the spi controller should write complete buffer and
> decide on the transfer block size,
> so there shouldn't be any remaining data. Can someone confirm?

This is not about spi transfer, it is the fpga_manager_ops.write could
be called multiple times during one time reprogramming. Please
investigate more about the FPGA mgr core.

Thanks,
Yilun

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

* Re: [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-07-27 15:58         ` Xu Yilun
@ 2024-07-28 11:44           ` Ian Dannapel
  2024-07-29 14:50             ` Xu Yilun
  0 siblings, 1 reply; 24+ messages in thread
From: Ian Dannapel @ 2024-07-28 11:44 UTC (permalink / raw)
  To: Xu Yilun
  Cc: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel

Am Sa., 27. Juli 2024 um 18:00 Uhr schrieb Xu Yilun <yilun.xu@linux.intel.com>:
>
> On Thu, Jul 25, 2024 at 03:44:54PM +0200, Ian Dannapel wrote:
> > Hi Yilun, thanks for the review.
> >
> > Am Fr., 12. Juli 2024 um 09:00 Uhr schrieb Xu Yilun <yilun.xu@linux.intel.com>:
> > >
> > > On Fri, Jun 28, 2024 at 05:23:46PM +0200, iansdannapel@gmail.com wrote:
> > > > From: Ian Dannapel <iansdannapel@gmail.com>
> > > >
> > >
> > > Please don't reply to the previous series when you post a new version.
> > sure
> > >
> > > > Add a new driver for loading binary firmware using "SPI passive
> > >
> > > Loading to some nvram or reporgraming to FPGA logic blocks.
>
> Sorry for typo, this is a question:
>
>   Loading to some nvram or reporgraming to FPGA logic blocks?
The datasheet refers to it as configuration RAM (CRAM) and must be
loaded on every boot up.
>
> > >
> > > > programming" on Efinix FPGAs.
> > > >
> > > > Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> > > > ---
> > > >  drivers/fpga/Kconfig                    |   8 +
> > > >  drivers/fpga/Makefile                   |   1 +
> > > >  drivers/fpga/efinix-trion-spi-passive.c | 219 ++++++++++++++++++++++++
> > > >  3 files changed, 228 insertions(+)
> > > >  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> > > >
> > > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > > > index 37b35f58f0df..25579510e49e 100644
> > > > --- a/drivers/fpga/Kconfig
> > > > +++ b/drivers/fpga/Kconfig
> > > > @@ -83,6 +83,14 @@ config FPGA_MGR_XILINX_SPI
> > > >         FPGA manager driver support for Xilinx FPGA configuration
> > > >         over slave serial interface.
> > > >
> > > > +config FPGA_MGR_EFINIX_SPI
> > > > +     tristate "Efinix FPGA configuration over SPI passive"
> > > > +     depends on SPI
> > > > +     help
> > > > +       This option enables support for the FPGA manager driver to
> > > > +       configure Efinix Trion and Titanium Series FPGAs over SPI
> > > > +       using passive serial mode.
> > > > +
> > > >  config FPGA_MGR_ICE40_SPI
> > > >       tristate "Lattice iCE40 SPI"
> > > >       depends on OF && SPI
> > > > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> > > > index aeb89bb13517..1a95124ff847 100644
> > > > --- a/drivers/fpga/Makefile
> > > > +++ b/drivers/fpga/Makefile
> > > > @@ -18,6 +18,7 @@ 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_EFINIX_SPI)    += efinix-trion-spi-passive.o
> > > >  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)     += zynq-fpga.o
> > > >  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)   += zynqmp-fpga.o
> > > >  obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)   += versal-fpga.o
> > > > diff --git a/drivers/fpga/efinix-trion-spi-passive.c b/drivers/fpga/efinix-trion-spi-passive.c
> > > > new file mode 100644
> > > > index 000000000000..eb2592e788b9
> > > > --- /dev/null
> > > > +++ b/drivers/fpga/efinix-trion-spi-passive.c
> > > > @@ -0,0 +1,219 @@
> > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > +/*
> > > > + * Trion and Titanium Series FPGA SPI Passive Programming Driver
> > > > + *
> > > > + * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
> > > > + *
> > > > + * Ian Dannapel <iansdannapel@gmail.com>
> > > > + *
> > > > + * Manage Efinix FPGA firmware that is loaded over SPI using
> > > > + * the serial configuration interface.
> > > > + */
> > > > +
> > > > +#include <linux/delay.h>
> > > > +#include <linux/device.h>
> > > > +#include <linux/fpga/fpga-mgr.h>
> > > > +#include <linux/gpio/consumer.h>
> > > > +#include <linux/module.h>
> > > > +#include <linux/mod_devicetable.h>
> > > > +#include <linux/of.h>
> > > > +#include <linux/spi/spi.h>
> > > > +#include <linux/sizes.h>
> > > > +
> > > > +struct efinix_spi_conf {
> > > > +     struct spi_device *spi;
> > > > +     struct gpio_desc *cdone;
> > > > +     struct gpio_desc *creset;
> > > > +     struct gpio_desc *cs;
> > > > +};
> > > > +
> > > > +static int get_cdone_gpio(struct fpga_manager *mgr)
> > >
> > > Is it better use 'struct efinix_spi_conf *conf' as parameter?
> > >
> > > Same for the following functions.
> > >
> > > > +{
> > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > +     int ret;
> > > > +
> > > > +     ret = gpiod_get_value(conf->cdone);
> > > > +     if (ret < 0)
> > > > +             dev_err(&mgr->dev, "Error reading CDONE (%d)\n", ret);
> > > > +
> > > > +     return ret;
> > > > +}
> > > > +
> > > > +static void reset(struct fpga_manager *mgr)
> > >
> > > Please unify the naming of the internal functions. You use
> > > 'efinix_spi_apply_clk_cycles()' below.
> > >
> > > > +{
> > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > +
> > > > +     gpiod_set_value(conf->creset, 1);
> > > > +     /* wait tCRESET_N */
> > > > +     usleep_range(5, 15);
> > > > +     gpiod_set_value(conf->creset, 0);
> > > > +}
> > > > +
> > > > +static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
> > > > +{
> > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > +
> > > > +     if (conf->cdone && get_cdone_gpio(mgr) == 1)
> > > > +             return FPGA_MGR_STATE_OPERATING;
> > > > +
> > > > +     return FPGA_MGR_STATE_UNKNOWN;
> > > > +}
> > > > +
> > > > +static int efinix_spi_apply_clk_cycles(struct fpga_manager *mgr)
> > > > +{
> > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > +     char data[13] = {0};
> > > > +
> > > > +     return spi_write(conf->spi, data, sizeof(data));
> > > > +}
> > > > +
> > > > +static int efinix_spi_write_init(struct fpga_manager *mgr,
> > > > +                              struct fpga_image_info *info,
> > > > +                              const char *buf, size_t count)
> > > > +{
> > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > +
> > > > +     if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> > > > +             dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     /* reset with chip select active */
> > > > +     gpiod_set_value(conf->cs, 1);
> > >
> > > Why operating chip selective at SPI client driver? Isn't it the job for SPI
> > > controller?
> > to enter the passive programming mode, a reset must be executed while
> > the chip select is active.
> > The is controlling the chip select from here, since I expect that the
> > SPI controller to only activate
> > the CS when communicating.
>
> The concern is, it may conflict with the underlying cs control in spi
> controller.
>
> There are several control flags in struct spi_transfter to affect cs. Is
> there any chance using them, or try to improve if they doesn't meet your
> request?
The main problem of this chip is that probably the of SPI is out of
spec, so would like to avoid changes in the spi contoller for this
edge case.
That is probably one the reasons that the datasheet does not recommend
other devices on the same SPI bus.
>
> > >
> > > > +     usleep_range(5, 15);
> > > > +     reset(mgr);
> > > > +
> > > > +     /* wait tDMIN */
> > > > +     usleep_range(100, 150);
>
> And these ones, or you could use some delay controls in struct spi_transfer.
I don't think spi_transfer delay option could work in this case, the
data transfer did not start yet.
>
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
> > > > +                         size_t count)
> > > > +{
> > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > +     int ret;
> > > > +
> > > > +     ret = spi_write(conf->spi, buf, count);
> > > > +     if (ret) {
> > > > +             dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
> > > > +                     ret);
> > > > +             return ret;
> > > > +     }
> > > > +
> > > > +     /* append at least 100 clock cycles */
> > > > +     efinix_spi_apply_clk_cycles(mgr);
> > > > +
> > > > +     /* release chip select */
> > > > +     gpiod_set_value(conf->cs, 0);
> > >
> > > Is it correct? What if there is remaining data to write?
> > I assumed that the spi controller should write complete buffer and
> > decide on the transfer block size,
> > so there shouldn't be any remaining data. Can someone confirm?
>
> This is not about spi transfer, it is the fpga_manager_ops.write could
> be called multiple times during one time reprogramming. Please
> investigate more about the FPGA mgr core.
I see, I should move this to write_complete since the CS must stay low
throughout the configuration.
That is also a reason to avoid letting the SPI controller manage the CS gpio.
>
> Thanks,
> Yilun

Thanks
Ian

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

* Re: [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-07-28 11:44           ` Ian Dannapel
@ 2024-07-29 14:50             ` Xu Yilun
  2024-08-09 10:38               ` Ian Dannapel
  0 siblings, 1 reply; 24+ messages in thread
From: Xu Yilun @ 2024-07-29 14:50 UTC (permalink / raw)
  To: Ian Dannapel
  Cc: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel

On Sun, Jul 28, 2024 at 01:44:03PM +0200, Ian Dannapel wrote:
> Am Sa., 27. Juli 2024 um 18:00 Uhr schrieb Xu Yilun <yilun.xu@linux.intel.com>:
> >
> > On Thu, Jul 25, 2024 at 03:44:54PM +0200, Ian Dannapel wrote:
> > > Hi Yilun, thanks for the review.
> > >
> > > Am Fr., 12. Juli 2024 um 09:00 Uhr schrieb Xu Yilun <yilun.xu@linux.intel.com>:
> > > >
> > > > On Fri, Jun 28, 2024 at 05:23:46PM +0200, iansdannapel@gmail.com wrote:
> > > > > From: Ian Dannapel <iansdannapel@gmail.com>
> > > > >
> > > >
> > > > Please don't reply to the previous series when you post a new version.
> > > sure
> > > >
> > > > > Add a new driver for loading binary firmware using "SPI passive
> > > >
> > > > Loading to some nvram or reporgraming to FPGA logic blocks.
> >
> > Sorry for typo, this is a question:
> >
> >   Loading to some nvram or reporgraming to FPGA logic blocks?
> The datasheet refers to it as configuration RAM (CRAM) and must be
> loaded on every boot up.

The FPGA reprogramming is about loading the FPGA logic blocks, and from
the POV of the System, it is about runtime changing the HW and
re-enumerate the devices.

But some submitted fpga-mgr drivers are just used to to write nvram
backend for FPGA, don't affect any running device at all. I think these
drivers virtually have nothing to do with fpga-mgr. Some generic
storage (e.g. nvram, mtd) or firmware image loading interfaces better
fit them. I assume this driver is also of this kind.

> >
> > > >
> > > > > programming" on Efinix FPGAs.
> > > > >
> > > > > Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> > > > > ---
> > > > >  drivers/fpga/Kconfig                    |   8 +
> > > > >  drivers/fpga/Makefile                   |   1 +
> > > > >  drivers/fpga/efinix-trion-spi-passive.c | 219 ++++++++++++++++++++++++
> > > > >  3 files changed, 228 insertions(+)
> > > > >  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> > > > >
> > > > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > > > > index 37b35f58f0df..25579510e49e 100644
> > > > > --- a/drivers/fpga/Kconfig
> > > > > +++ b/drivers/fpga/Kconfig
> > > > > @@ -83,6 +83,14 @@ config FPGA_MGR_XILINX_SPI
> > > > >         FPGA manager driver support for Xilinx FPGA configuration
> > > > >         over slave serial interface.
> > > > >
> > > > > +config FPGA_MGR_EFINIX_SPI
> > > > > +     tristate "Efinix FPGA configuration over SPI passive"
> > > > > +     depends on SPI
> > > > > +     help
> > > > > +       This option enables support for the FPGA manager driver to
> > > > > +       configure Efinix Trion and Titanium Series FPGAs over SPI
> > > > > +       using passive serial mode.
> > > > > +
> > > > >  config FPGA_MGR_ICE40_SPI
> > > > >       tristate "Lattice iCE40 SPI"
> > > > >       depends on OF && SPI
> > > > > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> > > > > index aeb89bb13517..1a95124ff847 100644
> > > > > --- a/drivers/fpga/Makefile
> > > > > +++ b/drivers/fpga/Makefile
> > > > > @@ -18,6 +18,7 @@ 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_EFINIX_SPI)    += efinix-trion-spi-passive.o
> > > > >  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)     += zynq-fpga.o
> > > > >  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)   += zynqmp-fpga.o
> > > > >  obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)   += versal-fpga.o
> > > > > diff --git a/drivers/fpga/efinix-trion-spi-passive.c b/drivers/fpga/efinix-trion-spi-passive.c
> > > > > new file mode 100644
> > > > > index 000000000000..eb2592e788b9
> > > > > --- /dev/null
> > > > > +++ b/drivers/fpga/efinix-trion-spi-passive.c
> > > > > @@ -0,0 +1,219 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > > +/*
> > > > > + * Trion and Titanium Series FPGA SPI Passive Programming Driver
> > > > > + *
> > > > > + * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
> > > > > + *
> > > > > + * Ian Dannapel <iansdannapel@gmail.com>
> > > > > + *
> > > > > + * Manage Efinix FPGA firmware that is loaded over SPI using
> > > > > + * the serial configuration interface.
> > > > > + */
> > > > > +
> > > > > +#include <linux/delay.h>
> > > > > +#include <linux/device.h>
> > > > > +#include <linux/fpga/fpga-mgr.h>
> > > > > +#include <linux/gpio/consumer.h>
> > > > > +#include <linux/module.h>
> > > > > +#include <linux/mod_devicetable.h>
> > > > > +#include <linux/of.h>
> > > > > +#include <linux/spi/spi.h>
> > > > > +#include <linux/sizes.h>
> > > > > +
> > > > > +struct efinix_spi_conf {
> > > > > +     struct spi_device *spi;
> > > > > +     struct gpio_desc *cdone;
> > > > > +     struct gpio_desc *creset;
> > > > > +     struct gpio_desc *cs;
> > > > > +};
> > > > > +
> > > > > +static int get_cdone_gpio(struct fpga_manager *mgr)
> > > >
> > > > Is it better use 'struct efinix_spi_conf *conf' as parameter?
> > > >
> > > > Same for the following functions.
> > > >
> > > > > +{
> > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > +     int ret;
> > > > > +
> > > > > +     ret = gpiod_get_value(conf->cdone);
> > > > > +     if (ret < 0)
> > > > > +             dev_err(&mgr->dev, "Error reading CDONE (%d)\n", ret);
> > > > > +
> > > > > +     return ret;
> > > > > +}
> > > > > +
> > > > > +static void reset(struct fpga_manager *mgr)
> > > >
> > > > Please unify the naming of the internal functions. You use
> > > > 'efinix_spi_apply_clk_cycles()' below.
> > > >
> > > > > +{
> > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > +
> > > > > +     gpiod_set_value(conf->creset, 1);
> > > > > +     /* wait tCRESET_N */
> > > > > +     usleep_range(5, 15);
> > > > > +     gpiod_set_value(conf->creset, 0);
> > > > > +}
> > > > > +
> > > > > +static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
> > > > > +{
> > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > +
> > > > > +     if (conf->cdone && get_cdone_gpio(mgr) == 1)
> > > > > +             return FPGA_MGR_STATE_OPERATING;
> > > > > +
> > > > > +     return FPGA_MGR_STATE_UNKNOWN;
> > > > > +}
> > > > > +
> > > > > +static int efinix_spi_apply_clk_cycles(struct fpga_manager *mgr)
> > > > > +{
> > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > +     char data[13] = {0};
> > > > > +
> > > > > +     return spi_write(conf->spi, data, sizeof(data));
> > > > > +}
> > > > > +
> > > > > +static int efinix_spi_write_init(struct fpga_manager *mgr,
> > > > > +                              struct fpga_image_info *info,
> > > > > +                              const char *buf, size_t count)
> > > > > +{
> > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > +
> > > > > +     if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> > > > > +             dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     /* reset with chip select active */
> > > > > +     gpiod_set_value(conf->cs, 1);
> > > >
> > > > Why operating chip selective at SPI client driver? Isn't it the job for SPI
> > > > controller?
> > > to enter the passive programming mode, a reset must be executed while
> > > the chip select is active.
> > > The is controlling the chip select from here, since I expect that the
> > > SPI controller to only activate
> > > the CS when communicating.
> >
> > The concern is, it may conflict with the underlying cs control in spi
> > controller.
> >
> > There are several control flags in struct spi_transfter to affect cs. Is
> > there any chance using them, or try to improve if they doesn't meet your
> > request?
> The main problem of this chip is that probably the of SPI is out of
> spec, so would like to avoid changes in the spi contoller for this
> edge case.
> That is probably one the reasons that the datasheet does not recommend
> other devices on the same SPI bus.

I think anyway you need to communicate with spi controller driver and
have one voice how/who to take control of cs, rather than blindly
operate at both sides.

Thanks,
Yilun

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

* Re: [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-07-29 14:50             ` Xu Yilun
@ 2024-08-09 10:38               ` Ian Dannapel
  0 siblings, 0 replies; 24+ messages in thread
From: Ian Dannapel @ 2024-08-09 10:38 UTC (permalink / raw)
  To: Xu Yilun
  Cc: Moritz Fischer, Wu Hao, Xu Yilun, Tom Rix, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner, Neil Armstrong,
	Sebastian Reichel, Chris Morgan, Michael Riesch,
	Rafał Miłecki, Andre Przywara, Linus Walleij,
	linux-fpga, devicetree, linux-kernel

Am Mo., 29. Juli 2024 um 16:52 Uhr schrieb Xu Yilun <yilun.xu@linux.intel.com>:
>
> On Sun, Jul 28, 2024 at 01:44:03PM +0200, Ian Dannapel wrote:
> > Am Sa., 27. Juli 2024 um 18:00 Uhr schrieb Xu Yilun <yilun.xu@linux.intel.com>:
> > >
> > > On Thu, Jul 25, 2024 at 03:44:54PM +0200, Ian Dannapel wrote:
> > > > Hi Yilun, thanks for the review.
> > > >
> > > > Am Fr., 12. Juli 2024 um 09:00 Uhr schrieb Xu Yilun <yilun.xu@linux.intel.com>:
> > > > >
> > > > > On Fri, Jun 28, 2024 at 05:23:46PM +0200, iansdannapel@gmail.com wrote:
> > > > > > From: Ian Dannapel <iansdannapel@gmail.com>
> > > > > >
> > > > >
> > > > > Please don't reply to the previous series when you post a new version.
> > > > sure
> > > > >
> > > > > > Add a new driver for loading binary firmware using "SPI passive
> > > > >
> > > > > Loading to some nvram or reporgraming to FPGA logic blocks.
> > >
> > > Sorry for typo, this is a question:
> > >
> > >   Loading to some nvram or reporgraming to FPGA logic blocks?
> > The datasheet refers to it as configuration RAM (CRAM) and must be
> > loaded on every boot up.
>
> The FPGA reprogramming is about loading the FPGA logic blocks, and from
> the POV of the System, it is about runtime changing the HW and
> re-enumerate the devices.
>
> But some submitted fpga-mgr drivers are just used to to write nvram
> backend for FPGA, don't affect any running device at all. I think these
> drivers virtually have nothing to do with fpga-mgr. Some generic
> storage (e.g. nvram, mtd) or firmware image loading interfaces better
> fit them. I assume this driver is also of this kind.
To clarify, this driver does not write to a nvram or any persistent
memory. Programming or reprogramming at runtime is necessary, but
partial reprogramming is not supported.
>
> > >
> > > > >
> > > > > > programming" on Efinix FPGAs.
> > > > > >
> > > > > > Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> > > > > > ---
> > > > > >  drivers/fpga/Kconfig                    |   8 +
> > > > > >  drivers/fpga/Makefile                   |   1 +
> > > > > >  drivers/fpga/efinix-trion-spi-passive.c | 219 ++++++++++++++++++++++++
> > > > > >  3 files changed, 228 insertions(+)
> > > > > >  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> > > > > >
> > > > > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > > > > > index 37b35f58f0df..25579510e49e 100644
> > > > > > --- a/drivers/fpga/Kconfig
> > > > > > +++ b/drivers/fpga/Kconfig
> > > > > > @@ -83,6 +83,14 @@ config FPGA_MGR_XILINX_SPI
> > > > > >         FPGA manager driver support for Xilinx FPGA configuration
> > > > > >         over slave serial interface.
> > > > > >
> > > > > > +config FPGA_MGR_EFINIX_SPI
> > > > > > +     tristate "Efinix FPGA configuration over SPI passive"
> > > > > > +     depends on SPI
> > > > > > +     help
> > > > > > +       This option enables support for the FPGA manager driver to
> > > > > > +       configure Efinix Trion and Titanium Series FPGAs over SPI
> > > > > > +       using passive serial mode.
> > > > > > +
> > > > > >  config FPGA_MGR_ICE40_SPI
> > > > > >       tristate "Lattice iCE40 SPI"
> > > > > >       depends on OF && SPI
> > > > > > diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> > > > > > index aeb89bb13517..1a95124ff847 100644
> > > > > > --- a/drivers/fpga/Makefile
> > > > > > +++ b/drivers/fpga/Makefile
> > > > > > @@ -18,6 +18,7 @@ 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_EFINIX_SPI)    += efinix-trion-spi-passive.o
> > > > > >  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)     += zynq-fpga.o
> > > > > >  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)   += zynqmp-fpga.o
> > > > > >  obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)   += versal-fpga.o
> > > > > > diff --git a/drivers/fpga/efinix-trion-spi-passive.c b/drivers/fpga/efinix-trion-spi-passive.c
> > > > > > new file mode 100644
> > > > > > index 000000000000..eb2592e788b9
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/fpga/efinix-trion-spi-passive.c
> > > > > > @@ -0,0 +1,219 @@
> > > > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > > > +/*
> > > > > > + * Trion and Titanium Series FPGA SPI Passive Programming Driver
> > > > > > + *
> > > > > > + * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
> > > > > > + *
> > > > > > + * Ian Dannapel <iansdannapel@gmail.com>
> > > > > > + *
> > > > > > + * Manage Efinix FPGA firmware that is loaded over SPI using
> > > > > > + * the serial configuration interface.
> > > > > > + */
> > > > > > +
> > > > > > +#include <linux/delay.h>
> > > > > > +#include <linux/device.h>
> > > > > > +#include <linux/fpga/fpga-mgr.h>
> > > > > > +#include <linux/gpio/consumer.h>
> > > > > > +#include <linux/module.h>
> > > > > > +#include <linux/mod_devicetable.h>
> > > > > > +#include <linux/of.h>
> > > > > > +#include <linux/spi/spi.h>
> > > > > > +#include <linux/sizes.h>
> > > > > > +
> > > > > > +struct efinix_spi_conf {
> > > > > > +     struct spi_device *spi;
> > > > > > +     struct gpio_desc *cdone;
> > > > > > +     struct gpio_desc *creset;
> > > > > > +     struct gpio_desc *cs;
> > > > > > +};
> > > > > > +
> > > > > > +static int get_cdone_gpio(struct fpga_manager *mgr)
> > > > >
> > > > > Is it better use 'struct efinix_spi_conf *conf' as parameter?
> > > > >
> > > > > Same for the following functions.
> > > > >
> > > > > > +{
> > > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > > +     int ret;
> > > > > > +
> > > > > > +     ret = gpiod_get_value(conf->cdone);
> > > > > > +     if (ret < 0)
> > > > > > +             dev_err(&mgr->dev, "Error reading CDONE (%d)\n", ret);
> > > > > > +
> > > > > > +     return ret;
> > > > > > +}
> > > > > > +
> > > > > > +static void reset(struct fpga_manager *mgr)
> > > > >
> > > > > Please unify the naming of the internal functions. You use
> > > > > 'efinix_spi_apply_clk_cycles()' below.
> > > > >
> > > > > > +{
> > > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > > +
> > > > > > +     gpiod_set_value(conf->creset, 1);
> > > > > > +     /* wait tCRESET_N */
> > > > > > +     usleep_range(5, 15);
> > > > > > +     gpiod_set_value(conf->creset, 0);
> > > > > > +}
> > > > > > +
> > > > > > +static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
> > > > > > +{
> > > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > > +
> > > > > > +     if (conf->cdone && get_cdone_gpio(mgr) == 1)
> > > > > > +             return FPGA_MGR_STATE_OPERATING;
> > > > > > +
> > > > > > +     return FPGA_MGR_STATE_UNKNOWN;
> > > > > > +}
> > > > > > +
> > > > > > +static int efinix_spi_apply_clk_cycles(struct fpga_manager *mgr)
> > > > > > +{
> > > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > > +     char data[13] = {0};
> > > > > > +
> > > > > > +     return spi_write(conf->spi, data, sizeof(data));
> > > > > > +}
> > > > > > +
> > > > > > +static int efinix_spi_write_init(struct fpga_manager *mgr,
> > > > > > +                              struct fpga_image_info *info,
> > > > > > +                              const char *buf, size_t count)
> > > > > > +{
> > > > > > +     struct efinix_spi_conf *conf = mgr->priv;
> > > > > > +
> > > > > > +     if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> > > > > > +             dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> > > > > > +             return -EINVAL;
> > > > > > +     }
> > > > > > +
> > > > > > +     /* reset with chip select active */
> > > > > > +     gpiod_set_value(conf->cs, 1);
> > > > >
> > > > > Why operating chip selective at SPI client driver? Isn't it the job for SPI
> > > > > controller?
> > > > to enter the passive programming mode, a reset must be executed while
> > > > the chip select is active.
> > > > The is controlling the chip select from here, since I expect that the
> > > > SPI controller to only activate
> > > > the CS when communicating.
> > >
> > > The concern is, it may conflict with the underlying cs control in spi
> > > controller.
> > >
> > > There are several control flags in struct spi_transfter to affect cs. Is
> > > there any chance using them, or try to improve if they doesn't meet your
> > > request?
> > The main problem of this chip is that probably the of SPI is out of
> > spec, so would like to avoid changes in the spi contoller for this
> > edge case.
> > That is probably one the reasons that the datasheet does not recommend
> > other devices on the same SPI bus.
>
> I think anyway you need to communicate with spi controller driver and
> have one voice how/who to take control of cs, rather than blindly
> operate at both sides.
I did not find a clear solution yet. This FGPA device requires an SPI
without a chip-select signal and no other device transaction should be
allowed in between reprogramming, which seems to be a very specific
case for the SPI Controller to manage
>
> Thanks,
> Yilun

Thank
Ian

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

* [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
@ 2024-09-27 14:14 iansdannapel
  2024-09-27 14:22 ` Krzysztof Kozlowski
  2024-10-18  1:37 ` Xu Yilun
  0 siblings, 2 replies; 24+ messages in thread
From: iansdannapel @ 2024-09-27 14:14 UTC (permalink / raw)
  To: mdf, hao.wu, yilun.xu, trix, robh, krzk+dt, conor+dt,
	neil.armstrong, heiko.stuebner, rafal, linus.walleij,
	iansdannapel, linux-fpga, devicetree, linux-kernel

From: Ian Dannapel <iansdannapel@gmail.com>

Add a new driver for loading binary firmware to volatile
configuration RAM using "SPI passive programming" on Efinix FPGAs.

Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
---
 drivers/fpga/Kconfig                    |  10 ++
 drivers/fpga/Makefile                   |   1 +
 drivers/fpga/efinix-trion-spi-passive.c | 211 ++++++++++++++++++++++++
 3 files changed, 222 insertions(+)
 create mode 100644 drivers/fpga/efinix-trion-spi-passive.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 37b35f58f0df..eb1e44c4e3e0 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -83,6 +83,16 @@ config FPGA_MGR_XILINX_SPI
 	  FPGA manager driver support for Xilinx FPGA configuration
 	  over slave serial interface.
 
+config FPGA_MGR_EFINIX_SPI
+	tristate "Efinix FPGA configuration over SPI passive"
+	depends on SPI
+	help
+	  This option enables support for the FPGA manager driver to
+	  configure Efinix Trion and Titanium Series FPGAs over SPI
+	  using passive serial mode.
+	  Warning: Do not activate this if there are other SPI devices
+	  on the same bus as it might interfere with the transmission.
+
 config FPGA_MGR_ICE40_SPI
 	tristate "Lattice iCE40 SPI"
 	depends on OF && SPI
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index aeb89bb13517..1a95124ff847 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -18,6 +18,7 @@ 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_EFINIX_SPI)	+= efinix-trion-spi-passive.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
 obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
 obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)	+= versal-fpga.o
diff --git a/drivers/fpga/efinix-trion-spi-passive.c b/drivers/fpga/efinix-trion-spi-passive.c
new file mode 100644
index 000000000000..87ff645265ca
--- /dev/null
+++ b/drivers/fpga/efinix-trion-spi-passive.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Trion and Titanium Series FPGA SPI Passive Programming Driver
+ *
+ * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
+ *
+ * Ian Dannapel <iansdannapel@gmail.com>
+ *
+ * Manage Efinix FPGA firmware that is loaded over SPI using
+ * the serial configuration interface.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+#include <linux/sizes.h>
+
+struct efinix_spi_conf {
+	struct spi_device *spi;
+	struct gpio_desc *cdone;
+	struct gpio_desc *creset;
+	struct gpio_desc *cs;
+};
+
+static int efinix_spi_get_cdone_gpio(struct efinix_spi_conf *conf)
+{
+	int ret;
+
+	ret = gpiod_get_value(conf->cdone);
+	return ret;
+}
+
+static void efinix_spi_reset(struct efinix_spi_conf *conf)
+{
+	gpiod_set_value(conf->creset, 1);
+	/* wait tCRESET_N */
+	usleep_range(5, 15);
+	gpiod_set_value(conf->creset, 0);
+}
+
+static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+
+	if (conf->cdone && efinix_spi_get_cdone_gpio(conf) == 1)
+		return FPGA_MGR_STATE_OPERATING;
+
+	return FPGA_MGR_STATE_UNKNOWN;
+}
+
+static int efinix_spi_apply_clk_cycles(struct efinix_spi_conf *conf)
+{
+	char data[13] = {0};
+
+	return spi_write(conf->spi, data, sizeof(data));
+}
+
+static int efinix_spi_write_init(struct fpga_manager *mgr,
+				 struct fpga_image_info *info,
+				 const char *buf, size_t count)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+
+	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
+		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
+		return -EINVAL;
+	}
+
+	/* reset with chip select active */
+	gpiod_set_value(conf->cs, 1);
+	usleep_range(5, 15);
+	efinix_spi_reset(conf);
+
+	/* wait tDMIN */
+	usleep_range(100, 150);
+
+	return 0;
+}
+
+static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
+			    size_t count)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	int ret;
+
+	ret = spi_write(conf->spi, buf, count);
+	if (ret) {
+		dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int efinix_spi_write_complete(struct fpga_manager *mgr,
+				     struct fpga_image_info *info)
+{
+	struct efinix_spi_conf *conf = mgr->priv;
+	unsigned long timeout =
+		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
+	bool expired = false;
+	int done;
+
+	/* append at least 100 clock cycles */
+	efinix_spi_apply_clk_cycles(conf);
+
+	/* release chip select */
+	gpiod_set_value(conf->cs, 0);
+
+	if (conf->cdone) {
+		while (!expired) {
+			expired = time_after(jiffies, timeout);
+
+			done = efinix_spi_get_cdone_gpio(conf);
+			if (done < 0)
+				return done;
+
+			if (done)
+				break;
+		}
+	}
+
+	if (expired)
+		return -ETIMEDOUT;
+
+	/* wait tUSER */
+	usleep_range(75, 125);
+
+	return 0;
+}
+
+static const struct fpga_manager_ops efinix_spi_ops = {
+	.state = efinix_spi_state,
+	.write_init = efinix_spi_write_init,
+	.write = efinix_spi_write,
+	.write_complete = efinix_spi_write_complete,
+};
+
+static int efinix_spi_probe(struct spi_device *spi)
+{
+	struct efinix_spi_conf *conf;
+	struct fpga_manager *mgr;
+
+	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
+	if (!conf)
+		return -ENOMEM;
+
+	conf->spi = spi;
+
+	conf->creset = devm_gpiod_get(&spi->dev, "creset", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->creset))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->creset),
+				"Failed to get RESET gpio\n");
+
+	conf->cs = devm_gpiod_get(&spi->dev, "cs", GPIOD_OUT_HIGH);
+	if (IS_ERR(conf->cs))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
+				"Failed to get CHIP_SELECT gpio\n");
+
+	if (!(spi->mode & SPI_CPHA) || !(spi->mode & SPI_CPOL))
+		return dev_err_probe(&spi->dev, -EINVAL,
+				"Unsupported SPI mode, set CPHA and CPOL\n");
+
+	conf->cdone = devm_gpiod_get_optional(&spi->dev, "cdone", GPIOD_IN);
+	if (IS_ERR(conf->cdone))
+		return dev_err_probe(&spi->dev, PTR_ERR(conf->cdone),
+				"Failed to get CDONE gpio\n");
+
+	mgr = devm_fpga_mgr_register(&spi->dev,
+				"Efinix SPI Passive Programming FPGA Manager",
+					&efinix_spi_ops, conf);
+
+	return PTR_ERR_OR_ZERO(mgr);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id efinix_spi_of_match[] = {
+	{ .compatible = "efinix,trion-spi-passive", },
+	{ .compatible = "efinix,titanium-spi-passive", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, efinix_spi_of_match);
+#endif
+
+static const struct spi_device_id efinix_ids[] = {
+	{ "trion-spi-passive", 0 },
+	{ "titanium-spi-passive", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(spi, efinix_ids);
+
+static struct spi_driver efinix_spi_passive_driver = {
+	.driver = {
+		.name = "efinix-fpga-spi-passive",
+		.of_match_table = of_match_ptr(efinix_spi_of_match),
+	},
+	.probe = efinix_spi_probe,
+	.id_table = efinix_ids,
+};
+
+module_spi_driver(efinix_spi_passive_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ian Dannapel <iansdannapel@gmail.com>");
+MODULE_DESCRIPTION("Load Efinix FPGA firmware over SPI passive");
-- 
2.34.1


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

* Re: [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-09-27 14:14 [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
@ 2024-09-27 14:22 ` Krzysztof Kozlowski
  2024-10-18  1:22   ` Xu Yilun
  2024-10-18  1:37 ` Xu Yilun
  1 sibling, 1 reply; 24+ messages in thread
From: Krzysztof Kozlowski @ 2024-09-27 14:22 UTC (permalink / raw)
  To: iansdannapel, mdf, hao.wu, yilun.xu, trix, robh, krzk+dt,
	conor+dt, neil.armstrong, heiko.stuebner, rafal, linus.walleij,
	linux-fpga, devicetree, linux-kernel

On 27/09/2024 16:14, iansdannapel@gmail.com wrote:
> From: Ian Dannapel <iansdannapel@gmail.com>
> 
> Add a new driver for loading binary firmware to volatile
> configuration RAM using "SPI passive programming" on Efinix FPGAs.
> 
> Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>

Thank you for your patch. There is something to discuss/improve.

> ---
>  drivers/fpga/Kconfig                    |  10 ++
>  drivers/fpga/Makefile                   |   1 +
>  drivers/fpga/efinix-trion-spi-passive.c | 211 ++++++++++++++++++++++++
>  3 files changed, 222 insertions(+)
>  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 37b35f58f0df..eb1e44c4e3e0 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -83,6 +83,16 @@ config FPGA_MGR_XILINX_SPI
>  	  FPGA manager driver support for Xilinx FPGA configuration
>  	  over slave serial interface.
>  
> +config FPGA_MGR_EFINIX_SPI
> +	tristate "Efinix FPGA configuration over SPI passive"
> +	depends on SPI
> +	help
> +	  This option enables support for the FPGA manager driver to
> +	  configure Efinix Trion and Titanium Series FPGAs over SPI
> +	  using passive serial mode.
> +	  Warning: Do not activate this if there are other SPI devices
> +	  on the same bus as it might interfere with the transmission.
> +
>  config FPGA_MGR_ICE40_SPI
>  	tristate "Lattice iCE40 SPI"
>  	depends on OF && SPI
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index aeb89bb13517..1a95124ff847 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -18,6 +18,7 @@ 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_EFINIX_SPI)	+= efinix-trion-spi-passive.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)	+= zynq-fpga.o
>  obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)	+= zynqmp-fpga.o
>  obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA)	+= versal-fpga.o
> diff --git a/drivers/fpga/efinix-trion-spi-passive.c b/drivers/fpga/efinix-trion-spi-passive.c
> new file mode 100644
> index 000000000000..87ff645265ca
> --- /dev/null
> +++ b/drivers/fpga/efinix-trion-spi-passive.c
> @@ -0,0 +1,211 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Trion and Titanium Series FPGA SPI Passive Programming Driver
> + *
> + * Copyright (C) 2024 iris-GmbH infrared & intelligent sensors
> + *
> + * Ian Dannapel <iansdannapel@gmail.com>
> + *
> + * Manage Efinix FPGA firmware that is loaded over SPI using
> + * the serial configuration interface.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/of.h>
> +#include <linux/spi/spi.h>
> +#include <linux/sizes.h>
> +
> +struct efinix_spi_conf {
> +	struct spi_device *spi;
> +	struct gpio_desc *cdone;
> +	struct gpio_desc *creset;
> +	struct gpio_desc *cs;
> +};
> +
> +static int efinix_spi_get_cdone_gpio(struct efinix_spi_conf *conf)
> +{
> +	int ret;
> +
> +	ret = gpiod_get_value(conf->cdone);

This should be just return gpiod_get_value()... but then it's quite
simple wrapper, so just use it directly.

> +	return ret;
> +}
> +
> +static void efinix_spi_reset(struct efinix_spi_conf *conf)
> +{
> +	gpiod_set_value(conf->creset, 1);
> +	/* wait tCRESET_N */
> +	usleep_range(5, 15);
> +	gpiod_set_value(conf->creset, 0);
> +}
> +
> +static enum fpga_mgr_states efinix_spi_state(struct fpga_manager *mgr)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +
> +	if (conf->cdone && efinix_spi_get_cdone_gpio(conf) == 1)
> +		return FPGA_MGR_STATE_OPERATING;
> +
> +	return FPGA_MGR_STATE_UNKNOWN;
> +}
> +
> +static int efinix_spi_apply_clk_cycles(struct efinix_spi_conf *conf)
> +{
> +	char data[13] = {0};
> +
> +	return spi_write(conf->spi, data, sizeof(data));

Hm, aren't buffers from stack discouraged? spi-summary explicitly
mentions this case or I am getting this wrong?

> +}
> +
> +static int efinix_spi_write_init(struct fpga_manager *mgr,
> +				 struct fpga_image_info *info,
> +				 const char *buf, size_t count)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +
> +	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
> +		dev_err(&mgr->dev, "Partial reconfiguration not supported\n");
> +		return -EINVAL;
> +	}
> +
> +	/* reset with chip select active */
> +	gpiod_set_value(conf->cs, 1);
> +	usleep_range(5, 15);
> +	efinix_spi_reset(conf);
> +
> +	/* wait tDMIN */
> +	usleep_range(100, 150);
> +
> +	return 0;
> +}
> +
> +static int efinix_spi_write(struct fpga_manager *mgr, const char *buf,
> +			    size_t count)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	int ret;
> +
> +	ret = spi_write(conf->spi, buf, count);
> +	if (ret) {
> +		dev_err(&mgr->dev, "SPI error in firmware write: %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int efinix_spi_write_complete(struct fpga_manager *mgr,
> +				     struct fpga_image_info *info)
> +{
> +	struct efinix_spi_conf *conf = mgr->priv;
> +	unsigned long timeout =
> +		jiffies + usecs_to_jiffies(info->config_complete_timeout_us);
> +	bool expired = false;
> +	int done;
> +
> +	/* append at least 100 clock cycles */
> +	efinix_spi_apply_clk_cycles(conf);
> +
> +	/* release chip select */
> +	gpiod_set_value(conf->cs, 0);
> +
> +	if (conf->cdone) {
> +		while (!expired) {
> +			expired = time_after(jiffies, timeout);
> +
> +			done = efinix_spi_get_cdone_gpio(conf);
> +			if (done < 0)
> +				return done;
> +
> +			if (done)
> +				break;
> +		}
> +	}
> +
> +	if (expired)
> +		return -ETIMEDOUT;
> +
> +	/* wait tUSER */
> +	usleep_range(75, 125);
> +
> +	return 0;
> +}
> +
> +static const struct fpga_manager_ops efinix_spi_ops = {
> +	.state = efinix_spi_state,
> +	.write_init = efinix_spi_write_init,
> +	.write = efinix_spi_write,
> +	.write_complete = efinix_spi_write_complete,
> +};
> +
> +static int efinix_spi_probe(struct spi_device *spi)
> +{
> +	struct efinix_spi_conf *conf;
> +	struct fpga_manager *mgr;
> +
> +	conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
> +	if (!conf)
> +		return -ENOMEM;
> +
> +	conf->spi = spi;
> +
> +	conf->creset = devm_gpiod_get(&spi->dev, "creset", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->creset))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->creset),
> +				"Failed to get RESET gpio\n");
> +
> +	conf->cs = devm_gpiod_get(&spi->dev, "cs", GPIOD_OUT_HIGH);
> +	if (IS_ERR(conf->cs))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->cs),
> +				"Failed to get CHIP_SELECT gpio\n");
> +
> +	if (!(spi->mode & SPI_CPHA) || !(spi->mode & SPI_CPOL))
> +		return dev_err_probe(&spi->dev, -EINVAL,
> +				"Unsupported SPI mode, set CPHA and CPOL\n");
> +
> +	conf->cdone = devm_gpiod_get_optional(&spi->dev, "cdone", GPIOD_IN);
> +	if (IS_ERR(conf->cdone))
> +		return dev_err_probe(&spi->dev, PTR_ERR(conf->cdone),
> +				"Failed to get CDONE gpio\n");
> +
> +	mgr = devm_fpga_mgr_register(&spi->dev,
> +				"Efinix SPI Passive Programming FPGA Manager",
> +					&efinix_spi_ops, conf);
> +
> +	return PTR_ERR_OR_ZERO(mgr);
> +}
> +
> +#ifdef CONFIG_OF

Drop

> +static const struct of_device_id efinix_spi_of_match[] = {
> +	{ .compatible = "efinix,trion-spi-passive", },
> +	{ .compatible = "efinix,titanium-spi-passive", },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, efinix_spi_of_match);
> +#endif
> +
> +static const struct spi_device_id efinix_ids[] = {
> +	{ "trion-spi-passive", 0 },
> +	{ "titanium-spi-passive", 0 },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(spi, efinix_ids);
> +
> +static struct spi_driver efinix_spi_passive_driver = {
> +	.driver = {
> +		.name = "efinix-fpga-spi-passive",
> +		.of_match_table = of_match_ptr(efinix_spi_of_match),

Drop of_match_ptr


Best regards,
Krzysztof


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

* Re: [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-09-27 14:22 ` Krzysztof Kozlowski
@ 2024-10-18  1:22   ` Xu Yilun
  0 siblings, 0 replies; 24+ messages in thread
From: Xu Yilun @ 2024-10-18  1:22 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: iansdannapel, mdf, hao.wu, yilun.xu, trix, robh, krzk+dt,
	conor+dt, neil.armstrong, heiko.stuebner, rafal, linus.walleij,
	linux-fpga, devicetree, linux-kernel

> > +static int efinix_spi_apply_clk_cycles(struct efinix_spi_conf *conf)
> > +{
> > +	char data[13] = {0};
> > +
> > +	return spi_write(conf->spi, data, sizeof(data));
> 
> Hm, aren't buffers from stack discouraged? spi-summary explicitly
> mentions this case or I am getting this wrong?

You are right. And there were already some fixes for this issue in FPGA. E.g.

https://lore.kernel.org/all/20221230092922.18822-2-i.bornyakov@metrotek.ru/

Thanks,
Yilun

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

* Re: [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-09-27 14:14 [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
  2024-09-27 14:22 ` Krzysztof Kozlowski
@ 2024-10-18  1:37 ` Xu Yilun
  2024-10-18 16:58   ` Conor Dooley
  1 sibling, 1 reply; 24+ messages in thread
From: Xu Yilun @ 2024-10-18  1:37 UTC (permalink / raw)
  To: iansdannapel
  Cc: mdf, hao.wu, yilun.xu, trix, robh, krzk+dt, conor+dt,
	neil.armstrong, heiko.stuebner, rafal, linus.walleij, linux-fpga,
	devicetree, linux-kernel

On Fri, Sep 27, 2024 at 04:14:42PM +0200, iansdannapel@gmail.com wrote:
> From: Ian Dannapel <iansdannapel@gmail.com>
> 
> Add a new driver for loading binary firmware to volatile
> configuration RAM using "SPI passive programming" on Efinix FPGAs.
> 
> Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> ---
>  drivers/fpga/Kconfig                    |  10 ++
>  drivers/fpga/Makefile                   |   1 +
>  drivers/fpga/efinix-trion-spi-passive.c | 211 ++++++++++++++++++++++++
>  3 files changed, 222 insertions(+)
>  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 37b35f58f0df..eb1e44c4e3e0 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -83,6 +83,16 @@ config FPGA_MGR_XILINX_SPI
>  	  FPGA manager driver support for Xilinx FPGA configuration
>  	  over slave serial interface.
>  
> +config FPGA_MGR_EFINIX_SPI
> +	tristate "Efinix FPGA configuration over SPI passive"
> +	depends on SPI
> +	help
> +	  This option enables support for the FPGA manager driver to
> +	  configure Efinix Trion and Titanium Series FPGAs over SPI
> +	  using passive serial mode.
> +	  Warning: Do not activate this if there are other SPI devices
> +	  on the same bus as it might interfere with the transmission.

Sorry, this won't work. As you can see, the conflict usage of CS causes
several concerns. Just a text here is far from enough.

You need to actively work with SPI core/controller drivers to find a
solution that coordinate the usage of this pin.

Thanks
Yilun

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

* Re: [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-10-18  1:37 ` Xu Yilun
@ 2024-10-18 16:58   ` Conor Dooley
  2024-10-21  2:10     ` Xu Yilun
  0 siblings, 1 reply; 24+ messages in thread
From: Conor Dooley @ 2024-10-18 16:58 UTC (permalink / raw)
  To: Xu Yilun
  Cc: iansdannapel, mdf, hao.wu, yilun.xu, trix, robh, krzk+dt,
	conor+dt, neil.armstrong, heiko.stuebner, rafal, linus.walleij,
	linux-fpga, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2031 bytes --]

On Fri, Oct 18, 2024 at 09:37:22AM +0800, Xu Yilun wrote:
> On Fri, Sep 27, 2024 at 04:14:42PM +0200, iansdannapel@gmail.com wrote:
> > From: Ian Dannapel <iansdannapel@gmail.com>
> > 
> > Add a new driver for loading binary firmware to volatile
> > configuration RAM using "SPI passive programming" on Efinix FPGAs.
> > 
> > Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> > ---
> >  drivers/fpga/Kconfig                    |  10 ++
> >  drivers/fpga/Makefile                   |   1 +
> >  drivers/fpga/efinix-trion-spi-passive.c | 211 ++++++++++++++++++++++++
> >  3 files changed, 222 insertions(+)
> >  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> > 
> > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > index 37b35f58f0df..eb1e44c4e3e0 100644
> > --- a/drivers/fpga/Kconfig
> > +++ b/drivers/fpga/Kconfig
> > @@ -83,6 +83,16 @@ config FPGA_MGR_XILINX_SPI
> >  	  FPGA manager driver support for Xilinx FPGA configuration
> >  	  over slave serial interface.
> >  
> > +config FPGA_MGR_EFINIX_SPI
> > +	tristate "Efinix FPGA configuration over SPI passive"
> > +	depends on SPI
> > +	help
> > +	  This option enables support for the FPGA manager driver to
> > +	  configure Efinix Trion and Titanium Series FPGAs over SPI
> > +	  using passive serial mode.
> > +	  Warning: Do not activate this if there are other SPI devices
> > +	  on the same bus as it might interfere with the transmission.
> 
> Sorry, this won't work. As you can see, the conflict usage of CS causes
> several concerns. Just a text here is far from enough.
> 
> You need to actively work with SPI core/controller drivers to find a
> solution that coordinate the usage of this pin.

Why does it even impact other SPI devices on the bus? It's not /their/
CS line that is being modified here, it is the line for the FPGA's
programming interface, right?
What am I missing here that makes it any different to any other SPI
device that may need it's CS toggled?

Cheers,
Conor.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-10-18 16:58   ` Conor Dooley
@ 2024-10-21  2:10     ` Xu Yilun
  2024-10-21 12:18       ` Conor Dooley
  0 siblings, 1 reply; 24+ messages in thread
From: Xu Yilun @ 2024-10-21  2:10 UTC (permalink / raw)
  To: Conor Dooley
  Cc: iansdannapel, mdf, hao.wu, yilun.xu, trix, robh, krzk+dt,
	conor+dt, neil.armstrong, heiko.stuebner, rafal, linus.walleij,
	linux-fpga, devicetree, linux-kernel

On Fri, Oct 18, 2024 at 05:58:44PM +0100, Conor Dooley wrote:
> On Fri, Oct 18, 2024 at 09:37:22AM +0800, Xu Yilun wrote:
> > On Fri, Sep 27, 2024 at 04:14:42PM +0200, iansdannapel@gmail.com wrote:
> > > From: Ian Dannapel <iansdannapel@gmail.com>
> > > 
> > > Add a new driver for loading binary firmware to volatile
> > > configuration RAM using "SPI passive programming" on Efinix FPGAs.
> > > 
> > > Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> > > ---
> > >  drivers/fpga/Kconfig                    |  10 ++
> > >  drivers/fpga/Makefile                   |   1 +
> > >  drivers/fpga/efinix-trion-spi-passive.c | 211 ++++++++++++++++++++++++
> > >  3 files changed, 222 insertions(+)
> > >  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> > > 
> > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > > index 37b35f58f0df..eb1e44c4e3e0 100644
> > > --- a/drivers/fpga/Kconfig
> > > +++ b/drivers/fpga/Kconfig
> > > @@ -83,6 +83,16 @@ config FPGA_MGR_XILINX_SPI
> > >  	  FPGA manager driver support for Xilinx FPGA configuration
> > >  	  over slave serial interface.
> > >  
> > > +config FPGA_MGR_EFINIX_SPI
> > > +	tristate "Efinix FPGA configuration over SPI passive"
> > > +	depends on SPI
> > > +	help
> > > +	  This option enables support for the FPGA manager driver to
> > > +	  configure Efinix Trion and Titanium Series FPGAs over SPI
> > > +	  using passive serial mode.
> > > +	  Warning: Do not activate this if there are other SPI devices
> > > +	  on the same bus as it might interfere with the transmission.
> > 
> > Sorry, this won't work. As you can see, the conflict usage of CS causes
> > several concerns. Just a text here is far from enough.
> > 
> > You need to actively work with SPI core/controller drivers to find a
> > solution that coordinate the usage of this pin.
> 
> Why does it even impact other SPI devices on the bus? It's not /their/
> CS line that is being modified here, it is the line for the FPGA's
> programming interface, right?
> What am I missing here that makes it any different to any other SPI
> device that may need it's CS toggled?

IIUC, now spi core or controller driver should fully responsible for
HW operations of CS. And every good behaved spi device driver should
declare their logical CS index defined by SPI controller and let SPI
core/controller driver to proxy the CS change.

But if this spi device driver directly aquires CS, it conflicts with
the controller and just fails.

Thanks,
Yilun

> 
> Cheers,
> Conor.



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

* Re: [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-10-21  2:10     ` Xu Yilun
@ 2024-10-21 12:18       ` Conor Dooley
  2024-10-21 13:23         ` Ian Dannapel
  0 siblings, 1 reply; 24+ messages in thread
From: Conor Dooley @ 2024-10-21 12:18 UTC (permalink / raw)
  To: Xu Yilun
  Cc: iansdannapel, mdf, hao.wu, yilun.xu, trix, robh, krzk+dt,
	conor+dt, neil.armstrong, heiko.stuebner, rafal, linus.walleij,
	linux-fpga, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3049 bytes --]

On Mon, Oct 21, 2024 at 10:10:20AM +0800, Xu Yilun wrote:
> On Fri, Oct 18, 2024 at 05:58:44PM +0100, Conor Dooley wrote:
> > On Fri, Oct 18, 2024 at 09:37:22AM +0800, Xu Yilun wrote:
> > > On Fri, Sep 27, 2024 at 04:14:42PM +0200, iansdannapel@gmail.com wrote:
> > > > From: Ian Dannapel <iansdannapel@gmail.com>
> > > > 
> > > > Add a new driver for loading binary firmware to volatile
> > > > configuration RAM using "SPI passive programming" on Efinix FPGAs.
> > > > 
> > > > Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> > > > ---
> > > >  drivers/fpga/Kconfig                    |  10 ++
> > > >  drivers/fpga/Makefile                   |   1 +
> > > >  drivers/fpga/efinix-trion-spi-passive.c | 211 ++++++++++++++++++++++++
> > > >  3 files changed, 222 insertions(+)
> > > >  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> > > > 
> > > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > > > index 37b35f58f0df..eb1e44c4e3e0 100644
> > > > --- a/drivers/fpga/Kconfig
> > > > +++ b/drivers/fpga/Kconfig
> > > > @@ -83,6 +83,16 @@ config FPGA_MGR_XILINX_SPI
> > > >  	  FPGA manager driver support for Xilinx FPGA configuration
> > > >  	  over slave serial interface.
> > > >  
> > > > +config FPGA_MGR_EFINIX_SPI
> > > > +	tristate "Efinix FPGA configuration over SPI passive"
> > > > +	depends on SPI
> > > > +	help
> > > > +	  This option enables support for the FPGA manager driver to
> > > > +	  configure Efinix Trion and Titanium Series FPGAs over SPI
> > > > +	  using passive serial mode.
> > > > +	  Warning: Do not activate this if there are other SPI devices
> > > > +	  on the same bus as it might interfere with the transmission.
> > > 
> > > Sorry, this won't work. As you can see, the conflict usage of CS causes
> > > several concerns. Just a text here is far from enough.
> > > 
> > > You need to actively work with SPI core/controller drivers to find a
> > > solution that coordinate the usage of this pin.
> > 
> > Why does it even impact other SPI devices on the bus? It's not /their/
> > CS line that is being modified here, it is the line for the FPGA's
> > programming interface, right?
> > What am I missing here that makes it any different to any other SPI
> > device that may need it's CS toggled?
> 
> IIUC, now spi core or controller driver should fully responsible for
> HW operations of CS. And every good behaved spi device driver should
> declare their logical CS index defined by SPI controller and let SPI
> core/controller driver to proxy the CS change.
> 
> But if this spi device driver directly aquires CS, it conflicts with
> the controller and just fails.

Right, I don't think you answered my question here at all, but just
reading over the kconfig text again I think I understand what it means.
I'd interpreted this as other devices being impacted by what this driver
is doing, but actually it is talking about other devices on the bus
interfering with this one because of how it handles the chip select.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver
  2024-10-21 12:18       ` Conor Dooley
@ 2024-10-21 13:23         ` Ian Dannapel
  0 siblings, 0 replies; 24+ messages in thread
From: Ian Dannapel @ 2024-10-21 13:23 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Xu Yilun, mdf, hao.wu, yilun.xu, trix, robh, krzk+dt, conor+dt,
	neil.armstrong, heiko.stuebner, rafal, linus.walleij, linux-fpga,
	devicetree, linux-kernel

Am Mo., 21. Okt. 2024 um 14:18 Uhr schrieb Conor Dooley <conor@kernel.org>:
>
> On Mon, Oct 21, 2024 at 10:10:20AM +0800, Xu Yilun wrote:
> > On Fri, Oct 18, 2024 at 05:58:44PM +0100, Conor Dooley wrote:
> > > On Fri, Oct 18, 2024 at 09:37:22AM +0800, Xu Yilun wrote:
> > > > On Fri, Sep 27, 2024 at 04:14:42PM +0200, iansdannapel@gmail.com wrote:
> > > > > From: Ian Dannapel <iansdannapel@gmail.com>
> > > > >
> > > > > Add a new driver for loading binary firmware to volatile
> > > > > configuration RAM using "SPI passive programming" on Efinix FPGAs.
> > > > >
> > > > > Signed-off-by: Ian Dannapel <iansdannapel@gmail.com>
> > > > > ---
> > > > >  drivers/fpga/Kconfig                    |  10 ++
> > > > >  drivers/fpga/Makefile                   |   1 +
> > > > >  drivers/fpga/efinix-trion-spi-passive.c | 211 ++++++++++++++++++++++++
> > > > >  3 files changed, 222 insertions(+)
> > > > >  create mode 100644 drivers/fpga/efinix-trion-spi-passive.c
> > > > >
> > > > > diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> > > > > index 37b35f58f0df..eb1e44c4e3e0 100644
> > > > > --- a/drivers/fpga/Kconfig
> > > > > +++ b/drivers/fpga/Kconfig
> > > > > @@ -83,6 +83,16 @@ config FPGA_MGR_XILINX_SPI
> > > > >           FPGA manager driver support for Xilinx FPGA configuration
> > > > >           over slave serial interface.
> > > > >
> > > > > +config FPGA_MGR_EFINIX_SPI
> > > > > +       tristate "Efinix FPGA configuration over SPI passive"
> > > > > +       depends on SPI
> > > > > +       help
> > > > > +         This option enables support for the FPGA manager driver to
> > > > > +         configure Efinix Trion and Titanium Series FPGAs over SPI
> > > > > +         using passive serial mode.
> > > > > +         Warning: Do not activate this if there are other SPI devices
> > > > > +         on the same bus as it might interfere with the transmission.
> > > >
> > > > Sorry, this won't work. As you can see, the conflict usage of CS causes
> > > > several concerns. Just a text here is far from enough.
> > > >
> > > > You need to actively work with SPI core/controller drivers to find a
> > > > solution that coordinate the usage of this pin.
> > >
> > > Why does it even impact other SPI devices on the bus? It's not /their/
> > > CS line that is being modified here, it is the line for the FPGA's
> > > programming interface, right?
> > > What am I missing here that makes it any different to any other SPI
> > > device that may need it's CS toggled?
> >
> > IIUC, now spi core or controller driver should fully responsible for
> > HW operations of CS. And every good behaved spi device driver should
> > declare their logical CS index defined by SPI controller and let SPI
> > core/controller driver to proxy the CS change.
> >
> > But if this spi device driver directly aquires CS, it conflicts with
> > the controller and just fails.
>
> Right, I don't think you answered my question here at all, but just
> reading over the kconfig text again I think I understand what it means.
> I'd interpreted this as other devices being impacted by what this driver
> is doing, but actually it is talking about other devices on the bus
> interfering with this one because of how it handles the chip select.

Correct, the problem lies when other devices initiate a transfer in
between the device programming:
If the CS goes inactive in between, the fpga won't be programmed
correctly since it requires that all bytes are transferred within the
same CS active.
If the CS remains active, the fpga will be programmed with random payloads.

But I might have found a solution to coordinate the CS with the
controller (set_cs in struct spi_controller), since the cs state must
be set before any transfer to enter the programming mode.

Regards,
Ian

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

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

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-20 14:42 [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
2024-06-20 18:05 ` Marco Pagani
2024-06-28 15:23 ` [PATCH v2 0/3] Summary of changes iansdannapel
2024-06-28 15:23   ` [PATCH v2 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
2024-07-02 21:27     ` Dan Carpenter
2024-07-12  6:53     ` Xu Yilun
2024-07-25 13:44       ` Ian Dannapel
2024-07-27 15:58         ` Xu Yilun
2024-07-28 11:44           ` Ian Dannapel
2024-07-29 14:50             ` Xu Yilun
2024-08-09 10:38               ` Ian Dannapel
2024-06-28 15:23   ` [PATCH v2 2/3] dt-bindings: fpga: Add Efinix serial SPI programming bindings iansdannapel
2024-06-28 16:07     ` Conor Dooley
2024-06-28 15:23   ` [PATCH v2 3/3] dt-bindings: vendor-prefix: Add prefix for Efinix, Inc iansdannapel
2024-06-28 16:00     ` Conor Dooley
2024-07-02  8:57     ` Alexander Dahl
  -- strict thread matches above, loose matches on Subject: below --
2024-09-27 14:14 [PATCH 1/3] fpga: Add Efinix Trion & Titanium serial SPI programming driver iansdannapel
2024-09-27 14:22 ` Krzysztof Kozlowski
2024-10-18  1:22   ` Xu Yilun
2024-10-18  1:37 ` Xu Yilun
2024-10-18 16:58   ` Conor Dooley
2024-10-21  2:10     ` Xu Yilun
2024-10-21 12:18       ` Conor Dooley
2024-10-21 13:23         ` Ian Dannapel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).