* [PATCH 1/4] Add a Firmware programming framework
2013-11-12 14:31 Sascha Hauer
@ 2013-11-12 14:31 ` Sascha Hauer
2013-11-12 14:31 ` [PATCH 2/4] Firmware: provide a handler to program Altera FPGAs Sascha Hauer
` (2 subsequent siblings)
3 siblings, 0 replies; 12+ messages in thread
From: Sascha Hauer @ 2013-11-12 14:31 UTC (permalink / raw)
To: barebox; +Cc: Juergen Beisert
From: Juergen Beisert <jbe@pengutronix.de>
This framework handles a list of registered Firmware programming handlers
to unify a firmware programming interface by hiding the details how
to program a specific Firmware in its handler. This is created with FPGAs
in mind but should be usable for other devices aswell.
A user has two possibilities to load a firmware. A device file is create
under /dev/ which can be used to copy a firmware to. Additionally a
firmwareload command is introduced which can list the registered firmware
handlers and also to upload a firmware.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/Kconfig | 8 ++
commands/Makefile | 1 +
commands/firmwareload.c | 67 ++++++++++++++++
common/Kconfig | 3 +
common/Makefile | 1 +
common/firmware.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++
include/firmware.h | 42 ++++++++++
7 files changed, 329 insertions(+)
create mode 100644 commands/firmwareload.c
create mode 100644 common/firmware.c
create mode 100644 include/firmware.h
diff --git a/commands/Kconfig b/commands/Kconfig
index 9738ec4..3d2c198 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -605,6 +605,14 @@ config CMD_BAREBOX_UPDATE
select BAREBOX_UPDATE
prompt "barebox-update"
+config CMD_FIRMWARELOAD
+ bool
+ select FIRMWARE
+ prompt "firmwareload"
+ help
+ Provides the "firmwareload" command which deals with devices which need
+ firmware to work. It is also used to upload firmware to FPGA devices.
+
config CMD_TIMEOUT
tristate
prompt "timeout"
diff --git a/commands/Makefile b/commands/Makefile
index 58d27fa..6130c8f 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -93,3 +93,4 @@ obj-$(CONFIG_CMD_MIITOOL) += miitool.o
obj-$(CONFIG_CMD_DETECT) += detect.o
obj-$(CONFIG_CMD_BOOT) += boot.o
obj-$(CONFIG_CMD_DEVINFO) += devinfo.o
+obj-$(CONFIG_CMD_FIRMWARELOAD) += firmwareload.o
diff --git a/commands/firmwareload.c b/commands/firmwareload.c
new file mode 100644
index 0000000..16326f4
--- /dev/null
+++ b/commands/firmwareload.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 Juergen Beisert <kernel@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <getopt.h>
+#include <firmware.h>
+
+static int do_firmwareload(int argc, char *argv[])
+{
+ int ret, opt;
+ const char *name = NULL, *firmware;
+ struct firmware_mgr *mgr;
+
+ while ((opt = getopt(argc, argv, "t:l")) > 0) {
+ switch (opt) {
+ case 't':
+ name = optarg;
+ break;
+ case 'l':
+ firmwaremgr_list_handlers();
+ return 0;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ if (!(argc - optind))
+ return COMMAND_ERROR_USAGE;
+
+ firmware = argv[optind];
+
+ mgr = firmwaremgr_find(name);
+
+ if (!mgr) {
+ printf("No such programming handler found: %s\n",
+ name ? name : "default");
+ return 1;
+ }
+
+ ret = firmwaremgr_load_file(mgr, firmware);
+
+ return ret;
+}
+
+BAREBOX_CMD_HELP_START(firmwareload)
+BAREBOX_CMD_HELP_USAGE("firmwareload [OPTIONS] <firmware>\n")
+BAREBOX_CMD_HELP_SHORT("Program a firmware file into a device\n")
+BAREBOX_CMD_HELP_OPT("-t <target>", "define the firmware handler by name\n")
+BAREBOX_CMD_HELP_OPT("-l\t", "list devices capable of firmware loading\n")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(firmwareload)
+ .cmd = do_firmwareload,
+ .usage = "program a firmware",
+ BAREBOX_CMD_HELP(cmd_firmwareload_help)
+BAREBOX_CMD_END
diff --git a/common/Kconfig b/common/Kconfig
index ccfbc80..375b979 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -297,6 +297,9 @@ config MAXARGS
prompt "max. Number of arguments accepted for monitor commands"
default 16
+config FIRMWARE
+ bool
+
choice
prompt "Select your shell"
diff --git a/common/Makefile b/common/Makefile
index 6f6e360..76d24db 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -48,6 +48,7 @@ obj-y += bootsource.o
obj-$(CONFIG_BOOTM) += bootm.o
extra-$(CONFIG_MODULES) += module.lds
extra-y += barebox_default_env barebox_default_env.h
+obj-$(CONFIG_FIRMWARE) += firmware.o
ifdef CONFIG_DEFAULT_ENVIRONMENT
$(obj)/startup.o: $(obj)/barebox_default_env.h
diff --git a/common/firmware.c b/common/firmware.c
new file mode 100644
index 0000000..7cb1e83
--- /dev/null
+++ b/common/firmware.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2013 Juergen Beisert <kernel@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <firmware.h>
+#include <common.h>
+#include <malloc.h>
+#include <xfuncs.h>
+#include <fcntl.h>
+#include <libbb.h>
+#include <fs.h>
+#include <linux/list.h>
+#include <linux/stat.h>
+#include <linux/err.h>
+
+#define BUFSIZ 4096
+
+struct firmware_mgr {
+ struct list_head list;
+ struct firmware_handler *handler; /* the program handler */
+ struct cdev cdev;
+ u8 buf[BUFSIZ];
+ int ofs;
+};
+
+static LIST_HEAD(firmwaremgr_list);
+
+/*
+ * firmwaremgr_find - find a firmware device handler
+ *
+ * Find a firmware device handler based on the unique id. If @id is
+ * NULL this returns the single firmware device handler if only one
+ * is registered. If multiple handlers are registered @id is mandatory
+ *
+ */
+struct firmware_mgr *firmwaremgr_find(const char *id)
+{
+ struct firmware_mgr *mgr;
+
+ if (!id) {
+ if (list_is_singular(&firmwaremgr_list))
+ return list_first_entry(&firmwaremgr_list,
+ struct firmware_mgr, list);
+ else
+ return NULL;
+ }
+
+ list_for_each_entry(mgr, &firmwaremgr_list, list)
+ if (!strcmp(mgr->handler->id, id))
+ return mgr;
+
+ return NULL;
+}
+
+/*
+ * firmwaremgr_list_handlers - list registered firmware device handlers
+ * in pretty format
+ */
+void firmwaremgr_list_handlers(void)
+{
+ struct firmware_mgr *mgr;
+
+ printf("firmware programming handlers:\n\n");
+
+ if (list_empty(&firmwaremgr_list)) {
+ printf("(none)\n");
+ return;
+ }
+
+ printf("%-11s%-11s\n", "name:", "model:");
+
+ list_for_each_entry(mgr, &firmwaremgr_list, list) {
+ printf("%-11s", mgr->handler->id);
+ if (mgr->handler->model)
+ printf("%-11s", mgr->handler->model);
+ printf("\n");
+ }
+}
+
+static int firmware_open(struct cdev *cdev, unsigned long flags)
+{
+ struct firmware_mgr *mgr = cdev->priv;
+ int ret;
+
+ mgr->ofs = 0;
+
+ ret = mgr->handler->open(mgr->handler);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static ssize_t firmware_write(struct cdev *cdev, const void *buf, size_t insize,
+ loff_t offset, ulong flags)
+{
+ struct firmware_mgr *mgr = cdev->priv;
+ int ret;
+ size_t count = insize;
+
+ /*
+ * We guarantee the write handler of the firmware device that only the
+ * last write is a short write. All others are 4k in size.
+ */
+
+ while (count) {
+ size_t space = BUFSIZ - mgr->ofs;
+ size_t now = min(count, space);
+
+ memcpy(mgr->buf + mgr->ofs, buf, now);
+
+ buf += now;
+ mgr->ofs += now;
+ count -= now;
+
+ if (mgr->ofs == BUFSIZ) {
+ ret = mgr->handler->write(mgr->handler, mgr->buf, BUFSIZ);
+ if (ret < 0)
+ return ret;
+
+ mgr->ofs = 0;
+ }
+ }
+
+ return insize;
+}
+
+static int firmware_close(struct cdev *cdev)
+{
+ struct firmware_mgr *mgr = cdev->priv;
+ int ret;
+
+ if (mgr->ofs) {
+ ret = mgr->handler->write(mgr->handler, mgr->buf, mgr->ofs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct file_operations firmware_ops = {
+ .open = firmware_open,
+ .write = firmware_write,
+ .close = firmware_close,
+};
+
+/*
+ * firmwaremgr_register - register a device which needs firmware
+ */
+int firmwaremgr_register(struct firmware_handler *fh)
+{
+ struct firmware_mgr *mgr;
+ int ret;
+ struct cdev *cdev;
+
+ if (firmwaremgr_find(fh->id))
+ return -EBUSY;
+
+ mgr = xzalloc(sizeof(struct firmware_mgr));
+ mgr->handler = fh;
+
+ cdev = &mgr->cdev;
+
+ cdev->name = xstrdup(fh->id);
+ cdev->size = FILE_SIZE_STREAM;
+ cdev->ops = &firmware_ops;
+ cdev->priv = mgr;
+ cdev->dev = fh->dev;
+
+ ret = devfs_create(cdev);
+ if (ret)
+ goto out;
+
+ list_add_tail(&mgr->list, &firmwaremgr_list);
+
+ return 0;
+out:
+ free(cdev->name);
+ free(mgr);
+
+ return ret;
+}
+
+/*
+ * firmware_load_file - load a firmware to a device
+ */
+int firmwaremgr_load_file(struct firmware_mgr *mgr, const char *firmware)
+{
+ int ret;
+ char *name = asprintf("/dev/%s", mgr->handler->id);
+
+ ret = copy_file(firmware, name, 0);
+
+ free(name);
+
+ return ret;
+}
diff --git a/include/firmware.h b/include/firmware.h
new file mode 100644
index 0000000..f6f78c8
--- /dev/null
+++ b/include/firmware.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Juergen Beisert <kernel@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef FIRMWARE_H
+#define FIRMWARE_H
+
+#include <types.h>
+#include <driver.h>
+
+struct firmware_handler {
+ char *id; /* unique identifier for this firmware device */
+ char *model; /* description for this device */
+ struct device_d *dev;
+ /* called once to prepare the firmware's programming cycle */
+ int (*open)(struct firmware_handler*);
+ /* called multiple times to program the firmware with the given data */
+ int (*write)(struct firmware_handler*, const void*, size_t);
+ /* called once to finish programming cycle */
+ int (*close)(struct firmware_handler*);
+};
+
+struct firmware_mgr;
+
+int firmwaremgr_register(struct firmware_handler *);
+
+struct firmware_mgr *firmwaremgr_find(const char *);
+
+void firmwaremgr_list_handlers(void);
+
+int firmwaremgr_load_file(struct firmware_mgr *, const char *path);
+
+#endif /* FIRMWARE_H */
--
1.8.4.2
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 2/4] Firmware: provide a handler to program Altera FPGAs
2013-11-12 14:31 Sascha Hauer
2013-11-12 14:31 ` [PATCH 1/4] Add a Firmware programming framework Sascha Hauer
@ 2013-11-12 14:31 ` Sascha Hauer
2013-11-12 14:46 ` Jürgen Beisert
2013-11-12 16:03 ` Jean-Christophe PLAGNIOL-VILLARD
2013-11-12 14:31 ` [PATCH 3/4] DT: Add binding for Altera FPGAs in passive-serial mode Sascha Hauer
2013-11-12 14:31 ` [PATCH 4/4] Firmware: socfpga: Add SoCFPGA FPGA program support Sascha Hauer
3 siblings, 2 replies; 12+ messages in thread
From: Sascha Hauer @ 2013-11-12 14:31 UTC (permalink / raw)
To: barebox; +Cc: Juergen Beisert
From: Juergen Beisert <jbe@pengutronix.de>
This handler uses a regular SPI master and a few GPIOs to program an
Altera FPGA in serial mode.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/Kconfig | 1 +
drivers/Makefile | 1 +
drivers/firmware/Kconfig | 11 ++
drivers/firmware/Makefile | 1 +
drivers/firmware/altera_serial.c | 307 +++++++++++++++++++++++++++++++++++++++
5 files changed, 321 insertions(+)
create mode 100644 drivers/firmware/Kconfig
create mode 100644 drivers/firmware/Makefile
create mode 100644 drivers/firmware/altera_serial.c
diff --git a/drivers/Kconfig b/drivers/Kconfig
index d34d2c7..71d840c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -25,5 +25,6 @@ source "drivers/gpio/Kconfig"
source "drivers/w1/Kconfig"
source "drivers/pinctrl/Kconfig"
source "drivers/bus/Kconfig"
+source "drivers/firmware/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index ba1dc6d..bf03d54 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_OFTREE) += of/
obj-$(CONFIG_W1) += w1/
obj-y += pinctrl/
obj-y += bus/
+obj-y += firmware/
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
new file mode 100644
index 0000000..28a173b
--- /dev/null
+++ b/drivers/firmware/Kconfig
@@ -0,0 +1,11 @@
+menu "Firmware Drivers"
+
+config FIRMWARE_ALTERA_SERIAL
+ bool "Altera SPI programming"
+ depends on OFDEVICE
+ select FIRMWARE
+ help
+ Programming an Altera FPGA via a few GPIOs for the control lines and
+ MOSI, MISO and clock from an SPI interface for the data lines
+
+endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
new file mode 100644
index 0000000..ec6a5a1
--- /dev/null
+++ b/drivers/firmware/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
diff --git a/drivers/firmware/altera_serial.c b/drivers/firmware/altera_serial.c
new file mode 100644
index 0000000..047b6bd
--- /dev/null
+++ b/drivers/firmware/altera_serial.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2013 Juergen Beisert <kernel@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <firmware.h>
+#include <of_gpio.h>
+#include <xfuncs.h>
+#include <malloc.h>
+#include <gpio.h>
+#include <clock.h>
+#include <spi/spi.h>
+
+#include <fcntl.h>
+#include <fs.h>
+
+/*
+ * Physical requirements:
+ * - three free GPIOs for the signals nCONFIG, CONFIGURE_DONE, nSTATUS
+ * - 32 bit per word, LSB first capable SPI master (MOSI + clock)
+ *
+ * Example how to configure this driver via device tree
+ *
+ * fpga@0 {
+ * compatible = "altera_serial";
+ * nstat-gpio = <&gpio4 18 0>;
+ * confd-gpio = <&gpio4 19 0>;
+ * nconfig-gpio = <&gpio4 20 0>;
+ * spi-max-frequency = <10000000>;
+ * reg = <0>;
+ * };
+ */
+
+struct fpga_spi {
+ struct firmware_handler fh;
+ int nstat_gpio; /* input GPIO to read the status line */
+ int confd_gpio; /* input GPIO to read the config done line */
+ int nconfig_gpio; /* output GPIO to start the FPGA's config */
+ struct device_d *dev;
+ struct spi_device *spi;
+ bool padding_done;
+};
+
+static int altera_spi_open(struct firmware_handler *fh)
+{
+ struct fpga_spi *this = container_of(fh, struct fpga_spi, fh);
+ struct device_d *dev = this->dev;
+ int ret;
+
+ dev_dbg(dev, "Initiating programming\n");
+
+ /* initiate an FPGA programming */
+ gpio_set_value(this->nconfig_gpio, 0);
+
+ /*
+ * after about 2 µs the FPGA must acknowledge with
+ * STATUS and CONFIG DONE lines at low level
+ */
+ ret = wait_on_timeout(2 * 1000,
+ (gpio_get_value(this->nstat_gpio) == 0) &&
+ (gpio_get_value(this->confd_gpio) == 0));
+
+ if (ret != 0) {
+ dev_err(dev, "FPGA does not acknowledge the programming initiation\n");
+ if (gpio_get_value(this->nstat_gpio))
+ dev_err(dev, "STATUS is still high!\n");
+ if (gpio_get_value(this->confd_gpio))
+ dev_err(dev, "CONFIG DONE is still high!\n");
+ return ret;
+ }
+
+ /* arm the FPGA to await its new firmware */
+ gpio_set_value(this->nconfig_gpio, 1);
+
+ /* once again, we might need padding the data */
+ this->padding_done = false;
+
+ /*
+ * after about 1506 µs the FPGA must acknowledge this step
+ * with the STATUS line at high level
+ */
+ ret = wait_on_timeout(1600 * 1000,
+ gpio_get_value(this->nstat_gpio) == 1);
+ if (ret != 0) {
+ dev_err(dev, "FPGA does not acknowledge the programming start\n");
+ return ret;
+ }
+
+ dev_dbg(dev, "Initiating passed\n");
+ /* at the end, wait at least 2 µs prior beginning writing data */
+ ndelay(2 * 1000);
+
+ return 0;
+}
+
+static int altera_spi_write(struct firmware_handler *fh, const void *buf, size_t sz)
+{
+ struct fpga_spi *this = container_of(fh, struct fpga_spi, fh);
+ struct device_d *dev = this->dev;
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u32 dummy;
+ int ret;
+
+ printf("%s: %d\n", __func__, sz);
+
+ spi_message_init(&m);
+
+ if (sz < sizeof(u32)) {
+ /* simple padding */
+ dummy = 0;
+ memcpy(&dummy, buf, sz);
+ buf = &dummy;
+ sz = sizeof(u32);
+ this->padding_done = true;
+ }
+
+ t[0].tx_buf = buf;
+ t[0].rx_buf = NULL;
+ t[0].len = sz;
+ spi_message_add_tail(&t[0], &m);
+
+ if (sz & 0x3) { /* padding required? */
+ u32 *word_buf = (u32 *)buf;
+ dummy = 0;
+ memcpy(&dummy, &word_buf[sz >> 2], sz & 0x3);
+ t[0].len &= ~0x03;
+ t[1].tx_buf = &dummy;
+ t[1].rx_buf = NULL;
+ t[1].len = sizeof(u32);
+ spi_message_add_tail(&t[1], &m);
+ this->padding_done = true;
+ }
+
+ ret = spi_sync(this->spi, &m);
+ if (ret != 0)
+ dev_err(dev, "programming failure\n");
+
+ return ret;
+}
+
+static int altera_spi_close(struct firmware_handler *fh)
+{
+ struct fpga_spi *this = container_of(fh, struct fpga_spi, fh);
+ struct device_d *dev = this->dev;
+ struct spi_transfer t;
+ struct spi_message m;
+ u32 dummy = 0;
+ int ret;
+
+ dev_dbg(dev, "Finalize programming\n");
+
+ if (this->padding_done == false) {
+ spi_message_init(&m);
+ t.tx_buf = &dummy;
+ t.rx_buf = NULL;
+ t.len = sizeof(dummy);
+ spi_message_add_tail(&t, &m);
+
+ ret = spi_sync(this->spi, &m);
+ if (ret != 0)
+ dev_err(dev, "programming failure\n");
+ }
+
+ /*
+ * when programming was successfully,
+ * both status lines should be at high level
+ */
+ ret = wait_on_timeout(10 * 1000,
+ (gpio_get_value(this->nstat_gpio) == 1) &&
+ (gpio_get_value(this->confd_gpio) == 1));
+ if (ret == 0) {
+ dev_dbg(dev, "Programming successfull\n");
+ return ret;
+ }
+
+ dev_err(dev, "Programming failed due to time out\n");
+ if (gpio_get_value(this->nstat_gpio) == 0)
+ dev_err(dev, "STATUS is still low!\n");
+ if (gpio_get_value(this->confd_gpio) == 0)
+ dev_err(dev, "CONFIG DONE is still low!\n");
+
+ return -EIO;
+}
+
+static int altera_spi_of(struct device_d *dev, struct fpga_spi *this)
+{
+ struct device_node *n = dev->device_node;
+ const char *name;
+ int ret;
+
+ name = "nstat-gpio";
+ this->nstat_gpio = of_get_named_gpio(n, name, 0);
+ if (this->nstat_gpio < 0) {
+ ret = this->nstat_gpio;
+ goto out;
+ }
+
+ name = "confd-gpio";
+ this->confd_gpio = of_get_named_gpio(n, name, 0);
+ if (this->confd_gpio < 0) {
+ ret = this->confd_gpio;
+ goto out;
+ }
+
+ name = "nconfig-gpio";
+ this->nconfig_gpio = of_get_named_gpio(n, name, 0);
+ if (this->nconfig_gpio < 0) {
+ ret = this->nconfig_gpio;
+ goto out;
+ }
+
+ /* init to passive and sane values */
+ gpio_direction_output(this->nconfig_gpio, 1);
+ gpio_direction_input(this->nstat_gpio);
+ gpio_direction_input(this->confd_gpio);
+
+ return 0;
+
+out:
+ dev_err(dev, "Cannot request \"%s\" gpio: %s\n", name, strerror(-ret));
+
+ return ret;
+}
+
+static void altera_spi_init_mode(struct spi_device *spi)
+{
+ spi->bits_per_word = 32;
+ /*
+ * CPHA = CPOL = 0
+ * the FPGA expects its firmware data with LSB first
+ */
+ spi->mode = SPI_MODE_0 | SPI_LSB_FIRST;
+}
+
+static int altera_spi_probe(struct device_d *dev)
+{
+ int rc;
+ struct fpga_spi *this;
+ struct firmware_handler *fh;
+ const char *alias = of_alias_get(dev->device_node);
+ const char *model = NULL;
+
+ dev_dbg(dev, "Probing FPGA firmware programmer\n");
+
+ this = xzalloc(sizeof(*this));
+ fh = &this->fh;
+
+ rc = altera_spi_of(dev, this);
+ if (rc != 0)
+ goto out;
+
+ if (alias)
+ fh->id = xstrdup(alias);
+ else
+ fh->id = xstrdup("altera-fpga");
+
+ fh->open = altera_spi_open;
+ fh->write = altera_spi_write;
+ fh->close = altera_spi_close;
+ of_property_read_string(dev->device_node, "compatible", &model);
+ if (model)
+ fh->model = xstrdup(model);
+ fh->dev = dev;
+
+ this->spi = (struct spi_device *)dev->type_data;
+ altera_spi_init_mode(this->spi);
+ this->dev = dev;
+
+ dev_dbg(dev, "Registering FPGA firmware programmer\n");
+ rc = firmwaremgr_register(fh);
+ if (rc != 0) {
+ free(this);
+ goto out;
+ }
+
+ return 0;
+out:
+ free(fh->id);
+ free(this);
+
+ return rc;
+}
+
+static struct of_device_id altera_spi_id_table[] = {
+ {
+ .compatible = "altr,passive-serial",
+ },
+};
+
+static struct driver_d altera_spi_driver = {
+ .name = "altera-fpga",
+ .of_compatible = DRV_OF_COMPAT(altera_spi_id_table),
+ .probe = altera_spi_probe,
+};
+device_spi_driver(altera_spi_driver);
--
1.8.4.2
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/4] Firmware: provide a handler to program Altera FPGAs
2013-11-12 14:31 ` [PATCH 2/4] Firmware: provide a handler to program Altera FPGAs Sascha Hauer
@ 2013-11-12 14:46 ` Jürgen Beisert
2013-11-12 16:03 ` Jean-Christophe PLAGNIOL-VILLARD
1 sibling, 0 replies; 12+ messages in thread
From: Jürgen Beisert @ 2013-11-12 14:46 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox
I know, documentation will never be read, but...
On Tuesday 12 November 2013 15:31:39 Sascha Hauer wrote:
> [...]
> +
> +/*
> + * Physical requirements:
> + * - three free GPIOs for the signals nCONFIG, CONFIGURE_DONE, nSTATUS
> + * - 32 bit per word, LSB first capable SPI master (MOSI + clock)
> + *
> + * Example how to configure this driver via device tree
> + *
> + * fpga@0 {
> + * compatible = "altera_serial";
> [...]
Then we also should should remove this sample or change it
to "altr,passive-serial"
jbe
--
Pengutronix e.K. | Juergen Beisert |
Linux Solutions for Science and Industry | http://www.pengutronix.de/ |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/4] Firmware: provide a handler to program Altera FPGAs
2013-11-12 14:31 ` [PATCH 2/4] Firmware: provide a handler to program Altera FPGAs Sascha Hauer
2013-11-12 14:46 ` Jürgen Beisert
@ 2013-11-12 16:03 ` Jean-Christophe PLAGNIOL-VILLARD
2013-11-13 10:23 ` Sascha Hauer
1 sibling, 1 reply; 12+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-11-12 16:03 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox, Juergen Beisert
On 15:31 Tue 12 Nov , Sascha Hauer wrote:
> From: Juergen Beisert <jbe@pengutronix.de>
>
> This handler uses a regular SPI master and a few GPIOs to program an
> Altera FPGA in serial mode.
>
> Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> drivers/Kconfig | 1 +
> drivers/Makefile | 1 +
> drivers/firmware/Kconfig | 11 ++
> drivers/firmware/Makefile | 1 +
> drivers/firmware/altera_serial.c | 307 +++++++++++++++++++++++++++++++++++++++
> 5 files changed, 321 insertions(+)
> create mode 100644 drivers/firmware/Kconfig
> create mode 100644 drivers/firmware/Makefile
> create mode 100644 drivers/firmware/altera_serial.c
>
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index d34d2c7..71d840c 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -25,5 +25,6 @@ source "drivers/gpio/Kconfig"
> source "drivers/w1/Kconfig"
> source "drivers/pinctrl/Kconfig"
> source "drivers/bus/Kconfig"
> +source "drivers/firmware/Kconfig"
>
> endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index ba1dc6d..bf03d54 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -24,3 +24,4 @@ obj-$(CONFIG_OFTREE) += of/
> obj-$(CONFIG_W1) += w1/
> obj-y += pinctrl/
> obj-y += bus/
> +obj-y += firmware/
> diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
> new file mode 100644
> index 0000000..28a173b
> --- /dev/null
> +++ b/drivers/firmware/Kconfig
> @@ -0,0 +1,11 @@
> +menu "Firmware Drivers"
> +
> +config FIRMWARE_ALTERA_SERIAL
> + bool "Altera SPI programming"
> + depends on OFDEVICE
> + select FIRMWARE
> + help
> + Programming an Altera FPGA via a few GPIOs for the control lines and
> + MOSI, MISO and clock from an SPI interface for the data lines
> +
> +endmenu
> diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
> new file mode 100644
> index 0000000..ec6a5a1
> --- /dev/null
> +++ b/drivers/firmware/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
> diff --git a/drivers/firmware/altera_serial.c b/drivers/firmware/altera_serial.c
> new file mode 100644
> index 0000000..047b6bd
> --- /dev/null
> +++ b/drivers/firmware/altera_serial.c
> @@ -0,0 +1,307 @@
> +/*
> + * Copyright (c) 2013 Juergen Beisert <kernel@pengutronix.de>, Pengutronix
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <driver.h>
> +#include <firmware.h>
> +#include <of_gpio.h>
> +#include <xfuncs.h>
> +#include <malloc.h>
> +#include <gpio.h>
> +#include <clock.h>
> +#include <spi/spi.h>
> +
> +#include <fcntl.h>
> +#include <fs.h>
> +
> +/*
> + * Physical requirements:
> + * - three free GPIOs for the signals nCONFIG, CONFIGURE_DONE, nSTATUS
> + * - 32 bit per word, LSB first capable SPI master (MOSI + clock)
> + *
> + * Example how to configure this driver via device tree
> + *
> + * fpga@0 {
> + * compatible = "altera_serial";
> + * nstat-gpio = <&gpio4 18 0>;
> + * confd-gpio = <&gpio4 19 0>;
> + * nconfig-gpio = <&gpio4 20 0>;
you are missing on 's' to gpio mandatory for all the gpios binding
Best Regards,
J.
> + * spi-max-frequency = <10000000>;
> + * reg = <0>;
> + * };
> + */
> +
> +struct fpga_spi {
> + struct firmware_handler fh;
> + int nstat_gpio; /* input GPIO to read the status line */
> + int confd_gpio; /* input GPIO to read the config done line */
> + int nconfig_gpio; /* output GPIO to start the FPGA's config */
> + struct device_d *dev;
> + struct spi_device *spi;
> + bool padding_done;
> +};
> +
> +static int altera_spi_open(struct firmware_handler *fh)
> +{
> + struct fpga_spi *this = container_of(fh, struct fpga_spi, fh);
> + struct device_d *dev = this->dev;
> + int ret;
> +
> + dev_dbg(dev, "Initiating programming\n");
> +
> + /* initiate an FPGA programming */
> + gpio_set_value(this->nconfig_gpio, 0);
> +
> + /*
> + * after about 2 µs the FPGA must acknowledge with
> + * STATUS and CONFIG DONE lines at low level
> + */
> + ret = wait_on_timeout(2 * 1000,
> + (gpio_get_value(this->nstat_gpio) == 0) &&
> + (gpio_get_value(this->confd_gpio) == 0));
> +
> + if (ret != 0) {
> + dev_err(dev, "FPGA does not acknowledge the programming initiation\n");
> + if (gpio_get_value(this->nstat_gpio))
> + dev_err(dev, "STATUS is still high!\n");
> + if (gpio_get_value(this->confd_gpio))
> + dev_err(dev, "CONFIG DONE is still high!\n");
> + return ret;
> + }
> +
> + /* arm the FPGA to await its new firmware */
> + gpio_set_value(this->nconfig_gpio, 1);
no one check the return of gpio_set but we need to
on a i2c-gpio it might fail
> +
> + /* once again, we might need padding the data */
> + this->padding_done = false;
> +
> + /*
> + * after about 1506 µs the FPGA must acknowledge this step
> + * with the STATUS line at high level
> + */
> + ret = wait_on_timeout(1600 * 1000,
> + gpio_get_value(this->nstat_gpio) == 1);
> + if (ret != 0) {
> + dev_err(dev, "FPGA does not acknowledge the programming start\n");
> + return ret;
> + }
> +
> + dev_dbg(dev, "Initiating passed\n");
> + /* at the end, wait at least 2 µs prior beginning writing data */
> + ndelay(2 * 1000);
so udelay(2);
> +
> + return 0;
> +}
> +
> +static int altera_spi_write(struct firmware_handler *fh, const void *buf, size_t sz)
> +{
> + struct fpga_spi *this = container_of(fh, struct fpga_spi, fh);
> + struct device_d *dev = this->dev;
> + struct spi_transfer t[2];
> + struct spi_message m;
> + u32 dummy;
> + int ret;
> +
> + printf("%s: %d\n", __func__, sz);
> +
> + spi_message_init(&m);
> +
> + if (sz < sizeof(u32)) {
> + /* simple padding */
> + dummy = 0;
> + memcpy(&dummy, buf, sz);
> + buf = &dummy;
> + sz = sizeof(u32);
> + this->padding_done = true;
> + }
> +
> + t[0].tx_buf = buf;
> + t[0].rx_buf = NULL;
> + t[0].len = sz;
> + spi_message_add_tail(&t[0], &m);
> +
> + if (sz & 0x3) { /* padding required? */
> + u32 *word_buf = (u32 *)buf;
> + dummy = 0;
> + memcpy(&dummy, &word_buf[sz >> 2], sz & 0x3);
> + t[0].len &= ~0x03;
> + t[1].tx_buf = &dummy;
> + t[1].rx_buf = NULL;
> + t[1].len = sizeof(u32);
> + spi_message_add_tail(&t[1], &m);
> + this->padding_done = true;
> + }
> +
> + ret = spi_sync(this->spi, &m);
> + if (ret != 0)
> + dev_err(dev, "programming failure\n");
> +
> + return ret;
> +}
> +
> +static int altera_spi_close(struct firmware_handler *fh)
> +{
> + struct fpga_spi *this = container_of(fh, struct fpga_spi, fh);
> + struct device_d *dev = this->dev;
> + struct spi_transfer t;
> + struct spi_message m;
> + u32 dummy = 0;
> + int ret;
> +
> + dev_dbg(dev, "Finalize programming\n");
> +
> + if (this->padding_done == false) {
> + spi_message_init(&m);
> + t.tx_buf = &dummy;
> + t.rx_buf = NULL;
> + t.len = sizeof(dummy);
> + spi_message_add_tail(&t, &m);
> +
> + ret = spi_sync(this->spi, &m);
> + if (ret != 0)
> + dev_err(dev, "programming failure\n");
> + }
> +
> + /*
> + * when programming was successfully,
> + * both status lines should be at high level
> + */
> + ret = wait_on_timeout(10 * 1000,
> + (gpio_get_value(this->nstat_gpio) == 1) &&
> + (gpio_get_value(this->confd_gpio) == 1));
> + if (ret == 0) {
> + dev_dbg(dev, "Programming successfull\n");
> + return ret;
> + }
> +
> + dev_err(dev, "Programming failed due to time out\n");
> + if (gpio_get_value(this->nstat_gpio) == 0)
> + dev_err(dev, "STATUS is still low!\n");
> + if (gpio_get_value(this->confd_gpio) == 0)
> + dev_err(dev, "CONFIG DONE is still low!\n");
> +
> + return -EIO;
> +}
> +
> +static int altera_spi_of(struct device_d *dev, struct fpga_spi *this)
> +{
> + struct device_node *n = dev->device_node;
> + const char *name;
> + int ret;
> +
> + name = "nstat-gpio";
> + this->nstat_gpio = of_get_named_gpio(n, name, 0);
> + if (this->nstat_gpio < 0) {
> + ret = this->nstat_gpio;
> + goto out;
> + }
> +
> + name = "confd-gpio";
> + this->confd_gpio = of_get_named_gpio(n, name, 0);
> + if (this->confd_gpio < 0) {
> + ret = this->confd_gpio;
> + goto out;
> + }
> +
> + name = "nconfig-gpio";
> + this->nconfig_gpio = of_get_named_gpio(n, name, 0);
> + if (this->nconfig_gpio < 0) {
> + ret = this->nconfig_gpio;
> + goto out;
> + }
> +
> + /* init to passive and sane values */
> + gpio_direction_output(this->nconfig_gpio, 1);
> + gpio_direction_input(this->nstat_gpio);
> + gpio_direction_input(this->confd_gpio);
we need to check the return and request the gpio correctly
> +
> + return 0;
> +
> +out:
> + dev_err(dev, "Cannot request \"%s\" gpio: %s\n", name, strerror(-ret));
> +
> + return ret;
> +}
> +
> +static void altera_spi_init_mode(struct spi_device *spi)
> +{
> + spi->bits_per_word = 32;
> + /*
> + * CPHA = CPOL = 0
> + * the FPGA expects its firmware data with LSB first
> + */
> + spi->mode = SPI_MODE_0 | SPI_LSB_FIRST;
> +}
> +
> +static int altera_spi_probe(struct device_d *dev)
> +{
> + int rc;
> + struct fpga_spi *this;
> + struct firmware_handler *fh;
> + const char *alias = of_alias_get(dev->device_node);
> + const char *model = NULL;
> +
> + dev_dbg(dev, "Probing FPGA firmware programmer\n");
> +
> + this = xzalloc(sizeof(*this));
> + fh = &this->fh;
> +
> + rc = altera_spi_of(dev, this);
> + if (rc != 0)
> + goto out;
> +
> + if (alias)
> + fh->id = xstrdup(alias);
> + else
> + fh->id = xstrdup("altera-fpga");
> +
> + fh->open = altera_spi_open;
> + fh->write = altera_spi_write;
> + fh->close = altera_spi_close;
> + of_property_read_string(dev->device_node, "compatible", &model);
> + if (model)
> + fh->model = xstrdup(model);
> + fh->dev = dev;
> +
> + this->spi = (struct spi_device *)dev->type_data;
> + altera_spi_init_mode(this->spi);
> + this->dev = dev;
> +
> + dev_dbg(dev, "Registering FPGA firmware programmer\n");
> + rc = firmwaremgr_register(fh);
> + if (rc != 0) {
> + free(this);
> + goto out;
> + }
> +
> + return 0;
> +out:
> + free(fh->id);
> + free(this);
> +
> + return rc;
> +}
> +
> +static struct of_device_id altera_spi_id_table[] = {
> + {
> + .compatible = "altr,passive-serial",
> + },
> +};
> +
> +static struct driver_d altera_spi_driver = {
> + .name = "altera-fpga",
> + .of_compatible = DRV_OF_COMPAT(altera_spi_id_table),
> + .probe = altera_spi_probe,
> +};
> +device_spi_driver(altera_spi_driver);
> --
> 1.8.4.2
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/4] Firmware: provide a handler to program Altera FPGAs
2013-11-12 16:03 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-11-13 10:23 ` Sascha Hauer
2013-11-13 13:36 ` Jean-Christophe PLAGNIOL-VILLARD
0 siblings, 1 reply; 12+ messages in thread
From: Sascha Hauer @ 2013-11-13 10:23 UTC (permalink / raw)
To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox, Juergen Beisert
On Tue, Nov 12, 2013 at 05:03:59PM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > + if (ret != 0) {
> > + dev_err(dev, "FPGA does not acknowledge the programming initiation\n");
> > + if (gpio_get_value(this->nstat_gpio))
> > + dev_err(dev, "STATUS is still high!\n");
> > + if (gpio_get_value(this->confd_gpio))
> > + dev_err(dev, "CONFIG DONE is still high!\n");
> > + return ret;
> > + }
> > +
> > + /* arm the FPGA to await its new firmware */
> > + gpio_set_value(this->nconfig_gpio, 1);
> no one check the return of gpio_set but we need to
>
> on a i2c-gpio it might fail
I don't think that's necessary here. If setting gpios fails the firmware
programming will fail later anyway.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/4] Firmware: provide a handler to program Altera FPGAs
2013-11-13 10:23 ` Sascha Hauer
@ 2013-11-13 13:36 ` Jean-Christophe PLAGNIOL-VILLARD
0 siblings, 0 replies; 12+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-11-13 13:36 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox, Juergen Beisert
On 11:23 Wed 13 Nov , Sascha Hauer wrote:
> On Tue, Nov 12, 2013 at 05:03:59PM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > > + if (ret != 0) {
> > > + dev_err(dev, "FPGA does not acknowledge the programming initiation\n");
> > > + if (gpio_get_value(this->nstat_gpio))
> > > + dev_err(dev, "STATUS is still high!\n");
> > > + if (gpio_get_value(this->confd_gpio))
> > > + dev_err(dev, "CONFIG DONE is still high!\n");
> > > + return ret;
> > > + }
> > > +
> > > + /* arm the FPGA to await its new firmware */
> > > + gpio_set_value(this->nconfig_gpio, 1);
> > no one check the return of gpio_set but we need to
> >
> > on a i2c-gpio it might fail
>
> I don't think that's necessary here. If setting gpios fails the firmware
> programming will fail later anyway.
except when you debug and want to known why and where it fail
Best Regards,
J.
>
> Sascha
>
> --
> Pengutronix e.K. | |
> Industrial Linux Solutions | http://www.pengutronix.de/ |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
> Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 3/4] DT: Add binding for Altera FPGAs in passive-serial mode
2013-11-12 14:31 Sascha Hauer
2013-11-12 14:31 ` [PATCH 1/4] Add a Firmware programming framework Sascha Hauer
2013-11-12 14:31 ` [PATCH 2/4] Firmware: provide a handler to program Altera FPGAs Sascha Hauer
@ 2013-11-12 14:31 ` Sascha Hauer
2013-11-12 14:51 ` Jürgen Beisert
2013-11-12 16:21 ` Kumar Gala
2013-11-12 14:31 ` [PATCH 4/4] Firmware: socfpga: Add SoCFPGA FPGA program support Sascha Hauer
3 siblings, 2 replies; 12+ messages in thread
From: Sascha Hauer @ 2013-11-12 14:31 UTC (permalink / raw)
To: barebox; +Cc: devicetree, jbe
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Cc: devicetree@vger.kernel.org
---
.../devicetree/bindings/firmware/altr,passive-serial.txt | 13 +++++++++++++
1 file changed, 13 insertions(+)
create mode 100644 Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
diff --git a/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt b/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
new file mode 100644
index 0000000..6d40c91
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
@@ -0,0 +1,13 @@
+Altera FPGAs in passive serial mode
+-----------------------------------
+
+This binding defines the control interface to Altera FPGAs in
+passive serial mode. This is used to upload the firmware and
+to start the FPGA.
+
+Required properties:
+- compatible: shall be "altr,passive-serial"
+- reg: SPI chip select
+- nstat-gpio: Specify GPIO for controlling the nstat pin
+- confd-gpio: Specify GPIO for controlling the confd pin
+- nconfig-gpio: Specify GPIO for controlling the nconfig pin
--
1.8.4.2
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/4] DT: Add binding for Altera FPGAs in passive-serial mode
2013-11-12 14:31 ` [PATCH 3/4] DT: Add binding for Altera FPGAs in passive-serial mode Sascha Hauer
@ 2013-11-12 14:51 ` Jürgen Beisert
2013-11-12 16:21 ` Kumar Gala
1 sibling, 0 replies; 12+ messages in thread
From: Jürgen Beisert @ 2013-11-12 14:51 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox, devicetree
On Tuesday 12 November 2013 15:31:40 Sascha Hauer wrote:
> [...]
> +Required properties:
> +- compatible: shall be "altr,passive-serial"
> +- reg: SPI chip select
> +- nstat-gpio: Specify GPIO for controlling the nstat pin
> +- confd-gpio: Specify GPIO for controlling the confd pin
> +- nconfig-gpio: Specify GPIO for controlling the nconfig pin
A suggestion was to use the genuine signal names at the FPGA side:
"nstatus", "config-done" and "nconfig" (all with the trailing "-gpio")
jbe
--
Pengutronix e.K. | Juergen Beisert |
Linux Solutions for Science and Industry | http://www.pengutronix.de/ |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/4] DT: Add binding for Altera FPGAs in passive-serial mode
2013-11-12 14:31 ` [PATCH 3/4] DT: Add binding for Altera FPGAs in passive-serial mode Sascha Hauer
2013-11-12 14:51 ` Jürgen Beisert
@ 2013-11-12 16:21 ` Kumar Gala
2013-11-12 22:02 ` Sascha Hauer
1 sibling, 1 reply; 12+ messages in thread
From: Kumar Gala @ 2013-11-12 16:21 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox, jbe, devicetree
On Nov 12, 2013, at 8:31 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: devicetree@vger.kernel.org
> ---
> .../devicetree/bindings/firmware/altr,passive-serial.txt | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
>
> diff --git a/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt b/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
> new file mode 100644
> index 0000000..6d40c91
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
> @@ -0,0 +1,13 @@
> +Altera FPGAs in passive serial mode
> +-----------------------------------
> +
> +This binding defines the control interface to Altera FPGAs in
> +passive serial mode. This is used to upload the firmware and
> +to start the FPGA.
> +
> +Required properties:
> +- compatible: shall be "altr,passive-serial”
This doesn’t seem quite descriptive enough, easy to confuse with a serial port.
> +- reg: SPI chip select
Is this a SPI device than?
> +- nstat-gpio: Specify GPIO for controlling the nstat pin
> +- confd-gpio: Specify GPIO for controlling the confd pin
> +- nconfig-gpio: Specify GPIO for controlling the nconfig pin
> --
> 1.8.4.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/4] DT: Add binding for Altera FPGAs in passive-serial mode
2013-11-12 16:21 ` Kumar Gala
@ 2013-11-12 22:02 ` Sascha Hauer
0 siblings, 0 replies; 12+ messages in thread
From: Sascha Hauer @ 2013-11-12 22:02 UTC (permalink / raw)
To: Kumar Gala; +Cc: barebox, jbe, devicetree
On Tue, Nov 12, 2013 at 10:21:02AM -0600, Kumar Gala wrote:
>
> On Nov 12, 2013, at 8:31 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
>
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > Cc: devicetree@vger.kernel.org
> > ---
> > .../devicetree/bindings/firmware/altr,passive-serial.txt | 13 +++++++++++++
> > 1 file changed, 13 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
> >
> > diff --git a/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt b/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
> > new file mode 100644
> > index 0000000..6d40c91
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
> > @@ -0,0 +1,13 @@
> > +Altera FPGAs in passive serial mode
> > +-----------------------------------
> > +
> > +This binding defines the control interface to Altera FPGAs in
> > +passive serial mode. This is used to upload the firmware and
> > +to start the FPGA.
> > +
> > +Required properties:
> > +- compatible: shall be "altr,passive-serial”
>
> This doesn’t seem quite descriptive enough, easy to confuse with a serial port.
How about altr,fpga-passive-serial? Other suggestions?
>
> > +- reg: SPI chip select
>
> Is this a SPI device than?
Yes, it is.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 4/4] Firmware: socfpga: Add SoCFPGA FPGA program support
2013-11-12 14:31 Sascha Hauer
` (2 preceding siblings ...)
2013-11-12 14:31 ` [PATCH 3/4] DT: Add binding for Altera FPGAs in passive-serial mode Sascha Hauer
@ 2013-11-12 14:31 ` Sascha Hauer
3 siblings, 0 replies; 12+ messages in thread
From: Sascha Hauer @ 2013-11-12 14:31 UTC (permalink / raw)
To: barebox; +Cc: jbe
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/dts/socfpga_cyclone5.dtsi | 5 +
arch/arm/mach-socfpga/Makefile | 1 +
arch/arm/mach-socfpga/include/mach/socfpga-regs.h | 2 +
drivers/firmware/Kconfig | 3 +
drivers/firmware/Makefile | 1 +
drivers/firmware/socfpga.c | 437 ++++++++++++++++++++++
6 files changed, 449 insertions(+)
create mode 100644 drivers/firmware/socfpga.c
diff --git a/arch/arm/dts/socfpga_cyclone5.dtsi b/arch/arm/dts/socfpga_cyclone5.dtsi
index ee2ec6c..188b91b 100644
--- a/arch/arm/dts/socfpga_cyclone5.dtsi
+++ b/arch/arm/dts/socfpga_cyclone5.dtsi
@@ -47,6 +47,11 @@
};
};
+ fpgamgr@ff706000 {
+ compatible = "altr,fpga-mgr";
+ reg = <0xff706000 0x1000 0xffb90000 0x1000>;
+ };
+
timer@ffc08000 {
clock-frequency = <100000000>;
};
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index d8bf067..12585c5 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -2,3 +2,4 @@ obj-y += generic.o nic301.o bootsource.o reset-manager.o
pbl-y += init.o freeze-controller.o scan-manager.o system-manager.o
pbl-y += clock-manager.o iocsr-config-cyclone5.o
obj-$(CONFIG_ARCH_SOCFPGA_XLOAD) += xload.o
+obj-$(CONFIG_ARCH_SOCFPGA_FPGA) += fpga.o
diff --git a/arch/arm/mach-socfpga/include/mach/socfpga-regs.h b/arch/arm/mach-socfpga/include/mach/socfpga-regs.h
index 9d1e677..b124ed6 100644
--- a/arch/arm/mach-socfpga/include/mach/socfpga-regs.h
+++ b/arch/arm/mach-socfpga/include/mach/socfpga-regs.h
@@ -2,10 +2,12 @@
#define __MACH_SOCFPGA_REGS_H
#define CYCLONE5_SDMMC_ADDRESS 0xff704000
+#define CYCLONE5_FPGAMGRREGS_ADDRESS 0xff706000
#define CYCLONE5_GPIO0_BASE 0xff708000
#define CYCLONE5_GPIO1_BASE 0xff709000
#define CYCLONE5_GPIO2_BASE 0xff70A000
#define CYCLONE5_L3REGS_ADDRESS 0xff800000
+#define CYCLONE5_FPGAMGRDATA_ADDRESS 0xffb90000
#define CYCLONE5_UART0_ADDRESS 0xffc02000
#define CYCLONE5_UART1_ADDRESS 0xffc03000
#define CYCLONE5_SDR_ADDRESS 0xffc20000
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 28a173b..5866063 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -8,4 +8,7 @@ config FIRMWARE_ALTERA_SERIAL
Programming an Altera FPGA via a few GPIOs for the control lines and
MOSI, MISO and clock from an SPI interface for the data lines
+config FIRMWARE_ALTERA_SOCFPGA
+ bool "Altera SoCFPGA fpga loader"
+
endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index ec6a5a1..c3a3c34 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
+obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
diff --git a/drivers/firmware/socfpga.c b/drivers/firmware/socfpga.c
new file mode 100644
index 0000000..7d8f888
--- /dev/null
+++ b/drivers/firmware/socfpga.c
@@ -0,0 +1,437 @@
+/*
+ *
+ * Copyright (C) 2012 Altera Corporation <www.altera.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of the Altera Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL ALTERA CORPORATION BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <firmware.h>
+#include <command.h>
+#include <common.h>
+#include <malloc.h>
+#include <clock.h>
+#include <fcntl.h>
+#include <init.h>
+#include <io.h>
+#include <mach/system-manager.h>
+#include <mach/reset-manager.h>
+#include <mach/socfpga-regs.h>
+#include <mach/sdram.h>
+
+#define FPGAMGRREGS_STAT 0x0
+#define FPGAMGRREGS_CTRL 0x4
+#define FPGAMGRREGS_DCLKCNT 0x8
+#define FPGAMGRREGS_DCLKSTAT 0xc
+
+#define FPGAMGRREGS_MON_GPIO_PORTA_EOI_ADDRESS 0x84c
+#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_ADDRESS 0x850
+
+#define FPGAMGRREGS_CTRL_CFGWDTH_MASK 0x200
+#define FPGAMGRREGS_CTRL_AXICFGEN_MASK 0x100
+#define FPGAMGRREGS_CTRL_NCONFIGPULL_MASK 0x4
+#define FPGAMGRREGS_CTRL_NCE_MASK 0x2
+#define FPGAMGRREGS_CTRL_EN_MASK 0x1
+#define FPGAMGRREGS_CTRL_CDRATIO_LSB 6
+
+#define FPGAMGRREGS_STAT_MODE_MASK 0x7
+#define FPGAMGRREGS_STAT_MSEL_MASK 0xf8
+#define FPGAMGRREGS_STAT_MSEL_LSB 3
+
+#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CRC_MASK 0x8
+#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_ID_MASK 0x4
+#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK 0x2
+#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK 0x1
+
+/* FPGA Mode */
+#define FPGAMGRREGS_MODE_FPGAOFF 0x0
+#define FPGAMGRREGS_MODE_RESETPHASE 0x1
+#define FPGAMGRREGS_MODE_CFGPHASE 0x2
+#define FPGAMGRREGS_MODE_INITPHASE 0x3
+#define FPGAMGRREGS_MODE_USERMODE 0x4
+#define FPGAMGRREGS_MODE_UNKNOWN 0x5
+
+/* FPGA CD Ratio Value */
+#define CDRATIO_x1 0x0
+#define CDRATIO_x2 0x1
+#define CDRATIO_x4 0x2
+#define CDRATIO_x8 0x3
+
+struct fpgamgr {
+ struct firmware_handler fh;
+ struct device_d *dev;
+ void __iomem *regs;
+ void __iomem *regs_data;
+};
+
+/* Get the FPGA mode */
+static uint32_t fpgamgr_get_mode(struct fpgamgr *mgr)
+{
+ return readl(mgr->regs + FPGAMGRREGS_STAT) & FPGAMGRREGS_STAT_MODE_MASK;
+}
+
+static int fpgamgr_dclkcnt_set(struct fpgamgr *mgr, unsigned long cnt)
+{
+ uint64_t start;
+
+ /* clear any existing done status */
+ if (readl(mgr->regs + FPGAMGRREGS_DCLKSTAT))
+ writel(0x1, mgr->regs + FPGAMGRREGS_DCLKSTAT);
+
+ writel(cnt, mgr->regs + FPGAMGRREGS_DCLKCNT);
+
+ /* wait till the dclkcnt done */
+ start = get_time_ns();
+ while (1) {
+ if (readl(mgr->regs + FPGAMGRREGS_DCLKSTAT)) {
+ writel(0x1, mgr->regs + FPGAMGRREGS_DCLKSTAT);
+ return 0;
+ }
+
+ if (is_timeout(start, 100 * MSECOND))
+ return -ETIMEDOUT;
+ }
+}
+
+/* Start the FPGA programming by initialize the FPGA Manager */
+static int fpgamgr_program_init(struct fpgamgr *mgr)
+{
+ unsigned long reg;
+ uint32_t ctrl = 0, ratio;
+ uint64_t start;
+
+ /* get the MSEL value */
+ reg = readl(mgr->regs + FPGAMGRREGS_STAT);
+ reg = ((reg & FPGAMGRREGS_STAT_MSEL_MASK) >> FPGAMGRREGS_STAT_MSEL_LSB);
+
+ if (reg & 0x8)
+ ctrl |= FPGAMGRREGS_CTRL_CFGWDTH_MASK;
+ else
+ ctrl &= ~FPGAMGRREGS_CTRL_CFGWDTH_MASK;
+
+ switch (reg & 0xb) {
+ case 0xa:
+ ratio = CDRATIO_x8;
+ break;
+ case 0x2:
+ case 0x9:
+ ratio = CDRATIO_x4;
+ break;
+ case 0x1:
+ ratio = CDRATIO_x2;
+ break;
+ case 0x8:
+ case 0xb:
+ default:
+ ratio = CDRATIO_x1;
+ break;
+ }
+
+ ctrl |= ratio << FPGAMGRREGS_CTRL_CDRATIO_LSB;
+
+ /* to enable FPGA Manager drive over configuration line */
+ ctrl |= FPGAMGRREGS_CTRL_EN_MASK;
+
+ /* put FPGA into reset phase */
+ ctrl |= FPGAMGRREGS_CTRL_NCONFIGPULL_MASK;
+
+ writel(ctrl, mgr->regs + FPGAMGRREGS_CTRL);
+
+ /* (1) wait until FPGA enter reset phase */
+ start = get_time_ns();
+ while (1) {
+ if (fpgamgr_get_mode(mgr) == FPGAMGRREGS_MODE_RESETPHASE)
+ break;
+ if (is_timeout(start, 100 * MSECOND))
+ return -ETIMEDOUT;
+ }
+
+ /* release FPGA from reset phase */
+ ctrl = readl(mgr->regs + FPGAMGRREGS_CTRL);
+ ctrl &= ~FPGAMGRREGS_CTRL_NCONFIGPULL_MASK;
+ writel(ctrl, mgr->regs + FPGAMGRREGS_CTRL);
+
+ /* (2) wait until FPGA enter configuration phase */
+ start = get_time_ns();
+ while (1) {
+ if (fpgamgr_get_mode(mgr) == FPGAMGRREGS_MODE_CFGPHASE)
+ break;
+ if (is_timeout(start, 100 * MSECOND))
+ return -ETIMEDOUT;
+ }
+
+ /* clear all interrupt in CB Monitor */
+ writel(0xFFF, (mgr->regs + FPGAMGRREGS_MON_GPIO_PORTA_EOI_ADDRESS));
+
+ /* enable AXI configuration */
+ ctrl = readl(mgr->regs + FPGAMGRREGS_CTRL);
+ ctrl |= FPGAMGRREGS_CTRL_AXICFGEN_MASK;
+ writel(ctrl, mgr->regs + FPGAMGRREGS_CTRL);
+
+ return 0;
+}
+
+/* Ensure the FPGA entering config done */
+static int fpgamgr_program_poll_cd(struct fpgamgr *mgr)
+{
+ unsigned long reg;
+ uint32_t val;
+ uint64_t start;
+
+ /* (3) wait until full config done */
+ start = get_time_ns();
+ while (1) {
+ reg = readl(mgr->regs + FPGAMGRREGS_MON_GPIO_EXT_PORTA_ADDRESS);
+
+ /* config error */
+ if (!(reg & FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK) &&
+ !(reg & FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK))
+ return -EIO;
+
+ /* config done without error */
+ if ((reg & FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK) &&
+ (reg & FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK))
+ break;
+
+ if (is_timeout(start, 100 * MSECOND))
+ return -ETIMEDOUT;
+ }
+
+ /* disable AXI configuration */
+ val = readl(mgr->regs + FPGAMGRREGS_CTRL);
+ val &= ~FPGAMGRREGS_CTRL_AXICFGEN_MASK;
+ writel(val, mgr->regs + FPGAMGRREGS_CTRL);
+
+ return 0;
+}
+
+/* Ensure the FPGA entering init phase */
+static int fpgamgr_program_poll_initphase(struct fpgamgr *mgr)
+{
+ uint64_t start;
+
+ /* additional clocks for the CB to enter initialization phase */
+ if (fpgamgr_dclkcnt_set(mgr, 0x4) != 0)
+ return -5;
+
+ /* (4) wait until FPGA enter init phase or user mode */
+ start = get_time_ns();
+ while (1) {
+ int mode = fpgamgr_get_mode(mgr);
+
+ if (mode == FPGAMGRREGS_MODE_INITPHASE ||
+ mode == FPGAMGRREGS_MODE_USERMODE)
+ break;
+
+ if (is_timeout(start, 100 * MSECOND))
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/* Ensure the FPGA entering user mode */
+static int fpgamgr_program_poll_usermode(struct fpgamgr *mgr)
+{
+ uint32_t val;
+ uint64_t start;
+
+ /* additional clocks for the CB to exit initialization phase */
+ if (fpgamgr_dclkcnt_set(mgr, 0x5000) != 0)
+ return -7;
+
+ /* (5) wait until FPGA enter user mode */
+ start = get_time_ns();
+ while (1) {
+ if (fpgamgr_get_mode(mgr) == FPGAMGRREGS_MODE_USERMODE)
+ break;
+ if (is_timeout(start, 100 * MSECOND))
+ return -ETIMEDOUT;
+ }
+
+ /* to release FPGA Manager drive over configuration line */
+ val = readl(mgr->regs + FPGAMGRREGS_CTRL);
+ val &= ~FPGAMGRREGS_CTRL_EN_MASK;
+ writel(val, mgr->regs + FPGAMGRREGS_CTRL);
+
+ return 0;
+}
+
+/*
+ * Using FPGA Manager to program the FPGA
+ * Return 0 for sucess
+ */
+static int fpgamgr_program_start(struct firmware_handler *fh)
+{
+ struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
+ int status;
+
+ /* prior programming the FPGA, all bridges need to be shut off */
+
+ /* disable all signals from hps peripheral controller to fpga */
+ writel(0, SYSMGR_FPGAINTF_MODULE);
+
+ /* disable all signals from fpga to hps sdram */
+ writel(0, (CYCLONE5_SDR_ADDRESS + SDR_CTRLGRP_FPGAPORTRST_ADDRESS));
+
+ /* disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */
+ writel(~0, CYCLONE5_RSTMGR_ADDRESS + RESET_MGR_BRG_MOD_RESET_OFS);
+
+ /* unmap the bridges from NIC-301 */
+ writel(0x1, CYCLONE5_L3REGS_ADDRESS);
+
+ dev_dbg(mgr->dev, "start programming...\n");
+
+ /* initialize the FPGA Manager */
+ status = fpgamgr_program_init(mgr);
+ if (status) {
+ dev_err(mgr->dev, "program init failed with: %s\n",
+ strerror(-status));
+ return status;
+ }
+
+ return 0;
+}
+
+/* Write the RBF data to FPGA Manager */
+static int fpgamgr_program_write_buf(struct firmware_handler *fh, const void *buf,
+ size_t size)
+{
+ struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
+ const uint32_t *buf32 = buf;
+
+ /* write to FPGA Manager AXI data */
+ while (size) {
+ writel(*buf32, mgr->regs_data);
+ readl(mgr->regs + FPGAMGRREGS_MON_GPIO_EXT_PORTA_ADDRESS);
+ buf32++;
+ size -= sizeof(uint32_t);
+ }
+
+ return 0;
+}
+
+static int fpgamgr_program_finish(struct firmware_handler *fh)
+{
+ struct fpgamgr *mgr = container_of(fh, struct fpgamgr, fh);
+ int status;
+
+ /* Ensure the FPGA entering config done */
+ status = fpgamgr_program_poll_cd(mgr);
+ if (status) {
+ dev_err(mgr->dev, "poll for config done failed with: %s\n",
+ strerror(-status));
+ return status;
+ }
+
+ dev_dbg(mgr->dev, "waiting for init phase...\n");
+
+ /* Ensure the FPGA entering init phase */
+ status = fpgamgr_program_poll_initphase(mgr);
+ if (status) {
+ dev_err(mgr->dev, "poll for init phase failed with: %s\n",
+ strerror(-status));
+ return status;
+ }
+
+ dev_dbg(mgr->dev, "waiting for user mode...\n");
+
+ /* Ensure the FPGA entering user mode */
+ status = fpgamgr_program_poll_usermode(mgr);
+ if (status) {
+ dev_err(mgr->dev, "poll for user mode with: %s\n",
+ strerror(-status));
+ return status;
+ }
+
+ return 0;
+}
+
+static int fpgamgr_probe(struct device_d *dev)
+{
+ struct fpgamgr *mgr;
+ struct firmware_handler *fh;
+ const char *alias = of_alias_get(dev->device_node);
+ const char *model = NULL;
+ int ret;
+
+ dev_dbg(dev, "Probing FPGA firmware programmer\n");
+
+ mgr = xzalloc(sizeof(*mgr));
+ fh = &mgr->fh;
+
+ mgr->regs = dev_request_mem_region(dev, 0);
+ if (!mgr->regs) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ mgr->regs_data = dev_request_mem_region(dev, 1);
+ if (!mgr->regs_data) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (alias)
+ fh->id = xstrdup(alias);
+ else
+ fh->id = xstrdup("socfpga-fpga");
+
+ fh->open = fpgamgr_program_start;
+ fh->write = fpgamgr_program_write_buf;
+ fh->close = fpgamgr_program_finish;
+ of_property_read_string(dev->device_node, "compatible", &model);
+ if (model)
+ fh->model = xstrdup(model);
+ fh->dev = dev;
+
+ mgr->dev = dev;
+
+ dev_dbg(dev, "Registering FPGA firmware programmer\n");
+
+ ret = firmwaremgr_register(fh);
+ if (ret != 0) {
+ free(mgr);
+ goto out;
+ }
+
+ return 0;
+out:
+ free(fh->id);
+ free(mgr);
+
+ return ret;
+}
+
+static struct of_device_id fpgamgr_id_table[] = {
+ {
+ .compatible = "altr,fpga-mgr",
+ },
+};
+
+static struct driver_d fpgamgr_driver = {
+ .name = "socfpa-fpgamgr",
+ .of_compatible = DRV_OF_COMPAT(fpgamgr_id_table),
+ .probe = fpgamgr_probe,
+};
+device_platform_driver(fpgamgr_driver);
--
1.8.4.2
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 12+ messages in thread