@@ -77,9 +77,15 @@ config FPGA_MGR_ICE40_SPI
help
FPGA manager driver support for Lattice iCE40 FPGAs over SPI.
+config FPGA_MGR_MACHXO2_COMMON
+ tristate
+ help
+ FPGA manager driver common code for Lattice MachXO2 configuration
+
config FPGA_MGR_MACHXO2_SPI
tristate "Lattice MachXO2 SPI"
depends on SPI
+ select FPGA_MGR_MACHXO2_COMMON
help
FPGA manager driver support for Lattice MachXO2 configuration
over slave SPI interface.
@@ -10,6 +10,7 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o
obj-$(CONFIG_FPGA_MGR_ALTERA_CVP) += altera-cvp.o
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_SOCFPGA) += socfpga.o
obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o
new file mode 100644
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Lattice MachXO2 Common Driver
+ *
+ * Manage Lattice FPGA firmware
+ *
+ * Copyright (C) 2018 Paolo Pisati <p.pisati@gmail.com>
+ * Copyright (C) 2022 Pengutronix, Johannes Zink <kernel@pengutronix.de>
+ */
+
+#include <linux/delay.h>
+#include <linux/bitfield.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include "machxo2-common.h"
+
+#define MACHXO2_LOW_DELAY_USEC 5
+#define MACHXO2_HIGH_DELAY_USEC 200
+#define MACHXO2_REFRESH_USEC 4800
+#define MACHXO2_MAX_BUSY_LOOP 128
+#define MACHXO2_MAX_REFRESH_LOOP 16
+
+#define MACHXO2_PAGE_SIZE 16
+#define MACHXO2_BUF_SIZE (MACHXO2_PAGE_SIZE + 4)
+
+/* Status register bits, errors and error mask */
+#define MACHXO2_BUSY BIT(12)
+#define MACHXO2_DONE BIT(8)
+#define MACHXO2_DVER BIT(27)
+#define MACHXO2_ENAB BIT(9)
+#define MACHXO2_ERR GENMASK(25, 23)
+#define MACHXO2_ERR_ENOERR 0 /* no error */
+#define MACHXO2_ERR_EEID 1
+#define MACHXO2_ERR_EECMD 2
+#define MACHXO2_ERR_EECRC 3
+#define MACHXO2_ERR_EEPREAM 4 /* preamble error */
+#define MACHXO2_ERR_EEABRT 5 /* abort error */
+#define MACHXO2_ERR_EEOVERFL 6 /* overflow error */
+#define MACHXO2_ERR_EESDMEOF 7 /* SDM EOF */
+#define MACHXO2_FAIL BIT(13)
+
+
+static inline u8 get_err(u32 status)
+{
+ return FIELD_GET(MACHXO2_ERR, status);
+}
+
+static const char *get_err_string(u8 err)
+{
+ switch (err) {
+ case MACHXO2_ERR_ENOERR: return "No Error";
+ case MACHXO2_ERR_EEID: return "ID ERR";
+ case MACHXO2_ERR_EECMD: return "CMD ERR";
+ case MACHXO2_ERR_EECRC: return "CRC ERR";
+ case MACHXO2_ERR_EEPREAM: return "Preamble ERR";
+ case MACHXO2_ERR_EEABRT: return "Abort ERR";
+ case MACHXO2_ERR_EEOVERFL: return "Overflow ERR";
+ case MACHXO2_ERR_EESDMEOF: return "SDM EOF";
+ }
+
+ return "Unknown";
+}
+
+static void dump_status_reg(u32 status)
+{
+ pr_debug("machxo2 status: 0x%08X - done=%d, cfgena=%d, busy=%d, fail=%d, devver=%d, err=%s\n",
+ status, !!FIELD_GET(MACHXO2_DONE, status), !!FIELD_GET(MACHXO2_ENAB, status),
+ !!FIELD_GET(MACHXO2_BUSY, status), !!FIELD_GET(MACHXO2_FAIL, status),
+ !!FIELD_GET(MACHXO2_DVER, status), get_err_string(get_err(status)));
+}
+
+static int machxo2_wait_until_not_busy(struct machxo2_common_priv *priv)
+{
+ u32 status;
+ int ret, loop = 0;
+
+ do {
+ ret = priv->get_status(priv, &status);
+ if (ret)
+ return ret;
+ if (++loop >= MACHXO2_MAX_BUSY_LOOP)
+ return -EBUSY;
+ } while (status & MACHXO2_BUSY);
+
+ return 0;
+}
+
+static int machxo2_cleanup(struct fpga_manager *mgr)
+{
+ struct machxo2_common_priv *priv = mgr->priv;
+ u8 erase[] = ISC_ERASE;
+ u8 refresh[] = LSC_REFRESH;
+ struct machxo2_cmd cmd = {};
+ int ret;
+
+ cmd.cmd = erase;
+ cmd.cmd_len = sizeof(erase);
+ ret = priv->write_commands(priv, &cmd, 1);
+ if (ret)
+ goto fail;
+
+ ret = machxo2_wait_until_not_busy(priv);
+ if (ret)
+ goto fail;
+
+ cmd.cmd = refresh;
+ cmd.cmd_len = sizeof(refresh);
+ cmd.delay_us = MACHXO2_REFRESH_USEC;
+ ret = priv->write_commands(priv, &cmd, 1);
+ if (ret)
+ goto fail;
+
+ return 0;
+fail:
+ dev_err(&mgr->dev, "Cleanup failed\n");
+
+ return ret;
+}
+
+static bool machxo2_status_done(unsigned long status)
+{
+ return (((status & (MACHXO2_BUSY | MACHXO2_DONE)) == MACHXO2_DONE) &&
+ get_err(status) == MACHXO2_ERR_ENOERR);
+}
+
+static enum fpga_mgr_states machxo2_state(struct fpga_manager *mgr)
+{
+ struct machxo2_common_priv *priv = mgr->priv;
+ u32 status;
+
+ priv->get_status(priv, &status);
+ if (machxo2_status_done(status))
+ return FPGA_MGR_STATE_OPERATING;
+
+ return FPGA_MGR_STATE_UNKNOWN;
+}
+
+static int machxo2_write_init(struct fpga_manager *mgr,
+ struct fpga_image_info *info,
+ const char *buf, size_t count)
+{
+ struct machxo2_common_priv *priv = mgr->priv;
+ u8 enable[] = ISC_ENABLE;
+ u8 erase[] = ISC_ERASE;
+ u8 initaddr[] = LSC_INITADDRESS;
+ struct machxo2_cmd cmd[2] = {};
+ u32 status;
+ int ret;
+
+ if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
+ dev_err(&mgr->dev,
+ "Partial reconfiguration is not supported\n");
+ return -ENOTSUPP;
+ }
+
+ priv->get_status(priv, &status);
+ dump_status_reg(status);
+
+ cmd[0].cmd = enable;
+ cmd[0].cmd_len = sizeof(enable);
+ cmd[0].delay_us = MACHXO2_LOW_DELAY_USEC;
+
+ cmd[1].cmd = erase;
+ cmd[1].cmd_len = sizeof(erase);
+ ret = priv->write_commands(priv, cmd, 2);
+ if (ret)
+ goto fail;
+
+ ret = machxo2_wait_until_not_busy(priv);
+ if (ret)
+ goto fail;
+
+ priv->get_status(priv, &status);
+ if (status & MACHXO2_FAIL) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ dump_status_reg(status);
+
+ cmd[0].cmd = initaddr;
+ cmd[0].cmd_len = sizeof(initaddr);
+ ret = priv->write_commands(priv, cmd, 1);
+ if (ret)
+ goto fail;
+
+ priv->get_status(priv, &status);
+ dump_status_reg(status);
+
+ return 0;
+fail:
+ dev_err(&mgr->dev, "Error during FPGA init.\n");
+
+ return ret;
+}
+
+static int machxo2_write(struct fpga_manager *mgr, const char *buf,
+ size_t count)
+{
+ struct machxo2_common_priv *priv = mgr->priv;
+ u8 progincr[] = LSC_PROGINCRNV;
+ u8 payload[MACHXO2_BUF_SIZE];
+ struct machxo2_cmd cmd = {};
+ u32 status;
+ int i, ret;
+
+ if (count % MACHXO2_PAGE_SIZE != 0) {
+ dev_err(&mgr->dev, "Malformed payload.\n");
+ return -EINVAL;
+ }
+ priv->get_status(priv, &status);
+ dump_status_reg(status);
+ cmd.cmd = payload;
+ cmd.cmd_len = MACHXO2_BUF_SIZE;
+ cmd.delay_us = MACHXO2_HIGH_DELAY_USEC;
+
+ memcpy(payload, &progincr, sizeof(progincr));
+ for (i = 0; i < count; i += MACHXO2_PAGE_SIZE) {
+ memcpy(&payload[sizeof(progincr)], &buf[i], MACHXO2_PAGE_SIZE);
+
+ cmd.cmd = payload;
+ cmd.cmd_len = MACHXO2_BUF_SIZE;
+ cmd.delay_us = MACHXO2_HIGH_DELAY_USEC;
+ ret = priv->write_commands(priv, &cmd, 1);
+ if (ret) {
+ dev_err(&mgr->dev, "Error loading the bitstream.\n");
+ return ret;
+ }
+ }
+ priv->get_status(priv, &status);
+ dump_status_reg(status);
+
+ return 0;
+}
+
+static int machxo2_write_complete(struct fpga_manager *mgr,
+ struct fpga_image_info *info)
+{
+ struct machxo2_common_priv *priv = mgr->priv;
+ struct machxo2_cmd cmd = {};
+ u8 progdone[] = ISC_PROGRAMDONE;
+ u8 refresh[] = LSC_REFRESH;
+ u32 status;
+ int ret, refreshloop = 0;
+
+ cmd.cmd = progdone;
+ cmd.cmd_len = sizeof(progdone);
+ ret = priv->write_commands(priv, &cmd, 1);
+ if (ret)
+ goto fail;
+ ret = machxo2_wait_until_not_busy(priv);
+ if (ret)
+ goto fail;
+
+ priv->get_status(priv, &status);
+ dump_status_reg(status);
+ if (!(status & MACHXO2_DONE)) {
+ machxo2_cleanup(mgr);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ cmd.cmd = refresh;
+ cmd.cmd_len = sizeof(refresh);
+ cmd.delay_us = MACHXO2_REFRESH_USEC;
+
+ do {
+ ret = priv->write_commands(priv, &cmd, 1);
+ if (ret)
+ goto fail;
+
+ /* check refresh status */
+ priv->get_status(priv, &status);
+ dump_status_reg(status);
+ if (machxo2_status_done(status))
+ break;
+ if (++refreshloop == MACHXO2_MAX_REFRESH_LOOP) {
+ machxo2_cleanup(mgr);
+ ret = -EINVAL;
+ goto fail;
+ }
+ } while (1);
+
+ priv->get_status(priv, &status);
+ dump_status_reg(status);
+
+ return 0;
+fail:
+ dev_err(&mgr->dev, "Refresh failed.\n");
+
+ return ret;
+}
+
+static const struct fpga_manager_ops machxo2_ops = {
+ .state = machxo2_state,
+ .write_init = machxo2_write_init,
+ .write = machxo2_write,
+ .write_complete = machxo2_write_complete,
+};
+
+int machxo2_common_init(struct machxo2_common_priv *priv, struct device *dev)
+{
+ struct fpga_manager *mgr;
+
+ mgr = devm_fpga_mgr_register(dev, "Lattice MachXO2 SPI FPGA Manager",
+ &machxo2_ops, priv);
+
+ return PTR_ERR_OR_ZERO(mgr);
+}
new file mode 100644
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Paolo Pisati <p.pisati@gmail.com>
+ * Copyright (C) 2021 Peter Jensen <pdj@bang-olufsen.dk>
+ * Copyright (C) 2022 Pengutronix, Johannes Zink <kernel@pengutronix.de>
+ */
+
+#ifndef __LINUX_FPGA_MGR_MACHXO2_COMMON_H
+#define __LINUX_FPGA_MGR_MACHXO2_COMMON_H
+
+#include <linux/types.h>
+
+/* MachXO2 Programming Guide - sysCONFIG Programming Commands */
+#define IDCODE_PUB {0xe0, 0x00, 0x00, 0x00}
+#define ISC_ENABLE {0xc6, 0x08, 0x00, 0x00}
+#define ISC_ERASE {0x0e, 0x04, 0x00, 0x00}
+#define ISC_PROGRAMDONE {0x5e, 0x00, 0x00, 0x00}
+#define LSC_INITADDRESS {0x46, 0x00, 0x00, 0x00}
+#define LSC_PROGINCRNV {0x70, 0x00, 0x00, 0x01}
+#define LSC_READ_STATUS {0x3c, 0x00, 0x00, 0x00}
+#define LSC_REFRESH {0x79, 0x00, 0x00, 0x00}
+
+struct machxo2_cmd {
+ u8 *cmd;
+ size_t cmd_len;
+ u16 delay_us;
+};
+
+struct machxo2_common_priv {
+ int (*write_commands)(struct machxo2_common_priv *priv,
+ struct machxo2_cmd *cmds, size_t cmd_count);
+ int (*get_status)(struct machxo2_common_priv *priv, u32 *status);
+};
+
+int machxo2_common_init(struct machxo2_common_priv *priv, struct device *dev);
+
+#endif
@@ -8,24 +8,10 @@
* Copyright (C) 2018 Paolo Pisati <p.pisati@gmail.com>
*/
-#include <linux/delay.h>
-#include <linux/bitfield.h>
-#include <linux/fpga/fpga-mgr.h>
-#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/of.h>
#include <linux/spi/spi.h>
#include <linux/container_of.h>
-
-/* MachXO2 Programming Guide - sysCONFIG Programming Commands */
-#define IDCODE_PUB {0xe0, 0x00, 0x00, 0x00}
-#define ISC_ENABLE {0xc6, 0x08, 0x00, 0x00}
-#define ISC_ERASE {0x0e, 0x04, 0x00, 0x00}
-#define ISC_PROGRAMDONE {0x5e, 0x00, 0x00, 0x00}
-#define LSC_INITADDRESS {0x46, 0x00, 0x00, 0x00}
-#define LSC_PROGINCRNV {0x70, 0x00, 0x00, 0x01}
-#define LSC_READ_STATUS {0x3c, 0x00, 0x00, 0x00}
-#define LSC_REFRESH {0x79, 0x00, 0x00, 0x00}
+#include "machxo2-common.h"
/*
* Max CCLK in Slave SPI mode according to 'MachXO2 Family Data
@@ -33,34 +19,6 @@
*/
#define MACHXO2_MAX_SPEED 66000000
-#define MACHXO2_LOW_DELAY_USEC 5
-#define MACHXO2_HIGH_DELAY_USEC 200
-#define MACHXO2_REFRESH_USEC 4800
-#define MACHXO2_MAX_BUSY_LOOP 128
-#define MACHXO2_MAX_REFRESH_LOOP 16
-
-#define MACHXO2_PAGE_SIZE 16
-#define MACHXO2_BUF_SIZE (MACHXO2_PAGE_SIZE + 4)
-
-/* Status register bits, errors and error mask */
-#define MACHXO2_BUSY BIT(12)
-#define MACHXO2_DONE BIT(8)
-#define MACHXO2_DVER BIT(27)
-#define MACHXO2_ENAB BIT(9)
-#define MACHXO2_ERR GENMASK(25, 23)
-#define MACHXO2_ERR_ENOERR 0 /* no error */
-#define MACHXO2_ERR_EID 1
-#define MACHXO2_ERR_ECMD 2
-#define MACHXO2_ERR_ECRC 3
-#define MACHXO2_ERR_EPREAM 4 /* preamble error */
-#define MACHXO2_ERR_EABRT 5 /* abort error */
-#define MACHXO2_ERR_EOVERFL 6 /* overflow error */
-#define MACHXO2_ERR_ESDMEOF 7 /* SDM EOF */
-#define MACHXO2_FAIL BIT(13)
-
-struct machxo2_common_priv {
-};
-
struct machxo2_spi_priv {
struct machxo2_common_priv common;
struct spi_device *spi;
@@ -71,12 +29,7 @@ static inline struct machxo2_spi_priv *to_machxo2_spi_priv(struct machxo2_common
return container_of(priv, struct machxo2_spi_priv, common);
}
-static inline u8 get_err(u32 status)
-{
- return FIELD_GET(MACHXO2_ERR, status);
-}
-
-static int get_status(struct machxo2_common_priv *priv, u32 *status)
+static int machxo2_get_status_spi(struct machxo2_common_priv *priv, u32 *status)
{
struct spi_device *spi = to_machxo2_spi_priv(priv)->spi;
struct spi_transfer transfers[2] = {};
@@ -98,52 +51,6 @@ static int get_status(struct machxo2_common_priv *priv, u32 *status)
return 0;
}
-static const char *get_err_string(u8 err)
-{
- switch (err) {
- case MACHXO2_ERR_ENOERR: return "No Error";
- case MACHXO2_ERR_EID: return "ID ERR";
- case MACHXO2_ERR_ECMD: return "CMD ERR";
- case MACHXO2_ERR_ECRC: return "CRC ERR";
- case MACHXO2_ERR_EPREAM: return "Preamble ERR";
- case MACHXO2_ERR_EABRT: return "Abort ERR";
- case MACHXO2_ERR_EOVERFL: return "Overflow ERR";
- case MACHXO2_ERR_ESDMEOF: return "SDM EOF";
- }
-
- return "Unknown";
-}
-
-static void dump_status_reg(u32 status)
-{
- pr_debug("machxo2 status: 0x%08X - done=%d, cfgena=%d, busy=%d, fail=%d, devver=%d, err=%s\n",
- status, !!FIELD_GET(MACHXO2_DONE, status), !!FIELD_GET(MACHXO2_ENAB, status),
- !!FIELD_GET(MACHXO2_BUSY, status), !!FIELD_GET(MACHXO2_FAIL, status),
- !!FIELD_GET(MACHXO2_DVER, status), get_err_string(get_err(status)));
-}
-
-static int machxo2_wait_until_not_busy(struct machxo2_common_priv *priv)
-{
- u32 status;
- int ret, loop = 0;
-
- do {
- ret = get_status(priv, &status);
- if (ret)
- return ret;
- if (++loop >= MACHXO2_MAX_BUSY_LOOP)
- return -EBUSY;
- } while (status & MACHXO2_BUSY);
-
- return 0;
-}
-
-struct machxo2_cmd {
- u8 *cmd;
- size_t cmd_len;
- u16 delay_us;
-};
-
static int machxo2_write_spi(struct machxo2_common_priv *priv,
struct machxo2_cmd *cmds, size_t cmd_count)
{
@@ -169,225 +76,10 @@ static int machxo2_write_spi(struct machxo2_common_priv *priv,
return ret;
}
-static int machxo2_cleanup(struct fpga_manager *mgr)
-{
- struct machxo2_common_priv *priv = mgr->priv;
- u8 erase[] = ISC_ERASE;
- u8 refresh[] = LSC_REFRESH;
- struct machxo2_cmd cmd = {};
- int ret;
-
- cmd.cmd = erase;
- cmd.cmd_len = sizeof(erase);
- ret = machxo2_write_spi(priv, &cmd, 1);
- if (ret)
- goto fail;
-
- ret = machxo2_wait_until_not_busy(priv);
- if (ret)
- goto fail;
-
- cmd.cmd = refresh;
- cmd.cmd_len = sizeof(refresh);
- cmd.delay_us = MACHXO2_REFRESH_USEC;
- ret = machxo2_write_spi(priv, &cmd, 1);
- if (ret)
- goto fail;
-
- return 0;
-fail:
- dev_err(&mgr->dev, "Cleanup failed\n");
-
- return ret;
-}
-
-static bool machxo2_status_done(unsigned long status)
-{
- return (((status & (MACHXO2_BUSY | MACHXO2_DONE)) == MACHXO2_DONE) &&
- get_err(status) == MACHXO2_ERR_ENOERR);
-}
-
-static enum fpga_mgr_states machxo2_spi_state(struct fpga_manager *mgr)
-{
- struct machxo2_common_priv *priv = mgr->priv;
- u32 status;
-
- get_status(priv, &status);
- if (machxo2_status_done(status))
- return FPGA_MGR_STATE_OPERATING;
-
- return FPGA_MGR_STATE_UNKNOWN;
-}
-
-static int machxo2_write_init(struct fpga_manager *mgr,
- struct fpga_image_info *info,
- const char *buf, size_t count)
-{
- struct machxo2_common_priv *priv = mgr->priv;
- u8 enable[] = ISC_ENABLE;
- u8 erase[] = ISC_ERASE;
- u8 initaddr[] = LSC_INITADDRESS;
- struct machxo2_cmd cmd[2] = {};
- u32 status;
- int ret;
-
- if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
- dev_err(&mgr->dev,
- "Partial reconfiguration is not supported\n");
- return -ENOTSUPP;
- }
-
- get_status(priv, &status);
- dump_status_reg(status);
-
- cmd[0].cmd = enable;
- cmd[0].cmd_len = sizeof(enable);
- cmd[0].delay_us = MACHXO2_LOW_DELAY_USEC;
-
- cmd[1].cmd = erase;
- cmd[1].cmd_len = sizeof(erase);
- ret = machxo2_write_spi(spi, cmd, ARRAY_SIZE(cmd));
-
- if (ret)
- goto fail;
-
- ret = machxo2_wait_until_not_busy(priv);
- if (ret)
- goto fail;
-
- get_status(priv, &status);
- if (status & MACHXO2_FAIL) {
- ret = -EINVAL;
- goto fail;
- }
- dump_status_reg(status);
-
- cmd[0].cmd = initaddr;
- cmd[0].cmd_len = sizeof(initaddr);
- ret = machxo2_write_spi(priv, &cmd[0], 1);
- if (ret)
- goto fail;
-
- get_status(priv, &status);
- dump_status_reg(status);
-
- return 0;
-fail:
- dev_err(&mgr->dev, "Error during FPGA init.\n");
-
- return ret;
-}
-
-static int machxo2_write(struct fpga_manager *mgr, const char *buf,
- size_t count)
-{
- struct machxo2_common_priv *priv = mgr->priv;
- u8 progincr[] = LSC_PROGINCRNV;
- u8 payload[MACHXO2_BUF_SIZE];
- struct machxo2_cmd cmd = {};
- u32 status;
- int i, ret;
-
- if (count % MACHXO2_PAGE_SIZE != 0) {
- dev_err(&mgr->dev, "Malformed payload.\n");
- return -EINVAL;
- }
- get_status(priv, &status);
- dump_status_reg(status);
-
- cmd.cmd = payload;
- cmd.cmd_len = MACHXO2_BUF_SIZE;
- cmd.delay_us = MACHXO2_HIGH_DELAY_USEC;
-
- memcpy(payload, &progincr, sizeof(progincr));
- for (i = 0; i < count; i += MACHXO2_PAGE_SIZE) {
- memcpy(&payload[sizeof(progincr)], &buf[i], MACHXO2_PAGE_SIZE);
-
- cmd.cmd = payload;
- cmd.cmd_len = MACHXO2_BUF_SIZE;
- cmd.delay_us = MACHXO2_HIGH_DELAY_USEC;
- ret = machxo2_write_spi(priv, &cmd, 1);
- if (ret) {
- dev_err(&mgr->dev, "Error loading the bitstream.\n");
- return ret;
- }
- }
- get_status(priv, &status);
- dump_status_reg(status);
-
- return 0;
-}
-
-static int machxo2_write_complete(struct fpga_manager *mgr,
- struct fpga_image_info *info)
-{
- struct machxo2_common_priv *priv = mgr->priv;
- struct machxo2_cmd cmd = {};
- u8 progdone[] = ISC_PROGRAMDONE;
- u8 refresh[] = LSC_REFRESH;
- u32 status;
- int ret, refreshloop = 0;
-
- cmd.cmd = progdone;
- cmd.cmd_len = sizeof(progdone);
- ret = machxo2_write_spi(priv, &cmd, 1);
- if (ret)
- goto fail;
- ret = machxo2_wait_until_not_busy(priv);
- if (ret)
- goto fail;
-
- get_status(priv, &status);
- dump_status_reg(status);
- if (!(status & MACHXO2_DONE)) {
- machxo2_cleanup(mgr);
- ret = -EINVAL;
- goto fail;
- }
-
- cmd.cmd = refresh;
- cmd.cmd_len = sizeof(refresh);
- cmd.delay_us = MACHXO2_REFRESH_USEC;
-
- do {
- ret = machxo2_write_spi(priv, &cmd, 1);
- if (ret)
- goto fail;
-
- /* check refresh status */
- get_status(priv, &status);
- dump_status_reg(status);
- if (machxo2_status_done(status))
- break;
- if (++refreshloop == MACHXO2_MAX_REFRESH_LOOP) {
- machxo2_cleanup(mgr);
- ret = -EINVAL;
- goto fail;
- }
- } while (1);
-
- get_status(priv, &status);
- dump_status_reg(status);
-
- return 0;
-fail:
- dev_err(&mgr->dev, "Refresh failed.\n");
-
- return ret;
-}
-
-static const struct fpga_manager_ops machxo2_ops = {
- .state = machxo2_spi_state,
- .write_init = machxo2_write_init,
- .write = machxo2_write,
- .write_complete = machxo2_write_complete,
-};
-
static int machxo2_spi_probe(struct spi_device *spi)
{
struct machxo2_spi_priv *priv;
struct device *dev = &spi->dev;
- struct fpga_manager *mgr;
if (spi->max_speed_hz > MACHXO2_MAX_SPEED) {
dev_err(dev, "Speed is too high\n");
@@ -399,10 +91,10 @@ static int machxo2_spi_probe(struct spi_device *spi)
return -ENOMEM;
priv->spi = spi;
+ priv->common.write_commands = machxo2_write_spi;
+ priv->common.get_status = machxo2_get_status_spi;
- mgr = devm_fpga_mgr_register(dev, "Lattice MachXO2 SPI FPGA Manager",
- &machxo2_ops, &priv->common);
- return PTR_ERR_OR_ZERO(mgr);
+ return machxo2_common_init(&(priv->common), dev);
}
#ifdef CONFIG_OF
This commit seperates the general programming algorithm from bus-specific access functions. This is a preparation for adding i2c as another bus. While at it: rename some functions to allow easier separation between spi-specific functions and common code. While at it: clean up includes Signed-off-by: Johannes Zink <j.zink@pengutronix.de> --- drivers/fpga/Kconfig | 6 + drivers/fpga/Makefile | 1 + drivers/fpga/machxo2-common.c | 310 +++++++++++++++++++++++++++++++++ drivers/fpga/machxo2-common.h | 37 ++++ drivers/fpga/machxo2-spi.c | 318 +--------------------------------- 5 files changed, 359 insertions(+), 313 deletions(-) create mode 100644 drivers/fpga/machxo2-common.c create mode 100644 drivers/fpga/machxo2-common.h