2016-12-07 22:15:17

by Joshua Clayton

[permalink] [raw]
Subject: [PATCH v5 0/3] Altera Cyclone Passive Serial SPI FPGA Manager

This series adds an FPGA manager for Altera cyclone FPGAs
that can program them using an spi port and a couple of gpios, using
Alteras passive serial protocol.

Still need an ACK from Russell King on the ARM specific portion of
patch 1. Any comment/criticism on the addition of bitrev8x4() to bitrev.h
would be welcome as well.

Changes from v4:
- Added the needed return statement to __arch_bitrev8x4()
- Added Rob Herrings ACK for and fix a typo in the commit log of patch 2

Changes from v3:
- Fixed up the state() function to return the state of the status pin
reqested by Alan Tull
- Switched the pin to ACTIVE_LOW and coresponding logic level, and updated
the corresponding documentation. Thanks Rob Herring for pointing out my
mistake.
- Per Rob Herring, switched from "gpio" to "gpios" in dts

Changes from v2:
- Merged patch 3 and 4 as suggested in review by Moritz Fischer
- Changed FPGA_MIN_DELAY from 250 to 50 ms is the time advertized by
Altera. This now works, as we don't assume it is done

Changes from v1:
- Changed the name from cyclone-spi-fpga-mgr to cyclone-ps-spi-fpga-mgr
This name change was requested by Alan Tull, to be specific about which
programming method is being employed on the fpga.
- Changed the name of the reset-gpio to config-gpio to closer match the
way the pins are described in the Altera manual
- Moved MODULE_LICENCE, _AUTHOR, and _DESCRIPTION to the bottom

- Added a bitrev8x4() function to the bitrev headers and implemented ARM
const, runtime, and ARM specific faster versions (This may end up
needing to be a standalone patch)

- Moved the bitswapping into cyclonespi_write(), as requested.
This falls short of my desired generic lsb first spi support, but is a step
in that direction.

- Fixed whitespace problems introduced during refactoring

- Replaced magic number for initial delay with a descriptive macro
- Poll the fpga to see when it is ready rather than a fixed 1 ms sleep

Joshua Clayton (3):
lib: add bitrev8x4()
doc: dt: add cyclone-ps-spi binding document
fpga manager: Add cyclone-ps-spi driver for Altera FPGAs

.../bindings/fpga/cyclone-ps-spi-fpga-mgr.txt | 25 +++
arch/arm/include/asm/bitrev.h | 6 +
drivers/fpga/Kconfig | 7 +
drivers/fpga/Makefile | 1 +
drivers/fpga/cyclone-ps-spi.c | 181 +++++++++++++++++++++
include/linux/bitrev.h | 26 +++
6 files changed, 246 insertions(+)
create mode 100644 Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
create mode 100644 drivers/fpga/cyclone-ps-spi.c

--
2.9.3


2016-12-07 21:19:23

by Joshua Clayton

[permalink] [raw]
Subject: [PATCH v5 1/3] lib: add bitrev8x4()

Add a function to reverse bytes within a 32 bit word.
This function is more efficient than using the 8 bit version when
iterating over an array

Signed-off-by: Joshua Clayton <[email protected]>
---
arch/arm/include/asm/bitrev.h | 6 ++++++
include/linux/bitrev.h | 26 ++++++++++++++++++++++++++
2 files changed, 32 insertions(+)

diff --git a/arch/arm/include/asm/bitrev.h b/arch/arm/include/asm/bitrev.h
index ec291c3..9482f78 100644
--- a/arch/arm/include/asm/bitrev.h
+++ b/arch/arm/include/asm/bitrev.h
@@ -17,4 +17,10 @@ static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x)
return __arch_bitrev32((u32)x) >> 24;
}

+static __always_inline __attribute_const__ u32 __arch_bitrev8x4(u32 x)
+{
+ __asm__ ("rbit %0, %1; rev %0, %0" : "=r" (x) : "r" (x));
+ return x;
+}
+
#endif
diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h
index fb790b8..b1cfa1a 100644
--- a/include/linux/bitrev.h
+++ b/include/linux/bitrev.h
@@ -9,6 +9,7 @@
#define __bitrev32 __arch_bitrev32
#define __bitrev16 __arch_bitrev16
#define __bitrev8 __arch_bitrev8
+#define __bitrev8x4 __arch_bitrev8x4

#else
extern u8 const byte_rev_table[256];
@@ -27,6 +28,14 @@ static inline u32 __bitrev32(u32 x)
return (__bitrev16(x & 0xffff) << 16) | __bitrev16(x >> 16);
}

+static inline u32 __bitrev8x4(u32 x)
+{
+ return(__bitrev8(x & 0xff) |
+ (__bitrev8((x >> 8) & 0xff) << 8) |
+ (__bitrev8((x >> 16) & 0xff) << 16) |
+ (__bitrev8((x >> 24) & 0xff) << 24));
+}
+
#endif /* CONFIG_HAVE_ARCH_BITREVERSE */

#define __constant_bitrev32(x) \
@@ -50,6 +59,15 @@ static inline u32 __bitrev32(u32 x)
__x; \
})

+#define __constant_bitrev8x4(x) \
+({ \
+ u32 __x = x; \
+ __x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4); \
+ __x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2); \
+ __x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1); \
+ __x; \
+})
+
#define __constant_bitrev8(x) \
({ \
u8 __x = x; \
@@ -75,6 +93,14 @@ static inline u32 __bitrev32(u32 x)
__bitrev16(__x); \
})

+#define bitrev8x4(x) \
+({ \
+ u32 __x = x; \
+ __builtin_constant_p(__x) ? \
+ __constant_bitrev8x4(__x) : \
+ __bitrev8x4(__x); \
+})
+
#define bitrev8(x) \
({ \
u8 __x = x; \
--
2.9.3

2016-12-07 21:20:31

by Joshua Clayton

[permalink] [raw]
Subject: [PATCH v5 3/3] fpga manager: Add cyclone-ps-spi driver for Altera FPGAs

cyclone-ps-spi loads FPGA firmware over spi, using the "passive serial"
interface on Altera Cyclone FPGAS.

This is one of the simpler ways to set up an FPGA at runtime.
The signal interface is close to unidirectional spi with lsb first.

Signed-off-by: Joshua Clayton <[email protected]>
---
drivers/fpga/Kconfig | 7 ++
drivers/fpga/Makefile | 1 +
drivers/fpga/cyclone-ps-spi.c | 181 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 189 insertions(+)
create mode 100644 drivers/fpga/cyclone-ps-spi.c

diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index cd84934..2462707 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -13,6 +13,13 @@ config FPGA

if FPGA

+config FPGA_MGR_CYCLONE_PS_SPI
+ tristate "Altera Cyclone FPGA Passive Serial over SPI"
+ depends on SPI
+ help
+ FPGA manager driver support for Altera Cyclone using the
+ passive serial interface over SPI
+
config FPGA_MGR_SOCFPGA
tristate "Altera SOCFPGA FPGA Manager"
depends on ARCH_SOCFPGA
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 8d83fc6..8f93930 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -6,5 +6,6 @@
obj-$(CONFIG_FPGA) += fpga-mgr.o

# FPGA Manager Drivers
+obj-$(CONFIG_FPGA_MGR_CYCLONE_PS_SPI) += cyclone-ps-spi.o
obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
diff --git a/drivers/fpga/cyclone-ps-spi.c b/drivers/fpga/cyclone-ps-spi.c
new file mode 100644
index 0000000..82a754a
--- /dev/null
+++ b/drivers/fpga/cyclone-ps-spi.c
@@ -0,0 +1,181 @@
+/**
+ * Copyright (c) 2015 United Western Technologies, Corporation
+ *
+ * Joshua Clayton <[email protected]>
+ *
+ * Manage Altera fpga firmware that is loaded over spi.
+ * Firmware must be in binary "rbf" format.
+ * Works on Cyclone V. Should work on cyclone series.
+ * May work on other Altera fpgas.
+ *
+ */
+
+#include <linux/bitrev.h>
+#include <linux/delay.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/sizes.h>
+
+#define FPGA_RESET_TIME 50 /* time in usecs to trigger FPGA config */
+#define FPGA_MIN_DELAY 50 /* min usecs to wait for config status */
+#define FPGA_MAX_DELAY 1000 /* max usecs to wait for config status */
+
+struct cyclonespi_conf {
+ struct gpio_desc *config;
+ struct gpio_desc *status;
+ struct spi_device *spi;
+};
+
+static const struct of_device_id of_ef_match[] = {
+ { .compatible = "altr,cyclone-ps-spi-fpga-mgr", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_ef_match);
+
+static enum fpga_mgr_states cyclonespi_state(struct fpga_manager *mgr)
+{
+ struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
+
+ if (gpiod_get_value(conf->status))
+ return FPGA_MGR_STATE_RESET;
+
+ return FPGA_MGR_STATE_UNKNOWN;
+}
+
+static int cyclonespi_write_init(struct fpga_manager *mgr, u32 flags,
+ const char *buf, size_t count)
+{
+ struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
+ int i;
+
+ if (flags & FPGA_MGR_PARTIAL_RECONFIG) {
+ dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
+ return -EINVAL;
+ }
+
+ gpiod_set_value(conf->config, 1);
+ usleep_range(FPGA_RESET_TIME, FPGA_RESET_TIME + 20);
+ if (!gpiod_get_value(conf->status)) {
+ dev_err(&mgr->dev, "Status pin should be low.\n");
+ return -EIO;
+ }
+
+ gpiod_set_value(conf->config, 0);
+ for (i = 0; i < (FPGA_MAX_DELAY / FPGA_MIN_DELAY); i++) {
+ usleep_range(FPGA_MIN_DELAY, FPGA_MIN_DELAY + 20);
+ if (!gpiod_get_value(conf->status))
+ return 0;
+ }
+
+ dev_err(&mgr->dev, "Status pin not ready.\n");
+ return -EIO;
+}
+
+static void rev_buf(void *buf, size_t len)
+{
+ u32 *fw32 = (u32 *)buf;
+ const u32 *fw_end = (u32 *)(buf + len);
+
+ /* set buffer to lsb first */
+ while (fw32 < fw_end) {
+ *fw32 = bitrev8x4(*fw32);
+ fw32++;
+ }
+}
+
+static int cyclonespi_write(struct fpga_manager *mgr, const char *buf,
+ size_t count)
+{
+ struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
+ const char *fw_data = buf;
+ const char *fw_data_end = fw_data + count;
+
+ while (fw_data < fw_data_end) {
+ int ret;
+ size_t stride = min(fw_data_end - fw_data, SZ_4K);
+
+ rev_buf((void *)fw_data, stride);
+ ret = spi_write(conf->spi, fw_data, stride);
+ if (ret) {
+ dev_err(&mgr->dev, "spi error in firmware write: %d\n",
+ ret);
+ return ret;
+ }
+ fw_data += stride;
+ }
+
+ return 0;
+}
+
+static int cyclonespi_write_complete(struct fpga_manager *mgr, u32 flags)
+{
+ struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv;
+
+ if (gpiod_get_value(conf->status)) {
+ dev_err(&mgr->dev, "Error during configuration.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct fpga_manager_ops cyclonespi_ops = {
+ .state = cyclonespi_state,
+ .write_init = cyclonespi_write_init,
+ .write = cyclonespi_write,
+ .write_complete = cyclonespi_write_complete,
+};
+
+static int cyclonespi_probe(struct spi_device *spi)
+{
+ struct cyclonespi_conf *conf = devm_kzalloc(&spi->dev, sizeof(*conf),
+ GFP_KERNEL);
+
+ if (!conf)
+ return -ENOMEM;
+
+ conf->spi = spi;
+ conf->config = devm_gpiod_get(&spi->dev, "config", GPIOD_OUT_HIGH);
+ if (IS_ERR(conf->config)) {
+ dev_err(&spi->dev, "Failed to get config gpio: %ld\n",
+ PTR_ERR(conf->config));
+ return PTR_ERR(conf->config);
+ }
+
+ conf->status = devm_gpiod_get(&spi->dev, "status", GPIOD_IN);
+ if (IS_ERR(conf->status)) {
+ dev_err(&spi->dev, "Failed to get status gpio: %ld\n",
+ PTR_ERR(conf->status));
+ return PTR_ERR(conf->status);
+ }
+
+ return fpga_mgr_register(&spi->dev,
+ "Altera Cyclone PS SPI FPGA Manager",
+ &cyclonespi_ops, conf);
+}
+
+static int cyclonespi_remove(struct spi_device *spi)
+{
+ fpga_mgr_unregister(&spi->dev);
+
+ return 0;
+}
+
+static struct spi_driver cyclonespi_driver = {
+ .driver = {
+ .name = "cyclone-ps-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(of_ef_match),
+ },
+ .probe = cyclonespi_probe,
+ .remove = cyclonespi_remove,
+};
+
+module_spi_driver(cyclonespi_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Joshua Clayton <[email protected]>");
+MODULE_DESCRIPTION("Module to load Altera FPGA firmware over spi");
--
2.9.3

2016-12-07 21:20:37

by Joshua Clayton

[permalink] [raw]
Subject: [PATCH v5 2/3] doc: dt: add cyclone-ps-spi binding document

Describe a cyclone-ps-spi devicetree entry, required features

Signed-off-by: Joshua Clayton <[email protected]>
Acked-by: Rob Herring <[email protected]>
---
.../bindings/fpga/cyclone-ps-spi-fpga-mgr.txt | 25 ++++++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100644 Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt

diff --git a/Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
new file mode 100644
index 0000000..3f515c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/cyclone-ps-spi-fpga-mgr.txt
@@ -0,0 +1,25 @@
+Altera Cyclone Passive Serial SPI FPGA Manager
+
+Altera Cyclone FPGAs support a method of loading the bitstream over what is
+referred to as "passive serial".
+The passive serial link is not technically spi, and might require extra
+circuits in order to play nicely with other spi slaves on the same bus.
+
+See https://www.altera.com/literature/hb/cyc/cyc_c51013.pdf
+
+Required properties:
+- compatible : should contain "altr,cyclone-ps-spi-fpga-mgr"
+- reg : spi slave id of the fpga
+- config-gpios : config pin (referred to as nCONFIG in the cyclone manual)
+- status-gpios : status pin (referred to as nSTATUS in the cyclone manual)
+
+both gpios pins are normally active low open drain.
+
+Example:
+ fpga_spi: evi-fpga-spi@0 {
+ compatible = "altr,cyclone-ps-spi-fpga-mgr";
+ spi-max-frequency = <20000000>;
+ reg = <0>;
+ config-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>;
+ status-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>;
+ };
--
2.9.3

2016-12-07 21:22:53

by Anatolij Gustschin

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] fpga manager: Add cyclone-ps-spi driver for Altera FPGAs

On Wed, 7 Dec 2016 13:04:40 -0800
Joshua Clayton [email protected] wrote:
...
>+static int cyclonespi_write_init(struct fpga_manager *mgr, u32 flags,
>+ const char *buf, size_t count)

there is a minor API change in linux-next [1]. struct fpga_image_info *
is passed instead of u32 flags. I assume this will be merged soon, so
please prepare this driver accordingly.

...
>+static int cyclonespi_write_complete(struct fpga_manager *mgr, u32 flags)

same here.

[1] http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/drivers/fpga?id=1df2865f8dd9d56cb76aa7aa1298921e7bece2af

--
Anatolij

2016-12-07 21:29:35

by Joshua Clayton

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] fpga manager: Add cyclone-ps-spi driver for Altera FPGAs

Anatolij,
Thanks for the quick look and response.
I guess I should have rebased before submitting.
I just realized I also forgot to send this patch series to
the newly minted FPGA Manager mailing list. V6 coming soon :)

On 12/07/2016 01:21 PM, Anatolij Gustschin wrote:
> On Wed, 7 Dec 2016 13:04:40 -0800
> Joshua Clayton [email protected] wrote:
> ...
>> +static int cyclonespi_write_init(struct fpga_manager *mgr, u32 flags,
>> + const char *buf, size_t count)
> there is a minor API change in linux-next [1]. struct fpga_image_info *
> is passed instead of u32 flags. I assume this will be merged soon, so
> please prepare this driver accordingly.
>
> ...
Ah. Thanks.

>> +static int cyclonespi_write_complete(struct fpga_manager *mgr, u32 flags)
> same here.
OK.
>
> [1] http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/drivers/fpga?id=1df2865f8dd9d56cb76aa7aa1298921e7bece2af
>
> --
> Anatolij
Joshua

2016-12-07 21:34:06

by Anatolij Gustschin

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] fpga manager: Add cyclone-ps-spi driver for Altera FPGAs

On Wed, 7 Dec 2016 13:29:29 -0800
Joshua Clayton [email protected] wrote:

>Anatolij,
>Thanks for the quick look and response.
>I guess I should have rebased before submitting.

yes, Makefile and Kconfig changes need rebasing, I think.

>I just realized I also forgot to send this patch series to
>the newly minted FPGA Manager mailing list. V6 coming soon :)

okay, thanks.

--
Anatolij

2016-12-11 06:06:44

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] fpga manager: Add cyclone-ps-spi driver for Altera FPGAs

Hi Joshua,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.9-rc8]
[cannot apply to next-20161209]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Joshua-Clayton/lib-add-bitrev8x4/20161208-070638
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64

All errors (new ones prefixed by >>):

In file included from drivers/fpga/cyclone-ps-spi.c:13:0:
drivers/fpga/cyclone-ps-spi.c: In function 'rev_buf':
>> include/linux/bitrev.h:12:21: error: implicit declaration of function '__arch_bitrev8x4' [-Werror=implicit-function-declaration]
#define __bitrev8x4 __arch_bitrev8x4
^
include/linux/bitrev.h:101:2: note: in expansion of macro '__bitrev8x4'
__bitrev8x4(__x); \
^~~~~~~~~~~
drivers/fpga/cyclone-ps-spi.c:84:11: note: in expansion of macro 'bitrev8x4'
*fw32 = bitrev8x4(*fw32);
^~~~~~~~~
In file included from include/linux/delay.h:10:0,
from drivers/fpga/cyclone-ps-spi.c:14:
drivers/fpga/cyclone-ps-spi.c: In function 'cyclonespi_write':
include/linux/kernel.h:739:16: warning: comparison of distinct pointer types lacks a cast
(void) (&min1 == &min2); \
^
include/linux/kernel.h:742:2: note: in expansion of macro '__min'
__min(typeof(x), typeof(y), \
^~~~~
drivers/fpga/cyclone-ps-spi.c:98:19: note: in expansion of macro 'min'
size_t stride = min(fw_data_end - fw_data, SZ_4K);
^~~
cc1: some warnings being treated as errors

vim +/__arch_bitrev8x4 +12 include/linux/bitrev.h

556d2f05 Yalin Wang 2014-11-03 6 #ifdef CONFIG_HAVE_ARCH_BITREVERSE
556d2f05 Yalin Wang 2014-11-03 7 #include <asm/bitrev.h>
556d2f05 Yalin Wang 2014-11-03 8
556d2f05 Yalin Wang 2014-11-03 9 #define __bitrev32 __arch_bitrev32
556d2f05 Yalin Wang 2014-11-03 10 #define __bitrev16 __arch_bitrev16
556d2f05 Yalin Wang 2014-11-03 11 #define __bitrev8 __arch_bitrev8
533d0eab Joshua Clayton 2016-12-07 @12 #define __bitrev8x4 __arch_bitrev8x4
a5cfc1ec Akinobu Mita 2006-12-08 13
556d2f05 Yalin Wang 2014-11-03 14 #else
556d2f05 Yalin Wang 2014-11-03 15 extern u8 const byte_rev_table[256];

:::::: The code at line 12 was first introduced by commit
:::::: 533d0eabff8f37edfdec7fdf6e705fdecb297daa lib: add bitrev8x4()

:::::: TO: Joshua Clayton <[email protected]>
:::::: CC: 0day robot <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (2.96 kB)
.config.gz (51.23 kB)
Download all attachments