All of lore.kernel.org
 help / color / mirror / Atom feed
From: Johannes Zink <j.zink@pengutronix.de>
To: linux-fpga@vger.kernel.org
Cc: devicetree@vger.kernel.org, Rob Herring <robh+dt@kernel.org>,
	Moritz Fischer <mdf@kernel.org>, Wu Hao <hao.wu@intel.com>,
	Xu Yilun <yilun.xu@intel.com>,
	kernel@pengutronix.de, Johannes Zink <j.zink@pengutronix.de>
Subject: [PATCH 16/16] fpga: machxo2: add configuration over i2c
Date: Thu, 25 Aug 2022 16:13:43 +0200	[thread overview]
Message-ID: <20220825141343.1375690-17-j.zink@pengutronix.de> (raw)
In-Reply-To: <20220825141343.1375690-1-j.zink@pengutronix.de>

From: Peter Jensen <pdj@bang-olufsen.dk>

The configuration flash of the machxo2 fpga can also be erased and
written over i2c instead of spi. Add this functionality to the
refactored common driver. Since some commands are shorter over I2C than
they are over SPI some quirks are added to the common driver in order to
account for that.

Signed-off-by: Peter Jensen <pdj@bang-olufsen.dk>
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Johannes Zink <j.zink@pengutronix.de>
---
 drivers/fpga/Kconfig          |   8 ++
 drivers/fpga/Makefile         |   1 +
 drivers/fpga/machxo2-common.c |  15 +++-
 drivers/fpga/machxo2-common.h |   3 +
 drivers/fpga/machxo2-i2c.c    | 137 ++++++++++++++++++++++++++++++++++
 5 files changed, 163 insertions(+), 1 deletion(-)
 create mode 100644 drivers/fpga/machxo2-i2c.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index e5869a732246..97081bbd7c19 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -90,6 +90,14 @@ config FPGA_MGR_MACHXO2_SPI
 	  FPGA manager driver support for Lattice MachXO2 configuration
 	  over slave SPI interface.
 
+config FPGA_MGR_MACHXO2_I2C
+	tristate "Lattice MachXO2 I2C"
+	depends on I2C
+	select FPGA_MGR_MACHXO2_COMMON
+	help
+	  FPGA manager driver support for Lattice MachXO2 configuration
+	  over slave I2C interface.
+
 config FPGA_MGR_TS73XX
 	tristate "Technologic Systems TS-73xx SBC FPGA Manager"
 	depends on ARCH_EP93XX && MACH_TS72XX
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index f247a8de83ad..fcdf79f4d424 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_FPGA_MGR_ALTERA_PS_SPI)	+= altera-ps-spi.o
 obj-$(CONFIG_FPGA_MGR_ICE40_SPI)	+= ice40-spi.o
 obj-$(CONFIG_FPGA_MGR_MACHXO2_COMMON)	+= machxo2-common.o
 obj-$(CONFIG_FPGA_MGR_MACHXO2_SPI)	+= machxo2-spi.o
+obj-$(CONFIG_FPGA_MGR_MACHXO2_I2C)	+= machxo2-i2c.o
 obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
 obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
 obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)	+= stratix10-soc.o
diff --git a/drivers/fpga/machxo2-common.c b/drivers/fpga/machxo2-common.c
index e8967cdee2c6..0a3c126675da 100644
--- a/drivers/fpga/machxo2-common.c
+++ b/drivers/fpga/machxo2-common.c
@@ -100,7 +100,7 @@ static void dump_status_reg(struct device *dev, u32 status)
 		!!FIELD_GET(MACHXO2_DVER, status), get_err_string(get_err(status)));
 }
 
-static int machxo2_wait_until_not_busy(struct machxo2_common_priv *priv)
+int machxo2_wait_until_not_busy(struct machxo2_common_priv *priv)
 {
 	u32 status;
 	int ret, loop = 0;
@@ -143,6 +143,11 @@ static int machxo2_cleanup(struct fpga_manager *mgr)
 	cmd.cmd = refresh;
 	cmd.cmd_len = sizeof(refresh);
 	cmd.delay_us = MACHXO2_REFRESH_USEC;
+
+	/* quirk: refresh command over i2c is 1 byte shorter */
+	if (priv->refresh_3b)
+		cmd.cmd_len--;
+
 	ret = priv->write_commands(priv, &cmd, 1);
 	if (ret)
 		goto fail;
@@ -207,6 +212,10 @@ static int machxo2_write_init(struct fpga_manager *mgr,
 	cmd[0].cmd_len = sizeof(enable);
 	cmd[0].delay_us = MACHXO2_LOW_DELAY_USEC;
 
+	/* quirk: enable command over i2c is 1 byte shorter */
+	if (priv->enable_3b)
+		cmd[0].cmd_len--;
+
 	cmd[1].cmd = (u8 *)&priv->erase_cmd;
 	cmd[1].cmd_len = sizeof(priv->erase_cmd);
 
@@ -313,6 +322,10 @@ static int machxo2_write_complete(struct fpga_manager *mgr,
 	cmd.cmd_len = sizeof(refresh);
 	cmd.delay_us = MACHXO2_REFRESH_USEC;
 
+	/* quirk: refresh command over i2c is 1 byte shorter */
+	if (priv->refresh_3b)
+		cmd.cmd_len--;
+
 	do {
 		ret = priv->write_commands(priv, &cmd, 1);
 		if (ret)
diff --git a/drivers/fpga/machxo2-common.h b/drivers/fpga/machxo2-common.h
index 0f9f53b48152..8c09345adee5 100644
--- a/drivers/fpga/machxo2-common.h
+++ b/drivers/fpga/machxo2-common.h
@@ -32,9 +32,12 @@ struct machxo2_common_priv {
 	int (*get_status)(struct machxo2_common_priv *priv, u32 *status);
 	struct device *dev;
 	__be32 erase_cmd;
+	u8 enable_3b:1;
+	u8 refresh_3b:1;
 	struct gpio_desc *fpga_program_n;
 };
 
 int machxo2_common_init(struct machxo2_common_priv *priv, struct device *dev);
+int machxo2_wait_until_not_busy(struct machxo2_common_priv *priv);
 
 #endif
diff --git a/drivers/fpga/machxo2-i2c.c b/drivers/fpga/machxo2-i2c.c
new file mode 100644
index 000000000000..a309016def1c
--- /dev/null
+++ b/drivers/fpga/machxo2-i2c.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lattice MachXO2 Slave I2C Driver
+ *
+ * Manage Lattice FPGA firmware that is loaded over I2C using
+ * the slave serial configuration interface.
+ *
+ * Copyright (C) 2018 Paolo Pisati <p.pisati@gmail.com>
+ * Copyright (C) 2021 Peter Jensen <pdj@bang-olufsen.dk>
+ */
+
+#include <linux/i2c.h>
+#include <linux/container_of.h>
+#include <linux/delay.h>
+#include "machxo2-common.h"
+
+
+struct machxo2_i2c_priv {
+	struct machxo2_common_priv common;
+	struct i2c_client *client;
+};
+
+static inline struct machxo2_i2c_priv *to_machxo2_i2c_priv(struct machxo2_common_priv *common)
+{
+	return container_of(common, struct machxo2_i2c_priv, common);
+}
+
+static int machxo2_i2c_get_status(struct machxo2_common_priv *bus, u32 *status)
+{
+	struct machxo2_i2c_priv *i2cPriv = to_machxo2_i2c_priv(bus);
+	struct i2c_client *client = i2cPriv->client;
+	u8 read_status[] = LSC_READ_STATUS;
+	__be32 tmp;
+	int ret;
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.buf = read_status,
+			.len = ARRAY_SIZE(read_status),
+		}, {
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.buf = (u8 *) &tmp,
+			.len = sizeof(tmp)
+		}
+	};
+
+	ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+	if (ret < 0)
+		return ret;
+	if (ret != ARRAY_SIZE(msg))
+		return -EIO;
+	*status = be32_to_cpu(tmp);
+
+	return 0;
+}
+
+static int machxo2_i2c_write(struct machxo2_common_priv *common,
+			     struct machxo2_cmd *cmds, size_t cmd_count)
+{
+	struct machxo2_i2c_priv *i2c_priv = to_machxo2_i2c_priv(common);
+	struct i2c_client *client = i2c_priv->client;
+	size_t i;
+	int ret;
+
+	for (i = 0; i < cmd_count; i++) {
+		struct i2c_msg msg[] = {
+			{
+				.addr = client->addr,
+				.buf = cmds[i].cmd,
+				.len = cmds[i].cmd_len,
+			},
+		};
+
+		ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+		if (ret < 0)
+			return ret;
+		if (ret != ARRAY_SIZE(msg))
+			return -EIO;
+		if (cmds[i].delay_us)
+			usleep_range(cmds[i].delay_us, cmds[i].delay_us +
+				     cmds[i].delay_us / 4);
+		if (i < cmd_count - 1) /* on any iteration except for the last one... */
+			ret = machxo2_wait_until_not_busy(common);
+	}
+
+	return 0;
+}
+
+static int machxo2_i2c_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct machxo2_i2c_priv *priv;
+
+	priv = devm_kzalloc(dev, sizeof(struct machxo2_i2c_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->client = client;
+	priv->common.get_status = machxo2_i2c_get_status;
+	priv->common.write_commands = machxo2_i2c_write;
+
+	/* Commands are usually 4b, but these aren't for i2c */
+	priv->common.enable_3b = true;
+	priv->common.refresh_3b = true;
+
+	return machxo2_common_init(&priv->common, dev);
+}
+
+static const struct of_device_id of_match[] = {
+	{ .compatible = "lattice,machxo2-slave-i2c", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, of_match);
+
+static const struct i2c_device_id lattice_ids[] = {
+	{ "machxo2-slave-i2c", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, lattice_ids);
+
+static struct i2c_driver machxo2_i2c_driver = {
+	.driver = {
+		.name = "machxo2-slave-i2c",
+		.of_match_table = of_match_ptr(of_match),
+	},
+	.probe = machxo2_i2c_probe,
+	.id_table = lattice_ids,
+};
+
+module_i2c_driver(machxo2_i2c_driver);
+
+MODULE_AUTHOR("Peter Jensen <pdj@bang-olufsen.dk>");
+MODULE_DESCRIPTION("Load Lattice FPGA firmware over I2C");
+MODULE_LICENSE("GPL");
-- 
2.30.2


  parent reply	other threads:[~2022-08-25 14:16 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-25 14:13 [PATCH 00/16] Add support for Lattice MachXO2 programming via I2C Johannes Zink
2022-08-25 14:13 ` [PATCH 01/16] dt-bindings: fpga: convert Lattice MachXO2 Slave binding to YAML Johannes Zink
2022-08-30 20:30   ` Rob Herring
2022-08-31  7:12     ` Johannes Zink
2022-08-25 14:13 ` [PATCH 02/16] dt-bindings: fpga: machxo2-slave: add erasure properties Johannes Zink
2022-08-29  7:39   ` Xu Yilun
     [not found]     ` <9d5512768acb4d57f339942007402a9ed9483e84.camel@pengutronix.de>
     [not found]       ` <YwzWt8KjyfdyqehI@yilunxu-OptiPlex-7050>
2022-08-31  7:38         ` Johannes Zink
2022-09-03 14:49           ` Xu Yilun
2022-08-30 20:36   ` Rob Herring
2022-08-31  7:07     ` Johannes Zink
2022-08-25 14:13 ` [PATCH 03/16] dt-bindings: fpga: machxo2-slave: add pin for program sequence init Johannes Zink
2022-08-25 18:51   ` Rob Herring
2022-08-26  7:56     ` Johannes Zink
2022-08-29  7:45   ` Xu Yilun
     [not found]     ` <a42d72cd71c96ca675f5bb0cf59128c7f1cb04bb.camel@pengutronix.de>
     [not found]       ` <YwzZYM6GU0GiqBiq@yilunxu-OptiPlex-7050>
2022-08-31  7:51         ` Johannes Zink
2022-08-31  8:08           ` Johannes Zink
2022-08-25 14:13 ` [PATCH 04/16] dt-bindings: fpga: machxo2-slave: add lattice,machxo2-slave-i2c compatible Johannes Zink
2022-08-30 20:40   ` Rob Herring
2022-08-31  7:10     ` Johannes Zink
2022-08-25 14:13 ` [PATCH 05/16] fpga: machxo2-spi: remove #ifdef DEBUG Johannes Zink
2022-08-25 14:13 ` [PATCH 06/16] fpga: machxo2-spi: factor out status check for readability Johannes Zink
2022-08-25 14:13 ` [PATCH 07/16] fpga: machxo2-spi: fix big-endianness incompatibility Johannes Zink
2022-08-29  8:19   ` Xu Yilun
2022-08-29 10:41     ` Johannes Zink
2022-08-25 14:13 ` [PATCH 08/16] fpga: machxo2-spi: simplify with spi_sync_transfer() Johannes Zink
2022-08-25 14:13 ` [PATCH 09/16] fpga: machxo2-spi: simplify spi write commands Johannes Zink
2022-08-25 14:13 ` [PATCH 10/16] fpga: machxo2-spi: prepare extraction of common code Johannes Zink
2022-08-25 14:13 ` [PATCH 11/16] fpga: machxo2: move non-spi-related functionality to " Johannes Zink
2022-08-25 14:13 ` [PATCH 12/16] fpga: machxo2: improve status register dump Johannes Zink
2022-08-25 14:13 ` [PATCH 13/16] fpga: machxo2: add optional additional flash areas to be erased Johannes Zink
2022-08-25 14:13 ` [PATCH 14/16] fpga: machxo2: add program initialization signalling via gpio Johannes Zink
2022-08-25 14:13 ` [PATCH 15/16] fpga: machxo2: extend erase timeout for machxo2 FPGA Johannes Zink
2022-08-29  9:26   ` Xu Yilun
2022-08-29 10:51     ` Johannes Zink
2022-08-29 14:57       ` Xu Yilun
2022-08-31  7:56         ` Johannes Zink
2022-08-25 14:13 ` Johannes Zink [this message]
2022-08-29  9:47   ` [PATCH 16/16] fpga: machxo2: add configuration over i2c Xu Yilun
2022-08-29 13:21     ` Johannes Zink
2022-08-29 14:45       ` Xu Yilun
2022-08-31 16:07         ` Johannes Zink
2022-08-25 15:25 ` [PATCH 00/16] Add support for Lattice MachXO2 programming via I2C Ivan Bornyakov
2022-08-26  6:32   ` Johannes Zink
2022-08-26  8:15     ` Ivan Bornyakov
2022-08-26  8:25   ` Sascha Hauer
2022-08-26  9:00     ` Ivan Bornyakov
2022-08-26  9:19       ` Ivan Bornyakov
2022-08-26 15:26         ` Xu Yilun

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220825141343.1375690-17-j.zink@pengutronix.de \
    --to=j.zink@pengutronix.de \
    --cc=devicetree@vger.kernel.org \
    --cc=hao.wu@intel.com \
    --cc=kernel@pengutronix.de \
    --cc=linux-fpga@vger.kernel.org \
    --cc=mdf@kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=yilun.xu@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.