* [PATCH v4 0/5] firmware programming interface
@ 2014-09-08 9:29 Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 1/5] Add a Firmware programming framework Steffen Trumtrar
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2014-09-08 9:29 UTC (permalink / raw)
To: barebox; +Cc: Steffen Trumtrar
Hi!
Changes since v3:
- minor clean up
- add binding documentation in 5/5
- rebase to v2014.09.0
The interface was tested on a Socfpga SoCkit board with v2014.09.0.
Regards,
Steffen
Juergen Beisert (2):
Add a Firmware programming framework
Firmware: provide a handler to program Altera FPGAs
Sascha Hauer (2):
DT: Add binding for Altera FPGAs in passive-serial mode
Firmware: socfpga: Add SoCFPGA FPGA program support
Steffen Trumtrar (1):
DT: Add binding for Altera SOCFPGA FPGA Manager
.../bindings/firmware/altr,passive-serial.txt | 24 ++
.../bindings/firmware/altr,socfpga-fpga-mgr.txt | 19 +
arch/arm/dts/socfpga.dtsi | 6 +
arch/arm/mach-socfpga/Makefile | 1 +
arch/arm/mach-socfpga/include/mach/socfpga-regs.h | 2 +
commands/Kconfig | 9 +
commands/Makefile | 1 +
commands/firmwareload.c | 66 ++++
common/Kconfig | 3 +
common/Makefile | 1 +
common/firmware.c | 211 ++++++++++
drivers/Kconfig | 1 +
drivers/Makefile | 1 +
drivers/firmware/Kconfig | 14 +
drivers/firmware/Makefile | 2 +
drivers/firmware/altera_serial.c | 315 +++++++++++++++
drivers/firmware/socfpga.c | 440 +++++++++++++++++++++
include/firmware.h | 42 ++
18 files changed, 1158 insertions(+)
create mode 100644 Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
create mode 100644 Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.txt
create mode 100644 commands/firmwareload.c
create mode 100644 common/firmware.c
create mode 100644 drivers/firmware/Kconfig
create mode 100644 drivers/firmware/Makefile
create mode 100644 drivers/firmware/altera_serial.c
create mode 100644 drivers/firmware/socfpga.c
create mode 100644 include/firmware.h
--
2.1.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 1/5] Add a Firmware programming framework
2014-09-08 9:29 [PATCH v4 0/5] firmware programming interface Steffen Trumtrar
@ 2014-09-08 9:29 ` Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 2/5] Firmware: provide a handler to program Altera FPGAs Steffen Trumtrar
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2014-09-08 9:29 UTC (permalink / raw)
To: barebox; +Cc: Juergen Beisert, Steffen Trumtrar
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>
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
Notes:
Changes since v3:
- change list_handlers formatting
commands/Kconfig | 9 +++
commands/Makefile | 1 +
commands/firmwareload.c | 66 +++++++++++++++
common/Kconfig | 3 +
common/Makefile | 1 +
common/firmware.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++
include/firmware.h | 42 ++++++++++
7 files changed, 333 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 3a49bafd27a7..0b1939ef5718 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1905,6 +1905,15 @@ config CMD_BAREBOX_UPDATE
-y autom. use 'yes' when asking confirmations
-f LEVEL set force level
+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_LINUX_EXEC
bool "linux exec"
depends on LINUX
diff --git a/commands/Makefile b/commands/Makefile
index 52b6137c01ab..d6a6f822a8da 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -103,3 +103,4 @@ obj-$(CONFIG_CMD_LSPCI) += lspci.o
obj-$(CONFIG_CMD_IMD) += imd.o
obj-$(CONFIG_CMD_HWCLOCK) += hwclock.o
obj-$(CONFIG_CMD_USBGADGET) += usbgadget.o
+obj-$(CONFIG_CMD_FIRMWARELOAD) += firmwareload.o
diff --git a/commands/firmwareload.c b/commands/firmwareload.c
new file mode 100644
index 000000000000..a2596951a795
--- /dev/null
+++ b/commands/firmwareload.c
@@ -0,0 +1,66 @@
+/*
+ * 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_TEXT("Options:")
+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,
+ BAREBOX_CMD_DESC("Program a firmware file into a device")
+ BAREBOX_CMD_HELP(cmd_firmwareload_help)
+BAREBOX_CMD_END
diff --git a/common/Kconfig b/common/Kconfig
index 9cc96b776deb..8c8f840c23b9 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -328,6 +328,9 @@ config CBSIZE
prompt "Buffer size for input from the Console"
default 1024
+config FIRMWARE
+ bool
+
choice
prompt "Select your shell"
diff --git a/common/Makefile b/common/Makefile
index 51b7d4ea85ad..282ddbca256d 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_EFI_DEVICEPATH) += efi-devicepath.o
lwl-$(CONFIG_IMD) += imd-barebox.o
obj-$(CONFIG_IMD) += imd.o
obj-$(CONFIG_FILE_LIST) += file-list.o
+obj-$(CONFIG_FIRMWARE) += firmware.o
quiet_cmd_pwd_h = PWDH $@
ifdef CONFIG_PASSWORD
diff --git a/common/firmware.c b/common/firmware.c
new file mode 100644
index 000000000000..2a62a81c7845
--- /dev/null
+++ b/common/firmware.c
@@ -0,0 +1,211 @@
+/*
+ * 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;
+ }
+
+ ret = mgr->handler->close(mgr->handler);
+ 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 000000000000..f6f78c840cac
--- /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 */
--
2.1.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 2/5] Firmware: provide a handler to program Altera FPGAs
2014-09-08 9:29 [PATCH v4 0/5] firmware programming interface Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 1/5] Add a Firmware programming framework Steffen Trumtrar
@ 2014-09-08 9:29 ` Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 3/5] DT: Add binding for Altera FPGAs in passive-serial mode Steffen Trumtrar
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2014-09-08 9:29 UTC (permalink / raw)
To: barebox; +Cc: Juergen Beisert, Steffen Trumtrar
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>
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
Notes:
Changes since v3:
- fix some typos
- use USECOND instead of 1000
- replace printf with dev_dbg
drivers/Kconfig | 1 +
drivers/Makefile | 1 +
drivers/firmware/Kconfig | 11 ++
drivers/firmware/Makefile | 1 +
drivers/firmware/altera_serial.c | 315 +++++++++++++++++++++++++++++++++++++++
5 files changed, 329 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 d38032c0e606..e126f62c8f93 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -29,5 +29,6 @@ source "drivers/regulator/Kconfig"
source "drivers/reset/Kconfig"
source "drivers/pci/Kconfig"
source "drivers/rtc/Kconfig"
+source "drivers/firmware/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 4591f9a4086f..cf42190b7bef 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_REGULATOR) += regulator/
obj-$(CONFIG_RESET_CONTROLLER) += reset/
obj-$(CONFIG_PCI) += pci/
obj-y += rtc/
+obj-$(CONFIG_FIRMWARE) += firmware/
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
new file mode 100644
index 000000000000..28a173b63f2a
--- /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 000000000000..ec6a5a17083d
--- /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 000000000000..23ba3b00a478
--- /dev/null
+++ b/drivers/firmware/altera_serial.c
@@ -0,0 +1,315 @@
+/*
+ * 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 = "altr,fpga-passive-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 * USECOND,
+ (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 */
+ ret = gpio_set_value(this->nconfig_gpio, 1);
+ if (ret)
+ return ret;
+
+ /* 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 * USECOND,
+ 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 */
+ 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;
+
+ dev_dbg(dev, "Start writing %d bytes.\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 successful,
+ * both status lines should be at high level
+ */
+ ret = wait_on_timeout(10 * USECOND,
+ (gpio_get_value(this->nstat_gpio) == 1) &&
+ (gpio_get_value(this->confd_gpio) == 1));
+ if (ret == 0) {
+ dev_dbg(dev, "Programming successful\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 */
+ ret = gpio_direction_output(this->nconfig_gpio, 1);
+ if (ret)
+ return ret;
+ ret = gpio_direction_input(this->nstat_gpio);
+ if (ret)
+ return ret;
+ ret = gpio_direction_input(this->confd_gpio);
+ if (ret)
+ return ret;
+
+ 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);
--
2.1.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 3/5] DT: Add binding for Altera FPGAs in passive-serial mode
2014-09-08 9:29 [PATCH v4 0/5] firmware programming interface Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 1/5] Add a Firmware programming framework Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 2/5] Firmware: provide a handler to program Altera FPGAs Steffen Trumtrar
@ 2014-09-08 9:29 ` Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 4/5] Firmware: socfpga: Add SoCFPGA FPGA program support Steffen Trumtrar
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2014-09-08 9:29 UTC (permalink / raw)
To: barebox; +Cc: devicetree, Steffen Trumtrar
From: Sascha Hauer <s.hauer@pengutronix.de>
Altera FPGAs that are programmed via SPI use the passive serial protocol.
Add a simple binding that describes the setup for this usecase.
Cc: devicetree@vger.kernel.org
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
.../bindings/firmware/altr,passive-serial.txt | 24 ++++++++++++++++++++++
1 file changed, 24 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 000000000000..d357dd39cf67
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/altr,passive-serial.txt
@@ -0,0 +1,24 @@
+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,fpga-passive-serial"
+- reg: SPI chip select
+- nstat-gpios: Specify GPIO for controlling the nstat pin
+- confd-gpios: Specify GPIO for controlling the confd pin
+- nconfig-gpios: Specify GPIO for controlling the nconfig pin
+
+Example:
+
+ fpga@0 {
+ compatible = "altr,fpga-passive-serial";
+ nstat-gpios = <&gpio4 18 0>;
+ confd-gpios = <&gpio4 19 0>;
+ nconfig-gpios = <&gpio4 20 0>;
+ spi-max-frequency = <10000000>;
+ reg = <0>;
+ };
--
2.1.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 4/5] Firmware: socfpga: Add SoCFPGA FPGA program support
2014-09-08 9:29 [PATCH v4 0/5] firmware programming interface Steffen Trumtrar
` (2 preceding siblings ...)
2014-09-08 9:29 ` [PATCH v4 3/5] DT: Add binding for Altera FPGAs in passive-serial mode Steffen Trumtrar
@ 2014-09-08 9:29 ` Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 5/5] DT: Add binding for Altera SOCFPGA FPGA Manager Steffen Trumtrar
2014-09-09 8:30 ` [PATCH v4 0/5] firmware programming interface Sascha Hauer
5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2014-09-08 9:29 UTC (permalink / raw)
To: barebox
From: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/dts/socfpga.dtsi | 6 +
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 | 440 ++++++++++++++++++++++
6 files changed, 453 insertions(+)
create mode 100644 drivers/firmware/socfpga.c
diff --git a/arch/arm/dts/socfpga.dtsi b/arch/arm/dts/socfpga.dtsi
index 3368b459d030..afac867c991d 100644
--- a/arch/arm/dts/socfpga.dtsi
+++ b/arch/arm/dts/socfpga.dtsi
@@ -465,6 +465,12 @@
status = "disabled";
};
+ fpgamgr@ff706000 {
+ compatible = "altr,socfpga-fpga-mgr";
+ reg = <0xff706000 0x1000>,
+ <0xffb90000 0x1000>;
+ };
+
gpio0: gpio@ff708000 {
compatible = "snps,dw-apb-gpio";
reg = <0xff708000 0x1000>;
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index d8bf0674306e..12585c547673 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 9d1e677cb736..b124ed675cfc 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 28a173b63f2a..58660632519e 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 ec6a5a17083d..c3a3c3400485 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 000000000000..a5dc6072aab4
--- /dev/null
+++ b/drivers/firmware/socfpga.c
@@ -0,0 +1,440 @@
+/*
+ *
+ * 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;
+
+ /* clear nce bit to allow HPS configuration */
+ ctrl &= ~FPGAMGRREGS_CTRL_NCE_MASK;
+
+ /* 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,socfpga-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);
--
2.1.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 5/5] DT: Add binding for Altera SOCFPGA FPGA Manager
2014-09-08 9:29 [PATCH v4 0/5] firmware programming interface Steffen Trumtrar
` (3 preceding siblings ...)
2014-09-08 9:29 ` [PATCH v4 4/5] Firmware: socfpga: Add SoCFPGA FPGA program support Steffen Trumtrar
@ 2014-09-08 9:29 ` Steffen Trumtrar
2014-09-09 8:30 ` [PATCH v4 0/5] firmware programming interface Sascha Hauer
5 siblings, 0 replies; 7+ messages in thread
From: Steffen Trumtrar @ 2014-09-08 9:29 UTC (permalink / raw)
To: barebox; +Cc: devicetree, Steffen Trumtrar
Altera SOCFPGA have a FPGA Manager, that manages and monitors the FPGA portion
of the SoC.
Cc: devicetree@vger.kernel.org
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
.../bindings/firmware/altr,socfpga-fpga-mgr.txt | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.txt
diff --git a/Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.txt b/Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.txt
new file mode 100644
index 000000000000..70ec4abf25b4
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/altr,socfpga-fpga-mgr.txt
@@ -0,0 +1,19 @@
+Altera SOCFPGA FPGA Manager
+---------------------------
+
+This binding defines the FPGA Manager on Altera SOCFPGAs. This is used to upload
+the firmware to the FPGA part of the SoC.
+
+Required properties:
+- compatible: shall be "altr,socfpga-fpga-mgr"
+- reg: Must contain 2 register ranges:
+ 1. The control address space of the FPGA manager.
+ 2. The configuration data address space where the firmware data is written to.
+
+Example:
+
+ fpgamgr@ff706000 {
+ compatible = "altr,socfpga-fpga-mgr";
+ reg = <0xff706000 0x1000>,
+ <0xffb90000 0x1000>;
+ };
--
2.1.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 0/5] firmware programming interface
2014-09-08 9:29 [PATCH v4 0/5] firmware programming interface Steffen Trumtrar
` (4 preceding siblings ...)
2014-09-08 9:29 ` [PATCH v4 5/5] DT: Add binding for Altera SOCFPGA FPGA Manager Steffen Trumtrar
@ 2014-09-09 8:30 ` Sascha Hauer
5 siblings, 0 replies; 7+ messages in thread
From: Sascha Hauer @ 2014-09-09 8:30 UTC (permalink / raw)
To: Steffen Trumtrar; +Cc: barebox
On Mon, Sep 08, 2014 at 11:29:06AM +0200, Steffen Trumtrar wrote:
> Hi!
>
> Changes since v3:
> - minor clean up
> - add binding documentation in 5/5
> - rebase to v2014.09.0
>
> The interface was tested on a Socfpga SoCkit board with v2014.09.0.
>
> Regards,
> Steffen
>
>
> Juergen Beisert (2):
> Add a Firmware programming framework
> Firmware: provide a handler to program Altera FPGAs
>
> Sascha Hauer (2):
> DT: Add binding for Altera FPGAs in passive-serial mode
> Firmware: socfpga: Add SoCFPGA FPGA program support
>
> Steffen Trumtrar (1):
> DT: Add binding for Altera SOCFPGA FPGA Manager
Applied, thanks
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] 7+ messages in thread
end of thread, other threads:[~2014-09-09 8:31 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-08 9:29 [PATCH v4 0/5] firmware programming interface Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 1/5] Add a Firmware programming framework Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 2/5] Firmware: provide a handler to program Altera FPGAs Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 3/5] DT: Add binding for Altera FPGAs in passive-serial mode Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 4/5] Firmware: socfpga: Add SoCFPGA FPGA program support Steffen Trumtrar
2014-09-08 9:29 ` [PATCH v4 5/5] DT: Add binding for Altera SOCFPGA FPGA Manager Steffen Trumtrar
2014-09-09 8:30 ` [PATCH v4 0/5] firmware programming interface Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox