From: Alan Tull <[email protected]>
For v14 I'm dropping the concept of "simple-fpga-bus" for "fpga-area"
with reworked bindings.
An FPGA Area describes a section of an FPGA including the FPGA image needed to
program it and the hardware contained once it is programmed. The intent is
to support Device Tree controlled programming of FPGA's.
Alan Tull (7):
fpga: add usage documentation for fpga area
fpga: add bindings document for fpga area
add sysfs document for fpga bridge class
ARM: socfpga: add bindings document for fpga bridge drivers
fpga: add fpga bridge framework
fpga: fpga-area: support device tree control for FPGA programming
ARM: socfpga: fpga bridge driver support
Documentation/ABI/testing/sysfs-class-fpga-bridge | 11 +
.../bindings/fpga/altera-fpga2sdram-bridge.txt | 15 +
.../bindings/fpga/altera-hps2fpga-bridge.txt | 43 +++
.../devicetree/bindings/fpga/fpga-area.txt | 70 ++++
Documentation/fpga/fpga-area.txt | 299 +++++++++++++++
drivers/fpga/Kconfig | 21 ++
drivers/fpga/Makefile | 7 +
drivers/fpga/altera-fpga2sdram.c | 174 +++++++++
drivers/fpga/altera-hps2fpga.c | 213 +++++++++++
drivers/fpga/fpga-area.c | 313 ++++++++++++++++
drivers/fpga/fpga-bridge.c | 388 ++++++++++++++++++++
include/linux/fpga/fpga-bridge.h | 56 +++
12 files changed, 1610 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-class-fpga-bridge
create mode 100644 Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt
create mode 100644 Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt
create mode 100644 Documentation/devicetree/bindings/fpga/fpga-area.txt
create mode 100644 Documentation/fpga/fpga-area.txt
create mode 100644 drivers/fpga/altera-fpga2sdram.c
create mode 100644 drivers/fpga/altera-hps2fpga.c
create mode 100644 drivers/fpga/fpga-area.c
create mode 100644 drivers/fpga/fpga-bridge.c
create mode 100644 include/linux/fpga/fpga-bridge.h
--
1.7.9.5
From: Alan Tull <[email protected]>
Add a document spelling out usage of the FPGA Area for
reprogramming FPGA's under Device Tree control.
Signed-off-by: Alan Tull <[email protected]>
---
v9: Initial version of this patch in patchset
v10: s/fpga/FPGA/g
improve formatting
some rewriting
move to staging/simple-fpga-bus
v11: No change in this patch for v11 of the patch set
v12: Moved out of staging
Small changes due to using FPGA bridge framework and not
representing the bridges as resets.
v13: Fix some nits
v14: fpga-area instead of simple-fpga-bus
---
Documentation/fpga/fpga-area.txt | 299 ++++++++++++++++++++++++++++++++++++++
1 file changed, 299 insertions(+)
create mode 100644 Documentation/fpga/fpga-area.txt
diff --git a/Documentation/fpga/fpga-area.txt b/Documentation/fpga/fpga-area.txt
new file mode 100644
index 0000000..f031522
--- /dev/null
+++ b/Documentation/fpga/fpga-area.txt
@@ -0,0 +1,299 @@
+FPGA Area
+
+Alan Tull 2015
+
+Overview
+========
+
+An FPGA Area details information about a section of an FPGA including the FPGA
+image needed to program it and the hardware contained once it is programmed.
+
+Loading a Device Tree overlay which contains an FPGA Area will cause the
+FPGA to be programmed and the children of the FPGA Area will get probed.
+
+There may be FPGA Bridges involved to prevent spurious data from going out onto
+the processor bus during FPGA programming. If so, the FPGA Area will need to
+disable and enable bridges that will only affect the child devices that are
+below the FPGA Area. In the case of partial reconfiguration, bridges will
+be required within the FPGA design such that the active sections of the
+FPGA are on the bus while sections that are not programmed or being
+reprogrammed at the moment are isolated.
+
+Removing the overlay will result in the child devices getting removed and the
+bridges disabled. Note that in the case of partial reconfiguration the rest of
+the FPGA continues to function as normal while this is happening.
+
+Below are more details on the structuring of the Device Tree for this.
+
+Terminology
+===========
+
+Full Reconfiguration
+ * The entire FPGA is reprogrammed.
+
+Partial Reconfiguration (PR)
+ * Part of the FPGA is reprogrammed while the rest of the FPGA is live and
+ active. Not all FPGA's support this.
+
+Associated Blocks
+=================
+
+FPGA Manager Framework
+ * An FPGA Manager is a hardware block that programs an FPGA under the control
+ of a host processor.
+ * The FPGA Manager Framework provides drivers and functions to program an
+ FPGA.
+
+FPGA Bridge Framework
+ * Provides drivers and functions to control bridges that enable/disable
+ data to the FPGA.
+ * FPGA bridges should be disabled while the FPGA is being programmed to
+ prevent spurious data on the bus.
+ * FPGA bridges are not needed in implementations where the FPGA Manager
+ handles this.
+
+Device Tree
+===========
+
+For the purposes of this document, I'm dividing the Device Tree (DT) into two parts,
+each with its own requirements. The two parts are:
+ * The live DT prior to the overlay being added
+ * The overlay containing an FPGA Area
+
+The live DT will contain:
+ * FPGA Manager
+ * FPGA Bridges as children of the FPGA Manager (optional, architecture specific)
+
+The live Device Tree must contain an FPGA Manager to handle programming the FPGA.
+If FPGA Bridges need to be involved, they show up in the DT as direct children
+of the FPGA Manager. During full reconfiguration, the FPGA Area will disable
+any bridges that are direct children of the manager during full reconfiguration
+and will re-enable them afterwards.
+
+The insertion point in the live tree will also need the "simple-bus"
+compatibility string to enable populating the child nodes for the overlay.
+That includes the nodes for the FPGA Manager and controlling FPGA Bridges
+as explained below.
+
+The Device Tree Overlay will contain:
+ * "target-path"
+ The insertion point where the the contents of the overlay will go into the
+ live tree.
+ * "ranges"
+ * "firmware-name"
+ Specifies the name of the FPGA image file on the firmware search
+ path. The search path is described in the firmware class documentation.
+ * "partial-reconfig"
+ This binding is a boolean and should be present if partial reconfiguration
+ is to be done.
+ * child nodes corresponding to hardware that will be loaded in this
+ region of the FPGA.
+
+Supported use models
+====================
+
+Here's a list of the superset of supported use models. We may need to add
+more. Some uses are specific to one FPGA or another.
+
+ * No FPGA Bridges
+ In this case, the FPGA Manager which programs the FPGA also handles the
+ bridges and no FPGA Bridge devices are needed for full reconfiguration.
+
+ The DT overlay will specify the FPGA Manager as the overlay target.
+
+ * Full reconfiguration with bridges
+ In the case, there are several bridges between the processor and FPGA,
+ that need to be disabled during full reconfiguration.
+ The DT before the overlay is applied will have an FPGA Manager. The
+ immediate children of the manager will be the FPGA Bridges that need to be
+ disabled during FPGA programming.
+
+ The DT overlay will specify one of those bridges as the overlay target,
+ typically the bridge that allows memory mapped register access ("the
+ controlling bridge").
+
+ * Partial reconfiguration with bridges in the FPGA
+ In this case, the FPGA can have more than one section that will be
+ reprogrammed separately. Other sections may be active on the bus while FPGA
+ is being programmed. To manage this, FPGA Bridges need to exist on the FPGA
+ that can freeze all the buses going to one FPGA area while the buses are
+ enabled for other sections.
+
+Controlling Bridge
+==================
+
+It is possible that there are multiple FPGA Bridges connecting the processor
+and FPGA. In a text based hierarchy, it is difficult to show this properly
+so what we do is consider the bridge that handles register access to be
+the controlling bridge. The overlay is targeted to be inserted under the
+controlling bridge. Other bridges are on the same level of the device tree
+as the controlling bridge, i.e. all are children of the FPGA Manager. The
+ranges property handles mapping memory ranges through multiple bridges.
+
+Sequence
+========
+
+Load the DT overlay. One way to do that from user space is to use Pantelis
+Antoniou's DT-Overlay configfs interface. In that case the sequence from
+userspace is:
+
+ $ mkdir /config/device-tree/overlays/1
+ $ echo "some_overlay.dtb.o" > /config/device-tree/overlays/1/path
+
+This causes the FPGA Area to be probed and will do the following:
+ 1. Disable the FPGA bridges.
+ 2. Use the the FPGA manager core to program the FPGA.
+ 3. Enable the FPGA bridges.
+ 4. Call of_platform_populate resulting in device drivers getting probed.
+
+Removing the overlay is done by:
+
+ $ rmdir /config/device-tree/overlays/1
+
+This causes the child nodes to be removed and then the bridges are disabled.
+
+Device Tree Examples
+====================
+
+The intention of this section is to give some simple examples, focusing on
+the placement of the elements detailed above in, especially:
+ * FPGA Managers
+ * FPGA Bridges in some cases
+ * FPGA Areas and associated properties
+ * simple-bus
+ * ranges
+ * target-path
+
+Please note the "simple-bus" compatible string added for FPGA Managers and for
+FPGA Bridges where the overlay is targeted for insertion. This is required for
+populating the child nodes.
+
+Device Tree Example: Partial Reconfiguration with no Bridges
+============================================================
+
+Live Device Tree contains:
+ fpgamgr@0 {
+ compatible = "altr,socfpga-a10-fpga-mgr", "simple-bus";
+ clocks = <&l4_mp_clk>;
+ resets = <&rst FPGAMGR_RESET>;
+ reset-names = "fpgamgr";
+ reg = <0xffd03000 0x1000
+ 0xffcfe400 0x1000>;
+
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ ranges;
+ };
+
+DT Overlay contains:
+/dts-v1/;
+/plugin/;
+/ {
+ fragment@0 {
+ target-path="/soc/fpgamgr@0"; /* targeted to the manager */
+ __overlay__ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ area@0 {
+ compatible = "fpga-area";
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x10010 0xff210010 0x10>;
+
+ firmware-name = "fit_pr_v1.rbf";
+ partial-reconfig;
+
+ gpio@0x100010010 {
+ compatible = "altr,pio-1.0";
+ reg = <0x10010 0x10>;
+ altr,ngpio = <4>;
+ #gpio-cells = <0x2>;
+ gpio-controller;
+ };
+ };
+ };
+ };
+};
+
+
+Device Tree Example: Full Reconfiguration with Bridges
+======================================================
+
+Live Device Tree contains:
+ fpgamgr@0 {
+ compatible = "altr,socfpga-fpga-mgr", "simple-bus";
+ reg = <0xFF706000 0x1000
+ 0xFFB90000 0x1000>;
+ interrupts = <0 175 4>;
+
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ ranges;
+
+ bridge@0 {
+ /* both the manager and the controlling bridge have
+ * the added simple-bus compatible to allow child
+ * devices to be populated. */
+ compatible = "altr,socfpga-lwhps2fpga-bridge",
+ "simple-bus";
+ resets = <&rst LWHPS2FPGA_RESET>;
+ reset-names = "lwhps2fpga";
+ clocks = <&l4_main_clk>;
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ ranges;
+ };
+
+ bridge@1 {
+ /* In the case of full reconfiguration, both bridge@0
+ * and bridge@1 will be disabled during FPGA
+ * programming and enabled afterwards. */
+ compatible = "altr,socfpga-hps2fpga-bridge";
+ resets = <&rst HPS2FPGA_RESET>;
+ reset-names = "hps2fpga";
+ clocks = <&l4_main_clk>;
+ };
+ };
+
+DT Overlay contains:
+/dts-v1/;
+/plugin/;
+/ {
+ fragment@0 {
+ target-path="/soc/fpgamgr@0/bridge@0"; /* controlling bridge */
+ __overlay__ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ area@0 {
+ compatible = "fpga-area";
+
+ #address-cells = <2>;
+ #size-cells = <1>;
+ /* Note that two ranges are mapped due to the
+ * two bridges. */
+ ranges = <0 0x00000000 0xc0000000 0x00010000>,
+ <1 0x00020000 0xff220000 0x00000008>;
+
+ firmware-name = "soc_system.rbf";
+
+ onchip_memory2_0: memory@000000000 {
+ device_type = "memory";
+ compatible = "altr,onchipmem-15.1";
+ reg = <0 0x00000000 0x00010000>;
+ };
+
+ jtag_uart: serial@0x100020000 {
+ compatible = "altr,juart-1.0";
+ reg = <1 0x00020000 0x00000008>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 42 4>;
+ clocks = <&osc2>;
+ };
+ };
+ };
+ };
+};
+
--
1.7.9.5
From: Alan Tull <[email protected]>
New bindings document for FPGA Area for reprogramming
FPGA's under Device Tree control
Signed-off-by: Alan Tull <[email protected]>
---
v9: initial version added to this patchset
v10: s/fpga/FPGA/g
replace DT overlay example with slightly more complicated example
move to staging/simple-fpga-bus
v11: No change in this patch for v11 of the patch set
v12: Moved out of staging.
Changed to use FPGA bridges framework instead of resets
for bridges.
v13: bridge@0xff20000 -> bridge@ff200000, etc
Leave out directly talking about overlays
Remove regs and clocks directly under simple-fpga-bus in example
Use common "firmware-name" binding instead of "fpga-firmware"
v14: Use firmware-name in bindings description
Call it FPGA Area
Remove bindings that specify FPGA Manager and FPGA Bridges
---
.../devicetree/bindings/fpga/fpga-area.txt | 70 ++++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 Documentation/devicetree/bindings/fpga/fpga-area.txt
diff --git a/Documentation/devicetree/bindings/fpga/fpga-area.txt b/Documentation/devicetree/bindings/fpga/fpga-area.txt
new file mode 100644
index 0000000..d656e35
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/fpga-area.txt
@@ -0,0 +1,70 @@
+FPGA Area
+=========
+
+A FPGA Area details information about a section of an FPGA including the FPGA
+image needed to program it and the hardware contained in this section of the
+FPGA once it is programmed.
+
+A FPGA Area corresponds to the whole FPGA in the case of full reconfiguration
+or a section of a FPGA in the case of partial reconfiguration.
+
+Required properties:
+- compatible : should contain "fpga-area"
+- #address-cells, #size-cells, ranges: must be present to handle address space
+ mapping for children.
+
+Optional properties:
+- firmware-name : should contain the name of a FPGA image file located on the
+ firmware search path.
+- partial-reconfig : boolean property should be defined if partial
+ reconfiguration of the FPGA is to be done, otherwise full reconfiguration
+ is done.
+
+Example:
+
+/dts-v1/;
+/plugin/;
+/ {
+ fragment@0 {
+ target-path="/soc/fpgamgr@0/bridge@0";
+ __overlay__ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ bridge@ff200000 {
+ compatible = "fpga-area";
+
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ ranges = <0 0x00000000 0xc0000000 0x00010000>,
+ <1 0x00020000 0xff220000 0x00000008>,
+ <1 0x00010040 0xff210040 0x00000020>;
+
+ firmware-name = "soc_system.rbf";
+
+ onchip_memory2_0: memory@000000000 {
+ device_type = "memory";
+ compatible = "altr,onchipmem-15.1";
+ reg = <0 0x00000000 0x00010000>;
+ };
+
+ jtag_uart: serial@100020000 {
+ compatible = "altr,juart-1.0";
+ reg = <1 0x00020000 0x00000008>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 42 4>;
+ };
+
+ led_pio: gpio@100010040 {
+ compatible = "altr,pio-1.0";
+ reg = <1 0x00010040 0x00000020>;
+ altr,gpio-bank-width = <4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+ };
+ };
+};
+
--
1.7.9.5
From: Alan Tull <[email protected]>
Add documentation for new FPGA bridge class's sysfs interface.
Signed-off-by: Alan Tull <[email protected]>
---
Documentation/ABI/testing/sysfs-class-fpga-bridge | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-class-fpga-bridge
diff --git a/Documentation/ABI/testing/sysfs-class-fpga-bridge b/Documentation/ABI/testing/sysfs-class-fpga-bridge
new file mode 100644
index 0000000..e45d952
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-fpga-bridge
@@ -0,0 +1,11 @@
+What: /sys/class/fpga_bridge/<bridge>/name
+Date: December 2015
+KernelVersion: 4.4
+Contact: Alan Tull <[email protected]>
+Description: Name of low level FPGA bridge driver.
+
+What: /sys/class/fpga_bridge/<bridge>/state
+Date: December 2015
+KernelVersion: 4.4
+Contact: Alan Tull <[email protected]>
+Description: Show bridge state as "enabled" or "disabled"
--
1.7.9.5
From: Alan Tull <[email protected]>
Add bindings documentation for Altera SOCFPGA bridges:
* fpga2sdram
* fpga2hps
* hps2fpga
* lwhps2fpga
Signed-off-by: Alan Tull <[email protected]>
Signed-off-by: Matthew Gerlach <[email protected]>
Signed-off-by: Dinh Nguyen <[email protected]>
---
v2: separate into 2 documents for the 2 drivers
v12: bump version to line up with simple-fpga-bus version
remove Linux specific notes such as references to sysfs
move non-DT specific documentation elsewhere
remove bindings that would have been used to pass configuration
clean up formatting
v13: Remove 'label' property
Change property from init-val to bridge-enable
Fix email address
v14: Add resets
Change order of bridges to put lw bridge (controlling bridge) first
---
.../bindings/fpga/altera-fpga2sdram-bridge.txt | 15 +++++++
.../bindings/fpga/altera-hps2fpga-bridge.txt | 43 ++++++++++++++++++++
2 files changed, 58 insertions(+)
create mode 100644 Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt
create mode 100644 Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt
diff --git a/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt
new file mode 100644
index 0000000..81e2f06
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt
@@ -0,0 +1,15 @@
+Altera FPGA To SDRAM Bridge Driver
+
+Required properties:
+- compatible : Should contain "altr,socfpga-fpga2sdram-bridge"
+
+Optional properties:
+- bridge-enable : 0 if driver should disable bridge at startup
+ 1 if driver should enable bridge at startup
+ Default is to leave bridge in current state.
+
+Example:
+ fpga2sdram_br: fpgabridge@3 {
+ compatible = "altr,socfpga-fpga2sdram-bridge";
+ bridge-enable = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt
new file mode 100644
index 0000000..16db3b0
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt
@@ -0,0 +1,43 @@
+Altera FPGA/HPS Bridge Driver
+
+Required properties:
+- compatible : Should contain one of:
+ "altr,socfpga-lwhps2fpga-bridge",
+ "altr,socfpga-hps2fpga-bridge", or
+ "altr,socfpga-fpga2hps-bridge"
+- reset-names : Should contain one of:
+ "lwhps2fpga",
+ "hps2fpga", or
+ "fpga2hps"
+- resets : Phandle and reset specifier for the reset listed in
+ reset-names
+- clocks : Clocks used by this module.
+
+Optional properties:
+- bridge-enable : 0 if driver should disable bridge at startup.
+ 1 if driver should enable bridge at startup.
+ Default is to leave bridge in its current state.
+
+Example:
+ hps_fpgabridge0: fpgabridge@0 {
+ compatible = "altr,socfpga-lwhps2fpga-bridge";
+ resets = <&rst LWHPS2FPGA_RESET>;
+ reset-names = "lwhps2fpga";
+ clocks = <&l4_main_clk>;
+ bridge-enable = <0>;
+ };
+
+ hps_fpgabridge1: fpgabridge@1 {
+ compatible = "altr,socfpga-hps2fpga-bridge";
+ resets = <&rst HPS2FPGA_RESET>;
+ reset-names = "hps2fpga";
+ clocks = <&l4_main_clk>;
+ bridge-enable = <1>;
+ };
+
+ hps_fpgabridge2: fpgabridge@2 {
+ compatible = "altr,socfpga-fpga2hps-bridge";
+ resets = <&rst FPGA2HPS_RESET>;
+ reset-names = "fpga2hps";
+ clocks = <&l4_main_clk>;
+ };
--
1.7.9.5
From: Alan Tull <[email protected]>
This framework adds API functions for enabling/
disabling FPGA bridges under kernel control.
This allows the Linux kernel to disable FPGA bridges
during FPGA reprogramming and to enable FPGA bridges
when FPGA reprogramming is done. This framework is
be manufacturer-agnostic, allowing it to be used in
interfaces that use the FPGA Manager Framework to
reprogram FPGA's.
The functions are:
* of_fpga_bridge_get
* fpga_bridge_put
Get/put an exclusive reference to a FPGA bridge.
* fpga_bridge_enable
* fpga_bridge_disable
Enable/Disable traffic through a bridge.
* fpga_bridge_register
* fpga_bridge_unregister
Register/unregister a device-specific low level FPGA
Bridge driver.
Get an exclusive reference to a bridge and add it to a list:
* fpga_bridge_get_to_list
To enable/disable/put a set of bridges that are on a list:
* fpga_bridges_enable
* fpga_bridges_disable
* fpga_bridges_put
Signed-off-by: Alan Tull <[email protected]>
---
v2: Minor cleanup
v12: Bump version to line up with simple fpga bus
Remove sysfs
Improve get/put functions, get the low level driver too.
Clean up class implementation
Add kernel doc documentation
Rename (un)register_fpga_bridge -> fpga_bridge_(un)register
v13: Add inlined empty functions for if not CONFIG_FPGA_BRIDGE
Clean up debugging
Remove unneeded #include in .h
Remove unnecessary prints
Remove 'label' DT binding.
Document the mutex
v14: Allow bridges with no ops
*const* struct fpga_bridge_ops
Add functions to git/put/enable/disable list of bridges
Add list node to struct fpga_bridge
Do of_node_get/put in of_fpga_bridge_get()
Add r/o attributes: name and state
---
drivers/fpga/Kconfig | 7 +
drivers/fpga/Makefile | 3 +
drivers/fpga/fpga-bridge.c | 388 ++++++++++++++++++++++++++++++++++++++
include/linux/fpga/fpga-bridge.h | 56 ++++++
4 files changed, 454 insertions(+)
create mode 100644 drivers/fpga/fpga-bridge.c
create mode 100644 include/linux/fpga/fpga-bridge.h
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index c9b9fdf..b6cfd89 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -24,6 +24,13 @@ config FPGA_MGR_ZYNQ_FPGA
help
FPGA manager driver support for Xilinx Zynq FPGAs.
+config FPGA_BRIDGE
+ bool "FPGA Bridge Framework"
+ depends on OF
+ help
+ Say Y here if you want to support bridges connected between host
+ processors and FPGAs or between FPGAs.
+
endif # FPGA
endmenu
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 8d83fc6..4baef00 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -8,3 +8,6 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o
# FPGA Manager Drivers
obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
+
+# FPGA Bridge Drivers
+obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c
new file mode 100644
index 0000000..5119d8e
--- /dev/null
+++ b/drivers/fpga/fpga-bridge.c
@@ -0,0 +1,388 @@
+/*
+ * FPGA Bridge Framework Driver
+ *
+ * Copyright (C) 2013-2015 Altera Corporation, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/fpga/fpga-bridge.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+static DEFINE_IDA(fpga_bridge_ida);
+static struct class *fpga_bridge_class;
+
+/* Lock for adding/removing bridges to linked lists*/
+spinlock_t bridge_list_lock;
+
+static int fpga_bridge_of_node_match(struct device *dev, const void *data)
+{
+ return dev->of_node == data;
+}
+
+/**
+ * fpga_bridge_enable - Enable transactions on the bridge
+ *
+ * @bridge: FPGA bridge
+ *
+ * Return: 0 for success, error code otherwise.
+ */
+int fpga_bridge_enable(struct fpga_bridge *bridge)
+{
+ dev_dbg(&bridge->dev, "enable\n");
+
+ if (bridge->br_ops && bridge->br_ops->enable_set)
+ return bridge->br_ops->enable_set(bridge, 1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fpga_bridge_enable);
+
+/**
+ * fpga_bridge_disable - Disable transactions on the bridge
+ *
+ * @bridge: FPGA bridge
+ *
+ * Return: 0 for success, error code otherwise.
+ */
+int fpga_bridge_disable(struct fpga_bridge *bridge)
+{
+ dev_dbg(&bridge->dev, "disable\n");
+
+ if (bridge->br_ops && bridge->br_ops->enable_set)
+ return bridge->br_ops->enable_set(bridge, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fpga_bridge_disable);
+
+/**
+ * of_fpga_bridge_get - get an exclusive reference to a fpga bridge
+ *
+ * @np: node pointer of a FPGA bridge
+ *
+ * Return fpga_bridge struct if successful.
+ * Return -EBUSY if someone already has a reference to the bridge.
+ * Return -ENODEV if @np is not a FPGA Bridge.
+ */
+struct fpga_bridge *of_fpga_bridge_get(struct device_node *np)
+{
+ struct device *dev;
+ struct fpga_bridge *bridge;
+ int ret = -ENODEV;
+
+ of_node_get(np);
+
+ dev = class_find_device(fpga_bridge_class, NULL, np,
+ fpga_bridge_of_node_match);
+ if (!dev)
+ goto err_dev;
+
+ bridge = to_fpga_bridge(dev);
+ if (!bridge)
+ goto err_dev;
+
+ if (!mutex_trylock(&bridge->mutex)) {
+ ret = -EBUSY;
+ goto err_dev;
+ }
+
+ if (!try_module_get(dev->parent->driver->owner))
+ goto err_ll_mod;
+
+ dev_dbg(&bridge->dev, "get\n");
+
+ return bridge;
+
+err_ll_mod:
+ mutex_unlock(&bridge->mutex);
+err_dev:
+ put_device(dev);
+ of_node_put(np);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(of_fpga_bridge_get);
+
+/**
+ * fpga_bridge_put - release a reference to a bridge
+ *
+ * @bridge: FPGA bridge
+ */
+void fpga_bridge_put(struct fpga_bridge *bridge)
+{
+ dev_dbg(&bridge->dev, "put\n");
+
+ module_put(bridge->dev.parent->driver->owner);
+ mutex_unlock(&bridge->mutex);
+ put_device(&bridge->dev);
+}
+EXPORT_SYMBOL_GPL(fpga_bridge_put);
+
+/**
+ * fpga_bridges_enable - enable bridges in a list
+ * @bridge_list: list of FPGA bridges
+ *
+ * Enable each bridge in the list. If list is empty, do nothing.
+ *
+ * Return 0 for success or empty bridge list; return error code otherwise.
+ */
+int fpga_bridges_enable(struct list_head *bridge_list)
+{
+ struct fpga_bridge *bridge;
+ struct list_head *node;
+ int ret;
+
+ list_for_each(node, bridge_list) {
+ bridge = list_entry(node, struct fpga_bridge, node);
+ ret = fpga_bridge_enable(bridge);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fpga_bridges_enable);
+
+/**
+ * fpga_bridges_disable - disable bridges in a list
+ *
+ * @bridge_list: list of FPGA bridges
+ *
+ * Disable each bridge in the list. If list is empty, do nothing.
+ *
+ * Return 0 for success or empty bridge list; return error code otherwise.
+ */
+int fpga_bridges_disable(struct list_head *bridge_list)
+{
+ struct fpga_bridge *bridge;
+ struct list_head *node;
+ int ret;
+
+ list_for_each(node, bridge_list) {
+ bridge = list_entry(node, struct fpga_bridge, node);
+ ret = fpga_bridge_disable(bridge);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fpga_bridges_disable);
+
+/**
+ * fpga_bridges_put - put bridges
+ *
+ * @bridge_list: list of FPGA bridges
+ *
+ * For each bridge in the list, put the bridge and remove it from the list.
+ * If list is empty, do nothing.
+ */
+void fpga_bridges_put(struct list_head *bridge_list)
+{
+ struct fpga_bridge *bridge;
+ struct list_head *node, *next;
+ unsigned long flags;
+
+ list_for_each_safe(node, next, bridge_list) {
+ bridge = list_entry(node, struct fpga_bridge, node);
+
+ fpga_bridge_put(bridge);
+
+ spin_lock_irqsave(&bridge_list_lock, flags);
+ list_del(&bridge->node);
+ spin_unlock_irqrestore(&bridge_list_lock, flags);
+ }
+}
+EXPORT_SYMBOL_GPL(fpga_bridges_put);
+
+/**
+ * fpga_bridges_get_to_list - get a bridge, add it to a list
+ *
+ * @np: node pointer of a FPGA bridge
+ * @bridge_list: list of FPGA bridges
+ *
+ * Get an exclusive reference to the bridge and and it to the list.
+ *
+ * Return 0 for success, error code from of_fpga_bridge_get() othewise.
+ */
+int fpga_bridge_get_to_list(struct device_node *np,
+ struct list_head *bridge_list)
+{
+ struct fpga_bridge *bridge;
+ unsigned long flags;
+
+ bridge = of_fpga_bridge_get(np);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
+
+ spin_lock_irqsave(&bridge_list_lock, flags);
+ list_add(&bridge->node, bridge_list);
+ spin_unlock_irqrestore(&bridge_list_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fpga_bridge_get_to_list);
+
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fpga_bridge *bridge = to_fpga_bridge(dev);
+
+ return sprintf(buf, "%s\n", bridge->name);
+}
+
+static ssize_t state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fpga_bridge *bridge = to_fpga_bridge(dev);
+ int enable = 1;
+
+ if (bridge->br_ops && bridge->br_ops->enable_show)
+ enable = bridge->br_ops->enable_show(bridge);
+
+ return sprintf(buf, "%s\n", enable ? "enabled" : "disabled");
+}
+
+static DEVICE_ATTR_RO(name);
+static DEVICE_ATTR_RO(state);
+
+static struct attribute *fpga_bridge_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_state.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(fpga_bridge);
+
+/**
+ * fpga_bridge_register - register a fpga bridge driver
+ * @dev: FPGA bridge device from pdev
+ * @name: FPGA bridge name
+ * @br_ops: pointer to structure of fpga bridge ops
+ * @priv: FPGA bridge private data
+ *
+ * Return: 0 for success, error code otherwise.
+ */
+int fpga_bridge_register(struct device *dev, const char *name,
+ const struct fpga_bridge_ops *br_ops, void *priv)
+{
+ struct fpga_bridge *bridge;
+ int id, ret = 0;
+
+ if (!name || !strlen(name)) {
+ dev_err(dev, "Attempt to register with no name!\n");
+ return -EINVAL;
+ }
+
+ bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+ if (!bridge)
+ return -ENOMEM;
+
+ id = ida_simple_get(&fpga_bridge_ida, 0, 0, GFP_KERNEL);
+ if (id < 0) {
+ ret = id;
+ goto error_kfree;
+ }
+
+ mutex_init(&bridge->mutex);
+ INIT_LIST_HEAD(&bridge->node);
+
+ bridge->name = name;
+ bridge->br_ops = br_ops;
+ bridge->priv = priv;
+
+ device_initialize(&bridge->dev);
+ bridge->dev.class = fpga_bridge_class;
+ bridge->dev.parent = dev;
+ bridge->dev.of_node = dev->of_node;
+ bridge->dev.id = id;
+ dev_set_drvdata(dev, bridge);
+
+ ret = dev_set_name(&bridge->dev, "br%d", id);
+ if (ret)
+ goto error_device;
+
+ ret = device_add(&bridge->dev);
+ if (ret)
+ goto error_device;
+
+ dev_info(bridge->dev.parent, "fpga bridge [%s] registered\n",
+ bridge->name);
+
+ return 0;
+
+error_device:
+ ida_simple_remove(&fpga_bridge_ida, id);
+error_kfree:
+ kfree(bridge);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fpga_bridge_register);
+
+/**
+ * fpga_bridge_unregister - unregister a fpga bridge driver
+ * @dev: FPGA bridge device from pdev
+ */
+void fpga_bridge_unregister(struct device *dev)
+{
+ struct fpga_bridge *bridge = dev_get_drvdata(dev);
+
+ /*
+ * If the low level driver provides a method for putting bridge into
+ * a desired state upon unregister, do it.
+ */
+ if (bridge->br_ops && bridge->br_ops->fpga_bridge_remove)
+ bridge->br_ops->fpga_bridge_remove(bridge);
+
+ device_unregister(&bridge->dev);
+}
+EXPORT_SYMBOL_GPL(fpga_bridge_unregister);
+
+static void fpga_bridge_dev_release(struct device *dev)
+{
+ struct fpga_bridge *bridge = to_fpga_bridge(dev);
+
+ ida_simple_remove(&fpga_bridge_ida, bridge->dev.id);
+ kfree(bridge);
+}
+
+static int __init fpga_bridge_dev_init(void)
+{
+ spin_lock_init(&bridge_list_lock);
+
+ fpga_bridge_class = class_create(THIS_MODULE, "fpga_bridge");
+ if (IS_ERR(fpga_bridge_class))
+ return PTR_ERR(fpga_bridge_class);
+
+ fpga_bridge_class->dev_groups = fpga_bridge_groups;
+ fpga_bridge_class->dev_release = fpga_bridge_dev_release;
+
+ return 0;
+}
+
+static void __exit fpga_bridge_dev_exit(void)
+{
+ class_destroy(fpga_bridge_class);
+ ida_destroy(&fpga_bridge_ida);
+}
+
+MODULE_DESCRIPTION("FPGA Bridge Driver");
+MODULE_AUTHOR("Alan Tull <[email protected]>");
+MODULE_LICENSE("GPL v2");
+
+subsys_initcall(fpga_bridge_dev_init);
+module_exit(fpga_bridge_dev_exit);
diff --git a/include/linux/fpga/fpga-bridge.h b/include/linux/fpga/fpga-bridge.h
new file mode 100644
index 0000000..ad8471c
--- /dev/null
+++ b/include/linux/fpga/fpga-bridge.h
@@ -0,0 +1,56 @@
+#include <linux/device.h>
+
+#ifndef _LINUX_FPGA_BRIDGE_H
+#define _LINUX_FPGA_BRIDGE_H
+
+struct fpga_bridge;
+
+/**
+ * struct fpga_bridge_ops - ops for low level FPGA bridge drivers
+ * @enable_show: returns the FPGA bridge's status
+ * @enable_set: set a FPGA bridge as enabled or disabled
+ * @fpga_bridge_remove: set FPGA into a specific state during driver remove
+ */
+struct fpga_bridge_ops {
+ int (*enable_show)(struct fpga_bridge *bridge);
+ int (*enable_set)(struct fpga_bridge *bridge, bool enable);
+ void (*fpga_bridge_remove)(struct fpga_bridge *bridge);
+};
+
+/**
+ * struct fpga_bridge - FPGA bridge structure
+ * @name: name of low level FPGA bridge
+ * @dev: FPGA bridge device
+ * @mutex: enforces exclusive reference to bridge
+ * @br_ops: pointer to struct of FPGA bridge ops
+ * @node: FPGA bridge list node
+ * @priv: low level driver private date
+ */
+struct fpga_bridge {
+ const char *name;
+ struct device dev;
+ struct mutex mutex; /* for exclusive reference to bridge */
+ const struct fpga_bridge_ops *br_ops;
+ struct list_head node;
+ void *priv;
+};
+
+#define to_fpga_bridge(d) container_of(d, struct fpga_bridge, dev)
+
+struct fpga_bridge *of_get_fpga_bus(struct device_node *np);
+struct fpga_bridge *of_fpga_bridge_get(struct device_node *node);
+void fpga_bridge_put(struct fpga_bridge *bridge);
+int fpga_bridge_enable(struct fpga_bridge *bridge);
+int fpga_bridge_disable(struct fpga_bridge *bridge);
+
+int fpga_bridges_enable(struct list_head *bridge_list);
+int fpga_bridges_disable(struct list_head *bridge_list);
+void fpga_bridges_put(struct list_head *bridge_list);
+int fpga_bridge_get_to_list(struct device_node *np,
+ struct list_head *bridge_list);
+
+int fpga_bridge_register(struct device *dev, const char *name,
+ const struct fpga_bridge_ops *br_ops, void *priv);
+void fpga_bridge_unregister(struct device *dev);
+
+#endif /* _LINUX_FPGA_BRIDGE_H */
--
1.7.9.5
From: Alan Tull <[email protected]>
FPGA Areas support programming FPGA under control of the
Device Tree.
When a Device Tree Overlay containing a FPGA Area is
applied, the FPGA Area will be probed and will:
* check to see if there is an image to program to a FPGA
* get references to the FPGA manager and bridges if any
* disable FPGA bridges to prevent spurious data on busses
* reprogram the FPGA
* enable the specified FPGA bridges
* populate the child devices
The use case where FPGA Bridges are not needed is supported.
Removing the Device Tree Overlay is also supported.
This supports fpga use where hardware blocks on a fpga will
need drivers.
Signed-off-by: Alan Tull <[email protected]>
---
v9: initial version (this patch added during rest of patchset's v9)
v10: request deferral if fpga mgr or bridges not available yet
cleanup as fpga manager core goes into the real kernel
Don't assume bridges are disabled before programming FPGA
Don't hang onto reference for fpga manager
Move to staging/simple-fpga-bus
v11: No change in this patch for v11 of the patch set
v12: Moved out of staging.
Use fpga bridges framework.
v13: If no bridges are specified, assume we don't need any.
Clean up debug messages
Some dev_info -> dev_dbg
Remove unneeded #include
Fix size of array of pointers
Don't need to specify .owner
Use common binding: firmware-name
v14: OK it's not a simple bus. Call it "FPGA Area"
Remove bindings that specify FPGA manager and FPGA bridges
Use parent FPGA bridge and bridges that are its peers
Use ancestor FPGA Manager
---
drivers/fpga/Kconfig | 7 ++
drivers/fpga/Makefile | 3 +
drivers/fpga/fpga-area.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 323 insertions(+)
create mode 100644 drivers/fpga/fpga-area.c
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index b6cfd89..6ac916b 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -31,6 +31,13 @@ config FPGA_BRIDGE
Say Y here if you want to support bridges connected between host
processors and FPGAs or between FPGAs.
+config FPGA_AREA
+ bool "Device Tree Based FPGA Reprogramming"
+ depends on FPGA_BRIDGE
+ help
+ Enable FPGA Area which supports programming FPGAs under control of
+ Device Tree.
+
endif # FPGA
endmenu
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 4baef00..4f7e49f 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -11,3 +11,6 @@ obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
# FPGA Bridge Drivers
obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o
+
+# High Level Interfaces
+obj-$(CONFIG_FPGA_AREA) += fpga-area.o
diff --git a/drivers/fpga/fpga-area.c b/drivers/fpga/fpga-area.c
new file mode 100644
index 0000000..d01dc14
--- /dev/null
+++ b/drivers/fpga/fpga-area.c
@@ -0,0 +1,313 @@
+/*
+ * FPGA Tree Area Support for Device Tree controlled FPGA reprogramming
+ *
+ * Copyright (C) 2013-2015 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/fpga/fpga-bridge.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+
+/*
+ * In the case of a FPGA doing full reconfiguration, the area == the whole
+ * FPGA. In the case of partial reconfiguration, several areas can be
+ * reconfigured separately.
+ */
+
+/**
+ * struct fpga_area
+ * @mgr: FPGA Manager that is the ancestor of the area
+ * @flags: Flags for reconfiguration
+ * @firmware_name: Name of FPGA image file
+ * @bridge_list: Linked list of FPGA bridges controlled by area
+ * @br: FPGA Bridge corresponding to area
+ */
+struct fpga_area {
+ struct fpga_manager *mgr;
+ u32 flags;
+ const char *firmware_name;
+ struct list_head bridge_list;
+ struct fpga_bridge *br;
+};
+
+/**
+ * fpga_area_get_parent_peer_bridges - get bridges that are peers of parent
+ * @area: FPGA Area struct
+ *
+ * Intended to support case where multiple bridges need to be disabled
+ * during FPGA reprogramming.
+ *
+ * Finds the FPGA bridge that is the parent of @area in the device tree.
+ * Creates a linked list of FPGA bridges that includes the parent bridge and
+ * its peers. Gets an exclusive reference to each of these bridges as they
+ * are added to the list. The list of bridges is saved in @area's
+ * fpga_bridge struct.
+ *
+ * These bridges must be disabled while the FPGA is being reprogrammed to
+ * support the children of the @area bridge and enabled after FPGA
+ * programming is finished.
+ *
+ * For the use case where no FPGA bridges are required, the parent node should
+ * be a FPGA Manager. In this case, the bridge list will end up empty.
+ *
+ * Returns error code or 0 for success. Returns 0 if the parent is a FPGA
+ * manager.
+ */
+static int fpga_area_get_parent_peer_bridges(struct fpga_area *area)
+{
+ struct device_node *parent, *child;
+ struct fpga_bridge *bridge;
+ int ret;
+
+ /* Create a list of bridges that are peers of area's parent */
+ parent = of_get_parent(area->br->dev.of_node);
+ parent = of_get_next_parent(parent);
+
+ for_each_child_of_node(parent, child) {
+ /* If node is a bridge, get it and add to list */
+ ret = fpga_bridge_get_to_list(child, &area->bridge_list);
+
+ /* if any of the bridges are in use, give up */
+ if (ret == -EBUSY) {
+ fpga_bridges_put(&area->bridge_list);
+ of_node_put(parent);
+ return PTR_ERR(bridge);
+ }
+ }
+ of_node_put(parent);
+
+ return 0;
+}
+
+/**
+ * fpga_area_get_bridges - create list of exclusive references to fpga bridges
+ * @area: FPGA Area struct
+ *
+ * Get exclusive references to a FPGA bridge or bridges.
+ * In the case of full reconfiguration build a list of bridges that are the
+ * parent of @area and its peers. We are reprogramming the full FPGA and
+ * need to have no communication on the processor/FPGA bridges while that
+ * is happening
+ * In the case of partial reconfiguration, only add the parent of @area to
+ * the list. This one bridge is a freeze block which is in the FPGA itself
+ * and is downstream from its parent bridge and the parent's peers.
+ *
+ * Return 0 for success. Return -ENODEV is there are no bridges.
+ * Pass other error codes ultimately from of_fpga_bridge_get() such as:
+ * Return -EBUSY if any of the bridges were already gotten.
+ */
+static int fpga_area_get_bridges(struct fpga_area *area)
+{
+ struct device_node *parent;
+ int ret = 0;
+
+ /* If parent is FPGA Manager, no bridges to get */
+ parent = of_get_parent(area->br->dev.of_node);
+ if (parent == area->mgr->dev.of_node) {
+ of_node_put(parent);
+ return -ENODEV;
+ }
+
+ if (area->flags & FPGA_MGR_PARTIAL_RECONFIG)
+ ret = fpga_bridge_get_to_list(parent, &area->bridge_list);
+ else
+ ret = fpga_area_get_parent_peer_bridges(area);
+
+ of_node_put(parent);
+
+ return ret;
+}
+
+/**
+ * fpga_area_load - program the FPGA based on info in area
+ * @area: FPGA Area struct
+ *
+ * Program the FPGA that the area has a reference to.
+ *
+ * Returns 0 for success or error codes passed down from
+ * fpga_mgr_firmware_load()
+ */
+static int fpga_area_load(struct fpga_area *area)
+{
+ return fpga_mgr_firmware_load(area->mgr,
+ area->flags,
+ area->firmware_name);
+}
+
+/**
+ * fpga_area_get_manager - get exclusive reference for FPGA manager
+ * @area: FPGA Area struct
+ *
+ * One of the ancestor nodes of the FPGA Area should be an FPGA Manager.
+ * This function goes up the tree to find it, gets exclusive reference,
+ * and saves it in the area struct.
+ *
+ * Return: 0 for success or IS_ERR() condition containing error code.
+ */
+static int fpga_area_get_manager(struct fpga_area *area)
+{
+ struct device_node *np = area->br->dev.of_node;
+ struct fpga_manager *mgr;
+ int ret = -EINVAL;
+
+ of_node_get(np);
+
+ while (np) {
+ mgr = of_fpga_mgr_get(np);
+ if (!IS_ERR(mgr)) {
+ area->mgr = mgr;
+ ret = 0;
+ break;
+ }
+ np = of_get_next_parent(np);
+ }
+
+ of_node_put(np);
+
+ return ret;
+}
+
+/**
+ * fpga_area_put_manager - put exclusive reference to FPGA manager
+ * @area: FPGA Area struct
+ */
+static void fpga_area_put_manager(struct fpga_area *area)
+{
+ fpga_mgr_put(area->mgr);
+ area->mgr = NULL;
+}
+
+/**
+ * fpga_area_probe - probe function for FPGA area
+ * @pdev: platform device
+ *
+ * If there is an image to program to a FPGA, get the FPGA manager and bridges,
+ * reprogram the FPGA, and populate the child devices.
+ *
+ * If there are FPGA Bridges, this function will hold the references to the
+ * bridges; they are released in fpga_area_remove().
+ *
+ * Return: 0 for success, -EBUSY if someone already got the bridges or manager.
+ */
+static int fpga_area_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct fpga_area *area;
+ int ret;
+
+ area = devm_kzalloc(dev, sizeof(*area), GFP_KERNEL);
+ if (!area)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&area->bridge_list);
+
+ ret = fpga_bridge_register(dev, "FPGA Area", NULL, area);
+ if (ret)
+ return ret;
+ area->br = dev_get_drvdata(dev);
+
+ if (of_property_read_string(np, "firmware-name",
+ &area->firmware_name)) {
+ of_platform_populate(np, of_default_bus_match_table, NULL, dev);
+ return 0;
+ }
+
+ if (of_property_read_bool(np, "partial-reconfig"))
+ area->flags |= FPGA_MGR_PARTIAL_RECONFIG;
+
+ ret = fpga_area_get_manager(area);
+ if (ret) {
+ dev_dbg(dev, "Should be child of a FPGA Manager");
+ goto err_unreg;
+ }
+
+ /* Give up if there is an error other than no bridges. */
+ ret = fpga_area_get_bridges(area);
+ if (ret && ret != -ENODEV)
+ goto err_release;
+
+ ret = fpga_bridges_disable(&area->bridge_list);
+ if (ret)
+ goto err_release;
+
+ ret = fpga_area_load(area);
+ if (ret)
+ goto err_release;
+
+ ret = fpga_bridges_enable(&area->bridge_list);
+ if (ret)
+ goto err_release;
+
+ /* If successful, put the mgr, but keep the bridges */
+ fpga_area_put_manager(area);
+
+ of_platform_populate(np, of_default_bus_match_table, NULL, dev);
+
+ return 0;
+
+err_release:
+ fpga_bridges_put(&area->bridge_list);
+ fpga_area_put_manager(area);
+err_unreg:
+ fpga_bridge_unregister(dev);
+
+ return ret;
+}
+
+/**
+ * fpga_area_remove - remove a FPGA area
+ *
+ * Called when an FPGA Area is removed. If there are any FPGA Bridges in the
+ * area's bridge list, disable them and put them.
+ *
+ * Return: 0
+ */
+static int fpga_area_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct fpga_bridge *bridge = dev_get_drvdata(dev);
+ struct fpga_area *area = bridge->priv;
+
+ fpga_bridges_disable(&area->bridge_list);
+ fpga_bridges_put(&area->bridge_list);
+
+ fpga_bridge_unregister(dev);
+
+ return 0;
+}
+
+static const struct of_device_id fpga_area_of_match[] = {
+ { .compatible = "fpga-area", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, fpga_area_of_match);
+
+static struct platform_driver fpga_area_driver = {
+ .probe = fpga_area_probe,
+ .remove = fpga_area_remove,
+ .driver = {
+ .name = "FPGA Area",
+ .of_match_table = of_match_ptr(fpga_area_of_match),
+ },
+};
+
+module_platform_driver(fpga_area_driver);
+
+MODULE_DESCRIPTION("Altera FPGA Bus");
+MODULE_AUTHOR("Alan Tull <[email protected]>");
+MODULE_LICENSE("GPL v2");
--
1.7.9.5
From: Alan Tull <[email protected]>
Supports Altera SOCFPGA bridges:
* fpga2sdram
* fpga2hps
* hps2fpga
* lwhps2fpga
Allows enabling/disabling the bridges through the FPGA
Bridge Framework API functions.
The fpga2sdram driver only supports enabling and disabling
of the ports that been configured early on. This is due to
a hardware limitation where the read, write, and command
ports on the fpga2sdram bridge can only be reconfigured
while there are no transactions to the sdram, i.e. when
running out of OCRAM before the kernel boots.
Device tree property 'init-val' configures the driver to
enable or disable the bridge during probe. If the property
does not exist, the driver will leave the bridge in its
current state.
Signed-off-by: Alan Tull <[email protected]>
Signed-off-by: Matthew Gerlach <[email protected]>
Signed-off-by: Dinh Nguyen <[email protected]>
---
v2: Use resets instead of directly writing reset registers
v12: Bump version to align with simple-fpga-bus version
Get rid of the sysfs interface
fpga2sdram: get configuration stored in handoff register
v13: Remove unneeded WARN_ON
Change property from init-val to bridge-enable
Checkpatch cleanup
Fix email address
v14: use module_platform_driver
remove unused struct field and some #defines
don't really need exclamation points on error msgs
*const* struct fpga_bridge_ops
---
drivers/fpga/Kconfig | 7 ++
drivers/fpga/Makefile | 1 +
drivers/fpga/altera-fpga2sdram.c | 174 +++++++++++++++++++++++++++++++
drivers/fpga/altera-hps2fpga.c | 213 ++++++++++++++++++++++++++++++++++++++
4 files changed, 395 insertions(+)
create mode 100644 drivers/fpga/altera-fpga2sdram.c
create mode 100644 drivers/fpga/altera-hps2fpga.c
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 6ac916b..30ebe42 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -38,6 +38,13 @@ config FPGA_AREA
Enable FPGA Area which supports programming FPGAs under control of
Device Tree.
+config SOCFPGA_FPGA_BRIDGE
+ bool "Altera SoCFPGA FPGA Bridges"
+ depends on ARCH_SOCFPGA && FPGA_BRIDGE
+ help
+ Say Y to enable drivers for FPGA bridges for Altera SOCFPGA
+ devices.
+
endif # FPGA
endmenu
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 4f7e49f..3efc132 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
# FPGA Bridge Drivers
obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o
+obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE) += altera-hps2fpga.o altera-fpga2sdram.o
# High Level Interfaces
obj-$(CONFIG_FPGA_AREA) += fpga-area.o
diff --git a/drivers/fpga/altera-fpga2sdram.c b/drivers/fpga/altera-fpga2sdram.c
new file mode 100644
index 0000000..91f4a40
--- /dev/null
+++ b/drivers/fpga/altera-fpga2sdram.c
@@ -0,0 +1,174 @@
+/*
+ * FPGA to SDRAM Bridge Driver for Altera SoCFPGA Devices
+ *
+ * Copyright (C) 2013-2015 Altera Corporation, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This driver manages a bridge between an FPGA and the SDRAM used by the ARM
+ * host processor system (HPS).
+ *
+ * The bridge contains 4 read ports, 4 write ports, and 6 command ports.
+ * Reconfiguring these ports requires that no SDRAM transactions occur during
+ * reconfiguration. The code reconfiguring the ports cannot run out of SDRAM
+ * nor can the FPGA access the SDRAM during reconfiguration. This driver does
+ * not support reconfiguring the ports. The ports are configured by code
+ * running out of on chip ram before Linux is started and the configuration
+ * is passed in a handoff register in the system manager.
+ *
+ * This driver supports enabling and disabling of the configured ports, which
+ * allows for safe reprogramming of the FPGA, assuming that the new FPGA image
+ * uses the same port configuration. Bridges must be disabled before
+ * reprogramming the FPGA and re-enabled after the FPGA has been programmed.
+ */
+
+#include <linux/fpga/fpga-bridge.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+
+#define ALT_SDR_CTL_FPGAPORTRST_OFST 0x80
+#define ALT_SDR_CTL_FPGAPORTRST_PORTRSTN_MSK 0x00003fff
+#define ALT_SDR_CTL_FPGAPORTRST_RD_SHIFT 0
+#define ALT_SDR_CTL_FPGAPORTRST_WR_SHIFT 4
+#define ALT_SDR_CTL_FPGAPORTRST_CTRL_SHIFT 8
+
+#define SYSMGR_ISWGRP_HANDOFF3 (0x8C)
+#define ISWGRP_HANDOFF_FPGA2SDR SYSMGR_ISWGRP_HANDOFF3
+
+#define F2S_BRIDGE_NAME "fpga2sdram"
+
+struct alt_fpga2sdram_data {
+ struct device *dev;
+ struct regmap *sdrctl;
+ int mask;
+};
+
+static int alt_fpga2sdram_enable_show(struct fpga_bridge *bridge)
+{
+ struct alt_fpga2sdram_data *priv = bridge->priv;
+ int value;
+
+ regmap_read(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST, &value);
+
+ return (value & priv->mask) == priv->mask;
+}
+
+static inline int _alt_fpga2sdram_enable_set(struct alt_fpga2sdram_data *priv,
+ bool enable)
+{
+ return regmap_update_bits(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST,
+ priv->mask, enable ? priv->mask : 0);
+}
+
+static int alt_fpga2sdram_enable_set(struct fpga_bridge *bridge, bool enable)
+{
+ return _alt_fpga2sdram_enable_set(bridge->priv, enable);
+}
+
+struct prop_map {
+ char *prop_name;
+ u32 *prop_value;
+ u32 prop_max;
+};
+
+static const struct fpga_bridge_ops altera_fpga2sdram_br_ops = {
+ .enable_set = alt_fpga2sdram_enable_set,
+ .enable_show = alt_fpga2sdram_enable_show,
+};
+
+static const struct of_device_id altera_fpga_of_match[] = {
+ { .compatible = "altr,socfpga-fpga2sdram-bridge" },
+ {},
+};
+
+static int alt_fpga_bridge_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct alt_fpga2sdram_data *priv;
+ u32 enable;
+ struct regmap *sysmgr;
+ int ret = 0;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+
+ priv->sdrctl = syscon_regmap_lookup_by_compatible("altr,sdr-ctl");
+ if (IS_ERR(priv->sdrctl)) {
+ dev_err(dev, "regmap for altr,sdr-ctl lookup failed.\n");
+ return PTR_ERR(priv->sdrctl);
+ }
+
+ sysmgr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
+ if (IS_ERR(priv->sdrctl)) {
+ dev_err(dev, "regmap for altr,sys-mgr lookup failed.\n");
+ return PTR_ERR(sysmgr);
+ }
+
+ /* Get f2s bridge configuration saved in handoff register */
+ regmap_read(sysmgr, SYSMGR_ISWGRP_HANDOFF3, &priv->mask);
+
+ ret = fpga_bridge_register(dev, F2S_BRIDGE_NAME,
+ &altera_fpga2sdram_br_ops, priv);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "driver initialized with handoff %08x\n", priv->mask);
+
+ if (!of_property_read_u32(dev->of_node, "bridge-enable", &enable)) {
+ if (enable > 1) {
+ dev_warn(dev, "invalid bridge-enable %u > 1\n", enable);
+ } else {
+ dev_info(dev, "%s bridge\n",
+ (enable ? "enabling" : "disabling"));
+ ret = _alt_fpga2sdram_enable_set(priv, enable);
+ if (ret) {
+ fpga_bridge_unregister(&pdev->dev);
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int alt_fpga_bridge_remove(struct platform_device *pdev)
+{
+ fpga_bridge_unregister(&pdev->dev);
+
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
+
+static struct platform_driver altera_fpga_driver = {
+ .probe = alt_fpga_bridge_probe,
+ .remove = alt_fpga_bridge_remove,
+ .driver = {
+ .name = "altera_fpga2sdram_bridge",
+ .of_match_table = of_match_ptr(altera_fpga_of_match),
+ },
+};
+
+module_platform_driver(altera_fpga_driver);
+
+MODULE_DESCRIPTION("Altera SoCFPGA FPGA to SDRAM Bridge");
+MODULE_AUTHOR("Alan Tull <[email protected]>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c
new file mode 100644
index 0000000..c15df47
--- /dev/null
+++ b/drivers/fpga/altera-hps2fpga.c
@@ -0,0 +1,213 @@
+/*
+ * FPGA to/from HPS Bridge Driver for Altera SoCFPGA Devices
+ *
+ * Copyright (C) 2013-2015 Altera Corporation, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This driver manages bridges on a Altera SOCFPGA between the ARM host
+ * processor system (HPS) and the embedded FPGA.
+ *
+ * This driver supports enabling and disabling of the configured ports, which
+ * allows for safe reprogramming of the FPGA, assuming that the new FPGA image
+ * uses the same port configuration. Bridges must be disabled before
+ * reprogramming the FPGA and re-enabled after the FPGA has been programmed.
+ */
+
+#include <linux/clk.h>
+#include <linux/fpga/fpga-bridge.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define ALT_L3_REMAP_OFST 0x0
+#define ALT_L3_REMAP_MPUZERO_MSK 0x00000001
+#define ALT_L3_REMAP_H2F_MSK 0x00000008
+#define ALT_L3_REMAP_LWH2F_MSK 0x00000010
+
+#define HPS2FPGA_BRIDGE_NAME "hps2fpga"
+#define LWHPS2FPGA_BRIDGE_NAME "lwhps2fpga"
+#define FPGA2HPS_BRIDGE_NAME "fpga2hps"
+
+struct altera_hps2fpga_data {
+ const char *name;
+ struct reset_control *bridge_reset;
+ struct regmap *l3reg;
+ /* The L3 REMAP register is write only, so keep a cached value. */
+ unsigned int l3_remap_value;
+ unsigned int remap_mask;
+ struct clk *clk;
+};
+
+static int alt_hps2fpga_enable_show(struct fpga_bridge *bridge)
+{
+ struct altera_hps2fpga_data *priv = bridge->priv;
+
+ return reset_control_status(priv->bridge_reset);
+}
+
+static int _alt_hps2fpga_enable_set(struct altera_hps2fpga_data *priv,
+ bool enable)
+{
+ int ret;
+
+ /* bring bridge out of reset */
+ if (enable)
+ ret = reset_control_deassert(priv->bridge_reset);
+ else
+ ret = reset_control_assert(priv->bridge_reset);
+ if (ret)
+ return ret;
+
+ /* Allow bridge to be visible to L3 masters or not */
+ if (priv->remap_mask) {
+ priv->l3_remap_value |= ALT_L3_REMAP_MPUZERO_MSK;
+
+ if (enable)
+ priv->l3_remap_value |= priv->remap_mask;
+ else
+ priv->l3_remap_value &= ~priv->remap_mask;
+
+ ret = regmap_write(priv->l3reg, ALT_L3_REMAP_OFST,
+ priv->l3_remap_value);
+ }
+
+ return ret;
+}
+
+static int alt_hps2fpga_enable_set(struct fpga_bridge *bridge, bool enable)
+{
+ return _alt_hps2fpga_enable_set(bridge->priv, enable);
+}
+
+static const struct fpga_bridge_ops altera_hps2fpga_br_ops = {
+ .enable_set = alt_hps2fpga_enable_set,
+ .enable_show = alt_hps2fpga_enable_show,
+};
+
+static struct altera_hps2fpga_data hps2fpga_data = {
+ .name = HPS2FPGA_BRIDGE_NAME,
+ .remap_mask = ALT_L3_REMAP_H2F_MSK,
+};
+
+static struct altera_hps2fpga_data lwhps2fpga_data = {
+ .name = LWHPS2FPGA_BRIDGE_NAME,
+ .remap_mask = ALT_L3_REMAP_LWH2F_MSK,
+};
+
+static struct altera_hps2fpga_data fpga2hps_data = {
+ .name = FPGA2HPS_BRIDGE_NAME,
+};
+
+static const struct of_device_id altera_fpga_of_match[] = {
+ { .compatible = "altr,socfpga-hps2fpga-bridge",
+ .data = &hps2fpga_data },
+ { .compatible = "altr,socfpga-lwhps2fpga-bridge",
+ .data = &lwhps2fpga_data },
+ { .compatible = "altr,socfpga-fpga2hps-bridge",
+ .data = &fpga2hps_data },
+ {},
+};
+
+static int alt_fpga_bridge_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct altera_hps2fpga_data *priv;
+ const struct of_device_id *of_id;
+ u32 enable;
+ int ret;
+
+ of_id = of_match_device(altera_fpga_of_match, dev);
+ priv = (struct altera_hps2fpga_data *)of_id->data;
+
+ priv->bridge_reset = devm_reset_control_get(dev, priv->name);
+ if (IS_ERR(priv->bridge_reset)) {
+ dev_err(dev, "Could not get %s reset control\n", priv->name);
+ return PTR_ERR(priv->bridge_reset);
+ }
+
+ priv->l3reg = syscon_regmap_lookup_by_compatible("altr,l3regs");
+ if (IS_ERR(priv->l3reg)) {
+ dev_err(dev, "regmap for altr,l3regs lookup failed\n");
+ return PTR_ERR(priv->l3reg);
+ }
+
+ priv->clk = of_clk_get(dev->of_node, 0);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "no clock specified\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "could not enable clock\n");
+ return -EBUSY;
+ }
+
+ ret = fpga_bridge_register(dev, priv->name, &altera_hps2fpga_br_ops,
+ priv);
+ if (ret)
+ return ret;
+
+ if (!of_property_read_u32(dev->of_node, "bridge-enable", &enable)) {
+ if (enable > 1) {
+ dev_warn(dev, "invalid bridge-enable %u > 1\n", enable);
+ } else {
+ dev_info(dev, "%s bridge\n",
+ (enable ? "enabling" : "disabling"));
+
+ ret = _alt_hps2fpga_enable_set(priv, enable);
+ if (ret) {
+ fpga_bridge_unregister(&pdev->dev);
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int alt_fpga_bridge_remove(struct platform_device *pdev)
+{
+ struct fpga_bridge *bridge = platform_get_drvdata(pdev);
+ struct altera_hps2fpga_data *priv = bridge->priv;
+
+ fpga_bridge_unregister(&pdev->dev);
+
+ clk_disable_unprepare(priv->clk);
+ clk_put(priv->clk);
+
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
+
+static struct platform_driver alt_fpga_bridge_driver = {
+ .probe = alt_fpga_bridge_probe,
+ .remove = alt_fpga_bridge_remove,
+ .driver = {
+ .name = "altera_hps2fpga_bridge",
+ .of_match_table = of_match_ptr(altera_fpga_of_match),
+ },
+};
+
+module_platform_driver(alt_fpga_bridge_driver);
+
+MODULE_DESCRIPTION("Altera SoCFPGA HPS to FPGA Bridge");
+MODULE_AUTHOR("Alan Tull <[email protected]>");
+MODULE_LICENSE("GPL v2");
--
1.7.9.5
On Thu, Dec 10, 2015 at 05:37:04PM -0600, [email protected] wrote:
> From: Alan Tull <[email protected]>
>
> New bindings document for FPGA Area for reprogramming
> FPGA's under Device Tree control
>
> Signed-off-by: Alan Tull <[email protected]>
> ---
> v9: initial version added to this patchset
> v10: s/fpga/FPGA/g
> replace DT overlay example with slightly more complicated example
> move to staging/simple-fpga-bus
> v11: No change in this patch for v11 of the patch set
> v12: Moved out of staging.
> Changed to use FPGA bridges framework instead of resets
> for bridges.
> v13: bridge@0xff20000 -> bridge@ff200000, etc
> Leave out directly talking about overlays
> Remove regs and clocks directly under simple-fpga-bus in example
> Use common "firmware-name" binding instead of "fpga-firmware"
> v14: Use firmware-name in bindings description
> Call it FPGA Area
> Remove bindings that specify FPGA Manager and FPGA Bridges
> ---
> .../devicetree/bindings/fpga/fpga-area.txt | 70 ++++++++++++++++++++
> 1 file changed, 70 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/fpga/fpga-area.txt
>
> diff --git a/Documentation/devicetree/bindings/fpga/fpga-area.txt b/Documentation/devicetree/bindings/fpga/fpga-area.txt
> new file mode 100644
> index 0000000..d656e35
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/fpga/fpga-area.txt
> @@ -0,0 +1,70 @@
> +FPGA Area
> +=========
> +
> +A FPGA Area details information about a section of an FPGA including the FPGA
> +image needed to program it and the hardware contained in this section of the
> +FPGA once it is programmed.
> +
> +A FPGA Area corresponds to the whole FPGA in the case of full reconfiguration
> +or a section of a FPGA in the case of partial reconfiguration.
> +
> +Required properties:
> +- compatible : should contain "fpga-area"
I'm not too sure about this. I think this needs to be FPGA specfic.
> +- #address-cells, #size-cells, ranges: must be present to handle address space
> + mapping for children.
> +
> +Optional properties:
> +- firmware-name : should contain the name of a FPGA image file located on the
> + firmware search path.
> +- partial-reconfig : boolean property should be defined if partial
> + reconfiguration of the FPGA is to be done, otherwise full reconfiguration
> + is done.
> +
> +Example:
> +
> +/dts-v1/;
> +/plugin/;
> +/ {
> + fragment@0 {
> + target-path="/soc/fpgamgr@0/bridge@0";
Does the bus really go thru the fpgamgr and then the bridge as this
implies? Or fpgamgr is a sideband controller? For example purposes, it
would be better to show this not as an overlay so I get the complete
picture.
Unit addresses of 0 look a bit questionable as I'd expect these to be
addresses.
> + __overlay__ {
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + bridge@ff200000 {
2 levels of bridge devices/buses?
There is nothing programmable for this bridge? clocks, resets, etc.?
> + compatible = "fpga-area";
> +
> + #address-cells = <2>;
> + #size-cells = <1>;
> +
> + ranges = <0 0x00000000 0xc0000000 0x00010000>,
> + <1 0x00020000 0xff220000 0x00000008>,
> + <1 0x00010040 0xff210040 0x00000020>;
> +
> + firmware-name = "soc_system.rbf";
> +
> + onchip_memory2_0: memory@000000000 {
> + device_type = "memory";
> + compatible = "altr,onchipmem-15.1";
> + reg = <0 0x00000000 0x00010000>;
> + };
> +
> + jtag_uart: serial@100020000 {
> + compatible = "altr,juart-1.0";
> + reg = <1 0x00020000 0x00000008>;
> + interrupt-parent = <&intc>;
> + interrupts = <0 42 4>;
> + };
> +
> + led_pio: gpio@100010040 {
> + compatible = "altr,pio-1.0";
> + reg = <1 0x00010040 0x00000020>;
> + altr,gpio-bank-width = <4>;
> + #gpio-cells = <2>;
> + gpio-controller;
> + };
> + };
> + };
> + };
> +};
> +
> --
> 1.7.9.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, Dec 10, 2015 at 05:37:03PM -0600, [email protected] wrote:
> From: Alan Tull <[email protected]>
>
> Add a document spelling out usage of the FPGA Area for
> reprogramming FPGA's under Device Tree control.
I'm not too sure about the split between this and the binding doc. This
one clears up a bit after reading the binding doc first and most of this
is about DT.
> Signed-off-by: Alan Tull <[email protected]>
>
> ---
> v9: Initial version of this patch in patchset
> v10: s/fpga/FPGA/g
> improve formatting
> some rewriting
> move to staging/simple-fpga-bus
> v11: No change in this patch for v11 of the patch set
> v12: Moved out of staging
> Small changes due to using FPGA bridge framework and not
> representing the bridges as resets.
> v13: Fix some nits
> v14: fpga-area instead of simple-fpga-bus
> ---
> Documentation/fpga/fpga-area.txt | 299 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 299 insertions(+)
> create mode 100644 Documentation/fpga/fpga-area.txt
>
> diff --git a/Documentation/fpga/fpga-area.txt b/Documentation/fpga/fpga-area.txt
> new file mode 100644
> index 0000000..f031522
> --- /dev/null
> +++ b/Documentation/fpga/fpga-area.txt
> @@ -0,0 +1,299 @@
> +FPGA Area
> +
> +Alan Tull 2015
> +
> +Overview
> +========
> +
> +An FPGA Area details information about a section of an FPGA including the FPGA
> +image needed to program it and the hardware contained once it is programmed.
> +
> +Loading a Device Tree overlay which contains an FPGA Area will cause the
> +FPGA to be programmed and the children of the FPGA Area will get probed.
> +
> +There may be FPGA Bridges involved to prevent spurious data from going out onto
> +the processor bus during FPGA programming. If so, the FPGA Area will need to
> +disable and enable bridges that will only affect the child devices that are
> +below the FPGA Area. In the case of partial reconfiguration, bridges will
> +be required within the FPGA design such that the active sections of the
> +FPGA are on the bus while sections that are not programmed or being
> +reprogrammed at the moment are isolated.
> +
> +Removing the overlay will result in the child devices getting removed and the
> +bridges disabled. Note that in the case of partial reconfiguration the rest of
> +the FPGA continues to function as normal while this is happening.
> +
> +Below are more details on the structuring of the Device Tree for this.
> +
> +Terminology
> +===========
> +
> +Full Reconfiguration
> + * The entire FPGA is reprogrammed.
> +
> +Partial Reconfiguration (PR)
> + * Part of the FPGA is reprogrammed while the rest of the FPGA is live and
> + active. Not all FPGA's support this.
> +
> +Associated Blocks
> +=================
> +
> +FPGA Manager Framework
> + * An FPGA Manager is a hardware block that programs an FPGA under the control
> + of a host processor.
> + * The FPGA Manager Framework provides drivers and functions to program an
> + FPGA.
> +
> +FPGA Bridge Framework
> + * Provides drivers and functions to control bridges that enable/disable
> + data to the FPGA.
> + * FPGA bridges should be disabled while the FPGA is being programmed to
> + prevent spurious data on the bus.
> + * FPGA bridges are not needed in implementations where the FPGA Manager
> + handles this.
> +
> +Device Tree
> +===========
> +
> +For the purposes of this document, I'm dividing the Device Tree (DT) into two parts,
> +each with its own requirements. The two parts are:
> + * The live DT prior to the overlay being added
> + * The overlay containing an FPGA Area
> +
> +The live DT will contain:
> + * FPGA Manager
> + * FPGA Bridges as children of the FPGA Manager (optional, architecture specific)
> +
> +The live Device Tree must contain an FPGA Manager to handle programming the FPGA.
> +If FPGA Bridges need to be involved, they show up in the DT as direct children
> +of the FPGA Manager. During full reconfiguration, the FPGA Area will disable
> +any bridges that are direct children of the manager during full reconfiguration
> +and will re-enable them afterwards.
> +
> +The insertion point in the live tree will also need the "simple-bus"
> +compatibility string to enable populating the child nodes for the overlay.
> +That includes the nodes for the FPGA Manager and controlling FPGA Bridges
> +as explained below.
> +
> +The Device Tree Overlay will contain:
> + * "target-path"
> + The insertion point where the the contents of the overlay will go into the
> + live tree.
> + * "ranges"
> + * "firmware-name"
> + Specifies the name of the FPGA image file on the firmware search
> + path. The search path is described in the firmware class documentation.
> + * "partial-reconfig"
> + This binding is a boolean and should be present if partial reconfiguration
> + is to be done.
> + * child nodes corresponding to hardware that will be loaded in this
> + region of the FPGA.
> +
> +Supported use models
> +====================
> +
> +Here's a list of the superset of supported use models. We may need to add
> +more. Some uses are specific to one FPGA or another.
> +
> + * No FPGA Bridges
> + In this case, the FPGA Manager which programs the FPGA also handles the
> + bridges and no FPGA Bridge devices are needed for full reconfiguration.
> +
> + The DT overlay will specify the FPGA Manager as the overlay target.
> +
> + * Full reconfiguration with bridges
> + In the case, there are several bridges between the processor and FPGA,
> + that need to be disabled during full reconfiguration.
> + The DT before the overlay is applied will have an FPGA Manager. The
> + immediate children of the manager will be the FPGA Bridges that need to be
> + disabled during FPGA programming.
> +
> + The DT overlay will specify one of those bridges as the overlay target,
> + typically the bridge that allows memory mapped register access ("the
> + controlling bridge").
> +
> + * Partial reconfiguration with bridges in the FPGA
> + In this case, the FPGA can have more than one section that will be
> + reprogrammed separately. Other sections may be active on the bus while FPGA
> + is being programmed. To manage this, FPGA Bridges need to exist on the FPGA
> + that can freeze all the buses going to one FPGA area while the buses are
> + enabled for other sections.
> +
> +Controlling Bridge
> +==================
> +
> +It is possible that there are multiple FPGA Bridges connecting the processor
> +and FPGA. In a text based hierarchy, it is difficult to show this properly
> +so what we do is consider the bridge that handles register access to be
> +the controlling bridge. The overlay is targeted to be inserted under the
> +controlling bridge. Other bridges are on the same level of the device tree
> +as the controlling bridge, i.e. all are children of the FPGA Manager. The
> +ranges property handles mapping memory ranges through multiple bridges.
> +
> +Sequence
> +========
> +
> +Load the DT overlay. One way to do that from user space is to use Pantelis
> +Antoniou's DT-Overlay configfs interface. In that case the sequence from
> +userspace is:
It will be a problem merging this series if you document things that are
not upstream yet.
> +
> + $ mkdir /config/device-tree/overlays/1
> + $ echo "some_overlay.dtb.o" > /config/device-tree/overlays/1/path
> +
> +This causes the FPGA Area to be probed and will do the following:
> + 1. Disable the FPGA bridges.
> + 2. Use the the FPGA manager core to program the FPGA.
> + 3. Enable the FPGA bridges.
> + 4. Call of_platform_populate resulting in device drivers getting probed.
> +
> +Removing the overlay is done by:
> +
> + $ rmdir /config/device-tree/overlays/1
> +
> +This causes the child nodes to be removed and then the bridges are disabled.
> +
> +Device Tree Examples
> +====================
> +
> +The intention of this section is to give some simple examples, focusing on
> +the placement of the elements detailed above in, especially:
> + * FPGA Managers
> + * FPGA Bridges in some cases
> + * FPGA Areas and associated properties
> + * simple-bus
> + * ranges
> + * target-path
> +
> +Please note the "simple-bus" compatible string added for FPGA Managers and for
> +FPGA Bridges where the overlay is targeted for insertion. This is required for
> +populating the child nodes.
> +
> +Device Tree Example: Partial Reconfiguration with no Bridges
> +============================================================
> +
> +Live Device Tree contains:
> + fpgamgr@0 {
Unit address should be ffd03000 here.
> + compatible = "altr,socfpga-a10-fpga-mgr", "simple-bus";
This should not have simple-bus. This would be broken in the case of
applying the overlay before booting the kernel. You don't want the
devices probed before the fpgamgr has programmed them.
> + clocks = <&l4_mp_clk>;
> + resets = <&rst FPGAMGR_RESET>;
> + reset-names = "fpgamgr";
> + reg = <0xffd03000 0x1000
> + 0xffcfe400 0x1000>;
> +
> + #address-cells = <0x1>;
> + #size-cells = <0x1>;
> + ranges;
> + };
> +
> +DT Overlay contains:
> +/dts-v1/;
> +/plugin/;
> +/ {
> + fragment@0 {
> + target-path="/soc/fpgamgr@0"; /* targeted to the manager */
> + __overlay__ {
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + area@0 {
> + compatible = "fpga-area";
> +
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0x10010 0xff210010 0x10>;
> +
> + firmware-name = "fit_pr_v1.rbf";
> + partial-reconfig;
> +
> + gpio@0x100010010 {
Remove 0x
> + compatible = "altr,pio-1.0";
> + reg = <0x10010 0x10>;
> + altr,ngpio = <4>;
> + #gpio-cells = <0x2>;
> + gpio-controller;
> + };
> + };
> + };
> + };
> +};
> +
> +
> +Device Tree Example: Full Reconfiguration with Bridges
> +======================================================
> +
> +Live Device Tree contains:
> + fpgamgr@0 {
unit address
> + compatible = "altr,socfpga-fpga-mgr", "simple-bus";
> + reg = <0xFF706000 0x1000
> + 0xFFB90000 0x1000>;
lower case
> + interrupts = <0 175 4>;
> +
> + #address-cells = <0x1>;
> + #size-cells = <0x1>;
> + ranges;
> +
> + bridge@0 {
Don't the outbound bridges have an address range associated with them?
Possibly, they should not be children of the fpgamgr unless the fpgamgr
itself is a bridge.
> + /* both the manager and the controlling bridge have
> + * the added simple-bus compatible to allow child
> + * devices to be populated. */
Why? Once you have initialized the bridge, you call of_platform_populate
with this node as the starting point. The root does not need any
matching string.
> + compatible = "altr,socfpga-lwhps2fpga-bridge",
> + "simple-bus";
> + resets = <&rst LWHPS2FPGA_RESET>;
> + reset-names = "lwhps2fpga";
> + clocks = <&l4_main_clk>;
> + #address-cells = <0x1>;
> + #size-cells = <0x1>;
> + ranges;
> + };
> +
> + bridge@1 {
> + /* In the case of full reconfiguration, both bridge@0
> + * and bridge@1 will be disabled during FPGA
> + * programming and enabled afterwards. */
> + compatible = "altr,socfpga-hps2fpga-bridge";
> + resets = <&rst HPS2FPGA_RESET>;
> + reset-names = "hps2fpga";
> + clocks = <&l4_main_clk>;
> + };
> + };
> +
> +DT Overlay contains:
> +/dts-v1/;
> +/plugin/;
> +/ {
> + fragment@0 {
> + target-path="/soc/fpgamgr@0/bridge@0"; /* controlling bridge */
> + __overlay__ {
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + area@0 {
> + compatible = "fpga-area";
> +
> + #address-cells = <2>;
> + #size-cells = <1>;
> + /* Note that two ranges are mapped due to the
> + * two bridges. */
> + ranges = <0 0x00000000 0xc0000000 0x00010000>,
> + <1 0x00020000 0xff220000 0x00000008>;
0 and 1 are address bits or mean something else (chip select # is common
example)?
> +
> + firmware-name = "soc_system.rbf";
> +
> + onchip_memory2_0: memory@000000000 {
Drop leading zeros (i.e. memory@0).
> + device_type = "memory";
> + compatible = "altr,onchipmem-15.1";
> + reg = <0 0x00000000 0x00010000>;
> + };
> +
> + jtag_uart: serial@0x100020000 {
Drop '0x'
> + compatible = "altr,juart-1.0";
> + reg = <1 0x00020000 0x00000008>;
> + interrupt-parent = <&intc>;
> + interrupts = <0 42 4>;
> + clocks = <&osc2>;
> + };
> + };
> + };
> + };
> +};
> +
> --
> 1.7.9.5
>
On Fri, 11 Dec 2015, Rob Herring wrote:
Hi Rob,
> > +Device Tree Example: Partial Reconfiguration with no Bridges
> > +============================================================
> > +
> > +Live Device Tree contains:
> > + fpgamgr@0 {
>
> Unit address should be ffd03000 here.
I'll clean up the addresses (and add that to my checklist!).
>
> > + compatible = "altr,socfpga-a10-fpga-mgr", "simple-bus";
>
> This should not have simple-bus. This would be broken in the case of
> applying the overlay before booting the kernel. You don't want the
> devices probed before the fpgamgr has programmed them.
>
I debugged this and had to add the simple-bus's to see my child devices
probe. Otherwise I can apply the overlay, but when I call
of_platform_populate, no child nodes get populated.
In drivers/of/platform.c's of_platform_notify(), the OF_POPULATED_BUS
flag has to be set for the parent (implying it was set for its parents
or it wouldn't be set). The child nodes do not get populated unless
the insertion point and all the ancestors of the insertion point are
simple-bus's.
So the issue of applying the overlay before booting the kernel:
if FPGA Area gets probed before its children get populated, then
I'm K since FPGA Area is responsible for programming the FPGA.
I can rework this to have a virtualized fpgabus that has the fpgamgr
and bridges as its children if that is more correct. I actually
worked this up several different ways so I have the code. I still
would like to keep the FPGA Area because that gives me a module that
gets probed that can be in charge of programming the FPGA. If I were
to rid of FPGA Area and just have an overlay of "firmware-name" plus
child nodes, then I have to add a notifier to the fpgabus. This I
can do (and have done and seen it work) so if that is preferable,
that's what v15 of this can easily be.
In that case, the target path for the overlay could be the fpgabus.
The fpgabus would need to also be a simple-bus but not the manager
or bridges.
So if I have a fpgabus, the live tree would be:
fpgabus@0 {
compatible = "altr,fpga-bus", "simple-bus";
#address-cells = <0x1>;
#size-cells = <0x1>;
ranges;
fpgamgr@ff706000 {
compatible = "altr,socfpga-fpga-mgr";
reg = <0xff706000 0x1000
0xffb90000 0x1000>;
interrupts = <0 175 4>;
};
bridge@0 {
compatible = "altr,socfpga-lwhps2fpga-bridge";
resets = <&rst LWHPS2FPGA_RESET>;
reset-names = "lwhps2fpga";
clocks = <&l4_main_clk>;
#address-cells = <0x1>;
#size-cells = <0x1>;
ranges;
};
bridge@1 {
compatible = "altr,socfpga-hps2fpga-bridge";
resets = <&rst HPS2FPGA_RESET>;
reset-names = "hps2fpga";
clocks = <&l4_main_clk>;
};
};
Alan
Hi Alan,
On Thu, Dec 10, 2015 at 3:37 PM, <[email protected]> wrote:
> From: Alan Tull <[email protected]>
>
> For v14 I'm dropping the concept of "simple-fpga-bus" for "fpga-area"
> with reworked bindings.
I had an offline discussion with Josh Cartwright about his concerns.
He brought up a good
point on w.r.t to the way FPGA Area (Bus) deals with things.
Currently we only support complete status = "okay" vs "disabled" kind
of overlays.
If now you have say a UART in the FPGA that you don't want to go away
and come back on reload,
we don't have a good way of expressing this. Is there a good way to
express non-mmio FPGA devices?
I've been toying around with hacking up struct device to include a
FPGA 'domain', and then, similar
to power domains allow devices to register suspend() / resume() style
callbacks (could call them pre_reload() or something like that ...)
I haven't gotten around to think it through. At this point it's just
an idea and I don't have real code to show.
I realize the issue with that is we'd have to make changes to struct device.
Cheers,
Moritz
On Mon, Dec 14, 2015 at 11:16 AM, Moritz Fischer
<[email protected]> wrote:
> Hi Alan,
>
> On Thu, Dec 10, 2015 at 3:37 PM, <[email protected]> wrote:
>> From: Alan Tull <[email protected]>
>>
>> For v14 I'm dropping the concept of "simple-fpga-bus" for "fpga-area"
>> with reworked bindings.
>
> I had an offline discussion with Josh Cartwright about his concerns.
> He brought up a good
> point on w.r.t to the way FPGA Area (Bus) deals with things.
>
> Currently we only support complete status = "okay" vs "disabled" kind
> of overlays.
>
> If now you have say a UART in the FPGA that you don't want to go away
> and come back on reload,
> we don't have a good way of expressing this.
Maybe i don't understand what you are saying; could you write out a
sequence you want to be able to do?
If you want suspend/resume functionality that would reload the FPGA
after a suspend powers off the FPGA, that would be simple to add to
the FPGA area code and it wasn't a hack at all.
> Is there a good way to
> express non-mmio FPGA devices?
Is this a separate question/issue from the above? Are you talking
about acceleration?
>
> I've been toying around with hacking up struct device to include a
> FPGA 'domain', and then, similar
> to power domains allow devices to register suspend() / resume() style
> callbacks (could call them pre_reload() or something like that ...)
>
> I haven't gotten around to think it through. At this point it's just
> an idea and I don't have real code to show.
>
> I realize the issue with that is we'd have to make changes to struct device.
That's interesting. Usually a FPGA image has many devices in it, so
so way of making that dependency clear would be needed. If any of the
devices involved are powered up, that FPGA image would need to be
loaded.
Currently I'm trying to get some bindings approved for doing device
tree control of loading the FPGA and probing the devices. My idea is
that these bindings could be useful for some use cases where we are
loading hardware onto the FPGA that needs to show up in the device
tree. Some of Rob's feedback is that my proposal may be
Altera-specific. If the bindings that I am proposing are useful for at
least some uses with Xilinx parts, that would be valuable feedback at
this point. If they are Altera-specific, then I may need to add
"altr," to some of the compatible strings like "altr,fpga-bus" and
"altr,fpga-area". My original intent was to implement something that
you could use also, so I hope that's not the future here.
So my question for you is: is this stuff useful for you?
Alan Tull
>
> Cheers,
>
> Moritz
Hi Alan,
On Mon, Dec 14, 2015 at 5:56 PM, Alan Tull <[email protected]> wrote:
>> I had an offline discussion with Josh Cartwright about his concerns.
>> He brought up a good
>> point on w.r.t to the way FPGA Area (Bus) deals with things.
>>
>> Currently we only support complete status = "okay" vs "disabled" kind
>> of overlays.
> Maybe i don't understand what you are saying; could you write out a
> sequence you want to be able to do?
Let's say you have a UART in the FPGA. You want to reprogram the FPGA
fabric that includes the UART (assuming proper resets etc happen)
1) Driver gets notified of impending doom, keeps hands off of FPGA
2) FPGA Manager reloads FPGA
3) FPGA Manager lets driver know FPGA is back
4) Driver can continue to function as always
It wouldn't even have to be a UART, on some boards simple SPI lines or UART
lines go from the processor through the FPGA logic out to a pin.
When you reload the FPGA for a short moment of time that doesn't work,
while after the reload it works just fine. Maybe something like extcon could
be used for that?
> Is this a separate question/issue from the above? Are you talking
> about acceleration?
I meant stuff like SPI that gets routed through the FPGA, sorry for
being unclear ;-)
>>
>> I've been toying around with hacking up struct device to include a
>> FPGA 'domain', and then, similar
>> to power domains allow devices to register suspend() / resume() style
>> callbacks (could call them pre_reload() or something like that ...)
>>
>> I haven't gotten around to think it through. At this point it's just
>> an idea and I don't have real code to show.
>>
>> I realize the issue with that is we'd have to make changes to struct device.
>
> That's interesting. Usually a FPGA image has many devices in it, so
> so way of making that dependency clear would be needed. If any of the
> devices involved are powered up, that FPGA image would need to be
> loaded.
Yeah. That's why I think the power domain model we have has a bunch of
similarities.
> Currently I'm trying to get some bindings approved for doing device
> tree control of loading the FPGA and probing the devices. My idea is
> that these bindings could be useful for some use cases where we are
> loading hardware onto the FPGA that needs to show up in the device
> tree. Some of Rob's feedback is that my proposal may be
> Altera-specific. If the bindings that I am proposing are useful for at
> least some uses with Xilinx parts, that would be valuable feedback at
> this point. If they are Altera-specific, then I may need to add
> "altr," to some of the compatible strings like "altr,fpga-bus" and
> "altr,fpga-area". My original intent was to implement something that
> you could use also, so I hope that's not the future here.
>
> So my question for you is: is this stuff useful for you?
Definitely, I'm pretty happy with what you have so far!
I think the points I mentioned above apply to Altera devices, too.
Maybe we can solve this in two parts, and the first step is getting the
loading bindings accepted ;-)
Cheers,
Moritz