mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [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