diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-08-02 18:59:58 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-08-02 18:59:58 -0700 |
commit | bbbf2916a71e64f2334fe61106fb3c6a6c665916 (patch) | |
tree | 96a960258367d1468f1a8dc0d6921ac91cf4a53c | |
parent | 66b71f9e8256717b94c4819ae84bd6d4beb1f3fa (diff) | |
download | ltsi-kernel-bbbf2916a71e64f2334fe61106fb3c6a6c665916.tar.gz |
SoCFPGA patches added
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
104 files changed, 10705 insertions, 0 deletions
diff --git a/patches.socfpga/0001-ARM-dts-socfpga-enable-arm-shared-override-in-the-pl.patch b/patches.socfpga/0001-ARM-dts-socfpga-enable-arm-shared-override-in-the-pl.patch new file mode 100644 index 00000000000000..8304e419c46fb9 --- /dev/null +++ b/patches.socfpga/0001-ARM-dts-socfpga-enable-arm-shared-override-in-the-pl.patch @@ -0,0 +1,37 @@ +From 2e23d6de091f3e5e913086e223ac30eb4aa1f2a2 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@opensource.altera.com> +Date: Mon, 26 Sep 2016 14:29:30 -0500 +Subject: [PATCH 001/103] ARM: dts: socfpga: enable arm,shared-override in the + pl310 + +Enable the bit(22) shared-override bit for the SoCFPGA family. While at it, +enable the prefetch-data and prefetch-instr settings for the Arria10. + +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga.dtsi | 1 + + arch/arm/boot/dts/socfpga_arria10.dtsi | 3 +++ + 2 files changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/socfpga.dtsi ++++ b/arch/arm/boot/dts/socfpga.dtsi +@@ -686,6 +686,7 @@ + arm,data-latency = <2 1 1>; + prefetch-data = <1>; + prefetch-instr = <1>; ++ arm,shared-override; + }; + + mmc: dwmmc0@ff704000 { +--- a/arch/arm/boot/dts/socfpga_arria10.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10.dtsi +@@ -573,6 +573,9 @@ + interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; + cache-unified; + cache-level = <2>; ++ prefetch-data = <1>; ++ prefetch-instr = <1>; ++ arm,shared-override; + }; + + mmc: dwmmc0@ff808000 { diff --git a/patches.socfpga/0002-ARM-socfpga_defconfig-Enable-HIGHMEM.patch b/patches.socfpga/0002-ARM-socfpga_defconfig-Enable-HIGHMEM.patch new file mode 100644 index 00000000000000..214247eae241fc --- /dev/null +++ b/patches.socfpga/0002-ARM-socfpga_defconfig-Enable-HIGHMEM.patch @@ -0,0 +1,26 @@ +From c9d8a75227efb5a538da3f00cc675f20d9191602 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@opensource.altera.com> +Date: Tue, 25 Oct 2016 10:55:40 -0500 +Subject: [PATCH 002/103] ARM: socfpga_defconfig: Enable HIGHMEM + +All of the SoCFPGA boards have at least 1GB of RAM, so enabling HIGHMEM +is necessary to avoid the following warning: + +[ 0.000000] Truncating RAM at 0x00000000-0x40000000 to -0x30000000 +[ 0.000000] Consider using a HIGHMEM enabled kernel. + +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/configs/socfpga_defconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/configs/socfpga_defconfig ++++ b/arch/arm/configs/socfpga_defconfig +@@ -25,6 +25,7 @@ CONFIG_PCIE_ALTERA_MSI=y + CONFIG_SMP=y + CONFIG_NR_CPUS=2 + CONFIG_AEABI=y ++CONFIG_HIGHMEM=y + CONFIG_ZBOOT_ROM_TEXT=0x0 + CONFIG_ZBOOT_ROM_BSS=0x0 + CONFIG_VFP=y diff --git a/patches.socfpga/0003-ARM-dts-socfpga-enable-qspi-on-the-Cyclone5-devkit.patch b/patches.socfpga/0003-ARM-dts-socfpga-enable-qspi-on-the-Cyclone5-devkit.patch new file mode 100644 index 00000000000000..52ced0ce41567f --- /dev/null +++ b/patches.socfpga/0003-ARM-dts-socfpga-enable-qspi-on-the-Cyclone5-devkit.patch @@ -0,0 +1,54 @@ +From 60dab8bcc4915614d4853861f6a6ff35c2799d57 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@opensource.altera.com> +Date: Tue, 18 Oct 2016 22:51:42 -0500 +Subject: [PATCH 003/103] ARM: dts: socfpga: enable qspi on the Cyclone5 devkit + +Enable the qspi controller on the devkit and add the flash chip. + +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 33 +++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +@@ -87,6 +87,39 @@ + status = "okay"; + }; + ++&qspi { ++ status = "okay"; ++ ++ flash0: n25q00@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "n25q00"; ++ reg = <0>; /* chip select */ ++ spi-max-frequency = <100000000>; ++ ++ m25p,fast-read; ++ cdns,page-size = <256>; ++ cdns,block-size = <16>; ++ cdns,read-delay = <4>; ++ cdns,tshsl-ns = <50>; ++ cdns,tsd2d-ns = <50>; ++ cdns,tchsh-ns = <4>; ++ cdns,tslch-ns = <4>; ++ ++ partition@qspi-boot { ++ /* 8MB for raw data. */ ++ label = "Flash 0 Raw Data"; ++ reg = <0x0 0x800000>; ++ }; ++ ++ partition@qspi-rootfs { ++ /* 120MB for jffs2 data. */ ++ label = "Flash 0 jffs2 Filesystem"; ++ reg = <0x800000 0x7800000>; ++ }; ++ }; ++}; ++ + &usb1 { + status = "okay"; + }; diff --git a/patches.socfpga/0004-ARM-dts-socfpga-Add-QSPI-node-for-the-Arria10.patch b/patches.socfpga/0004-ARM-dts-socfpga-Add-QSPI-node-for-the-Arria10.patch new file mode 100644 index 00000000000000..7fc973c163f5a9 --- /dev/null +++ b/patches.socfpga/0004-ARM-dts-socfpga-Add-QSPI-node-for-the-Arria10.patch @@ -0,0 +1,35 @@ +From ab6809e7a5eb396b38f0cee59b1cda615de6cd69 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@opensource.altera.com> +Date: Wed, 19 Oct 2016 10:56:33 -0500 +Subject: [PATCH 004/103] ARM: dts: socfpga: Add QSPI node for the Arria10 + +Add the QSPI device node for Arria10 SOC. + +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga_arria10.dtsi | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10.dtsi +@@ -660,6 +660,20 @@ + }; + }; + ++ qspi: spi@ff809000 { ++ compatible = "cdns,qspi-nor"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0xff809000 0x100>, ++ <0xffa00000 0x100000>; ++ interrupts = <0 100 IRQ_TYPE_LEVEL_HIGH>; ++ cdns,fifo-depth = <128>; ++ cdns,fifo-width = <4>; ++ cdns,trigger-address = <0x00000000>; ++ clocks = <&qspi_clk>; ++ status = "disabled"; ++ }; ++ + rst: rstmgr@ffd05000 { + #reset-cells = <1>; + compatible = "altr,rst-mgr"; diff --git a/patches.socfpga/0005-ARM-dts-socfpga-Enable-QSPI-in-Arria10-devkit.patch b/patches.socfpga/0005-ARM-dts-socfpga-Enable-QSPI-in-Arria10-devkit.patch new file mode 100644 index 00000000000000..d13b676b0062e2 --- /dev/null +++ b/patches.socfpga/0005-ARM-dts-socfpga-Enable-QSPI-in-Arria10-devkit.patch @@ -0,0 +1,76 @@ +From 9004406f4a7df7be3ba20eb5299db80ae89a4de8 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@opensource.altera.com> +Date: Wed, 19 Oct 2016 10:07:48 -0500 +Subject: [PATCH 005/103] ARM: dts: socfpga: Enable QSPI in Arria10 devkit + +Enable the QSPI node and add the flash chip. + +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts | 49 +++++++++++++++++++++++ + 2 files changed, 50 insertions(+) + create mode 100644 arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -693,6 +693,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \ + sh73a0-kzm9g.dtb + dtb-$(CONFIG_ARCH_SOCFPGA) += \ + socfpga_arria5_socdk.dtb \ ++ socfpga_arria10_socdk_qspi.dtb \ + socfpga_arria10_socdk_sdmmc.dtb \ + socfpga_cyclone5_mcvevk.dtb \ + socfpga_cyclone5_socdk.dtb \ +--- /dev/null ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 2016 Intel. 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/>. ++ */ ++ ++/dts-v1/; ++#include "socfpga_arria10_socdk.dtsi" ++ ++&qspi { ++ status = "okay"; ++ ++ flash0: n25q00@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "n25q00aa"; ++ reg = <0>; ++ spi-max-frequency = <100000000>; ++ ++ m25p,fast-read; ++ cdns,page-size = <256>; ++ cdns,block-size = <16>; ++ cdns,read-delay = <4>; ++ cdns,tshsl-ns = <50>; ++ cdns,tsd2d-ns = <50>; ++ cdns,tchsh-ns = <4>; ++ cdns,tslch-ns = <4>; ++ ++ partition@qspi-boot { ++ label = "Boot and fpga data"; ++ reg = <0x0 0x2720000>; ++ }; ++ ++ partition@qspi-rootfs { ++ label = "Root Filesystem - JFFS2"; ++ reg = <0x2720000 0x58E0000>; ++ }; ++ }; ++}; diff --git a/patches.socfpga/0006-ARM-dts-socfpga-Enable-QSPI-on-the-Cyclone5-sockit.patch b/patches.socfpga/0006-ARM-dts-socfpga-Enable-QSPI-on-the-Cyclone5-sockit.patch new file mode 100644 index 00000000000000..f6d1e7518e299c --- /dev/null +++ b/patches.socfpga/0006-ARM-dts-socfpga-Enable-QSPI-on-the-Cyclone5-sockit.patch @@ -0,0 +1,46 @@ +From 72315cbb4c67745c94487884687e469cff71fa88 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@opensource.altera.com> +Date: Wed, 19 Oct 2016 14:55:54 -0500 +Subject: [PATCH 006/103] ARM: dts: socfpga: Enable QSPI on the Cyclone5 sockit + +Enable the QSPI node and add the flash chip. + +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- +v3: Use n25q00 for the compatible entry for the flash part and + tested on SoCKit +v2: Remove partition entries for the SoCKIT +--- + arch/arm/boot/dts/socfpga_cyclone5_sockit.dts | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts +@@ -175,6 +175,27 @@ + status = "okay"; + }; + ++&qspi { ++ status = "okay"; ++ ++ flash: flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "n25q00"; ++ reg = <0>; ++ spi-max-frequency = <100000000>; ++ ++ m25p,fast-read; ++ cdns,page-size = <256>; ++ cdns,block-size = <16>; ++ cdns,read-delay = <4>; ++ cdns,tshsl-ns = <50>; ++ cdns,tsd2d-ns = <50>; ++ cdns,tchsh-ns = <4>; ++ cdns,tslch-ns = <4>; ++ }; ++}; ++ + &usb1 { + status = "okay"; + }; diff --git a/patches.socfpga/0007-ARM-dts-socfpga-Enable-QSPI-on-the-Arria5-devkit.patch b/patches.socfpga/0007-ARM-dts-socfpga-Enable-QSPI-on-the-Arria5-devkit.patch new file mode 100644 index 00000000000000..4b18dbdcb3f6e2 --- /dev/null +++ b/patches.socfpga/0007-ARM-dts-socfpga-Enable-QSPI-on-the-Arria5-devkit.patch @@ -0,0 +1,54 @@ +From b6010bd7a8f9436f60f0b07ea629b5607251f0b2 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@opensource.altera.com> +Date: Wed, 19 Oct 2016 15:48:07 -0500 +Subject: [PATCH 007/103] ARM: dts: socfpga: Enable QSPI on the Arria5 devkit + +Enable the QSPI node and add the flash chip. + +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga_arria5_socdk.dts | 33 +++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts +@@ -82,6 +82,39 @@ + status = "okay"; + }; + ++&qspi { ++ status = "okay"; ++ ++ flash: flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "n25q256a"; ++ reg = <0>; ++ spi-max-frequency = <100000000>; ++ ++ m25p,fast-read; ++ cdns,page-size = <256>; ++ cdns,block-size = <16>; ++ cdns,read-delay = <4>; ++ cdns,tshsl-ns = <50>; ++ cdns,tsd2d-ns = <50>; ++ cdns,tchsh-ns = <4>; ++ cdns,tslch-ns = <4>; ++ ++ partition@qspi-boot { ++ /* 8MB for raw data. */ ++ label = "Flash 0 Raw Data"; ++ reg = <0x0 0x800000>; ++ }; ++ ++ partition@qspi-rootfs { ++ /* 120MB for jffs2 data. */ ++ label = "Flash 0 jffs2 Filesystem"; ++ reg = <0x800000 0x7800000>; ++ }; ++ }; ++}; ++ + &usb1 { + status = "okay"; + }; diff --git a/patches.socfpga/0008-ARM-socfpga_defconfig-enable-FS-configs-to-support-A.patch b/patches.socfpga/0008-ARM-socfpga_defconfig-enable-FS-configs-to-support-A.patch new file mode 100644 index 00000000000000..aa320e347b5dbc --- /dev/null +++ b/patches.socfpga/0008-ARM-socfpga_defconfig-enable-FS-configs-to-support-A.patch @@ -0,0 +1,40 @@ +From 81e36c3e01bbc9cbee6a3882b18d836667758d25 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Tue, 8 Nov 2016 15:01:22 -0600 +Subject: [PATCH 008/103] ARM: socfpga_defconfig: enable FS configs to support + Angstrom filesystem + +systemd on the Angstrom root file system expects AUTOFS to be configured +as a module and NFSD to be statically linked into the kernel. This patch +adds the necessary configuration to get rid two "FAILED" error messages +during systemd startup. + +Signed-off-by: Matthew Gerlach <mgerlach@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- +v2: provide a more descriptive changelog +--- + arch/arm/configs/socfpga_defconfig | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/arm/configs/socfpga_defconfig ++++ b/arch/arm/configs/socfpga_defconfig +@@ -107,13 +107,18 @@ CONFIG_EXT2_FS=y + CONFIG_EXT2_FS_XATTR=y + CONFIG_EXT2_FS_POSIX_ACL=y + CONFIG_EXT3_FS=y ++CONFIG_AUTOFS4_FS=y + CONFIG_VFAT_FS=y + CONFIG_NTFS_FS=y + CONFIG_NTFS_RW=y + CONFIG_TMPFS=y + CONFIG_CONFIGFS_FS=y + CONFIG_NFS_FS=y ++CONFIG_NFS_V3_ACL=y + CONFIG_ROOT_NFS=y ++CONFIG_NFSD=y ++CONFIG_NFSD_V3_ACL=y ++CONFIG_NFSD_V4=y + CONFIG_NLS_CODEPAGE_437=y + CONFIG_NLS_ISO8859_1=y + CONFIG_PRINTK_TIME=y diff --git a/patches.socfpga/0009-dt-bindings-Add-Macnica-Americas-vendor-prefix.patch b/patches.socfpga/0009-dt-bindings-Add-Macnica-Americas-vendor-prefix.patch new file mode 100644 index 00000000000000..1487c49f8fd919 --- /dev/null +++ b/patches.socfpga/0009-dt-bindings-Add-Macnica-Americas-vendor-prefix.patch @@ -0,0 +1,24 @@ +From fdcef7128b2fcfa244e5b2ae5e2e323a819a2158 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Tue, 1 Nov 2016 10:36:30 -0500 +Subject: [PATCH 009/103] dt-bindings: Add Macnica Americas vendor prefix + +Add a vendor prefix for the Macnica company. +http://http://www.macnica.com + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +Signed-off-by: Rob Herring <robh@kernel.org> +--- + Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/vendor-prefixes.txt ++++ b/Documentation/devicetree/bindings/vendor-prefixes.txt +@@ -158,6 +158,7 @@ lg LG Corporation + linux Linux-specific binding + lltc Linear Technology Corporation + lsi LSI Corp. (LSI Logic) ++macnica Macnica Americas + marvell Marvell Technology Group Ltd. + maxim Maxim Integrated Products + meas Measurement Specialties diff --git a/patches.socfpga/0010-dt-bindings-Add-vendor-prefix-for-Terasic-Inc.patch b/patches.socfpga/0010-dt-bindings-Add-vendor-prefix-for-Terasic-Inc.patch new file mode 100644 index 00000000000000..7a2ff470699249 --- /dev/null +++ b/patches.socfpga/0010-dt-bindings-Add-vendor-prefix-for-Terasic-Inc.patch @@ -0,0 +1,25 @@ +From 5ae491dadecfd37b8f00965ada793be6c230dddc Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Tue, 1 Nov 2016 10:36:31 -0500 +Subject: [PATCH 010/103] dt-bindings: Add vendor prefix for Terasic Inc. + +Add a vendor prefix for Terasic. + +http://www.terasic.com + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +Signed-off-by: Rob Herring <robh@kernel.org> +--- + Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/vendor-prefixes.txt ++++ b/Documentation/devicetree/bindings/vendor-prefixes.txt +@@ -276,6 +276,7 @@ tcg Trusted Computing Group + tcl Toby Churchill Ltd. + technexion TechNexion + technologic Technologic Systems ++terasic Terasic Inc. + thine THine Electronics, Inc. + ti Texas Instruments + tlm Trusted Logic Mobility diff --git a/patches.socfpga/0011-dt-bindings-Add-vendor-prefix-for-Samtec.patch b/patches.socfpga/0011-dt-bindings-Add-vendor-prefix-for-Samtec.patch new file mode 100644 index 00000000000000..d0eb1bf2a90a79 --- /dev/null +++ b/patches.socfpga/0011-dt-bindings-Add-vendor-prefix-for-Samtec.patch @@ -0,0 +1,26 @@ +From 886e6363f55f9996be2c7f6e122fbd90fc01c85c Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Tue, 1 Nov 2016 10:36:32 -0500 +Subject: [PATCH 011/103] dt-bindings: Add vendor prefix for Samtec + +Add a vendor prefix for Samtec, a Softing company. + +http://www.samtec.de +http://www.samtec.org + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +Signed-off-by: Rob Herring <robh@kernel.org> +--- + Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/vendor-prefixes.txt ++++ b/Documentation/devicetree/bindings/vendor-prefixes.txt +@@ -232,6 +232,7 @@ richtek Richtek Technology Corporation + ricoh Ricoh Co. Ltd. + rockchip Fuzhou Rockchip Electronics Co., Ltd + samsung Samsung Semiconductor ++samtec Samtec/Softing company + sandisk Sandisk Corporation + sbs Smart Battery System + schindler Schindler diff --git a/patches.socfpga/0012-ARM-dts-socfpga-enable-GPIO-and-LEDs-for-Cyclone5-an.patch b/patches.socfpga/0012-ARM-dts-socfpga-enable-GPIO-and-LEDs-for-Cyclone5-an.patch new file mode 100644 index 00000000000000..861b7360c49b6c --- /dev/null +++ b/patches.socfpga/0012-ARM-dts-socfpga-enable-GPIO-and-LEDs-for-Cyclone5-an.patch @@ -0,0 +1,117 @@ +From 68ba0c63510af673e2400895aaaa5a6c7c9ec622 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Mon, 12 Dec 2016 22:02:44 -0600 +Subject: [PATCH 012/103] ARM: dts: socfpga: enable GPIO and LEDs for Cyclone5 + and Arria5 devkits + +Enable all the GPIO ports and define the GPIO-based leds on the Cyclone5 and +Arria5 devkits. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_arria5_socdk.dts | 35 +++++++++++++++++++++++++++ + arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 31 +++++++++++++++++++++++ + 2 files changed, 66 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts +@@ -39,6 +39,29 @@ + ethernet0 = &gmac1; + }; + ++ leds { ++ compatible = "gpio-leds"; ++ hps0 { ++ label = "hps_led0"; ++ gpios = <&porta 0 1>; ++ }; ++ ++ hps1 { ++ label = "hps_led1"; ++ gpios = <&portb 11 1>; ++ }; ++ ++ hps2 { ++ label = "hps_led2"; ++ gpios = <&porta 17 1>; ++ }; ++ ++ hps3 { ++ label = "hps_led3"; ++ gpios = <&porta 18 1>; ++ }; ++ }; ++ + regulator_3_3v: 3-3-v-regulator { + compatible = "regulator-fixed"; + regulator-name = "3.3V"; +@@ -61,6 +84,18 @@ + rxc-skew-ps = <2000>; + }; + ++&gpio0 { ++ status = "okay"; ++}; ++ ++&gpio1 { ++ status = "okay"; ++}; ++ ++&gpio2 { ++ status = "okay"; ++}; ++ + &i2c0 { + status = "okay"; + +--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +@@ -39,6 +39,29 @@ + ethernet0 = &gmac1; + }; + ++ leds { ++ compatible = "gpio-leds"; ++ hps0 { ++ label = "hps_led0"; ++ gpios = <&portb 15 1>; ++ }; ++ ++ hps1 { ++ label = "hps_led1"; ++ gpios = <&portb 14 1>; ++ }; ++ ++ hps2 { ++ label = "hps_led2"; ++ gpios = <&portb 13 1>; ++ }; ++ ++ hps3 { ++ label = "hps_led3"; ++ gpios = <&portb 12 1>; ++ }; ++ }; ++ + regulator_3_3v: 3-3-v-regulator { + compatible = "regulator-fixed"; + regulator-name = "3.3V"; +@@ -61,10 +84,18 @@ + rxc-skew-ps = <2000>; + }; + ++&gpio0 { ++ status = "okay"; ++}; ++ + &gpio1 { + status = "okay"; + }; + ++&gpio2 { ++ status = "okay"; ++}; ++ + &i2c0 { + status = "okay"; + diff --git a/patches.socfpga/0013-ARM-dts-socfpga-set-desired-i2c-clock-on-Cyclone5-an.patch b/patches.socfpga/0013-ARM-dts-socfpga-set-desired-i2c-clock-on-Cyclone5-an.patch new file mode 100644 index 00000000000000..ebcff2431c107c --- /dev/null +++ b/patches.socfpga/0013-ARM-dts-socfpga-set-desired-i2c-clock-on-Cyclone5-an.patch @@ -0,0 +1,50 @@ +From bae526e301c40e073379cbcf7d8239905ffcaf7f Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Tue, 13 Dec 2016 16:52:11 -0600 +Subject: [PATCH 013/103] ARM: dts: socfpga: set desired i2c clock on Cyclone5 + and Arria5 devkits + +The I2C LCD display on the Cyclone5 and Arria5 devkits is only capable of +the standard 100 kHz clock. Set the "clock-frequency" of the I2C node +to be 100000. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_arria5_socdk.dts | 8 ++++++++ + arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 8 ++++++++ + 2 files changed, 16 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts +@@ -98,6 +98,14 @@ + + &i2c0 { + status = "okay"; ++ clock-frequency = <100000>; ++ ++ /* ++ * adjust the falling times to decrease the i2c frequency to 50Khz ++ * because the LCD module does not work at the standard 100Khz ++ */ ++ i2c-sda-falling-time-ns = <5000>; ++ i2c-scl-falling-time-ns = <5000>; + + eeprom@51 { + compatible = "atmel,24c32"; +--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +@@ -98,6 +98,14 @@ + + &i2c0 { + status = "okay"; ++ clock-frequency = <100000>; ++ ++ /* ++ * adjust the falling times to decrease the i2c frequency to 50Khz ++ * because the LCD module does not work at the standard 100Khz ++ */ ++ i2c-sda-falling-time-ns = <5000>; ++ i2c-scl-falling-time-ns = <5000>; + + eeprom@51 { + compatible = "atmel,24c32"; diff --git a/patches.socfpga/0014-ARM-dts-socfpga-Add-Rohm-DH2228FV-DAC.patch b/patches.socfpga/0014-ARM-dts-socfpga-Add-Rohm-DH2228FV-DAC.patch new file mode 100644 index 00000000000000..4f3e40f26d38a0 --- /dev/null +++ b/patches.socfpga/0014-ARM-dts-socfpga-Add-Rohm-DH2228FV-DAC.patch @@ -0,0 +1,31 @@ +From 3f5e1bdb1957578c511107b2e4bef7c5d287b1bc Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Thu, 15 Dec 2016 23:30:03 -0600 +Subject: [PATCH 014/103] ARM: dts: socfpga: Add Rohm DH2228FV DAC + +Enable the SPI node and add the Rohm DH2228FV DAC. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +@@ -159,6 +159,16 @@ + }; + }; + ++&spi0 { ++ status = "okay"; ++ ++ spidev@0 { ++ compatible = "rohm,dh2228fv"; ++ reg = <0>; ++ spi-max-frequency = <1000000>; ++ }; ++}; ++ + &usb1 { + status = "okay"; + }; diff --git a/patches.socfpga/0015-ARM-dts-socfpga-enable-CAN-on-Cyclone5-devkit.patch b/patches.socfpga/0015-ARM-dts-socfpga-enable-CAN-on-Cyclone5-devkit.patch new file mode 100644 index 00000000000000..38c7c176aa172b --- /dev/null +++ b/patches.socfpga/0015-ARM-dts-socfpga-enable-CAN-on-Cyclone5-devkit.patch @@ -0,0 +1,25 @@ +From 70fa6f9a9bf3bbdcb24f77876dd3787986c4623a Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Fri, 16 Dec 2016 16:55:44 -0600 +Subject: [PATCH 015/103] ARM: dts: socfpga: enable CAN on Cyclone5 devkit + +Enable the CAN node on the Cyclone5 devkit. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +@@ -70,6 +70,10 @@ + }; + }; + ++&can0 { ++ status = "okay"; ++}; ++ + &gmac1 { + status = "okay"; + phy-mode = "rgmii"; diff --git a/patches.socfpga/0016-ARM-dts-socfpga-enable-watchdog-timer-on-Arria5-and-.patch b/patches.socfpga/0016-ARM-dts-socfpga-enable-watchdog-timer-on-Arria5-and-.patch new file mode 100644 index 00000000000000..136e3cfedfe762 --- /dev/null +++ b/patches.socfpga/0016-ARM-dts-socfpga-enable-watchdog-timer-on-Arria5-and-.patch @@ -0,0 +1,34 @@ +From 6442fc6873b15415fce505c7dbc3a8e824bb8163 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Fri, 16 Dec 2016 17:15:00 -0600 +Subject: [PATCH 016/103] ARM: dts: socfpga: enable watchdog timer on Arria5 + and Arria10 + +Enable the watchdog for Arria5 and Arria10. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_arria10_socdk.dtsi | 4 ++++ + arch/arm/boot/dts/socfpga_arria5.dtsi | 4 ++++ + 2 files changed, 8 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +@@ -105,3 +105,7 @@ + &usb0 { + status = "okay"; + }; ++ ++&watchdog0 { ++ status = "okay"; ++}; +--- a/arch/arm/boot/dts/socfpga_arria5.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria5.dtsi +@@ -42,3 +42,7 @@ + }; + }; + }; ++ ++&watchdog0 { ++ status = "okay"; ++}; diff --git a/patches.socfpga/0017-ARM-dts-socfpga-add-the-LTC2977-power-monitor-on-Arr.patch b/patches.socfpga/0017-ARM-dts-socfpga-add-the-LTC2977-power-monitor-on-Arr.patch new file mode 100644 index 00000000000000..656fbdc6a59b84 --- /dev/null +++ b/patches.socfpga/0017-ARM-dts-socfpga-add-the-LTC2977-power-monitor-on-Arr.patch @@ -0,0 +1,27 @@ +From b8ccfd2af325b1bb2cc3fa70cd688850a32e6a54 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Sat, 17 Dec 2016 21:42:32 -0600 +Subject: [PATCH 017/103] ARM: dts: socfpga: add the LTC2977 power monitor on + Arria10 devkit + +Add the I2C LTC 2977 power monitor that is on the Arria10 devkit. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_arria10_socdk.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +@@ -96,6 +96,11 @@ + compatible = "dallas,ds1339"; + reg = <0x68>; + }; ++ ++ ltc@5c { ++ compatible = "ltc2977"; ++ reg = <0x5c>; ++ }; + }; + + &uart1 { diff --git a/patches.socfpga/0018-ARM-dts-socfpga-add-fpga-manager-node-for-Arria10.patch b/patches.socfpga/0018-ARM-dts-socfpga-add-fpga-manager-node-for-Arria10.patch new file mode 100644 index 00000000000000..252f94d103422d --- /dev/null +++ b/patches.socfpga/0018-ARM-dts-socfpga-add-fpga-manager-node-for-Arria10.patch @@ -0,0 +1,30 @@ +From f968f1aa6c67873082498738e7756e2311eac0af Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Sat, 17 Dec 2016 22:45:03 -0600 +Subject: [PATCH 018/103] ARM: dts: socfpga: add fpga-manager node for Arria10 + +Add the FPGA manger DTS entry for Arria10. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_arria10.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10.dtsi +@@ -512,6 +512,15 @@ + }; + }; + ++ fpga_mgr: fpga-mgr@ffd03000 { ++ compatible = "altr,socfpga-a10-fpga-mgr"; ++ reg = <0xffd03000 0x100 ++ 0xffcfe400 0x20>; ++ clocks = <&l4_mp_clk>; ++ resets = <&rst FPGAMGR_RESET>; ++ reset-names = "fpgamgr"; ++ }; ++ + i2c0: i2c@ffc02200 { + #address-cells = <1>; + #size-cells = <0>; diff --git a/patches.socfpga/0019-ARM-dts-socfpga-fpga-manager-data-is-32-bits.patch b/patches.socfpga/0019-ARM-dts-socfpga-fpga-manager-data-is-32-bits.patch new file mode 100644 index 00000000000000..0be678f6503173 --- /dev/null +++ b/patches.socfpga/0019-ARM-dts-socfpga-fpga-manager-data-is-32-bits.patch @@ -0,0 +1,26 @@ +From 5a87081d681bad5b577d1fe2a2a83021cfca989f Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Mon, 19 Dec 2016 22:34:00 -0600 +Subject: [PATCH 019/103] ARM: dts: socfpga: fpga manager data is 32 bits + +Adjust regs property for the FPGA manager data register to +properly reflect that it is a single 32 bit register. + +Signed-off-by: Dalon Westergreen <dwesterg@altera.com> +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/socfpga.dtsi ++++ b/arch/arm/boot/dts/socfpga.dtsi +@@ -516,7 +516,7 @@ + fpgamgr0: fpgamgr@ff706000 { + compatible = "altr,socfpga-fpga-mgr"; + reg = <0xff706000 0x1000 +- 0xffb90000 0x1000>; ++ 0xffb90000 0x4>; + interrupts = <0 175 4>; + }; + diff --git a/patches.socfpga/0020-ARM-dts-socfpga-add-fpga-region-support-on-Arria10.patch b/patches.socfpga/0020-ARM-dts-socfpga-add-fpga-region-support-on-Arria10.patch new file mode 100644 index 00000000000000..273ebb6dc89dc5 --- /dev/null +++ b/patches.socfpga/0020-ARM-dts-socfpga-add-fpga-region-support-on-Arria10.patch @@ -0,0 +1,31 @@ +From f534c9a2d107eb6255532f19decc1dde219a25e7 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Mon, 19 Dec 2016 23:21:27 -0600 +Subject: [PATCH 020/103] ARM: dts: socfpga: add fpga region support on Arria10 + +Add the base FPGA region for DT overlay support in FPGA programming. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Matthew Gerlach <mgerlach@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_arria10.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10.dtsi +@@ -83,6 +83,14 @@ + }; + }; + ++ base_fpga_region { ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ ++ compatible = "fpga-region"; ++ fpga-mgr = <&fpga_mgr>; ++ }; ++ + clkmgr@ffd04000 { + compatible = "altr,clk-mgr"; + reg = <0xffd04000 0x1000>; diff --git a/patches.socfpga/0021-ARM-dts-socfpga-add-missing-compatible-string-for-SD.patch b/patches.socfpga/0021-ARM-dts-socfpga-add-missing-compatible-string-for-SD.patch new file mode 100644 index 00000000000000..ce6c1806b7400a --- /dev/null +++ b/patches.socfpga/0021-ARM-dts-socfpga-add-missing-compatible-string-for-SD.patch @@ -0,0 +1,36 @@ +From 36760f8265fe47bc7176a58aa85ca6c3ec59f812 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Tue, 20 Dec 2016 00:01:48 -0600 +Subject: [PATCH 021/103] ARM: dts: socfpga: add missing compatible string for + SDRAM controller + +Add "altr,sdr-ctl" to the SDRAM controller node. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga.dtsi | 2 +- + arch/arm/boot/dts/socfpga_arria10.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/socfpga.dtsi ++++ b/arch/arm/boot/dts/socfpga.dtsi +@@ -719,7 +719,7 @@ + }; + + sdr: sdr@ffc25000 { +- compatible = "syscon"; ++ compatible = "altr,sdr-ctl", "syscon"; + reg = <0xffc25000 0x1000>; + }; + +--- a/arch/arm/boot/dts/socfpga_arria10.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10.dtsi +@@ -580,7 +580,7 @@ + }; + + sdr: sdr@ffc25000 { +- compatible = "syscon"; ++ compatible = "altr,sdr-ctl", "syscon"; + reg = <0xffcfb100 0x80>; + }; + diff --git a/patches.socfpga/0022-ARM-dts-watchdog0-cannot-reliably-trigger-reset.patch b/patches.socfpga/0022-ARM-dts-watchdog0-cannot-reliably-trigger-reset.patch new file mode 100644 index 00000000000000..38c6f1ef7c16ae --- /dev/null +++ b/patches.socfpga/0022-ARM-dts-watchdog0-cannot-reliably-trigger-reset.patch @@ -0,0 +1,28 @@ +From 22f774c2c8c6b463883e3cbada27b5b74155b121 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Wed, 25 Jan 2017 10:01:28 -0600 +Subject: [PATCH 022/103] ARM: dts: watchdog0 cannot reliably trigger reset + +On the Arria10, because of hardware bug, watchdog0 cannot reliably trigger +a reset to the CPU. The workaround would be to use watchdog1 instead. + +Also for watchdog1, there is a dependency on the bootloader to enable the +boot_clk source to be from the cb_intosc_hs_clk/2, versus from EOSC1. This +corresponds to the (SWCTRLBTCLKEN & SWCTRLBTCLKSEL) bits enabled in the +control register in the clock manager module of Arria10. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_arria10_socdk.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +@@ -111,6 +111,6 @@ + status = "okay"; + }; + +-&watchdog0 { ++&watchdog1 { + status = "okay"; + }; diff --git a/patches.socfpga/0023-MAINTAINERS-socfpga-update-email-for-Dinh-Nguyen.patch b/patches.socfpga/0023-MAINTAINERS-socfpga-update-email-for-Dinh-Nguyen.patch new file mode 100644 index 00000000000000..0aa0b17e88b5e4 --- /dev/null +++ b/patches.socfpga/0023-MAINTAINERS-socfpga-update-email-for-Dinh-Nguyen.patch @@ -0,0 +1,33 @@ +From bd1f3567243bb08db75c610e7475968b2dec1373 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Fri, 3 Feb 2017 09:29:07 -0600 +Subject: [PATCH 023/103] MAINTAINERS: socfpga: update email for Dinh Nguyen + +My opensource.altera.com email will be going away soon. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +Signed-off-by: Arnd Bergmann <arnd@arndb.de> +--- + MAINTAINERS | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1751,7 +1751,7 @@ F: drivers/soc/renesas/ + F: include/linux/soc/renesas/ + + ARM/SOCFPGA ARCHITECTURE +-M: Dinh Nguyen <dinguyen@opensource.altera.com> ++M: Dinh Nguyen <dinguyen@kernel.org> + S: Maintained + F: arch/arm/mach-socfpga/ + F: arch/arm/boot/dts/socfpga* +@@ -1761,7 +1761,7 @@ W: http://www.rocketboards.org + T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git + + ARM/SOCFPGA CLOCK FRAMEWORK SUPPORT +-M: Dinh Nguyen <dinguyen@opensource.altera.com> ++M: Dinh Nguyen <dinguyen@kernel.org> + S: Maintained + F: drivers/clk/socfpga/ + diff --git a/patches.socfpga/0024-of-overlay-add-of-overlay-notifications.patch b/patches.socfpga/0024-of-overlay-add-of-overlay-notifications.patch new file mode 100644 index 00000000000000..bc47fd3b034c2b --- /dev/null +++ b/patches.socfpga/0024-of-overlay-add-of-overlay-notifications.patch @@ -0,0 +1,175 @@ +From 34c5493a5611f3c1481d98767657ead412c55c18 Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:22 -0500 +Subject: [PATCH 024/103] of/overlay: add of overlay notifications + +This patch add of overlay notifications. + +When DT overlays are being added, some drivers/subsystems +need to see device tree overlays before the changes go into +the live tree. + +This is distinct from reconfig notifiers that are +post-apply or post-remove and which issue very granular +notifications without providing access to the context +of a whole overlay. + +The following 4 notificatons are issued: + OF_OVERLAY_PRE_APPLY + OF_OVERLAY_POST_APPLY + OF_OVERLAY_PRE_REMOVE + OF_OVERLAY_POST_REMOVE + +In the case of pre-apply notification, if the notifier +returns error, the overlay will be rejected. + +This patch exports two functions for registering/unregistering +notifications: + of_overlay_notifier_register(struct notifier_block *nb) + of_overlay_notifier_unregister(struct notifier_block *nb) + +The of_mutex is held during these notifications. The +notification data includes pointers to the overlay target +and the overlay: + +struct of_overlay_notify_data { + struct device_node *overlay; + struct device_node *target; +}; + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Rob Herring <robh@kernel.org> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/of/overlay.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- + include/linux/of.h | 25 +++++++++++++++++++++++++ + 2 files changed, 71 insertions(+), 1 deletion(-) + +--- a/drivers/of/overlay.c ++++ b/drivers/of/overlay.c +@@ -58,6 +58,41 @@ struct of_overlay { + static int of_overlay_apply_one(struct of_overlay *ov, + struct device_node *target, const struct device_node *overlay); + ++static BLOCKING_NOTIFIER_HEAD(of_overlay_chain); ++ ++int of_overlay_notifier_register(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&of_overlay_chain, nb); ++} ++EXPORT_SYMBOL_GPL(of_overlay_notifier_register); ++ ++int of_overlay_notifier_unregister(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&of_overlay_chain, nb); ++} ++EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister); ++ ++static int of_overlay_notify(struct of_overlay *ov, ++ enum of_overlay_notify_action action) ++{ ++ struct of_overlay_notify_data nd; ++ int i, ret; ++ ++ for (i = 0; i < ov->count; i++) { ++ struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i]; ++ ++ nd.target = ovinfo->target; ++ nd.overlay = ovinfo->overlay; ++ ++ ret = blocking_notifier_call_chain(&of_overlay_chain, ++ action, &nd); ++ if (ret) ++ return notifier_to_errno(ret); ++ } ++ ++ return 0; ++} ++ + static int of_overlay_apply_single_property(struct of_overlay *ov, + struct device_node *target, struct property *prop) + { +@@ -368,6 +403,13 @@ int of_overlay_create(struct device_node + goto err_free_idr; + } + ++ err = of_overlay_notify(ov, OF_OVERLAY_PRE_APPLY); ++ if (err < 0) { ++ pr_err("%s: Pre-apply notifier failed (err=%d)\n", ++ __func__, err); ++ goto err_free_idr; ++ } ++ + /* apply the overlay */ + err = of_overlay_apply(ov); + if (err) +@@ -382,6 +424,8 @@ int of_overlay_create(struct device_node + /* add to the tail of the overlay list */ + list_add_tail(&ov->node, &ov_list); + ++ of_overlay_notify(ov, OF_OVERLAY_POST_APPLY); ++ + mutex_unlock(&of_mutex); + + return id; +@@ -498,9 +542,10 @@ int of_overlay_destroy(int id) + goto out; + } + +- ++ of_overlay_notify(ov, OF_OVERLAY_PRE_REMOVE); + list_del(&ov->node); + __of_changeset_revert(&ov->cset); ++ of_overlay_notify(ov, OF_OVERLAY_POST_REMOVE); + of_free_overlay_info(ov); + idr_remove(&ov_idr, id); + of_changeset_destroy(&ov->cset); +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -1266,6 +1266,18 @@ static inline bool of_device_is_system_p + * Overlay support + */ + ++enum of_overlay_notify_action { ++ OF_OVERLAY_PRE_APPLY, ++ OF_OVERLAY_POST_APPLY, ++ OF_OVERLAY_PRE_REMOVE, ++ OF_OVERLAY_POST_REMOVE, ++}; ++ ++struct of_overlay_notify_data { ++ struct device_node *overlay; ++ struct device_node *target; ++}; ++ + #ifdef CONFIG_OF_OVERLAY + + /* ID based overlays; the API for external users */ +@@ -1273,6 +1285,9 @@ int of_overlay_create(struct device_node + int of_overlay_destroy(int id); + int of_overlay_destroy_all(void); + ++int of_overlay_notifier_register(struct notifier_block *nb); ++int of_overlay_notifier_unregister(struct notifier_block *nb); ++ + #else + + static inline int of_overlay_create(struct device_node *tree) +@@ -1290,6 +1305,16 @@ static inline int of_overlay_destroy_all + return -ENOTSUPP; + } + ++static inline int of_overlay_notifier_register(struct notifier_block *nb) ++{ ++ return 0; ++} ++ ++static inline int of_overlay_notifier_unregister(struct notifier_block *nb) ++{ ++ return 0; ++} ++ + #endif + + #endif /* _LINUX_OF_H */ diff --git a/patches.socfpga/0025-fpga-add-method-to-get-fpga-manager-from-device.patch b/patches.socfpga/0025-fpga-add-method-to-get-fpga-manager-from-device.patch new file mode 100644 index 00000000000000..a671185167e684 --- /dev/null +++ b/patches.socfpga/0025-fpga-add-method-to-get-fpga-manager-from-device.patch @@ -0,0 +1,159 @@ +From 6cc9e7b146fc8e24e1ca6b7ae0b0e27ca6cc3fae Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:23 -0500 +Subject: [PATCH 025/103] fpga: add method to get fpga manager from device + +The intent is to provide a non-DT method of getting +ahold of a FPGA manager to do some FPGA programming. + +This patch refactors of_fpga_mgr_get() to reuse most of it +while adding a new method fpga_mgr_get() for getting a +pointer to a fpga manager struct, given the device. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + Documentation/fpga/fpga-mgr.txt | 6 ++- + drivers/fpga/fpga-mgr.c | 76 ++++++++++++++++++++++++++++------------ + include/linux/fpga/fpga-mgr.h | 2 + + 3 files changed, 60 insertions(+), 24 deletions(-) + +--- a/Documentation/fpga/fpga-mgr.txt ++++ b/Documentation/fpga/fpga-mgr.txt +@@ -38,11 +38,13 @@ To get/put a reference to a FPGA manager + ----------------------------------------- + + struct fpga_manager *of_fpga_mgr_get(struct device_node *node); ++ struct fpga_manager *fpga_mgr_get(struct device *dev); ++ ++Given a DT node or device, get an exclusive reference to a FPGA manager. + + void fpga_mgr_put(struct fpga_manager *mgr); + +-Given a DT node, get an exclusive reference to a FPGA manager or release +-the reference. ++Release the reference. + + + To register or unregister the low level FPGA-specific driver: +--- a/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c +@@ -39,7 +39,8 @@ static struct class *fpga_mgr_class; + * Step the low level fpga manager through the device-specific steps of getting + * an FPGA ready to be configured, writing the image to it, then doing whatever + * post-configuration steps necessary. This code assumes the caller got the +- * mgr pointer from of_fpga_mgr_get() and checked that it is not an error code. ++ * mgr pointer from of_fpga_mgr_get() or fpga_mgr_get() and checked that it is ++ * not an error code. + * + * Return: 0 on success, negative error code otherwise. + */ +@@ -99,7 +100,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); + * Request an FPGA image using the firmware class, then write out to the FPGA. + * Update the state before each step to provide info on what step failed if + * there is a failure. This code assumes the caller got the mgr pointer +- * from of_fpga_mgr_get() and checked that it is not an error code. ++ * from of_fpga_mgr_get() or fpga_mgr_get() and checked that it is not an error ++ * code. + * + * Return: 0 on success, negative error code otherwise. + */ +@@ -181,30 +183,11 @@ static struct attribute *fpga_mgr_attrs[ + }; + ATTRIBUTE_GROUPS(fpga_mgr); + +-static int fpga_mgr_of_node_match(struct device *dev, const void *data) +-{ +- return dev->of_node == data; +-} +- +-/** +- * of_fpga_mgr_get - get an exclusive reference to a fpga mgr +- * @node: device node +- * +- * Given a device node, get an exclusive reference to a fpga mgr. +- * +- * Return: fpga manager struct or IS_ERR() condition containing error code. +- */ +-struct fpga_manager *of_fpga_mgr_get(struct device_node *node) ++struct fpga_manager *__fpga_mgr_get(struct device *dev) + { + struct fpga_manager *mgr; +- struct device *dev; + int ret = -ENODEV; + +- dev = class_find_device(fpga_mgr_class, NULL, node, +- fpga_mgr_of_node_match); +- if (!dev) +- return ERR_PTR(-ENODEV); +- + mgr = to_fpga_manager(dev); + if (!mgr) + goto err_dev; +@@ -226,6 +209,55 @@ err_dev: + put_device(dev); + return ERR_PTR(ret); + } ++ ++static int fpga_mgr_dev_match(struct device *dev, const void *data) ++{ ++ return dev->parent == data; ++} ++ ++/** ++ * fpga_mgr_get - get an exclusive reference to a fpga mgr ++ * @dev: parent device that fpga mgr was registered with ++ * ++ * Given a device, get an exclusive reference to a fpga mgr. ++ * ++ * Return: fpga manager struct or IS_ERR() condition containing error code. ++ */ ++struct fpga_manager *fpga_mgr_get(struct device *dev) ++{ ++ struct device *mgr_dev = class_find_device(fpga_mgr_class, NULL, dev, ++ fpga_mgr_dev_match); ++ if (!mgr_dev) ++ return ERR_PTR(-ENODEV); ++ ++ return __fpga_mgr_get(mgr_dev); ++} ++EXPORT_SYMBOL_GPL(fpga_mgr_get); ++ ++static int fpga_mgr_of_node_match(struct device *dev, const void *data) ++{ ++ return dev->of_node == data; ++} ++ ++/** ++ * of_fpga_mgr_get - get an exclusive reference to a fpga mgr ++ * @node: device node ++ * ++ * Given a device node, get an exclusive reference to a fpga mgr. ++ * ++ * Return: fpga manager struct or IS_ERR() condition containing error code. ++ */ ++struct fpga_manager *of_fpga_mgr_get(struct device_node *node) ++{ ++ struct device *dev; ++ ++ dev = class_find_device(fpga_mgr_class, NULL, node, ++ fpga_mgr_of_node_match); ++ if (!dev) ++ return ERR_PTR(-ENODEV); ++ ++ return __fpga_mgr_get(dev); ++} + EXPORT_SYMBOL_GPL(of_fpga_mgr_get); + + /** +--- a/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h +@@ -117,6 +117,8 @@ int fpga_mgr_firmware_load(struct fpga_m + + struct fpga_manager *of_fpga_mgr_get(struct device_node *node); + ++struct fpga_manager *fpga_mgr_get(struct device *dev); ++ + void fpga_mgr_put(struct fpga_manager *mgr); + + int fpga_mgr_register(struct device *dev, const char *name, diff --git a/patches.socfpga/0026-doc-fpga-mgr-add-fpga-image-info-to-api.patch b/patches.socfpga/0026-doc-fpga-mgr-add-fpga-image-info-to-api.patch new file mode 100644 index 00000000000000..f7b3d359fc48b0 --- /dev/null +++ b/patches.socfpga/0026-doc-fpga-mgr-add-fpga-image-info-to-api.patch @@ -0,0 +1,110 @@ +From d4a7acc57d114fb9b54dd9dd9a21465393bb90e8 Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:24 -0500 +Subject: [PATCH 026/103] doc: fpga-mgr: add fpga image info to api + +This patch adds a minor change in the FPGA Manager API +to hold information that is specific to an FPGA image +file. This change is expected to bring little, if any, +pain. + +An FPGA image file will have particulars that affect how the +image is programmed to the FPGA. One example is that +current 'flags' currently has one bit which shows whether the +FPGA image was built for full reconfiguration or partial +reconfiguration. Another example is timeout values for +enabling or disabling the bridges in the FPGA. As the +complexity of the FPGA design increases, the bridges in the +FPGA may take longer times to enable or disable. + +This patch documents the change in the FPGA Manager API +functions, replacing the 'u32 flag' parameter with a pointer +to struct fpga_image_info. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + Documentation/fpga/fpga-mgr.txt | 34 ++++++++++++++++++++++------------ + 1 file changed, 22 insertions(+), 12 deletions(-) + +--- a/Documentation/fpga/fpga-mgr.txt ++++ b/Documentation/fpga/fpga-mgr.txt +@@ -18,21 +18,25 @@ API Functions: + To program the FPGA from a file or from a buffer: + ------------------------------------------------- + +- int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, ++ int fpga_mgr_buf_load(struct fpga_manager *mgr, ++ struct fpga_image_info *info, + const char *buf, size_t count); + + Load the FPGA from an image which exists as a buffer in memory. + +- int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags, ++ int fpga_mgr_firmware_load(struct fpga_manager *mgr, ++ struct fpga_image_info *info, + const char *image_name); + + Load the FPGA from an image which exists as a file. The image file must be on +-the firmware search path (see the firmware class documentation). +- +-For both these functions, flags == 0 for normal full reconfiguration or +-FPGA_MGR_PARTIAL_RECONFIG for partial reconfiguration. If successful, the FPGA +-ends up in operating mode. Return 0 on success or a negative error code. +- ++the firmware search path (see the firmware class documentation). If successful, ++the FPGA ends up in operating mode. Return 0 on success or a negative error ++code. ++ ++A FPGA design contained in a FPGA image file will likely have particulars that ++affect how the image is programmed to the FPGA. These are contained in struct ++fpga_image_info. Currently the only such particular is a single flag bit ++indicating whether the image is for full or partial reconfiguration. + + To get/put a reference to a FPGA manager: + ----------------------------------------- +@@ -72,8 +76,11 @@ struct device_node *mgr_node = ... + char *buf = ... + int count = ... + ++/* struct with information about the FPGA image to program. */ ++struct fpga_image_info info; ++ + /* flags indicates whether to do full or partial reconfiguration */ +-int flags = 0; ++info.flags = 0; + + int ret; + +@@ -81,7 +88,7 @@ int ret; + struct fpga_manager *mgr = of_fpga_mgr_get(mgr_node); + + /* Load the buffer to the FPGA */ +-ret = fpga_mgr_buf_load(mgr, flags, buf, count); ++ret = fpga_mgr_buf_load(mgr, &info, buf, count); + + /* Release the FPGA manager */ + fpga_mgr_put(mgr); +@@ -98,8 +105,11 @@ struct device_node *mgr_node = ... + /* FPGA image is in this file which is in the firmware search path */ + const char *path = "fpga-image-9.rbf" + ++/* struct with information about the FPGA image to program. */ ++struct fpga_image_info info; ++ + /* flags indicates whether to do full or partial reconfiguration */ +-int flags = 0; ++info.flags = 0; + + int ret; + +@@ -107,7 +117,7 @@ int ret; + struct fpga_manager *mgr = of_fpga_mgr_get(mgr_node); + + /* Get the firmware image (path) and load it to the FPGA */ +-ret = fpga_mgr_firmware_load(mgr, flags, path); ++ret = fpga_mgr_firmware_load(mgr, &info, path); + + /* Release the FPGA manager */ + fpga_mgr_put(mgr); diff --git a/patches.socfpga/0027-fpga-add-bindings-document-for-fpga-region.patch b/patches.socfpga/0027-fpga-add-bindings-document-for-fpga-region.patch new file mode 100644 index 00000000000000..78d970cc6b351f --- /dev/null +++ b/patches.socfpga/0027-fpga-add-bindings-document-for-fpga-region.patch @@ -0,0 +1,514 @@ +From a3f533d02f5643af9679ef50d4a2ea24d4766924 Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:25 -0500 +Subject: [PATCH 027/103] fpga: add bindings document for fpga region + +New bindings document for FPGA Region to support programming +FPGA's under Device Tree control + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Moritz Fischer <moritz.fischer@ettus.com> +Reviewed-by: Rob Herring <robh@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + Documentation/devicetree/bindings/fpga/fpga-region.txt | 494 +++++++++++++++++ + 1 file changed, 494 insertions(+) + create mode 100644 Documentation/devicetree/bindings/fpga/fpga-region.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/fpga/fpga-region.txt +@@ -0,0 +1,494 @@ ++FPGA Region Device Tree Binding ++ ++Alan Tull 2016 ++ ++ CONTENTS ++ - Introduction ++ - Terminology ++ - Sequence ++ - FPGA Region ++ - Supported Use Models ++ - Device Tree Examples ++ - Constraints ++ ++ ++Introduction ++============ ++ ++FPGA Regions represent FPGA's and partial reconfiguration regions of FPGA's in ++the Device Tree. FPGA Regions provide a way to program FPGAs under device tree ++control. ++ ++This device tree binding document hits some of the high points of FPGA usage and ++attempts to include terminology used by both major FPGA manufacturers. This ++document isn't a replacement for any manufacturers specifications for FPGA ++usage. ++ ++ ++Terminology ++=========== ++ ++Full Reconfiguration ++ * The entire FPGA is programmed. ++ ++Partial Reconfiguration (PR) ++ * A section of an FPGA is reprogrammed while the rest of the FPGA is not ++ affected. ++ * Not all FPGA's support PR. ++ ++Partial Reconfiguration Region (PRR) ++ * Also called a "reconfigurable partition" ++ * A PRR is a specific section of a FPGA reserved for reconfiguration. ++ * A base (or static) FPGA image may create a set of PRR's that later may ++ be independently reprogrammed many times. ++ * The size and specific location of each PRR is fixed. ++ * The connections at the edge of each PRR are fixed. The image that is loaded ++ into a PRR must fit and must use a subset of the region's connections. ++ * The busses within the FPGA are split such that each region gets its own ++ branch that may be gated independently. ++ ++Persona ++ * Also called a "partial bit stream" ++ * An FPGA image that is designed to be loaded into a PRR. There may be ++ any number of personas designed to fit into a PRR, but only one at at time ++ may be loaded. ++ * A persona may create more regions. ++ ++FPGA Bridge ++ * FPGA Bridges gate bus signals between a host and FPGA. ++ * FPGA Bridges should be disabled while the FPGA is being programmed to ++ prevent spurious signals on the cpu bus and to the soft logic. ++ * FPGA bridges may be actual hardware or soft logic on an FPGA. ++ * During Full Reconfiguration, hardware bridges between the host and FPGA ++ will be disabled. ++ * During Partial Reconfiguration of a specific region, that region's bridge ++ will be used to gate the busses. Traffic to other regions is not affected. ++ * In some implementations, the FPGA Manager transparantly handles gating the ++ buses, eliminating the need to show the hardware FPGA bridges in the ++ device tree. ++ * An FPGA image may create a set of reprogrammable regions, each having its ++ own bridge and its own split of the busses in the FPGA. ++ ++FPGA Manager ++ * An FPGA Manager is a hardware block that programs an FPGA under the control ++ of a host processor. ++ ++Base Image ++ * Also called the "static image" ++ * An FPGA image that is designed to do full reconfiguration of the FPGA. ++ * A base image may set up a set of partial reconfiguration regions that may ++ later be reprogrammed. ++ ++ ---------------- ---------------------------------- ++ | Host CPU | | FPGA | ++ | | | | ++ | ----| | ----------- -------- | ++ | | H | | |==>| Bridge0 |<==>| PRR0 | | ++ | | W | | | ----------- -------- | ++ | | | | | | ++ | | B |<=====>|<==| ----------- -------- | ++ | | R | | |==>| Bridge1 |<==>| PRR1 | | ++ | | I | | | ----------- -------- | ++ | | D | | | | ++ | | G | | | ----------- -------- | ++ | | E | | |==>| Bridge2 |<==>| PRR2 | | ++ | ----| | ----------- -------- | ++ | | | | ++ ---------------- ---------------------------------- ++ ++Figure 1: An FPGA set up with a base image that created three regions. Each ++region (PRR0-2) gets its own split of the busses that is independently gated by ++a soft logic bridge (Bridge0-2) in the FPGA. The contents of each PRR can be ++reprogrammed independently while the rest of the system continues to function. ++ ++ ++Sequence ++======== ++ ++When a DT overlay that targets a FPGA Region is applied, the FPGA Region will ++do the following: ++ ++ 1. Disable appropriate FPGA bridges. ++ 2. Program the FPGA using the FPGA manager. ++ 3. Enable the FPGA bridges. ++ 4. The Device Tree overlay is accepted into the live tree. ++ 5. Child devices are populated. ++ ++When the overlay is removed, the child nodes will be removed and the FPGA Region ++will disable the bridges. ++ ++ ++FPGA Region ++=========== ++ ++FPGA Regions represent FPGA's and FPGA PR regions in the device tree. An FPGA ++Region brings together the elements needed to program on a running system and ++add the child devices: ++ ++ * FPGA Manager ++ * FPGA Bridges ++ * image-specific information needed to to the programming. ++ * child nodes ++ ++The intended use is that a Device Tree overlay (DTO) can be used to reprogram an ++FPGA while an operating system is running. ++ ++An FPGA Region that exists in the live Device Tree reflects the current state. ++If the live tree shows a "firmware-name" property or child nodes under a FPGA ++Region, the FPGA already has been programmed. A DTO that targets a FPGA Region ++and adds the "firmware-name" property is taken as a request to reprogram the ++FPGA. After reprogramming is successful, the overlay is accepted into the live ++tree. ++ ++The base FPGA Region in the device tree represents the FPGA and supports full ++reconfiguration. It must include a phandle to an FPGA Manager. The base ++FPGA region will be the child of one of the hardware bridges (the bridge that ++allows register access) between the cpu and the FPGA. If there are more than ++one bridge to control during FPGA programming, the region will also contain a ++list of phandles to the additional hardware FPGA Bridges. ++ ++For partial reconfiguration (PR), each PR region will have an FPGA Region. ++These FPGA regions are children of FPGA bridges which are then children of the ++base FPGA region. The "Full Reconfiguration to add PRR's" example below shows ++this. ++ ++If an FPGA Region does not specify a FPGA Manager, it will inherit the FPGA ++Manager specified by its ancestor FPGA Region. This supports both the case ++where the same FPGA Manager is used for all of a FPGA as well the case where ++a different FPGA Manager is used for each region. ++ ++FPGA Regions do not inherit their ancestor FPGA regions' bridges. This prevents ++shutting down bridges that are upstream from the other active regions while one ++region is getting reconfigured (see Figure 1 above). During PR, the FPGA's ++hardware bridges remain enabled. The PR regions' bridges will be FPGA bridges ++within the static image of the FPGA. ++ ++Required properties: ++- compatible : should contain "fpga-region" ++- fpga-mgr : should contain a phandle to an FPGA Manager. Child FPGA Regions ++ inherit this property from their ancestor regions. A fpga-mgr property ++ in a region will override any inherited FPGA manager. ++- #address-cells, #size-cells, ranges : must be present to handle address space ++ mapping for child nodes. ++ ++Optional properties: ++- firmware-name : should contain the name of an FPGA image file located on the ++ firmware search path. If this property shows up in a live device tree ++ it indicates that the FPGA has already been programmed with this image. ++ If this property is in an overlay targeting a FPGA region, it is a ++ request to program the FPGA with that image. ++- fpga-bridges : should contain a list of phandles to FPGA Bridges that must be ++ controlled during FPGA programming along with the parent FPGA bridge. ++ This property is optional if the FPGA Manager handles the bridges. ++ If the fpga-region is the child of a fpga-bridge, the list should not ++ contain the parent bridge. ++- partial-fpga-config : boolean, set if partial reconfiguration is to be done, ++ otherwise full reconfiguration is done. ++- external-fpga-config : boolean, set if the FPGA has already been configured ++ prior to OS boot up. ++- region-unfreeze-timeout-us : The maximum time in microseconds to wait for ++ bridges to successfully become enabled after the region has been ++ programmed. ++- region-freeze-timeout-us : The maximum time in microseconds to wait for ++ bridges to successfully become disabled before the region has been ++ programmed. ++- child nodes : devices in the FPGA after programming. ++ ++In the example below, when an overlay is applied targeting fpga-region0, ++fpga_mgr is used to program the FPGA. Two bridges are controlled during ++programming: the parent fpga_bridge0 and fpga_bridge1. Because the region is ++the child of fpga_bridge0, only fpga_bridge1 needs to be specified in the ++fpga-bridges property. During programming, these bridges are disabled, the ++firmware specified in the overlay is loaded to the FPGA using the FPGA manager ++specified in the region. If FPGA programming succeeds, the bridges are ++reenabled and the overlay makes it into the live device tree. The child devices ++are then populated. If FPGA programming fails, the bridges are left disabled ++and the overlay is rejected. The overlay's ranges property maps the lwhps ++bridge's region (0xff200000) and the hps bridge's region (0xc0000000) for use by ++the two child devices. ++ ++Example: ++Base tree contains: ++ ++ fpga_mgr: fpga-mgr@ff706000 { ++ compatible = "altr,socfpga-fpga-mgr"; ++ reg = <0xff706000 0x1000 ++ 0xffb90000 0x20>; ++ interrupts = <0 175 4>; ++ }; ++ ++ fpga_bridge0: fpga-bridge@ff400000 { ++ compatible = "altr,socfpga-lwhps2fpga-bridge"; ++ reg = <0xff400000 0x100000>; ++ resets = <&rst LWHPS2FPGA_RESET>; ++ clocks = <&l4_main_clk>; ++ ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ fpga_region0: fpga-region0 { ++ compatible = "fpga-region"; ++ fpga-mgr = <&fpga_mgr>; ++ }; ++ }; ++ ++ fpga_bridge1: fpga-bridge@ff500000 { ++ compatible = "altr,socfpga-hps2fpga-bridge"; ++ reg = <0xff500000 0x10000>; ++ resets = <&rst HPS2FPGA_RESET>; ++ clocks = <&l4_main_clk>; ++ }; ++ ++Overlay contains: ++ ++/dts-v1/ /plugin/; ++/ { ++ fragment@0 { ++ target = <&fpga_region0>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ firmware-name = "soc_system.rbf"; ++ fpga-bridges = <&fpga_bridge1>; ++ ranges = <0x20000 0xff200000 0x100000>, ++ <0x0 0xc0000000 0x20000000>; ++ ++ gpio@10040 { ++ compatible = "altr,pio-1.0"; ++ reg = <0x10040 0x20>; ++ altr,gpio-bank-width = <4>; ++ #gpio-cells = <2>; ++ clocks = <2>; ++ gpio-controller; ++ }; ++ ++ onchip-memory { ++ device_type = "memory"; ++ compatible = "altr,onchipmem-15.1"; ++ reg = <0x0 0x10000>; ++ }; ++ }; ++ }; ++}; ++ ++ ++Supported Use Models ++==================== ++ ++In all cases the live DT must have the FPGA Manager, FPGA Bridges (if any), and ++a FPGA Region. The target of the Device Tree Overlay is the FPGA Region. Some ++uses are specific to a FPGA device. ++ ++ * No FPGA Bridges ++ In this case, the FPGA Manager which programs the FPGA also handles the ++ bridges behind the scenes. No FPGA Bridge devices are needed for full ++ reconfiguration. ++ ++ * Full reconfiguration with hardware bridges ++ In this case, there are hardware bridges between the processor and FPGA that ++ need to be controlled during full reconfiguration. Before the overlay is ++ applied, the live DT must include the FPGA Manager, FPGA Bridges, and a ++ FPGA Region. The FPGA Region is the child of the bridge that allows ++ register access to the FPGA. Additional bridges may be listed in a ++ fpga-bridges property in the FPGA region or in the device tree overlay. ++ ++ * Partial reconfiguration with bridges in the FPGA ++ In this case, the FPGA will have one or more PRR's that may be programmed ++ separately while the rest of the FPGA can remain active. To manage this, ++ bridges need to exist in the FPGA that can gate the buses going to each FPGA ++ region while the buses are enabled for other sections. Before any partial ++ reconfiguration can be done, a base FPGA image must be loaded which includes ++ PRR's with FPGA bridges. The device tree should have a FPGA region for each ++ PRR. ++ ++Device Tree Examples ++==================== ++ ++The intention of this section is to give some simple examples, focusing on ++the placement of the elements detailed above, especially: ++ * FPGA Manager ++ * FPGA Bridges ++ * FPGA Region ++ * ranges ++ * target-path or target ++ ++For the purposes of this section, I'm dividing the Device Tree into two parts, ++each with its own requirements. The two parts are: ++ * The live DT prior to the overlay being added ++ * The DT overlay ++ ++The live Device Tree must contain an FPGA Region, an FPGA Manager, and any FPGA ++Bridges. The FPGA Region's "fpga-mgr" property specifies the manager by phandle ++to handle programming the FPGA. If the FPGA Region is the child of another FPGA ++Region, the parent's FPGA Manager is used. If FPGA Bridges need to be involved, ++they are specified in the FPGA Region by the "fpga-bridges" property. During ++FPGA programming, the FPGA Region will disable the bridges that are in its ++"fpga-bridges" list and will re-enable them after FPGA programming has ++succeeded. ++ ++The Device Tree Overlay will contain: ++ * "target-path" or "target" ++ The insertion point where the the contents of the overlay will go into the ++ live tree. target-path is a full path, while target is a phandle. ++ * "ranges" ++ The address space mapping from processor to FPGA bus(ses). ++ * "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-fpga-config" ++ 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. ++ ++Device Tree Example: Full Reconfiguration without Bridges ++========================================================= ++ ++Live Device Tree contains: ++ fpga_mgr0: fpga-mgr@f8007000 { ++ compatible = "xlnx,zynq-devcfg-1.0"; ++ reg = <0xf8007000 0x100>; ++ interrupt-parent = <&intc>; ++ interrupts = <0 8 4>; ++ clocks = <&clkc 12>; ++ clock-names = "ref_clk"; ++ syscon = <&slcr>; ++ }; ++ ++ fpga_region0: fpga-region0 { ++ compatible = "fpga-region"; ++ fpga-mgr = <&fpga_mgr0>; ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ ranges; ++ }; ++ ++DT Overlay contains: ++/dts-v1/ /plugin/; ++/ { ++fragment@0 { ++ target = <&fpga_region0>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ firmware-name = "zynq-gpio.bin"; ++ ++ gpio1: gpio@40000000 { ++ compatible = "xlnx,xps-gpio-1.00.a"; ++ reg = <0x40000000 0x10000>; ++ gpio-controller; ++ #gpio-cells = <0x2>; ++ xlnx,gpio-width= <0x6>; ++ }; ++ }; ++}; ++ ++Device Tree Example: Full Reconfiguration to add PRR's ++====================================================== ++ ++The base FPGA Region is specified similar to the first example above. ++ ++This example programs the FPGA to have two regions that can later be partially ++configured. Each region has its own bridge in the FPGA fabric. ++ ++DT Overlay contains: ++/dts-v1/ /plugin/; ++/ { ++ fragment@0 { ++ target = <&fpga_region0>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ firmware-name = "base.rbf"; ++ ++ fpga-bridge@4400 { ++ compatible = "altr,freeze-bridge"; ++ reg = <0x4400 0x10>; ++ ++ fpga_region1: fpga-region1 { ++ compatible = "fpga-region"; ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ ranges; ++ }; ++ }; ++ ++ fpga-bridge@4420 { ++ compatible = "altr,freeze-bridge"; ++ reg = <0x4420 0x10>; ++ ++ fpga_region2: fpga-region2 { ++ compatible = "fpga-region"; ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ ranges; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++Device Tree Example: Partial Reconfiguration ++============================================ ++ ++This example reprograms one of the PRR's set up in the previous example. ++ ++The sequence that occurs when this overlay is similar to the above, the only ++differences are that the FPGA is partially reconfigured due to the ++"partial-fpga-config" boolean and the only bridge that is controlled during ++programming is the FPGA based bridge of fpga_region1. ++ ++/dts-v1/ /plugin/; ++/ { ++ fragment@0 { ++ target = <&fpga_region1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ firmware-name = "soc_image2.rbf"; ++ partial-fpga-config; ++ ++ gpio@10040 { ++ compatible = "altr,pio-1.0"; ++ reg = <0x10040 0x20>; ++ clocks = <0x2>; ++ altr,gpio-bank-width = <0x4>; ++ resetvalue = <0x0>; ++ #gpio-cells = <0x2>; ++ gpio-controller; ++ }; ++ }; ++ }; ++}; ++ ++Constraints ++=========== ++ ++It is beyond the scope of this document to fully describe all the FPGA design ++constraints required to make partial reconfiguration work[1] [2] [3], but a few ++deserve quick mention. ++ ++A persona must have boundary connections that line up with those of the partion ++or region it is designed to go into. ++ ++During programming, transactions through those connections must be stopped and ++the connections must be held at a fixed logic level. This can be achieved by ++FPGA Bridges that exist on the FPGA fabric prior to the partial reconfiguration. ++ ++-- ++[1] www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ug/ug_partrecon.pdf ++[2] tspace.library.utoronto.ca/bitstream/1807/67932/1/Byma_Stuart_A_201411_MAS_thesis.pdf ++[3] http://www.xilinx.com/support/documentation/sw_manuals/xilinx14_1/ug702.pdf diff --git a/patches.socfpga/0028-fpga-mgr-add-fpga-image-information-struct.patch b/patches.socfpga/0028-fpga-mgr-add-fpga-image-information-struct.patch new file mode 100644 index 00000000000000..c0283f582a8dbb --- /dev/null +++ b/patches.socfpga/0028-fpga-mgr-add-fpga-image-information-struct.patch @@ -0,0 +1,224 @@ +From dcc67124b4337a29ce04452a177953b3ff14b87a Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:26 -0500 +Subject: [PATCH 028/103] fpga-mgr: add fpga image information struct + +This patch adds a minor change in the FPGA Manager API +to hold information that is specific to an FPGA image +file. This change is expected to bring little, if any, +pain. The socfpga and zynq drivers are fixed up in +this patch. + +An FPGA image file will have particulars that affect how the +image is programmed to the FPGA. One example is that +current 'flags' currently has one bit which shows whether the +FPGA image was built for full reconfiguration or partial +reconfiguration. Another example is timeout values for +enabling or disabling the bridges in the FPGA. As the +complexity of the FPGA design increases, the bridges in the +FPGA may take longer times to enable or disable. + +This patch adds a new 'struct fpga_image_info', moves the +current 'u32 flags' to it. Two other image-specific u32's +are added for the bridge enable/disable timeouts. The FPGA +Manager API functions are changed, replacing the 'u32 flag' +parameter with a pointer to struct fpga_image_info. +Subsequent patches fix the existing low level FPGA manager +drivers. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/fpga-mgr.c | 17 +++++++++-------- + drivers/fpga/socfpga.c | 7 ++++--- + drivers/fpga/zynq-fpga.c | 10 ++++++---- + include/linux/fpga/fpga-mgr.h | 23 +++++++++++++++++++---- + 4 files changed, 38 insertions(+), 19 deletions(-) + +--- a/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c +@@ -32,7 +32,7 @@ static struct class *fpga_mgr_class; + /** + * fpga_mgr_buf_load - load fpga from image in buffer + * @mgr: fpga manager +- * @flags: flags setting fpga confuration modes ++ * @info: fpga image specific information + * @buf: buffer contain fpga image + * @count: byte count of buf + * +@@ -44,8 +44,8 @@ static struct class *fpga_mgr_class; + * + * Return: 0 on success, negative error code otherwise. + */ +-int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, const char *buf, +- size_t count) ++int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, ++ const char *buf, size_t count) + { + struct device *dev = &mgr->dev; + int ret; +@@ -56,7 +56,7 @@ int fpga_mgr_buf_load(struct fpga_manage + * ready to receive an FPGA image. + */ + mgr->state = FPGA_MGR_STATE_WRITE_INIT; +- ret = mgr->mops->write_init(mgr, flags, buf, count); ++ ret = mgr->mops->write_init(mgr, info, buf, count); + if (ret) { + dev_err(dev, "Error preparing FPGA for writing\n"); + mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR; +@@ -79,7 +79,7 @@ int fpga_mgr_buf_load(struct fpga_manage + * steps to finish and set the FPGA into operating mode. + */ + mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE; +- ret = mgr->mops->write_complete(mgr, flags); ++ ret = mgr->mops->write_complete(mgr, info); + if (ret) { + dev_err(dev, "Error after writing image data to FPGA\n"); + mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR; +@@ -94,7 +94,7 @@ EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); + /** + * fpga_mgr_firmware_load - request firmware and load to fpga + * @mgr: fpga manager +- * @flags: flags setting fpga confuration modes ++ * @info: fpga image specific information + * @image_name: name of image file on the firmware search path + * + * Request an FPGA image using the firmware class, then write out to the FPGA. +@@ -105,7 +105,8 @@ EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); + * + * Return: 0 on success, negative error code otherwise. + */ +-int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags, ++int fpga_mgr_firmware_load(struct fpga_manager *mgr, ++ struct fpga_image_info *info, + const char *image_name) + { + struct device *dev = &mgr->dev; +@@ -123,7 +124,7 @@ int fpga_mgr_firmware_load(struct fpga_m + return ret; + } + +- ret = fpga_mgr_buf_load(mgr, flags, fw->data, fw->size); ++ ret = fpga_mgr_buf_load(mgr, info, fw->data, fw->size); + + release_firmware(fw); + +--- a/drivers/fpga/socfpga.c ++++ b/drivers/fpga/socfpga.c +@@ -407,13 +407,14 @@ static int socfpga_fpga_reset(struct fpg + /* + * Prepare the FPGA to receive the configuration data. + */ +-static int socfpga_fpga_ops_configure_init(struct fpga_manager *mgr, u32 flags, ++static int socfpga_fpga_ops_configure_init(struct fpga_manager *mgr, ++ struct fpga_image_info *info, + const char *buf, size_t count) + { + struct socfpga_fpga_priv *priv = mgr->priv; + int ret; + +- if (flags & FPGA_MGR_PARTIAL_RECONFIG) { ++ if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { + dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); + return -EINVAL; + } +@@ -478,7 +479,7 @@ static int socfpga_fpga_ops_configure_wr + } + + static int socfpga_fpga_ops_configure_complete(struct fpga_manager *mgr, +- u32 flags) ++ struct fpga_image_info *info) + { + struct socfpga_fpga_priv *priv = mgr->priv; + u32 status; +--- a/drivers/fpga/zynq-fpga.c ++++ b/drivers/fpga/zynq-fpga.c +@@ -175,7 +175,8 @@ static irqreturn_t zynq_fpga_isr(int irq + return IRQ_HANDLED; + } + +-static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags, ++static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, ++ struct fpga_image_info *info, + const char *buf, size_t count) + { + struct zynq_fpga_priv *priv; +@@ -189,7 +190,7 @@ static int zynq_fpga_ops_write_init(stru + return err; + + /* don't globally reset PL if we're doing partial reconfig */ +- if (!(flags & FPGA_MGR_PARTIAL_RECONFIG)) { ++ if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { + /* assert AXI interface resets */ + regmap_write(priv->slcr, SLCR_FPGA_RST_CTRL_OFFSET, + FPGA_RST_ALL_MASK); +@@ -343,7 +344,8 @@ out_free: + return err; + } + +-static int zynq_fpga_ops_write_complete(struct fpga_manager *mgr, u32 flags) ++static int zynq_fpga_ops_write_complete(struct fpga_manager *mgr, ++ struct fpga_image_info *info) + { + struct zynq_fpga_priv *priv = mgr->priv; + int err; +@@ -364,7 +366,7 @@ static int zynq_fpga_ops_write_complete( + return err; + + /* for the partial reconfig case we didn't touch the level shifters */ +- if (!(flags & FPGA_MGR_PARTIAL_RECONFIG)) { ++ if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { + /* enable level shifters from PL to PS */ + regmap_write(priv->slcr, SLCR_LVL_SHFTR_EN_OFFSET, + LVL_SHFTR_ENABLE_PL_TO_PS); +--- a/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h +@@ -69,6 +69,18 @@ enum fpga_mgr_states { + #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + + /** ++ * struct fpga_image_info - information specific to a FPGA image ++ * @flags: boolean flags as defined above ++ * @enable_timeout_us: maximum time to enable traffic through bridge (uSec) ++ * @disable_timeout_us: maximum time to disable traffic through bridge (uSec) ++ */ ++struct fpga_image_info { ++ u32 flags; ++ u32 enable_timeout_us; ++ u32 disable_timeout_us; ++}; ++ ++/** + * struct fpga_manager_ops - ops for low level fpga manager drivers + * @state: returns an enum value of the FPGA's state + * @write_init: prepare the FPGA to receive confuration data +@@ -82,10 +94,12 @@ enum fpga_mgr_states { + */ + struct fpga_manager_ops { + enum fpga_mgr_states (*state)(struct fpga_manager *mgr); +- int (*write_init)(struct fpga_manager *mgr, u32 flags, ++ int (*write_init)(struct fpga_manager *mgr, ++ struct fpga_image_info *info, + const char *buf, size_t count); + int (*write)(struct fpga_manager *mgr, const char *buf, size_t count); +- int (*write_complete)(struct fpga_manager *mgr, u32 flags); ++ int (*write_complete)(struct fpga_manager *mgr, ++ struct fpga_image_info *info); + void (*fpga_remove)(struct fpga_manager *mgr); + }; + +@@ -109,10 +123,11 @@ struct fpga_manager { + + #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev) + +-int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, ++int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, + const char *buf, size_t count); + +-int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags, ++int fpga_mgr_firmware_load(struct fpga_manager *mgr, ++ struct fpga_image_info *info, + const char *image_name); + + struct fpga_manager *of_fpga_mgr_get(struct device_node *node); diff --git a/patches.socfpga/0029-add-sysfs-document-for-fpga-bridge-class.patch b/patches.socfpga/0029-add-sysfs-document-for-fpga-bridge-class.patch new file mode 100644 index 00000000000000..9fe70d9c7c4810 --- /dev/null +++ b/patches.socfpga/0029-add-sysfs-document-for-fpga-bridge-class.patch @@ -0,0 +1,29 @@ +From 61dfd4be91d2b0b62631b47d6fe2e775b97ca990 Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:27 -0500 +Subject: [PATCH 029/103] add sysfs document for fpga bridge class + +Add documentation for new FPGA bridge class's sysfs interface. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + Documentation/ABI/testing/sysfs-class-fpga-bridge | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 Documentation/ABI/testing/sysfs-class-fpga-bridge + +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-class-fpga-bridge +@@ -0,0 +1,11 @@ ++What: /sys/class/fpga_bridge/<bridge>/name ++Date: January 2016 ++KernelVersion: 4.5 ++Contact: Alan Tull <atull@opensource.altera.com> ++Description: Name of low level FPGA bridge driver. ++ ++What: /sys/class/fpga_bridge/<bridge>/state ++Date: January 2016 ++KernelVersion: 4.5 ++Contact: Alan Tull <atull@opensource.altera.com> ++Description: Show bridge state as "enabled" or "disabled" diff --git a/patches.socfpga/0030-fpga-add-fpga-bridge-framework.patch b/patches.socfpga/0030-fpga-add-fpga-bridge-framework.patch new file mode 100644 index 00000000000000..5a582d3cc3ac63 --- /dev/null +++ b/patches.socfpga/0030-fpga-add-fpga-bridge-framework.patch @@ -0,0 +1,534 @@ +From 2649550bc9bf2246dfe843874012c7cf621bdfca Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:28 -0500 +Subject: [PATCH 030/103] fpga: add fpga bridge framework + +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 <atull@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 7 + drivers/fpga/Makefile | 3 + drivers/fpga/fpga-bridge.c | 395 +++++++++++++++++++++++++++++++++++++++ + include/linux/fpga/fpga-bridge.h | 60 +++++ + 4 files changed, 465 insertions(+) + create mode 100644 drivers/fpga/fpga-bridge.c + create mode 100644 include/linux/fpga/fpga-bridge.h + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -26,6 +26,13 @@ config FPGA_MGR_ZYNQ_FPGA + help + FPGA manager driver support for Xilinx Zynq FPGAs. + ++config FPGA_BRIDGE ++ tristate "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 +--- 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 +--- /dev/null ++++ b/drivers/fpga/fpga-bridge.c +@@ -0,0 +1,395 @@ ++/* ++ * FPGA Bridge Framework Driver ++ * ++ * Copyright (C) 2013-2016 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 ++ * @info: fpga image specific information ++ * ++ * 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 fpga_image_info *info) ++ ++{ ++ struct device *dev; ++ struct fpga_bridge *bridge; ++ int ret = -ENODEV; ++ ++ 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; ++ ++ bridge->info = info; ++ ++ 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); ++ 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"); ++ ++ bridge->info = NULL; ++ 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 ++ * @info: fpga image specific information ++ * @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 fpga_image_info *info, ++ struct list_head *bridge_list) ++{ ++ struct fpga_bridge *bridge; ++ unsigned long flags; ++ ++ bridge = of_fpga_bridge_get(np, info); ++ 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; ++ ++ of_platform_populate(dev->of_node, NULL, NULL, dev); ++ ++ 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 <atull@opensource.altera.com>"); ++MODULE_LICENSE("GPL v2"); ++ ++subsys_initcall(fpga_bridge_dev_init); ++module_exit(fpga_bridge_dev_exit); +--- /dev/null ++++ b/include/linux/fpga/fpga-bridge.h +@@ -0,0 +1,60 @@ ++#include <linux/device.h> ++#include <linux/fpga/fpga-mgr.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 ++ * @info: fpga image specific information ++ * @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 fpga_image_info *info; ++ struct list_head node; ++ void *priv; ++}; ++ ++#define to_fpga_bridge(d) container_of(d, struct fpga_bridge, dev) ++ ++struct fpga_bridge *of_fpga_bridge_get(struct device_node *node, ++ struct fpga_image_info *info); ++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 fpga_image_info *info, ++ 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 */ diff --git a/patches.socfpga/0031-fpga-fpga-region-device-tree-control-for-FPGA.patch b/patches.socfpga/0031-fpga-fpga-region-device-tree-control-for-FPGA.patch new file mode 100644 index 00000000000000..e69a9ba70e42be --- /dev/null +++ b/patches.socfpga/0031-fpga-fpga-region-device-tree-control-for-FPGA.patch @@ -0,0 +1,662 @@ +From 1959ad1708f7ec01af7377787b9e117e2eae61f8 Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:29 -0500 +Subject: [PATCH 031/103] fpga: fpga-region: device tree control for FPGA + +FPGA Regions support programming FPGA under control of the Device +Tree. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 7 + drivers/fpga/Makefile | 3 + drivers/fpga/fpga-region.c | 603 ++++++++++++++++++++++++++++++++++++++++++ + include/linux/fpga/fpga-mgr.h | 2 + 4 files changed, 615 insertions(+) + create mode 100644 drivers/fpga/fpga-region.c + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -13,6 +13,13 @@ config FPGA + + if FPGA + ++config FPGA_REGION ++ tristate "FPGA Region" ++ depends on OF && FPGA_BRIDGE ++ help ++ FPGA Regions allow loading FPGA images under control of ++ the Device Tree. ++ + config FPGA_MGR_SOCFPGA + tristate "Altera SOCFPGA FPGA Manager" + depends on ARCH_SOCFPGA +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -11,3 +11,6 @@ obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq + + # FPGA Bridge Drivers + obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o ++ ++# High Level Interfaces ++obj-$(CONFIG_FPGA_REGION) += fpga-region.o +--- /dev/null ++++ b/drivers/fpga/fpga-region.c +@@ -0,0 +1,603 @@ ++/* ++ * FPGA Region - Device Tree support for FPGA programming under Linux ++ * ++ * Copyright (C) 2013-2016 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/idr.h> ++#include <linux/kernel.h> ++#include <linux/list.h> ++#include <linux/module.h> ++#include <linux/of_platform.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++ ++/** ++ * struct fpga_region - FPGA Region structure ++ * @dev: FPGA Region device ++ * @mutex: enforces exclusive reference to region ++ * @bridge_list: list of FPGA bridges specified in region ++ * @info: fpga image specific information ++ */ ++struct fpga_region { ++ struct device dev; ++ struct mutex mutex; /* for exclusive reference to region */ ++ struct list_head bridge_list; ++ struct fpga_image_info *info; ++}; ++ ++#define to_fpga_region(d) container_of(d, struct fpga_region, dev) ++ ++static DEFINE_IDA(fpga_region_ida); ++static struct class *fpga_region_class; ++ ++static const struct of_device_id fpga_region_of_match[] = { ++ { .compatible = "fpga-region", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, fpga_region_of_match); ++ ++static int fpga_region_of_node_match(struct device *dev, const void *data) ++{ ++ return dev->of_node == data; ++} ++ ++/** ++ * fpga_region_find - find FPGA region ++ * @np: device node of FPGA Region ++ * Caller will need to put_device(®ion->dev) when done. ++ * Returns FPGA Region struct or NULL ++ */ ++static struct fpga_region *fpga_region_find(struct device_node *np) ++{ ++ struct device *dev; ++ ++ dev = class_find_device(fpga_region_class, NULL, np, ++ fpga_region_of_node_match); ++ if (!dev) ++ return NULL; ++ ++ return to_fpga_region(dev); ++} ++ ++/** ++ * fpga_region_get - get an exclusive reference to a fpga region ++ * @region: FPGA Region struct ++ * ++ * Caller should call fpga_region_put() when done with region. ++ * ++ * Return fpga_region struct if successful. ++ * Return -EBUSY if someone already has a reference to the region. ++ * Return -ENODEV if @np is not a FPGA Region. ++ */ ++static struct fpga_region *fpga_region_get(struct fpga_region *region) ++{ ++ struct device *dev = ®ion->dev; ++ ++ if (!mutex_trylock(®ion->mutex)) { ++ dev_dbg(dev, "%s: FPGA Region already in use\n", __func__); ++ return ERR_PTR(-EBUSY); ++ } ++ ++ get_device(dev); ++ of_node_get(dev->of_node); ++ if (!try_module_get(dev->parent->driver->owner)) { ++ of_node_put(dev->of_node); ++ put_device(dev); ++ mutex_unlock(®ion->mutex); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ dev_dbg(®ion->dev, "get\n"); ++ ++ return region; ++} ++ ++/** ++ * fpga_region_put - release a reference to a region ++ * ++ * @region: FPGA region ++ */ ++static void fpga_region_put(struct fpga_region *region) ++{ ++ struct device *dev = ®ion->dev; ++ ++ dev_dbg(®ion->dev, "put\n"); ++ ++ module_put(dev->parent->driver->owner); ++ of_node_put(dev->of_node); ++ put_device(dev); ++ mutex_unlock(®ion->mutex); ++} ++ ++/** ++ * fpga_region_get_manager - get exclusive reference for FPGA manager ++ * @region: FPGA region ++ * ++ * Get FPGA Manager from "fpga-mgr" property or from ancestor region. ++ * ++ * Caller should call fpga_mgr_put() when done with manager. ++ * ++ * Return: fpga manager struct or IS_ERR() condition containing error code. ++ */ ++static struct fpga_manager *fpga_region_get_manager(struct fpga_region *region) ++{ ++ struct device *dev = ®ion->dev; ++ struct device_node *np = dev->of_node; ++ struct device_node *mgr_node; ++ struct fpga_manager *mgr; ++ ++ of_node_get(np); ++ while (np) { ++ if (of_device_is_compatible(np, "fpga-region")) { ++ mgr_node = of_parse_phandle(np, "fpga-mgr", 0); ++ if (mgr_node) { ++ mgr = of_fpga_mgr_get(mgr_node); ++ of_node_put(np); ++ return mgr; ++ } ++ } ++ np = of_get_next_parent(np); ++ } ++ of_node_put(np); ++ ++ return ERR_PTR(-EINVAL); ++} ++ ++/** ++ * fpga_region_get_bridges - create a list of bridges ++ * @region: FPGA region ++ * @overlay: device node of the overlay ++ * ++ * Create a list of bridges including the parent bridge and the bridges ++ * specified by "fpga-bridges" property. Note that the ++ * fpga_bridges_enable/disable/put functions are all fine with an empty list ++ * if that happens. ++ * ++ * Caller should call fpga_bridges_put(®ion->bridge_list) when ++ * done with the bridges. ++ * ++ * Return 0 for success (even if there are no bridges specified) ++ * or -EBUSY if any of the bridges are in use. ++ */ ++static int fpga_region_get_bridges(struct fpga_region *region, ++ struct device_node *overlay) ++{ ++ struct device *dev = ®ion->dev; ++ struct device_node *region_np = dev->of_node; ++ struct device_node *br, *np, *parent_br = NULL; ++ int i, ret; ++ ++ /* If parent is a bridge, add to list */ ++ ret = fpga_bridge_get_to_list(region_np->parent, region->info, ++ ®ion->bridge_list); ++ if (ret == -EBUSY) ++ return ret; ++ ++ if (!ret) ++ parent_br = region_np->parent; ++ ++ /* If overlay has a list of bridges, use it. */ ++ if (of_parse_phandle(overlay, "fpga-bridges", 0)) ++ np = overlay; ++ else ++ np = region_np; ++ ++ for (i = 0; ; i++) { ++ br = of_parse_phandle(np, "fpga-bridges", i); ++ if (!br) ++ break; ++ ++ /* If parent bridge is in list, skip it. */ ++ if (br == parent_br) ++ continue; ++ ++ /* If node is a bridge, get it and add to list */ ++ ret = fpga_bridge_get_to_list(br, region->info, ++ ®ion->bridge_list); ++ ++ /* If any of the bridges are in use, give up */ ++ if (ret == -EBUSY) { ++ fpga_bridges_put(®ion->bridge_list); ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * fpga_region_program_fpga - program FPGA ++ * @region: FPGA region ++ * @firmware_name: name of FPGA image firmware file ++ * @overlay: device node of the overlay ++ * Program an FPGA using information in the device tree. ++ * Function assumes that there is a firmware-name property. ++ * Return 0 for success or negative error code. ++ */ ++static int fpga_region_program_fpga(struct fpga_region *region, ++ const char *firmware_name, ++ struct device_node *overlay) ++{ ++ struct fpga_manager *mgr; ++ int ret; ++ ++ region = fpga_region_get(region); ++ if (IS_ERR(region)) { ++ pr_err("failed to get fpga region\n"); ++ return PTR_ERR(region); ++ } ++ ++ mgr = fpga_region_get_manager(region); ++ if (IS_ERR(mgr)) { ++ pr_err("failed to get fpga region manager\n"); ++ return PTR_ERR(mgr); ++ } ++ ++ ret = fpga_region_get_bridges(region, overlay); ++ if (ret) { ++ pr_err("failed to get fpga region bridges\n"); ++ goto err_put_mgr; ++ } ++ ++ ret = fpga_bridges_disable(®ion->bridge_list); ++ if (ret) { ++ pr_err("failed to disable region bridges\n"); ++ goto err_put_br; ++ } ++ ++ ret = fpga_mgr_firmware_load(mgr, region->info, firmware_name); ++ if (ret) { ++ pr_err("failed to load fpga image\n"); ++ goto err_put_br; ++ } ++ ++ ret = fpga_bridges_enable(®ion->bridge_list); ++ if (ret) { ++ pr_err("failed to enable region bridges\n"); ++ goto err_put_br; ++ } ++ ++ fpga_mgr_put(mgr); ++ fpga_region_put(region); ++ ++ return 0; ++ ++err_put_br: ++ fpga_bridges_put(®ion->bridge_list); ++err_put_mgr: ++ fpga_mgr_put(mgr); ++ fpga_region_put(region); ++ ++ return ret; ++} ++ ++/** ++ * child_regions_with_firmware ++ * @overlay: device node of the overlay ++ * ++ * If the overlay adds child FPGA regions, they are not allowed to have ++ * firmware-name property. ++ * ++ * Return 0 for OK or -EINVAL if child FPGA region adds firmware-name. ++ */ ++static int child_regions_with_firmware(struct device_node *overlay) ++{ ++ struct device_node *child_region; ++ const char *child_firmware_name; ++ int ret = 0; ++ ++ of_node_get(overlay); ++ ++ child_region = of_find_matching_node(overlay, fpga_region_of_match); ++ while (child_region) { ++ if (!of_property_read_string(child_region, "firmware-name", ++ &child_firmware_name)) { ++ ret = -EINVAL; ++ break; ++ } ++ child_region = of_find_matching_node(child_region, ++ fpga_region_of_match); ++ } ++ ++ of_node_put(child_region); ++ ++ if (ret) ++ pr_err("firmware-name not allowed in child FPGA region: %s", ++ child_region->full_name); ++ ++ return ret; ++} ++ ++/** ++ * fpga_region_notify_pre_apply - pre-apply overlay notification ++ * ++ * @region: FPGA region that the overlay was applied to ++ * @nd: overlay notification data ++ * ++ * Called after when an overlay targeted to a FPGA Region is about to be ++ * applied. Function will check the properties that will be added to the FPGA ++ * region. If the checks pass, it will program the FPGA. ++ * ++ * The checks are: ++ * The overlay must add either firmware-name or external-fpga-config property ++ * to the FPGA Region. ++ * ++ * firmware-name : program the FPGA ++ * external-fpga-config : FPGA is already programmed ++ * ++ * The overlay can add other FPGA regions, but child FPGA regions cannot have a ++ * firmware-name property since those regions don't exist yet. ++ * ++ * If the overlay that breaks the rules, notifier returns an error and the ++ * overlay is rejected before it goes into the main tree. ++ * ++ * Returns 0 for success or negative error code for failure. ++ */ ++static int fpga_region_notify_pre_apply(struct fpga_region *region, ++ struct of_overlay_notify_data *nd) ++{ ++ const char *firmware_name = NULL; ++ struct fpga_image_info *info; ++ int ret; ++ ++ info = devm_kzalloc(®ion->dev, sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ region->info = info; ++ ++ /* Reject overlay if child FPGA Regions have firmware-name property */ ++ ret = child_regions_with_firmware(nd->overlay); ++ if (ret) ++ return ret; ++ ++ /* Read FPGA region properties from the overlay */ ++ if (of_property_read_bool(nd->overlay, "partial-fpga-config")) ++ info->flags |= FPGA_MGR_PARTIAL_RECONFIG; ++ ++ if (of_property_read_bool(nd->overlay, "external-fpga-config")) ++ info->flags |= FPGA_MGR_EXTERNAL_CONFIG; ++ ++ of_property_read_string(nd->overlay, "firmware-name", &firmware_name); ++ ++ of_property_read_u32(nd->overlay, "region-unfreeze-timeout-us", ++ &info->enable_timeout_us); ++ ++ of_property_read_u32(nd->overlay, "region-freeze-timeout-us", ++ &info->disable_timeout_us); ++ ++ /* If FPGA was externally programmed, don't specify firmware */ ++ if ((info->flags & FPGA_MGR_EXTERNAL_CONFIG) && firmware_name) { ++ pr_err("error: specified firmware and external-fpga-config"); ++ return -EINVAL; ++ } ++ ++ /* FPGA is already configured externally. We're done. */ ++ if (info->flags & FPGA_MGR_EXTERNAL_CONFIG) ++ return 0; ++ ++ /* If we got this far, we should be programming the FPGA */ ++ if (!firmware_name) { ++ pr_err("should specify firmware-name or external-fpga-config\n"); ++ return -EINVAL; ++ } ++ ++ return fpga_region_program_fpga(region, firmware_name, nd->overlay); ++} ++ ++/** ++ * fpga_region_notify_post_remove - post-remove overlay notification ++ * ++ * @region: FPGA region that was targeted by the overlay that was removed ++ * @nd: overlay notification data ++ * ++ * Called after an overlay has been removed if the overlay's target was a ++ * FPGA region. ++ */ ++static void fpga_region_notify_post_remove(struct fpga_region *region, ++ struct of_overlay_notify_data *nd) ++{ ++ fpga_bridges_disable(®ion->bridge_list); ++ fpga_bridges_put(®ion->bridge_list); ++ devm_kfree(®ion->dev, region->info); ++ region->info = NULL; ++} ++ ++/** ++ * of_fpga_region_notify - reconfig notifier for dynamic DT changes ++ * @nb: notifier block ++ * @action: notifier action ++ * @arg: reconfig data ++ * ++ * This notifier handles programming a FPGA when a "firmware-name" property is ++ * added to a fpga-region. ++ * ++ * Returns NOTIFY_OK or error if FPGA programming fails. ++ */ ++static int of_fpga_region_notify(struct notifier_block *nb, ++ unsigned long action, void *arg) ++{ ++ struct of_overlay_notify_data *nd = arg; ++ struct fpga_region *region; ++ int ret; ++ ++ switch (action) { ++ case OF_OVERLAY_PRE_APPLY: ++ pr_debug("%s OF_OVERLAY_PRE_APPLY\n", __func__); ++ break; ++ case OF_OVERLAY_POST_APPLY: ++ pr_debug("%s OF_OVERLAY_POST_APPLY\n", __func__); ++ return NOTIFY_OK; /* not for us */ ++ case OF_OVERLAY_PRE_REMOVE: ++ pr_debug("%s OF_OVERLAY_PRE_REMOVE\n", __func__); ++ return NOTIFY_OK; /* not for us */ ++ case OF_OVERLAY_POST_REMOVE: ++ pr_debug("%s OF_OVERLAY_POST_REMOVE\n", __func__); ++ break; ++ default: /* should not happen */ ++ return NOTIFY_OK; ++ } ++ ++ region = fpga_region_find(nd->target); ++ if (!region) ++ return NOTIFY_OK; ++ ++ ret = 0; ++ switch (action) { ++ case OF_OVERLAY_PRE_APPLY: ++ ret = fpga_region_notify_pre_apply(region, nd); ++ break; ++ ++ case OF_OVERLAY_POST_REMOVE: ++ fpga_region_notify_post_remove(region, nd); ++ break; ++ } ++ ++ put_device(®ion->dev); ++ ++ if (ret) ++ return notifier_from_errno(ret); ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block fpga_region_of_nb = { ++ .notifier_call = of_fpga_region_notify, ++}; ++ ++static int fpga_region_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct fpga_region *region; ++ int id, ret = 0; ++ ++ region = kzalloc(sizeof(*region), GFP_KERNEL); ++ if (!region) ++ return -ENOMEM; ++ ++ id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL); ++ if (id < 0) { ++ ret = id; ++ goto err_kfree; ++ } ++ ++ mutex_init(®ion->mutex); ++ INIT_LIST_HEAD(®ion->bridge_list); ++ ++ device_initialize(®ion->dev); ++ region->dev.class = fpga_region_class; ++ region->dev.parent = dev; ++ region->dev.of_node = np; ++ region->dev.id = id; ++ dev_set_drvdata(dev, region); ++ ++ ret = dev_set_name(®ion->dev, "region%d", id); ++ if (ret) ++ goto err_remove; ++ ++ ret = device_add(®ion->dev); ++ if (ret) ++ goto err_remove; ++ ++ of_platform_populate(np, fpga_region_of_match, NULL, ®ion->dev); ++ ++ dev_info(dev, "FPGA Region probed\n"); ++ ++ return 0; ++ ++err_remove: ++ ida_simple_remove(&fpga_region_ida, id); ++err_kfree: ++ kfree(region); ++ ++ return ret; ++} ++ ++static int fpga_region_remove(struct platform_device *pdev) ++{ ++ struct fpga_region *region = platform_get_drvdata(pdev); ++ ++ device_unregister(®ion->dev); ++ ++ return 0; ++} ++ ++static struct platform_driver fpga_region_driver = { ++ .probe = fpga_region_probe, ++ .remove = fpga_region_remove, ++ .driver = { ++ .name = "fpga-region", ++ .of_match_table = of_match_ptr(fpga_region_of_match), ++ }, ++}; ++ ++static void fpga_region_dev_release(struct device *dev) ++{ ++ struct fpga_region *region = to_fpga_region(dev); ++ ++ ida_simple_remove(&fpga_region_ida, region->dev.id); ++ kfree(region); ++} ++ ++/** ++ * fpga_region_init - init function for fpga_region class ++ * Creates the fpga_region class and registers a reconfig notifier. ++ */ ++static int __init fpga_region_init(void) ++{ ++ int ret; ++ ++ fpga_region_class = class_create(THIS_MODULE, "fpga_region"); ++ if (IS_ERR(fpga_region_class)) ++ return PTR_ERR(fpga_region_class); ++ ++ fpga_region_class->dev_release = fpga_region_dev_release; ++ ++ ret = of_overlay_notifier_register(&fpga_region_of_nb); ++ if (ret) ++ goto err_class; ++ ++ ret = platform_driver_register(&fpga_region_driver); ++ if (ret) ++ goto err_plat; ++ ++ return 0; ++ ++err_plat: ++ of_overlay_notifier_unregister(&fpga_region_of_nb); ++err_class: ++ class_destroy(fpga_region_class); ++ ida_destroy(&fpga_region_ida); ++ return ret; ++} ++ ++static void __exit fpga_region_exit(void) ++{ ++ platform_driver_unregister(&fpga_region_driver); ++ of_overlay_notifier_unregister(&fpga_region_of_nb); ++ class_destroy(fpga_region_class); ++ ida_destroy(&fpga_region_ida); ++} ++ ++subsys_initcall(fpga_region_init); ++module_exit(fpga_region_exit); ++ ++MODULE_DESCRIPTION("FPGA Region"); ++MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); ++MODULE_LICENSE("GPL v2"); +--- a/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h +@@ -65,8 +65,10 @@ enum fpga_mgr_states { + /* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported ++ * FPGA_MGR_EXTERNAL_CONFIG: FPGA has been configured prior to Linux booting + */ + #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) ++#define FPGA_MGR_EXTERNAL_CONFIG BIT(1) + + /** + * struct fpga_image_info - information specific to a FPGA image diff --git a/patches.socfpga/0032-ARM-socfpga-fpga-bridge-driver-support.patch b/patches.socfpga/0032-ARM-socfpga-fpga-bridge-driver-support.patch new file mode 100644 index 00000000000000..c5a8ca92fec067 --- /dev/null +++ b/patches.socfpga/0032-ARM-socfpga-fpga-bridge-driver-support.patch @@ -0,0 +1,473 @@ +From ffe325ed88d349106ded4459366514e91fd1a175 Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:30 -0500 +Subject: [PATCH 032/103] ARM: socfpga: fpga bridge driver support + +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 <atull@opensource.altera.com> +Signed-off-by: Matthew Gerlach <mgerlach@altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 7 + + drivers/fpga/Makefile | 1 + drivers/fpga/altera-fpga2sdram.c | 180 +++++++++++++++++++++++++++++++ + drivers/fpga/altera-hps2fpga.c | 222 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 410 insertions(+) + create mode 100644 drivers/fpga/altera-fpga2sdram.c + create mode 100644 drivers/fpga/altera-hps2fpga.c + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -40,6 +40,13 @@ config FPGA_BRIDGE + Say Y here if you want to support bridges connected between host + processors and FPGAs or between FPGAs. + ++config SOCFPGA_FPGA_BRIDGE ++ tristate "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 +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq + + # 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_REGION) += fpga-region.o +--- /dev/null ++++ b/drivers/fpga/altera-fpga2sdram.c +@@ -0,0 +1,180 @@ ++/* ++ * FPGA to SDRAM Bridge Driver for Altera SoCFPGA Devices ++ * ++ * Copyright (C) 2013-2016 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 ++ ++/* ++ * From the Cyclone V HPS Memory Map document: ++ * These registers are used to store handoff information between the ++ * preloader and the OS. These 8 registers can be used to store any ++ * information. The contents of these registers have no impact on ++ * the state of the HPS hardware. ++ */ ++#define SYSMGR_ISWGRP_HANDOFF3 (0x8C) ++ ++#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 <atull@opensource.altera.com>"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/drivers/fpga/altera-hps2fpga.c +@@ -0,0 +1,222 @@ ++/* ++ * FPGA to/from HPS Bridge Driver for Altera SoCFPGA Devices ++ * ++ * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. ++ * ++ * Includes this patch from the mailing list: ++ * fpga: altera-hps2fpga: fix HPS2FPGA bridge visibility to L3 masters ++ * Signed-off-by: Anatolij Gustschin <agust@denx.de> ++ * ++ * 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> ++#include <linux/spinlock.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; ++ 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); ++} ++ ++/* The L3 REMAP register is write only, so keep a cached value. */ ++static unsigned int l3_remap_shadow; ++static spinlock_t l3_remap_lock; ++ ++static int _alt_hps2fpga_enable_set(struct altera_hps2fpga_data *priv, ++ bool enable) ++{ ++ unsigned long flags; ++ 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) { ++ spin_lock_irqsave(&l3_remap_lock, flags); ++ l3_remap_shadow |= ALT_L3_REMAP_MPUZERO_MSK; ++ ++ if (enable) ++ l3_remap_shadow |= priv->remap_mask; ++ else ++ l3_remap_shadow &= ~priv->remap_mask; ++ ++ ret = regmap_write(priv->l3reg, ALT_L3_REMAP_OFST, ++ l3_remap_shadow); ++ spin_unlock_irqrestore(&l3_remap_lock, flags); ++ } ++ ++ 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 = of_reset_control_get_by_index(dev->of_node, 0); ++ if (IS_ERR(priv->bridge_reset)) { ++ dev_err(dev, "Could not get %s reset control\n", priv->name); ++ return PTR_ERR(priv->bridge_reset); ++ } ++ ++ if (priv->remap_mask) { ++ 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 = devm_clk_get(dev, NULL); ++ 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; ++ } ++ ++ spin_lock_init(&l3_remap_lock); ++ ++ 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 fpga_bridge_register(dev, priv->name, &altera_hps2fpga_br_ops, ++ priv); ++} ++ ++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); ++ ++ 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 <atull@opensource.altera.com>"); ++MODULE_LICENSE("GPL v2"); diff --git a/patches.socfpga/0033-fpga-add-altera-freeze-bridge-support.patch b/patches.socfpga/0033-fpga-add-altera-freeze-bridge-support.patch new file mode 100644 index 00000000000000..f63baf12e02da1 --- /dev/null +++ b/patches.socfpga/0033-fpga-add-altera-freeze-bridge-support.patch @@ -0,0 +1,324 @@ +From cd1d46154270d9ee1e740b310999ae0bb7449e21 Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:31 -0500 +Subject: [PATCH 033/103] fpga: add altera freeze bridge support + +Add a low level driver for Altera Freeze Bridges to the FPGA Bridge +framework. A freeze bridge is a bridge that exists in the FPGA +fabric to isolate one region of the FPGA from the busses while that +one region is being reprogrammed. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Matthew Gerlach <mgerlach@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 9 + + drivers/fpga/Makefile | 1 + drivers/fpga/altera-freeze-bridge.c | 273 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 283 insertions(+) + create mode 100644 drivers/fpga/altera-freeze-bridge.c + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -47,6 +47,15 @@ config SOCFPGA_FPGA_BRIDGE + Say Y to enable drivers for FPGA bridges for Altera SOCFPGA + devices. + ++config ALTERA_FREEZE_BRIDGE ++ tristate "Altera FPGA Freeze Bridge" ++ depends on ARCH_SOCFPGA && FPGA_BRIDGE ++ help ++ Say Y to enable drivers for Altera FPGA Freeze bridges. A ++ freeze bridge is a bridge that exists in the FPGA fabric to ++ isolate one region of the FPGA from the busses while that ++ region is being reprogrammed. ++ + endif # FPGA + + endmenu +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq + # FPGA Bridge Drivers + obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o + obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE) += altera-hps2fpga.o altera-fpga2sdram.o ++obj-$(CONFIG_ALTERA_FREEZE_BRIDGE) += altera-freeze-bridge.o + + # High Level Interfaces + obj-$(CONFIG_FPGA_REGION) += fpga-region.o +--- /dev/null ++++ b/drivers/fpga/altera-freeze-bridge.c +@@ -0,0 +1,273 @@ ++/* ++ * FPGA Freeze Bridge Controller ++ * ++ * Copyright (C) 2016 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/delay.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/of_device.h> ++#include <linux/module.h> ++#include <linux/fpga/fpga-bridge.h> ++ ++#define FREEZE_CSR_STATUS_OFFSET 0 ++#define FREEZE_CSR_CTRL_OFFSET 4 ++#define FREEZE_CSR_ILLEGAL_REQ_OFFSET 8 ++#define FREEZE_CSR_REG_VERSION 12 ++ ++#define FREEZE_CSR_SUPPORTED_VERSION 2 ++ ++#define FREEZE_CSR_STATUS_FREEZE_REQ_DONE BIT(0) ++#define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE BIT(1) ++ ++#define FREEZE_CSR_CTRL_FREEZE_REQ BIT(0) ++#define FREEZE_CSR_CTRL_RESET_REQ BIT(1) ++#define FREEZE_CSR_CTRL_UNFREEZE_REQ BIT(2) ++ ++#define FREEZE_BRIDGE_NAME "freeze" ++ ++struct altera_freeze_br_data { ++ struct device *dev; ++ void __iomem *base_addr; ++ bool enable; ++}; ++ ++/* ++ * Poll status until status bit is set or we have a timeout. ++ */ ++static int altera_freeze_br_req_ack(struct altera_freeze_br_data *priv, ++ u32 timeout, u32 req_ack) ++{ ++ struct device *dev = priv->dev; ++ void __iomem *csr_illegal_req_addr = priv->base_addr + ++ FREEZE_CSR_ILLEGAL_REQ_OFFSET; ++ u32 status, illegal, ctrl; ++ int ret = -ETIMEDOUT; ++ ++ do { ++ illegal = readl(csr_illegal_req_addr); ++ if (illegal) { ++ dev_err(dev, "illegal request detected 0x%x", illegal); ++ ++ writel(1, csr_illegal_req_addr); ++ ++ illegal = readl(csr_illegal_req_addr); ++ if (illegal) ++ dev_err(dev, "illegal request not cleared 0x%x", ++ illegal); ++ ++ ret = -EINVAL; ++ break; ++ } ++ ++ status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); ++ dev_dbg(dev, "%s %x %x\n", __func__, status, req_ack); ++ status &= req_ack; ++ if (status) { ++ ctrl = readl(priv->base_addr + FREEZE_CSR_CTRL_OFFSET); ++ dev_dbg(dev, "%s request %x acknowledged %x %x\n", ++ __func__, req_ack, status, ctrl); ++ ret = 0; ++ break; ++ } ++ ++ udelay(1); ++ } while (timeout--); ++ ++ if (ret == -ETIMEDOUT) ++ dev_err(dev, "%s timeout waiting for 0x%x\n", ++ __func__, req_ack); ++ ++ return ret; ++} ++ ++static int altera_freeze_br_do_freeze(struct altera_freeze_br_data *priv, ++ u32 timeout) ++{ ++ struct device *dev = priv->dev; ++ void __iomem *csr_ctrl_addr = priv->base_addr + ++ FREEZE_CSR_CTRL_OFFSET; ++ u32 status; ++ int ret; ++ ++ status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); ++ ++ dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr)); ++ ++ if (status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE) { ++ dev_dbg(dev, "%s bridge already disabled %d\n", ++ __func__, status); ++ return 0; ++ } else if (!(status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE)) { ++ dev_err(dev, "%s bridge not enabled %d\n", __func__, status); ++ return -EINVAL; ++ } ++ ++ writel(FREEZE_CSR_CTRL_FREEZE_REQ, csr_ctrl_addr); ++ ++ ret = altera_freeze_br_req_ack(priv, timeout, ++ FREEZE_CSR_STATUS_FREEZE_REQ_DONE); ++ ++ if (ret) ++ writel(0, csr_ctrl_addr); ++ else ++ writel(FREEZE_CSR_CTRL_RESET_REQ, csr_ctrl_addr); ++ ++ return ret; ++} ++ ++static int altera_freeze_br_do_unfreeze(struct altera_freeze_br_data *priv, ++ u32 timeout) ++{ ++ struct device *dev = priv->dev; ++ void __iomem *csr_ctrl_addr = priv->base_addr + ++ FREEZE_CSR_CTRL_OFFSET; ++ u32 status; ++ int ret; ++ ++ writel(0, csr_ctrl_addr); ++ ++ status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); ++ ++ dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr)); ++ ++ if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) { ++ dev_dbg(dev, "%s bridge already enabled %d\n", ++ __func__, status); ++ return 0; ++ } else if (!(status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE)) { ++ dev_err(dev, "%s bridge not frozen %d\n", __func__, status); ++ return -EINVAL; ++ } ++ ++ writel(FREEZE_CSR_CTRL_UNFREEZE_REQ, csr_ctrl_addr); ++ ++ ret = altera_freeze_br_req_ack(priv, timeout, ++ FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE); ++ ++ status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); ++ ++ dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr)); ++ ++ writel(0, csr_ctrl_addr); ++ ++ return ret; ++} ++ ++/* ++ * enable = 1 : allow traffic through the bridge ++ * enable = 0 : disable traffic through the bridge ++ */ ++static int altera_freeze_br_enable_set(struct fpga_bridge *bridge, ++ bool enable) ++{ ++ struct altera_freeze_br_data *priv = bridge->priv; ++ struct fpga_image_info *info = bridge->info; ++ u32 timeout = 0; ++ int ret; ++ ++ if (enable) { ++ if (info) ++ timeout = info->enable_timeout_us; ++ ++ ret = altera_freeze_br_do_unfreeze(bridge->priv, timeout); ++ } else { ++ if (info) ++ timeout = info->disable_timeout_us; ++ ++ ret = altera_freeze_br_do_freeze(bridge->priv, timeout); ++ } ++ ++ if (!ret) ++ priv->enable = enable; ++ ++ return ret; ++} ++ ++static int altera_freeze_br_enable_show(struct fpga_bridge *bridge) ++{ ++ struct altera_freeze_br_data *priv = bridge->priv; ++ ++ return priv->enable; ++} ++ ++static struct fpga_bridge_ops altera_freeze_br_br_ops = { ++ .enable_set = altera_freeze_br_enable_set, ++ .enable_show = altera_freeze_br_enable_show, ++}; ++ ++static const struct of_device_id altera_freeze_br_of_match[] = { ++ { .compatible = "altr,freeze-bridge-controller", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, altera_freeze_br_of_match); ++ ++static int altera_freeze_br_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = pdev->dev.of_node; ++ struct altera_freeze_br_data *priv; ++ struct resource *res; ++ u32 status, revision; ++ ++ if (!np) ++ return -ENODEV; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->base_addr = devm_ioremap_resource(dev, res); ++ if (IS_ERR(priv->base_addr)) ++ return PTR_ERR(priv->base_addr); ++ ++ status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); ++ if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) ++ priv->enable = 1; ++ ++ revision = readl(priv->base_addr + FREEZE_CSR_REG_VERSION); ++ if (revision != FREEZE_CSR_SUPPORTED_VERSION) ++ dev_warn(dev, ++ "%s Freeze Controller unexpected revision %d != %d\n", ++ __func__, revision, FREEZE_CSR_SUPPORTED_VERSION); ++ ++ return fpga_bridge_register(dev, FREEZE_BRIDGE_NAME, ++ &altera_freeze_br_br_ops, priv); ++} ++ ++static int altera_freeze_br_remove(struct platform_device *pdev) ++{ ++ fpga_bridge_unregister(&pdev->dev); ++ ++ return 0; ++} ++ ++static struct platform_driver altera_freeze_br_driver = { ++ .probe = altera_freeze_br_probe, ++ .remove = altera_freeze_br_remove, ++ .driver = { ++ .name = "altera_freeze_br", ++ .of_match_table = of_match_ptr(altera_freeze_br_of_match), ++ }, ++}; ++ ++module_platform_driver(altera_freeze_br_driver); ++ ++MODULE_DESCRIPTION("Altera Freeze Bridge"); ++MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); ++MODULE_LICENSE("GPL v2"); diff --git a/patches.socfpga/0034-fpga-manager-Add-Socfpga-Arria10-support.patch b/patches.socfpga/0034-fpga-manager-Add-Socfpga-Arria10-support.patch new file mode 100644 index 00000000000000..7eed0ffbb38b86 --- /dev/null +++ b/patches.socfpga/0034-fpga-manager-Add-Socfpga-Arria10-support.patch @@ -0,0 +1,602 @@ +From d2d6523f3ef50daee666b364d8438de62ed5a40b Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 1 Nov 2016 14:14:32 -0500 +Subject: [PATCH 034/103] fpga-manager: Add Socfpga Arria10 support + +Add low level driver to support reprogramming FPGAs for Altera +SoCFPGA Arria10. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Reviewed-by: Moritz Fischer <moritz.fischer@ettus.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 6 + drivers/fpga/Makefile | 1 + drivers/fpga/socfpga-a10.c | 556 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 563 insertions(+) + create mode 100644 drivers/fpga/socfpga-a10.c + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -26,6 +26,12 @@ config FPGA_MGR_SOCFPGA + help + FPGA manager driver support for Altera SOCFPGA. + ++config FPGA_MGR_SOCFPGA_A10 ++ tristate "Altera SoCFPGA Arria10" ++ depends on ARCH_SOCFPGA ++ help ++ FPGA manager driver support for Altera Arria10 SoCFPGA. ++ + config FPGA_MGR_ZYNQ_FPGA + tristate "Xilinx Zynq FPGA" + depends on ARCH_ZYNQ || COMPILE_TEST +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -7,6 +7,7 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o + + # FPGA Manager Drivers + obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o ++obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o + obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o + + # FPGA Bridge Drivers +--- /dev/null ++++ b/drivers/fpga/socfpga-a10.c +@@ -0,0 +1,556 @@ ++/* ++ * FPGA Manager Driver for Altera Arria10 SoCFPGA ++ * ++ * Copyright (C) 2015-2016 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/clk.h> ++#include <linux/device.h> ++#include <linux/delay.h> ++#include <linux/fpga/fpga-mgr.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of_address.h> ++#include <linux/regmap.h> ++ ++#define A10_FPGAMGR_DCLKCNT_OFST 0x08 ++#define A10_FPGAMGR_DCLKSTAT_OFST 0x0c ++#define A10_FPGAMGR_IMGCFG_CTL_00_OFST 0x70 ++#define A10_FPGAMGR_IMGCFG_CTL_01_OFST 0x74 ++#define A10_FPGAMGR_IMGCFG_CTL_02_OFST 0x78 ++#define A10_FPGAMGR_IMGCFG_STAT_OFST 0x80 ++ ++#define A10_FPGAMGR_DCLKSTAT_DCLKDONE BIT(0) ++ ++#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG BIT(0) ++#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS BIT(1) ++#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE BIT(2) ++#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG BIT(8) ++#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NSTATUS_OE BIT(16) ++#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_CONDONE_OE BIT(24) ++ ++#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG BIT(0) ++#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST BIT(16) ++#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE BIT(24) ++ ++#define A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL BIT(0) ++#define A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_MASK (BIT(16) | BIT(17)) ++#define A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SHIFT 16 ++#define A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH BIT(24) ++#define A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SHIFT 24 ++ ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR BIT(0) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE BIT(1) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE BIT(2) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN BIT(4) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN BIT(6) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY BIT(9) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_DONE BIT(10) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR BIT(11) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN BIT(12) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_MASK (BIT(16) | BIT(17) | BIT(18)) ++#define A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SHIFT 16 ++ ++/* FPGA CD Ratio Value */ ++#define CDRATIO_x1 0x0 ++#define CDRATIO_x2 0x1 ++#define CDRATIO_x4 0x2 ++#define CDRATIO_x8 0x3 ++ ++/* Configuration width 16/32 bit */ ++#define CFGWDTH_32 1 ++#define CFGWDTH_16 0 ++ ++/* ++ * struct a10_fpga_priv - private data for fpga manager ++ * @regmap: regmap for register access ++ * @fpga_data_addr: iomap for single address data register to FPGA ++ * @clk: clock ++ */ ++struct a10_fpga_priv { ++ struct regmap *regmap; ++ void __iomem *fpga_data_addr; ++ struct clk *clk; ++}; ++ ++static bool socfpga_a10_fpga_writeable_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case A10_FPGAMGR_DCLKCNT_OFST: ++ case A10_FPGAMGR_DCLKSTAT_OFST: ++ case A10_FPGAMGR_IMGCFG_CTL_00_OFST: ++ case A10_FPGAMGR_IMGCFG_CTL_01_OFST: ++ case A10_FPGAMGR_IMGCFG_CTL_02_OFST: ++ return true; ++ } ++ return false; ++} ++ ++static bool socfpga_a10_fpga_readable_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case A10_FPGAMGR_DCLKCNT_OFST: ++ case A10_FPGAMGR_DCLKSTAT_OFST: ++ case A10_FPGAMGR_IMGCFG_CTL_00_OFST: ++ case A10_FPGAMGR_IMGCFG_CTL_01_OFST: ++ case A10_FPGAMGR_IMGCFG_CTL_02_OFST: ++ case A10_FPGAMGR_IMGCFG_STAT_OFST: ++ return true; ++ } ++ return false; ++} ++ ++static const struct regmap_config socfpga_a10_fpga_regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .writeable_reg = socfpga_a10_fpga_writeable_reg, ++ .readable_reg = socfpga_a10_fpga_readable_reg, ++ .max_register = A10_FPGAMGR_IMGCFG_STAT_OFST, ++ .cache_type = REGCACHE_NONE, ++}; ++ ++/* ++ * from the register map description of cdratio in imgcfg_ctrl_02: ++ * Normal Configuration : 32bit Passive Parallel ++ * Partial Reconfiguration : 16bit Passive Parallel ++ */ ++static void socfpga_a10_fpga_set_cfg_width(struct a10_fpga_priv *priv, ++ int width) ++{ ++ width <<= A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SHIFT; ++ ++ regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH, width); ++} ++ ++static void socfpga_a10_fpga_generate_dclks(struct a10_fpga_priv *priv, ++ u32 count) ++{ ++ u32 val; ++ ++ /* Clear any existing DONE status. */ ++ regmap_write(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, ++ A10_FPGAMGR_DCLKSTAT_DCLKDONE); ++ ++ /* Issue the DCLK regmap. */ ++ regmap_write(priv->regmap, A10_FPGAMGR_DCLKCNT_OFST, count); ++ ++ /* wait till the dclkcnt done */ ++ regmap_read_poll_timeout(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, val, ++ val, 1, 100); ++ ++ /* Clear DONE status. */ ++ regmap_write(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, ++ A10_FPGAMGR_DCLKSTAT_DCLKDONE); ++} ++ ++#define RBF_ENCRYPTION_MODE_OFFSET 69 ++#define RBF_DECOMPRESS_OFFSET 229 ++ ++static int socfpga_a10_fpga_encrypted(u32 *buf32, size_t buf32_size) ++{ ++ if (buf32_size < RBF_ENCRYPTION_MODE_OFFSET + 1) ++ return -EINVAL; ++ ++ /* Is the bitstream encrypted? */ ++ return ((buf32[RBF_ENCRYPTION_MODE_OFFSET] >> 2) & 3) != 0; ++} ++ ++static int socfpga_a10_fpga_compressed(u32 *buf32, size_t buf32_size) ++{ ++ if (buf32_size < RBF_DECOMPRESS_OFFSET + 1) ++ return -EINVAL; ++ ++ /* Is the bitstream compressed? */ ++ return !((buf32[RBF_DECOMPRESS_OFFSET] >> 1) & 1); ++} ++ ++static unsigned int socfpga_a10_fpga_get_cd_ratio(unsigned int cfg_width, ++ bool encrypt, bool compress) ++{ ++ unsigned int cd_ratio; ++ ++ /* ++ * cd ratio is dependent on cfg width and whether the bitstream ++ * is encrypted and/or compressed. ++ * ++ * | width | encr. | compr. | cd ratio | ++ * | 16 | 0 | 0 | 1 | ++ * | 16 | 0 | 1 | 4 | ++ * | 16 | 1 | 0 | 2 | ++ * | 16 | 1 | 1 | 4 | ++ * | 32 | 0 | 0 | 1 | ++ * | 32 | 0 | 1 | 8 | ++ * | 32 | 1 | 0 | 4 | ++ * | 32 | 1 | 1 | 8 | ++ */ ++ if (!compress && !encrypt) ++ return CDRATIO_x1; ++ ++ if (compress) ++ cd_ratio = CDRATIO_x4; ++ else ++ cd_ratio = CDRATIO_x2; ++ ++ /* If 32 bit, double the cd ratio by incrementing the field */ ++ if (cfg_width == CFGWDTH_32) ++ cd_ratio += 1; ++ ++ return cd_ratio; ++} ++ ++static int socfpga_a10_fpga_set_cdratio(struct fpga_manager *mgr, ++ unsigned int cfg_width, ++ const char *buf, size_t count) ++{ ++ struct a10_fpga_priv *priv = mgr->priv; ++ unsigned int cd_ratio; ++ int encrypt, compress; ++ ++ encrypt = socfpga_a10_fpga_encrypted((u32 *)buf, count / 4); ++ if (encrypt < 0) ++ return -EINVAL; ++ ++ compress = socfpga_a10_fpga_compressed((u32 *)buf, count / 4); ++ if (compress < 0) ++ return -EINVAL; ++ ++ cd_ratio = socfpga_a10_fpga_get_cd_ratio(cfg_width, encrypt, compress); ++ ++ regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_MASK, ++ cd_ratio << A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SHIFT); ++ ++ return 0; ++} ++ ++static u32 socfpga_a10_fpga_read_stat(struct a10_fpga_priv *priv) ++{ ++ u32 val; ++ ++ regmap_read(priv->regmap, A10_FPGAMGR_IMGCFG_STAT_OFST, &val); ++ ++ return val; ++} ++ ++static int socfpga_a10_fpga_wait_for_pr_ready(struct a10_fpga_priv *priv) ++{ ++ u32 reg, i; ++ ++ for (i = 0; i < 10 ; i++) { ++ reg = socfpga_a10_fpga_read_stat(priv); ++ ++ if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR) ++ return -EINVAL; ++ ++ if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY) ++ return 0; ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++static int socfpga_a10_fpga_wait_for_pr_done(struct a10_fpga_priv *priv) ++{ ++ u32 reg, i; ++ ++ for (i = 0; i < 10 ; i++) { ++ reg = socfpga_a10_fpga_read_stat(priv); ++ ++ if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR) ++ return -EINVAL; ++ ++ if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_DONE) ++ return 0; ++ } ++ ++ return -ETIMEDOUT; ++} ++ ++/* Start the FPGA programming by initialize the FPGA Manager */ ++static int socfpga_a10_fpga_write_init(struct fpga_manager *mgr, ++ struct fpga_image_info *info, ++ const char *buf, size_t count) ++{ ++ struct a10_fpga_priv *priv = mgr->priv; ++ unsigned int cfg_width; ++ u32 msel, stat, mask; ++ int ret; ++ ++ if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) ++ cfg_width = CFGWDTH_16; ++ else ++ return -EINVAL; ++ ++ /* Check for passive parallel (msel == 000 or 001) */ ++ msel = socfpga_a10_fpga_read_stat(priv); ++ msel &= A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_MASK; ++ msel >>= A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SHIFT; ++ if ((msel != 0) && (msel != 1)) { ++ dev_dbg(&mgr->dev, "Fail: invalid msel=%d\n", msel); ++ return -EINVAL; ++ } ++ ++ /* Make sure no external devices are interfering */ ++ stat = socfpga_a10_fpga_read_stat(priv); ++ mask = A10_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN | ++ A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN; ++ if ((stat & mask) != mask) ++ return -EINVAL; ++ ++ /* Set cfg width */ ++ socfpga_a10_fpga_set_cfg_width(priv, cfg_width); ++ ++ /* Determine cd ratio from bitstream header and set cd ratio */ ++ ret = socfpga_a10_fpga_set_cdratio(mgr, cfg_width, buf, count); ++ if (ret) ++ return ret; ++ ++ /* ++ * Clear s2f_nce to enable chip select. Leave pr_request ++ * unasserted and override disabled. ++ */ ++ regmap_write(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG); ++ ++ /* Set cfg_ctrl to enable s2f dclk and data */ ++ regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL, ++ A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL); ++ ++ /* ++ * Disable overrides not needed for pr. ++ * s2f_config==1 leaves reset deasseted. ++ */ ++ regmap_write(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_00_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG | ++ A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS | ++ A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE | ++ A10_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG); ++ ++ /* Enable override for data, dclk, nce, and pr_request to CSS */ ++ regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG, 0); ++ ++ /* Send some clocks to clear out any errors */ ++ socfpga_a10_fpga_generate_dclks(priv, 256); ++ ++ /* Assert pr_request */ ++ regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST, ++ A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST); ++ ++ /* Provide 2048 DCLKs before starting the config data streaming. */ ++ socfpga_a10_fpga_generate_dclks(priv, 0x7ff); ++ ++ /* Wait for pr_ready */ ++ return socfpga_a10_fpga_wait_for_pr_ready(priv); ++} ++ ++/* ++ * write data to the FPGA data register ++ */ ++static int socfpga_a10_fpga_write(struct fpga_manager *mgr, const char *buf, ++ size_t count) ++{ ++ struct a10_fpga_priv *priv = mgr->priv; ++ u32 *buffer_32 = (u32 *)buf; ++ size_t i = 0; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ /* Write out the complete 32-bit chunks */ ++ while (count >= sizeof(u32)) { ++ writel(buffer_32[i++], priv->fpga_data_addr); ++ count -= sizeof(u32); ++ } ++ ++ /* Write out remaining non 32-bit chunks */ ++ switch (count) { ++ case 3: ++ writel(buffer_32[i++] & 0x00ffffff, priv->fpga_data_addr); ++ break; ++ case 2: ++ writel(buffer_32[i++] & 0x0000ffff, priv->fpga_data_addr); ++ break; ++ case 1: ++ writel(buffer_32[i++] & 0x000000ff, priv->fpga_data_addr); ++ break; ++ case 0: ++ break; ++ default: ++ /* This will never happen */ ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int socfpga_a10_fpga_write_complete(struct fpga_manager *mgr, ++ struct fpga_image_info *info) ++{ ++ struct a10_fpga_priv *priv = mgr->priv; ++ u32 reg; ++ int ret; ++ ++ /* Wait for pr_done */ ++ ret = socfpga_a10_fpga_wait_for_pr_done(priv); ++ ++ /* Clear pr_request */ ++ regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST, 0); ++ ++ /* Send some clocks to clear out any errors */ ++ socfpga_a10_fpga_generate_dclks(priv, 256); ++ ++ /* Disable s2f dclk and data */ ++ regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL, 0); ++ ++ /* Deassert chip select */ ++ regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE, ++ A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE); ++ ++ /* Disable data, dclk, nce, and pr_request override to CSS */ ++ regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, ++ A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG, ++ A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG); ++ ++ /* Return any errors regarding pr_done or pr_error */ ++ if (ret) ++ return ret; ++ ++ /* Final check */ ++ reg = socfpga_a10_fpga_read_stat(priv); ++ ++ if (((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE) == 0) || ++ ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN) == 0) || ++ ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0)) { ++ dev_dbg(&mgr->dev, ++ "Timeout in final check. Status=%08xf\n", reg); ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static enum fpga_mgr_states socfpga_a10_fpga_state(struct fpga_manager *mgr) ++{ ++ struct a10_fpga_priv *priv = mgr->priv; ++ u32 reg = socfpga_a10_fpga_read_stat(priv); ++ ++ if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE) ++ return FPGA_MGR_STATE_OPERATING; ++ ++ if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY) ++ return FPGA_MGR_STATE_WRITE; ++ ++ if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR) ++ return FPGA_MGR_STATE_WRITE_COMPLETE_ERR; ++ ++ if ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0) ++ return FPGA_MGR_STATE_RESET; ++ ++ return FPGA_MGR_STATE_UNKNOWN; ++} ++ ++static const struct fpga_manager_ops socfpga_a10_fpga_mgr_ops = { ++ .state = socfpga_a10_fpga_state, ++ .write_init = socfpga_a10_fpga_write_init, ++ .write = socfpga_a10_fpga_write, ++ .write_complete = socfpga_a10_fpga_write_complete, ++}; ++ ++static int socfpga_a10_fpga_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct a10_fpga_priv *priv; ++ void __iomem *reg_base; ++ struct resource *res; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ /* First mmio base is for register access */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ reg_base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(reg_base)) ++ return PTR_ERR(reg_base); ++ ++ /* Second mmio base is for writing FPGA image data */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ priv->fpga_data_addr = devm_ioremap_resource(dev, res); ++ if (IS_ERR(priv->fpga_data_addr)) ++ return PTR_ERR(priv->fpga_data_addr); ++ ++ /* regmap for register access */ ++ priv->regmap = devm_regmap_init_mmio(dev, reg_base, ++ &socfpga_a10_fpga_regmap_config); ++ if (IS_ERR(priv->regmap)) ++ return -ENODEV; ++ ++ priv->clk = devm_clk_get(dev, NULL); ++ 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; ++ } ++ ++ return fpga_mgr_register(dev, "SoCFPGA Arria10 FPGA Manager", ++ &socfpga_a10_fpga_mgr_ops, priv); ++} ++ ++static int socfpga_a10_fpga_remove(struct platform_device *pdev) ++{ ++ struct fpga_manager *mgr = platform_get_drvdata(pdev); ++ struct a10_fpga_priv *priv = mgr->priv; ++ ++ fpga_mgr_unregister(&pdev->dev); ++ clk_disable_unprepare(priv->clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id socfpga_a10_fpga_of_match[] = { ++ { .compatible = "altr,socfpga-a10-fpga-mgr", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, socfpga_a10_fpga_of_match); ++ ++static struct platform_driver socfpga_a10_fpga_driver = { ++ .probe = socfpga_a10_fpga_probe, ++ .remove = socfpga_a10_fpga_remove, ++ .driver = { ++ .name = "socfpga_a10_fpga_manager", ++ .of_match_table = socfpga_a10_fpga_of_match, ++ }, ++}; ++ ++module_platform_driver(socfpga_a10_fpga_driver); ++ ++MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); ++MODULE_DESCRIPTION("SoCFPGA Arria10 FPGA Manager"); ++MODULE_LICENSE("GPL v2"); diff --git a/patches.socfpga/0035-ARM-socfpga-checking-the-wrong-variable.patch b/patches.socfpga/0035-ARM-socfpga-checking-the-wrong-variable.patch new file mode 100644 index 00000000000000..91fbf4400d6d9b --- /dev/null +++ b/patches.socfpga/0035-ARM-socfpga-checking-the-wrong-variable.patch @@ -0,0 +1,27 @@ +From 66990794c5c8e372ef07dd76272f5ac550e5be74 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter <dan.carpenter@oracle.com> +Date: Wed, 16 Nov 2016 19:54:40 -0600 +Subject: [PATCH 035/103] ARM: socfpga: checking the wrong variable + +This is a cut and paste bug. We had intended to check "sysmgr". + +Fixes: e5f8efa5c8bf ("ARM: socfpga: fpga bridge driver support") +Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/altera-fpga2sdram.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/fpga/altera-fpga2sdram.c ++++ b/drivers/fpga/altera-fpga2sdram.c +@@ -123,7 +123,7 @@ static int alt_fpga_bridge_probe(struct + } + + sysmgr = syscon_regmap_lookup_by_compatible("altr,sys-mgr"); +- if (IS_ERR(priv->sdrctl)) { ++ if (IS_ERR(sysmgr)) { + dev_err(dev, "regmap for altr,sys-mgr lookup failed.\n"); + return PTR_ERR(sysmgr); + } diff --git a/patches.socfpga/0036-fpga-Add-COMPILE_TEST-to-all-drivers.patch b/patches.socfpga/0036-fpga-Add-COMPILE_TEST-to-all-drivers.patch new file mode 100644 index 00000000000000..be90b9b133be09 --- /dev/null +++ b/patches.socfpga/0036-fpga-Add-COMPILE_TEST-to-all-drivers.patch @@ -0,0 +1,36 @@ +From 9ab5031fea8fa46c96663d537ad0652d944cf880 Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Date: Mon, 21 Nov 2016 22:26:42 +0000 +Subject: [PATCH 036/103] fpga: Add COMPILE_TEST to all drivers + +Like Zynq the Altera drivers compile fine on x86 and others too, +so make it easier to compile test this stuff. + +A10 requires REGMAP_MMIO to compile, so be explicit rather than +relying on it via ARCH_SOCFPGA. + +Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +--- + drivers/fpga/Kconfig | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -22,13 +22,14 @@ config FPGA_REGION + + config FPGA_MGR_SOCFPGA + tristate "Altera SOCFPGA FPGA Manager" +- depends on ARCH_SOCFPGA ++ depends on ARCH_SOCFPGA || COMPILE_TEST + help + FPGA manager driver support for Altera SOCFPGA. + + config FPGA_MGR_SOCFPGA_A10 + tristate "Altera SoCFPGA Arria10" +- depends on ARCH_SOCFPGA ++ depends on ARCH_SOCFPGA || COMPILE_TEST ++ select REGMAP_MMIO + help + FPGA manager driver support for Altera Arria10 SoCFPGA. + diff --git a/patches.socfpga/0037-fpga-zynq-Add-missing-n-to-messages.patch b/patches.socfpga/0037-fpga-zynq-Add-missing-n-to-messages.patch new file mode 100644 index 00000000000000..0a8a31a845a4d6 --- /dev/null +++ b/patches.socfpga/0037-fpga-zynq-Add-missing-n-to-messages.patch @@ -0,0 +1,112 @@ +From 5dc43314ce4663a705a0a91a3ad6e9aba3457de1 Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Date: Mon, 21 Nov 2016 22:26:43 +0000 +Subject: [PATCH 037/103] fpga zynq: Add missing \n to messages + +Function dev_err doesn't add a newline at the end of the string. This will +lead to a hard to read kernel log. + +Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Reviewed-by: Moritz Fischer <moritz.fischer@ettus.com> +Reviewed-by: Matthias Brugger <mbrugger@suse.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +--- + drivers/fpga/zynq-fpga.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +--- a/drivers/fpga/zynq-fpga.c ++++ b/drivers/fpga/zynq-fpga.c +@@ -218,7 +218,7 @@ static int zynq_fpga_ops_write_init(stru + INIT_POLL_DELAY, + INIT_POLL_TIMEOUT); + if (err) { +- dev_err(priv->dev, "Timeout waiting for PCFG_INIT"); ++ dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n"); + goto out_err; + } + +@@ -232,7 +232,7 @@ static int zynq_fpga_ops_write_init(stru + INIT_POLL_DELAY, + INIT_POLL_TIMEOUT); + if (err) { +- dev_err(priv->dev, "Timeout waiting for !PCFG_INIT"); ++ dev_err(priv->dev, "Timeout waiting for !PCFG_INIT\n"); + goto out_err; + } + +@@ -246,7 +246,7 @@ static int zynq_fpga_ops_write_init(stru + INIT_POLL_DELAY, + INIT_POLL_TIMEOUT); + if (err) { +- dev_err(priv->dev, "Timeout waiting for PCFG_INIT"); ++ dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n"); + goto out_err; + } + } +@@ -263,7 +263,7 @@ static int zynq_fpga_ops_write_init(stru + /* check that we have room in the command queue */ + status = zynq_fpga_read(priv, STATUS_OFFSET); + if (status & STATUS_DMA_Q_F) { +- dev_err(priv->dev, "DMA command queue full"); ++ dev_err(priv->dev, "DMA command queue full\n"); + err = -EBUSY; + goto out_err; + } +@@ -332,7 +332,7 @@ static int zynq_fpga_ops_write(struct fp + zynq_fpga_write(priv, INT_STS_OFFSET, intr_status); + + if (!((intr_status & IXR_D_P_DONE_MASK) == IXR_D_P_DONE_MASK)) { +- dev_err(priv->dev, "Error configuring FPGA"); ++ dev_err(priv->dev, "Error configuring FPGA\n"); + err = -EFAULT; + } + +@@ -428,7 +428,7 @@ static int zynq_fpga_probe(struct platfo + priv->slcr = syscon_regmap_lookup_by_phandle(dev->of_node, + "syscon"); + if (IS_ERR(priv->slcr)) { +- dev_err(dev, "unable to get zynq-slcr regmap"); ++ dev_err(dev, "unable to get zynq-slcr regmap\n"); + return PTR_ERR(priv->slcr); + } + +@@ -436,26 +436,26 @@ static int zynq_fpga_probe(struct platfo + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) { +- dev_err(dev, "No IRQ available"); ++ dev_err(dev, "No IRQ available\n"); + return priv->irq; + } + + err = devm_request_irq(dev, priv->irq, zynq_fpga_isr, 0, + dev_name(dev), priv); + if (err) { +- dev_err(dev, "unable to request IRQ"); ++ dev_err(dev, "unable to request IRQ\n"); + return err; + } + + priv->clk = devm_clk_get(dev, "ref_clk"); + if (IS_ERR(priv->clk)) { +- dev_err(dev, "input clock not found"); ++ dev_err(dev, "input clock not found\n"); + return PTR_ERR(priv->clk); + } + + err = clk_prepare_enable(priv->clk); + if (err) { +- dev_err(dev, "unable to enable clock"); ++ dev_err(dev, "unable to enable clock\n"); + return err; + } + +@@ -467,7 +467,7 @@ static int zynq_fpga_probe(struct platfo + err = fpga_mgr_register(dev, "Xilinx Zynq FPGA Manager", + &zynq_fpga_ops, priv); + if (err) { +- dev_err(dev, "unable to register FPGA manager"); ++ dev_err(dev, "unable to register FPGA manager\n"); + clk_unprepare(priv->clk); + return err; + } diff --git a/patches.socfpga/0038-fpga-zynq-Remove-priv-dev.patch b/patches.socfpga/0038-fpga-zynq-Remove-priv-dev.patch new file mode 100644 index 00000000000000..869b493871fe86 --- /dev/null +++ b/patches.socfpga/0038-fpga-zynq-Remove-priv-dev.patch @@ -0,0 +1,99 @@ +From df7528d1c3d7c2151dfe9419c7b3eed183860b8f Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Date: Mon, 21 Nov 2016 22:26:44 +0000 +Subject: [PATCH 038/103] fpga zynq: Remove priv->dev + +socfpga uses mgr->dev for debug prints, there should be consistency +here, so standardize on that. The only other use was for dma +which can be replaced with mgr->dev.parent. + +Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +--- + drivers/fpga/zynq-fpga.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +--- a/drivers/fpga/zynq-fpga.c ++++ b/drivers/fpga/zynq-fpga.c +@@ -118,7 +118,6 @@ + #define FPGA_RST_NONE_MASK 0x0 + + struct zynq_fpga_priv { +- struct device *dev; + int irq; + struct clk *clk; + +@@ -218,7 +217,7 @@ static int zynq_fpga_ops_write_init(stru + INIT_POLL_DELAY, + INIT_POLL_TIMEOUT); + if (err) { +- dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n"); ++ dev_err(&mgr->dev, "Timeout waiting for PCFG_INIT\n"); + goto out_err; + } + +@@ -232,7 +231,7 @@ static int zynq_fpga_ops_write_init(stru + INIT_POLL_DELAY, + INIT_POLL_TIMEOUT); + if (err) { +- dev_err(priv->dev, "Timeout waiting for !PCFG_INIT\n"); ++ dev_err(&mgr->dev, "Timeout waiting for !PCFG_INIT\n"); + goto out_err; + } + +@@ -246,7 +245,7 @@ static int zynq_fpga_ops_write_init(stru + INIT_POLL_DELAY, + INIT_POLL_TIMEOUT); + if (err) { +- dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n"); ++ dev_err(&mgr->dev, "Timeout waiting for PCFG_INIT\n"); + goto out_err; + } + } +@@ -263,7 +262,7 @@ static int zynq_fpga_ops_write_init(stru + /* check that we have room in the command queue */ + status = zynq_fpga_read(priv, STATUS_OFFSET); + if (status & STATUS_DMA_Q_F) { +- dev_err(priv->dev, "DMA command queue full\n"); ++ dev_err(&mgr->dev, "DMA command queue full\n"); + err = -EBUSY; + goto out_err; + } +@@ -296,7 +295,8 @@ static int zynq_fpga_ops_write(struct fp + in_count = count; + priv = mgr->priv; + +- kbuf = dma_alloc_coherent(priv->dev, count, &dma_addr, GFP_KERNEL); ++ kbuf = ++ dma_alloc_coherent(mgr->dev.parent, count, &dma_addr, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + +@@ -332,15 +332,14 @@ static int zynq_fpga_ops_write(struct fp + zynq_fpga_write(priv, INT_STS_OFFSET, intr_status); + + if (!((intr_status & IXR_D_P_DONE_MASK) == IXR_D_P_DONE_MASK)) { +- dev_err(priv->dev, "Error configuring FPGA\n"); ++ dev_err(&mgr->dev, "Error configuring FPGA\n"); + err = -EFAULT; + } + + clk_disable(priv->clk); + + out_free: +- dma_free_coherent(priv->dev, in_count, kbuf, dma_addr); +- ++ dma_free_coherent(mgr->dev.parent, count, kbuf, dma_addr); + return err; + } + +@@ -418,8 +417,6 @@ static int zynq_fpga_probe(struct platfo + if (!priv) + return -ENOMEM; + +- priv->dev = dev; +- + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->io_base)) diff --git a/patches.socfpga/0039-fpga-zynq-Fix-incorrect-ISR-state-on-bootup.patch b/patches.socfpga/0039-fpga-zynq-Fix-incorrect-ISR-state-on-bootup.patch new file mode 100644 index 00000000000000..21d94e81c9517f --- /dev/null +++ b/patches.socfpga/0039-fpga-zynq-Fix-incorrect-ISR-state-on-bootup.patch @@ -0,0 +1,56 @@ +From fb85a83e56bbe1a3899b8293a2db442696aa7631 Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Date: Mon, 21 Nov 2016 22:26:45 +0000 +Subject: [PATCH 039/103] fpga zynq: Fix incorrect ISR state on bootup + +It is best practice to clear and mask all interrupts before +associating the IRQ, and this should be done after the clock +is enabled. + +This corrects a bad result from zynq_fpga_ops_state on bootup +where left over latched values in INT_STS_OFFSET caused it to +report an unconfigured FPGA as configured. + +After this change the boot up operating state for an unconfigured +FPGA reports 'unknown'. + +Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +--- + drivers/fpga/zynq-fpga.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +--- a/drivers/fpga/zynq-fpga.c ++++ b/drivers/fpga/zynq-fpga.c +@@ -437,13 +437,6 @@ static int zynq_fpga_probe(struct platfo + return priv->irq; + } + +- err = devm_request_irq(dev, priv->irq, zynq_fpga_isr, 0, +- dev_name(dev), priv); +- if (err) { +- dev_err(dev, "unable to request IRQ\n"); +- return err; +- } +- + priv->clk = devm_clk_get(dev, "ref_clk"); + if (IS_ERR(priv->clk)) { + dev_err(dev, "input clock not found\n"); +@@ -459,6 +452,16 @@ static int zynq_fpga_probe(struct platfo + /* unlock the device */ + zynq_fpga_write(priv, UNLOCK_OFFSET, UNLOCK_MASK); + ++ zynq_fpga_write(priv, INT_MASK_OFFSET, 0xFFFFFFFF); ++ zynq_fpga_write(priv, INT_STS_OFFSET, IXR_ALL_MASK); ++ err = devm_request_irq(dev, priv->irq, zynq_fpga_isr, 0, dev_name(dev), ++ priv); ++ if (err) { ++ dev_err(dev, "unable to request IRQ\n"); ++ clk_disable_unprepare(priv->clk); ++ return err; ++ } ++ + clk_disable(priv->clk); + + err = fpga_mgr_register(dev, "Xilinx Zynq FPGA Manager", diff --git a/patches.socfpga/0040-fpga-Clarify-how-write_init-works-streaming-modes.patch b/patches.socfpga/0040-fpga-Clarify-how-write_init-works-streaming-modes.patch new file mode 100644 index 00000000000000..b5e5f0cb277afc --- /dev/null +++ b/patches.socfpga/0040-fpga-Clarify-how-write_init-works-streaming-modes.patch @@ -0,0 +1,82 @@ +From 66eb655c5286bd01e7fbe9db237ed4cbde6c4857 Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Date: Tue, 22 Nov 2016 18:22:09 +0000 +Subject: [PATCH 040/103] fpga: Clarify how write_init works streaming modes + +This interface was designed for streaming, but write_init's buf +argument has an unclear purpose. Define it to be the first bytes +of the bitstream. Each driver gets to set how many bytes (at most) +it wants to see. Short bitstreams will be passed through as-is, while +long ones will be truncated. + +The intent is to allow drivers to peek at the header before the transfer +actually starts. + +Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +--- + Documentation/fpga/fpga-mgr.txt | 5 ++++- + drivers/fpga/fpga-mgr.c | 6 ++++-- + drivers/fpga/socfpga-a10.c | 1 + + include/linux/fpga/fpga-mgr.h | 2 ++ + 4 files changed, 11 insertions(+), 3 deletions(-) + +--- a/Documentation/fpga/fpga-mgr.txt ++++ b/Documentation/fpga/fpga-mgr.txt +@@ -169,7 +169,10 @@ The programming sequence is: + 2. .write (may be called once or multiple times) + 3. .write_complete + +-The .write_init function will prepare the FPGA to receive the image data. ++The .write_init function will prepare the FPGA to receive the image data. The ++buffer passed into .write_init will be atmost .initial_header_size bytes long, ++if the whole bitstream is not immediately available then the core code will ++buffer up at least this much before starting. + + The .write function writes a buffer to the FPGA. The buffer may be contain the + whole FPGA image or may be a smaller chunk of an FPGA image. In the latter +--- a/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c +@@ -53,10 +53,12 @@ int fpga_mgr_buf_load(struct fpga_manage + /* + * Call the low level driver's write_init function. This will do the + * device-specific things to get the FPGA into the state where it is +- * ready to receive an FPGA image. ++ * ready to receive an FPGA image. The low level driver only gets to ++ * see the first initial_header_size bytes in the buffer. + */ + mgr->state = FPGA_MGR_STATE_WRITE_INIT; +- ret = mgr->mops->write_init(mgr, info, buf, count); ++ ret = mgr->mops->write_init(mgr, info, buf, ++ min(mgr->mops->initial_header_size, count)); + if (ret) { + dev_err(dev, "Error preparing FPGA for writing\n"); + mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR; +--- a/drivers/fpga/socfpga-a10.c ++++ b/drivers/fpga/socfpga-a10.c +@@ -470,6 +470,7 @@ static enum fpga_mgr_states socfpga_a10_ + } + + static const struct fpga_manager_ops socfpga_a10_fpga_mgr_ops = { ++ .initial_header_size = (RBF_DECOMPRESS_OFFSET + 1) * 4, + .state = socfpga_a10_fpga_state, + .write_init = socfpga_a10_fpga_write_init, + .write = socfpga_a10_fpga_write, +--- a/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h +@@ -84,6 +84,7 @@ struct fpga_image_info { + + /** + * struct fpga_manager_ops - ops for low level fpga manager drivers ++ * @initial_header_size: Maximum number of bytes that should be passed into write_init + * @state: returns an enum value of the FPGA's state + * @write_init: prepare the FPGA to receive confuration data + * @write: write count bytes of configuration data to the FPGA +@@ -95,6 +96,7 @@ struct fpga_image_info { + * called, so leaving them out is fine. + */ + struct fpga_manager_ops { ++ size_t initial_header_size; + enum fpga_mgr_states (*state)(struct fpga_manager *mgr); + int (*write_init)(struct fpga_manager *mgr, + struct fpga_image_info *info, diff --git a/patches.socfpga/0041-fpga-zynq-Check-for-errors-after-completing-DMA.patch b/patches.socfpga/0041-fpga-zynq-Check-for-errors-after-completing-DMA.patch new file mode 100644 index 00000000000000..2a0f8b5a428172 --- /dev/null +++ b/patches.socfpga/0041-fpga-zynq-Check-for-errors-after-completing-DMA.patch @@ -0,0 +1,130 @@ +From 5340a4560aaaaa7807b8e0070d6ee6541ee5fb3b Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Date: Wed, 1 Feb 2017 12:48:42 -0700 +Subject: [PATCH 041/103] fpga zynq: Check for errors after completing DMA + +The completion did not check the interrupt status to see if any error +bits were asserted, check error bits and dump some registers if things +went wrong. + +A few fixes are needed to make this work, the IXR_ERROR_FLAGS_MASK was +wrong, it included the done bits, which shows a bug in mask/unmask_irqs +which were using the wrong bits, simplify all of this stuff. + +Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Reviewed-by: Moritz Fischer <moritz.fischer@ettus.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/zynq-fpga.c | 54 +++++++++++++++++++++++++++-------------------- + 1 file changed, 32 insertions(+), 22 deletions(-) + +--- a/drivers/fpga/zynq-fpga.c ++++ b/drivers/fpga/zynq-fpga.c +@@ -89,7 +89,7 @@ + #define IXR_D_P_DONE_MASK BIT(12) + /* FPGA programmed */ + #define IXR_PCFG_DONE_MASK BIT(2) +-#define IXR_ERROR_FLAGS_MASK 0x00F0F860 ++#define IXR_ERROR_FLAGS_MASK 0x00F0C860 + #define IXR_ALL_MASK 0xF8F7F87F + + /* Miscellaneous constant values */ +@@ -143,23 +143,10 @@ static inline u32 zynq_fpga_read(const s + readl_poll_timeout(priv->io_base + addr, val, cond, sleep_us, \ + timeout_us) + +-static void zynq_fpga_mask_irqs(struct zynq_fpga_priv *priv) ++/* Cause the specified irq mask bits to generate IRQs */ ++static inline void zynq_fpga_set_irq(struct zynq_fpga_priv *priv, u32 enable) + { +- u32 intr_mask; +- +- intr_mask = zynq_fpga_read(priv, INT_MASK_OFFSET); +- zynq_fpga_write(priv, INT_MASK_OFFSET, +- intr_mask | IXR_DMA_DONE_MASK | IXR_ERROR_FLAGS_MASK); +-} +- +-static void zynq_fpga_unmask_irqs(struct zynq_fpga_priv *priv) +-{ +- u32 intr_mask; +- +- intr_mask = zynq_fpga_read(priv, INT_MASK_OFFSET); +- zynq_fpga_write(priv, INT_MASK_OFFSET, +- intr_mask +- & ~(IXR_D_P_DONE_MASK | IXR_ERROR_FLAGS_MASK)); ++ zynq_fpga_write(priv, INT_MASK_OFFSET, ~enable); + } + + static irqreturn_t zynq_fpga_isr(int irq, void *data) +@@ -167,7 +154,7 @@ static irqreturn_t zynq_fpga_isr(int irq + struct zynq_fpga_priv *priv = data; + + /* disable DMA and error IRQs */ +- zynq_fpga_mask_irqs(priv); ++ zynq_fpga_set_irq(priv, 0); + + complete(&priv->dma_done); + +@@ -285,6 +272,7 @@ static int zynq_fpga_ops_write(struct fp + const char *buf, size_t count) + { + struct zynq_fpga_priv *priv; ++ const char *why; + int err; + char *kbuf; + size_t in_count; +@@ -312,7 +300,7 @@ static int zynq_fpga_ops_write(struct fp + reinit_completion(&priv->dma_done); + + /* enable DMA and error IRQs */ +- zynq_fpga_unmask_irqs(priv); ++ zynq_fpga_set_irq(priv, IXR_D_P_DONE_MASK | IXR_ERROR_FLAGS_MASK); + + /* the +1 in the src addr is used to hold off on DMA_DONE IRQ + * until both AXI and PCAP are done ... +@@ -331,11 +319,33 @@ static int zynq_fpga_ops_write(struct fp + intr_status = zynq_fpga_read(priv, INT_STS_OFFSET); + zynq_fpga_write(priv, INT_STS_OFFSET, intr_status); + ++ if (intr_status & IXR_ERROR_FLAGS_MASK) { ++ why = "DMA reported error"; ++ err = -EIO; ++ goto out_report; ++ } ++ + if (!((intr_status & IXR_D_P_DONE_MASK) == IXR_D_P_DONE_MASK)) { +- dev_err(&mgr->dev, "Error configuring FPGA\n"); +- err = -EFAULT; ++ why = "DMA did not complete"; ++ err = -EIO; ++ goto out_report; + } + ++ err = 0; ++ goto out_clk; ++ ++out_report: ++ dev_err(&mgr->dev, ++ "%s: INT_STS:0x%x CTRL:0x%x LOCK:0x%x INT_MASK:0x%x STATUS:0x%x MCTRL:0x%x\n", ++ why, ++ intr_status, ++ zynq_fpga_read(priv, CTRL_OFFSET), ++ zynq_fpga_read(priv, LOCK_OFFSET), ++ zynq_fpga_read(priv, INT_MASK_OFFSET), ++ zynq_fpga_read(priv, STATUS_OFFSET), ++ zynq_fpga_read(priv, MCTRL_OFFSET)); ++ ++out_clk: + clk_disable(priv->clk); + + out_free: +@@ -452,7 +462,7 @@ static int zynq_fpga_probe(struct platfo + /* unlock the device */ + zynq_fpga_write(priv, UNLOCK_OFFSET, UNLOCK_MASK); + +- zynq_fpga_write(priv, INT_MASK_OFFSET, 0xFFFFFFFF); ++ zynq_fpga_set_irq(priv, 0); + zynq_fpga_write(priv, INT_STS_OFFSET, IXR_ALL_MASK); + err = devm_request_irq(dev, priv->irq, zynq_fpga_isr, 0, dev_name(dev), + priv); diff --git a/patches.socfpga/0042-fpga-zynq-Check-the-bitstream-for-validity.patch b/patches.socfpga/0042-fpga-zynq-Check-the-bitstream-for-validity.patch new file mode 100644 index 00000000000000..b5a3ac8f3f46d4 --- /dev/null +++ b/patches.socfpga/0042-fpga-zynq-Check-the-bitstream-for-validity.patch @@ -0,0 +1,72 @@ +From 1e390eb9365008a5f3713e390ffe4484f078468c Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Date: Wed, 1 Feb 2017 12:48:43 -0700 +Subject: [PATCH 042/103] fpga zynq: Check the bitstream for validity + +There is no sense in sending a bitstream we know will not work, and +with the variety of options for bitstream generation in Xilinx tools +it is not terribly clear what the correct input should be. + +This is particularly important for Zynq since auto-correction was +removed from the driver and the Zynq hardware only accepts a bitstream +format that is different from what the Xilinx tools typically produce. + +Worse, the hardware provides no indication why the bitstream fails, +it simply times out if the input is wrong. + +The best option here is to have the kernel print a message informing +the user they are using a malformed bistream and programming failure +isn't for any of the myriad of other reasons. + +Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/zynq-fpga.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +--- a/drivers/fpga/zynq-fpga.c ++++ b/drivers/fpga/zynq-fpga.c +@@ -161,6 +161,19 @@ static irqreturn_t zynq_fpga_isr(int irq + return IRQ_HANDLED; + } + ++/* Sanity check the proposed bitstream. It must start with the sync word in ++ * the correct byte order, and be dword aligned. The input is a Xilinx .bin ++ * file with every 32 bit quantity swapped. ++ */ ++static bool zynq_fpga_has_sync(const u8 *buf, size_t count) ++{ ++ for (; count >= 4; buf += 4, count -= 4) ++ if (buf[0] == 0x66 && buf[1] == 0x55 && buf[2] == 0x99 && ++ buf[3] == 0xaa) ++ return true; ++ return false; ++} ++ + static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t count) +@@ -177,6 +190,13 @@ static int zynq_fpga_ops_write_init(stru + + /* don't globally reset PL if we're doing partial reconfig */ + if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { ++ if (!zynq_fpga_has_sync(buf, count)) { ++ dev_err(&mgr->dev, ++ "Invalid bitstream, could not find a sync word. Bitstream must be a byte swapped .bin file\n"); ++ err = -EINVAL; ++ goto out_err; ++ } ++ + /* assert AXI interface resets */ + regmap_write(priv->slcr, SLCR_FPGA_RST_CTRL_OFFSET, + FPGA_RST_ALL_MASK); +@@ -410,6 +430,7 @@ static enum fpga_mgr_states zynq_fpga_op + } + + static const struct fpga_manager_ops zynq_fpga_ops = { ++ .initial_header_size = 128, + .state = zynq_fpga_ops_state, + .write_init = zynq_fpga_ops_write_init, + .write = zynq_fpga_ops_write, diff --git a/patches.socfpga/0043-fpga-Add-scatterlist-based-programming.patch b/patches.socfpga/0043-fpga-Add-scatterlist-based-programming.patch new file mode 100644 index 00000000000000..b2b44e9b930878 --- /dev/null +++ b/patches.socfpga/0043-fpga-Add-scatterlist-based-programming.patch @@ -0,0 +1,396 @@ +From 5b97663f81233b359315a0e26af540ad11e24171 Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Date: Wed, 1 Feb 2017 12:48:44 -0700 +Subject: [PATCH 043/103] fpga: Add scatterlist based programming + +Requiring contiguous kernel memory is not a good idea, this is a limited +resource and allocation can fail under normal work loads. + +This introduces a .write_sg op that supporting drivers can provide +to DMA directly from dis-contiguous memory and a new entry point +fpga_mgr_buf_load_sg that users can call to directly provide page +lists. + +The full matrix of compatibility is provided, either the linear or sg +interface can be used by the user with a driver supporting either +interface. + +A notable change for drivers is that the .write op can now be called +multiple times. + +Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + Documentation/fpga/fpga-mgr.txt | 19 ++- + drivers/fpga/fpga-mgr.c | 236 ++++++++++++++++++++++++++++++++++------ + include/linux/fpga/fpga-mgr.h | 5 + 3 files changed, 227 insertions(+), 33 deletions(-) + +--- a/Documentation/fpga/fpga-mgr.txt ++++ b/Documentation/fpga/fpga-mgr.txt +@@ -22,7 +22,16 @@ To program the FPGA from a file or from + struct fpga_image_info *info, + const char *buf, size_t count); + +-Load the FPGA from an image which exists as a buffer in memory. ++Load the FPGA from an image which exists as a contiguous buffer in ++memory. Allocating contiguous kernel memory for the buffer should be avoided, ++users are encouraged to use the _sg interface instead of this. ++ ++ int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, ++ struct fpga_image_info *info, ++ struct sg_table *sgt); ++ ++Load the FPGA from an image from non-contiguous in memory. Callers can ++construct a sg_table using alloc_page backed memory. + + int fpga_mgr_firmware_load(struct fpga_manager *mgr, + struct fpga_image_info *info, +@@ -166,7 +175,7 @@ success or negative error codes otherwis + + The programming sequence is: + 1. .write_init +- 2. .write (may be called once or multiple times) ++ 2. .write or .write_sg (may be called once or multiple times) + 3. .write_complete + + The .write_init function will prepare the FPGA to receive the image data. The +@@ -176,7 +185,11 @@ buffer up at least this much before star + + The .write function writes a buffer to the FPGA. The buffer may be contain the + whole FPGA image or may be a smaller chunk of an FPGA image. In the latter +-case, this function is called multiple times for successive chunks. ++case, this function is called multiple times for successive chunks. This interface ++is suitable for drivers which use PIO. ++ ++The .write_sg version behaves the same as .write except the input is a sg_table ++scatter list. This interface is suitable for drivers which use DMA. + + The .write_complete function is called after all the image has been written + to put the FPGA into operating mode. +--- a/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c +@@ -25,16 +25,106 @@ + #include <linux/of.h> + #include <linux/mutex.h> + #include <linux/slab.h> ++#include <linux/scatterlist.h> ++#include <linux/highmem.h> + + static DEFINE_IDA(fpga_mgr_ida); + static struct class *fpga_mgr_class; + ++/* ++ * Call the low level driver's write_init function. This will do the ++ * device-specific things to get the FPGA into the state where it is ready to ++ * receive an FPGA image. The low level driver only gets to see the first ++ * initial_header_size bytes in the buffer. ++ */ ++static int fpga_mgr_write_init_buf(struct fpga_manager *mgr, ++ struct fpga_image_info *info, ++ const char *buf, size_t count) ++{ ++ int ret; ++ ++ mgr->state = FPGA_MGR_STATE_WRITE_INIT; ++ if (!mgr->mops->initial_header_size) ++ ret = mgr->mops->write_init(mgr, info, NULL, 0); ++ else ++ ret = mgr->mops->write_init( ++ mgr, info, buf, min(mgr->mops->initial_header_size, count)); ++ ++ if (ret) { ++ dev_err(&mgr->dev, "Error preparing FPGA for writing\n"); ++ mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR; ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int fpga_mgr_write_init_sg(struct fpga_manager *mgr, ++ struct fpga_image_info *info, ++ struct sg_table *sgt) ++{ ++ struct sg_mapping_iter miter; ++ size_t len; ++ char *buf; ++ int ret; ++ ++ if (!mgr->mops->initial_header_size) ++ return fpga_mgr_write_init_buf(mgr, info, NULL, 0); ++ ++ /* ++ * First try to use miter to map the first fragment to access the ++ * header, this is the typical path. ++ */ ++ sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); ++ if (sg_miter_next(&miter) && ++ miter.length >= mgr->mops->initial_header_size) { ++ ret = fpga_mgr_write_init_buf(mgr, info, miter.addr, ++ miter.length); ++ sg_miter_stop(&miter); ++ return ret; ++ } ++ sg_miter_stop(&miter); ++ ++ /* Otherwise copy the fragments into temporary memory. */ ++ buf = kmalloc(mgr->mops->initial_header_size, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ len = sg_copy_to_buffer(sgt->sgl, sgt->nents, buf, ++ mgr->mops->initial_header_size); ++ ret = fpga_mgr_write_init_buf(mgr, info, buf, len); ++ ++ kfree(buf); ++ ++ return ret; ++} ++ ++/* ++ * After all the FPGA image has been written, do the device specific steps to ++ * finish and set the FPGA into operating mode. ++ */ ++static int fpga_mgr_write_complete(struct fpga_manager *mgr, ++ struct fpga_image_info *info) ++{ ++ int ret; ++ ++ mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE; ++ ret = mgr->mops->write_complete(mgr, info); ++ if (ret) { ++ dev_err(&mgr->dev, "Error after writing image data to FPGA\n"); ++ mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR; ++ return ret; ++ } ++ mgr->state = FPGA_MGR_STATE_OPERATING; ++ ++ return 0; ++} ++ + /** +- * fpga_mgr_buf_load - load fpga from image in buffer ++ * fpga_mgr_buf_load_sg - load fpga from image in buffer from a scatter list + * @mgr: fpga manager + * @info: fpga image specific information +- * @buf: buffer contain fpga image +- * @count: byte count of buf ++ * @sgt: scatterlist table + * + * Step the low level fpga manager through the device-specific steps of getting + * an FPGA ready to be configured, writing the image to it, then doing whatever +@@ -42,54 +132,139 @@ static struct class *fpga_mgr_class; + * mgr pointer from of_fpga_mgr_get() or fpga_mgr_get() and checked that it is + * not an error code. + * ++ * This is the preferred entry point for FPGA programming, it does not require ++ * any contiguous kernel memory. ++ * + * Return: 0 on success, negative error code otherwise. + */ +-int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, +- const char *buf, size_t count) ++int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, struct fpga_image_info *info, ++ struct sg_table *sgt) + { +- struct device *dev = &mgr->dev; + int ret; + +- /* +- * Call the low level driver's write_init function. This will do the +- * device-specific things to get the FPGA into the state where it is +- * ready to receive an FPGA image. The low level driver only gets to +- * see the first initial_header_size bytes in the buffer. +- */ +- mgr->state = FPGA_MGR_STATE_WRITE_INIT; +- ret = mgr->mops->write_init(mgr, info, buf, +- min(mgr->mops->initial_header_size, count)); ++ ret = fpga_mgr_write_init_sg(mgr, info, sgt); ++ if (ret) ++ return ret; ++ ++ /* Write the FPGA image to the FPGA. */ ++ mgr->state = FPGA_MGR_STATE_WRITE; ++ if (mgr->mops->write_sg) { ++ ret = mgr->mops->write_sg(mgr, sgt); ++ } else { ++ struct sg_mapping_iter miter; ++ ++ sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); ++ while (sg_miter_next(&miter)) { ++ ret = mgr->mops->write(mgr, miter.addr, miter.length); ++ if (ret) ++ break; ++ } ++ sg_miter_stop(&miter); ++ } ++ + if (ret) { +- dev_err(dev, "Error preparing FPGA for writing\n"); +- mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR; ++ dev_err(&mgr->dev, "Error while writing image data to FPGA\n"); ++ mgr->state = FPGA_MGR_STATE_WRITE_ERR; + return ret; + } + ++ return fpga_mgr_write_complete(mgr, info); ++} ++EXPORT_SYMBOL_GPL(fpga_mgr_buf_load_sg); ++ ++static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, ++ struct fpga_image_info *info, ++ const char *buf, size_t count) ++{ ++ int ret; ++ ++ ret = fpga_mgr_write_init_buf(mgr, info, buf, count); ++ if (ret) ++ return ret; ++ + /* + * Write the FPGA image to the FPGA. + */ + mgr->state = FPGA_MGR_STATE_WRITE; + ret = mgr->mops->write(mgr, buf, count); + if (ret) { +- dev_err(dev, "Error while writing image data to FPGA\n"); ++ dev_err(&mgr->dev, "Error while writing image data to FPGA\n"); + mgr->state = FPGA_MGR_STATE_WRITE_ERR; + return ret; + } + ++ return fpga_mgr_write_complete(mgr, info); ++} ++ ++/** ++ * fpga_mgr_buf_load - load fpga from image in buffer ++ * @mgr: fpga manager ++ * @flags: flags setting fpga confuration modes ++ * @buf: buffer contain fpga image ++ * @count: byte count of buf ++ * ++ * Step the low level fpga manager through the device-specific steps of getting ++ * an FPGA ready to be configured, writing the image to it, then doing whatever ++ * post-configuration steps necessary. This code assumes the caller got the ++ * mgr pointer from of_fpga_mgr_get() and checked that it is not an error code. ++ * ++ * Return: 0 on success, negative error code otherwise. ++ */ ++int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, ++ const char *buf, size_t count) ++{ ++ struct page **pages; ++ struct sg_table sgt; ++ const void *p; ++ int nr_pages; ++ int index; ++ int rc; ++ + /* +- * After all the FPGA image has been written, do the device specific +- * steps to finish and set the FPGA into operating mode. ++ * This is just a fast path if the caller has already created a ++ * contiguous kernel buffer and the driver doesn't require SG, non-SG ++ * drivers will still work on the slow path. + */ +- mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE; +- ret = mgr->mops->write_complete(mgr, info); +- if (ret) { +- dev_err(dev, "Error after writing image data to FPGA\n"); +- mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR; +- return ret; ++ if (mgr->mops->write) ++ return fpga_mgr_buf_load_mapped(mgr, info, buf, count); ++ ++ /* ++ * Convert the linear kernel pointer into a sg_table of pages for use ++ * by the driver. ++ */ ++ nr_pages = DIV_ROUND_UP((unsigned long)buf + count, PAGE_SIZE) - ++ (unsigned long)buf / PAGE_SIZE; ++ pages = kmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL); ++ if (!pages) ++ return -ENOMEM; ++ ++ p = buf - offset_in_page(buf); ++ for (index = 0; index < nr_pages; index++) { ++ if (is_vmalloc_addr(p)) ++ pages[index] = vmalloc_to_page(p); ++ else ++ pages[index] = kmap_to_page((void *)p); ++ if (!pages[index]) { ++ kfree(pages); ++ return -EFAULT; ++ } ++ p += PAGE_SIZE; + } +- mgr->state = FPGA_MGR_STATE_OPERATING; + +- return 0; ++ /* ++ * The temporary pages list is used to code share the merging algorithm ++ * in sg_alloc_table_from_pages ++ */ ++ rc = sg_alloc_table_from_pages(&sgt, pages, index, offset_in_page(buf), ++ count, GFP_KERNEL); ++ kfree(pages); ++ if (rc) ++ return rc; ++ ++ rc = fpga_mgr_buf_load_sg(mgr, info, &sgt); ++ sg_free_table(&sgt); ++ ++ return rc; + } + EXPORT_SYMBOL_GPL(fpga_mgr_buf_load); + +@@ -291,8 +466,9 @@ int fpga_mgr_register(struct device *dev + struct fpga_manager *mgr; + int id, ret; + +- if (!mops || !mops->write_init || !mops->write || +- !mops->write_complete || !mops->state) { ++ if (!mops || !mops->write_complete || !mops->state || ++ !mops->write_init || (!mops->write && !mops->write_sg) || ++ (mops->write && mops->write_sg)) { + dev_err(dev, "Attempt to register without fpga_manager_ops\n"); + return -EINVAL; + } +--- a/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h +@@ -22,6 +22,7 @@ + #define _LINUX_FPGA_MGR_H + + struct fpga_manager; ++struct sg_table; + + /** + * enum fpga_mgr_states - fpga framework states +@@ -88,6 +89,7 @@ struct fpga_image_info { + * @state: returns an enum value of the FPGA's state + * @write_init: prepare the FPGA to receive confuration data + * @write: write count bytes of configuration data to the FPGA ++ * @write_sg: write the scatter list of configuration data to the FPGA + * @write_complete: set FPGA to operating state after writing is done + * @fpga_remove: optional: Set FPGA into a specific state during driver remove + * +@@ -102,6 +104,7 @@ struct fpga_manager_ops { + struct fpga_image_info *info, + const char *buf, size_t count); + int (*write)(struct fpga_manager *mgr, const char *buf, size_t count); ++ int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt); + int (*write_complete)(struct fpga_manager *mgr, + struct fpga_image_info *info); + void (*fpga_remove)(struct fpga_manager *mgr); +@@ -129,6 +132,8 @@ struct fpga_manager { + + int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info, + const char *buf, size_t count); ++int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, struct fpga_image_info *info, ++ struct sg_table *sgt); + + int fpga_mgr_firmware_load(struct fpga_manager *mgr, + struct fpga_image_info *info, diff --git a/patches.socfpga/0044-fpga-zynq-Use-the-scatterlist-interface.patch b/patches.socfpga/0044-fpga-zynq-Use-the-scatterlist-interface.patch new file mode 100644 index 00000000000000..f14aebdac17660 --- /dev/null +++ b/patches.socfpga/0044-fpga-zynq-Use-the-scatterlist-interface.patch @@ -0,0 +1,304 @@ +From d8b26435b18259639f39aab9ff96cfbf5fdd1076 Mon Sep 17 00:00:00 2001 +From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Date: Wed, 1 Feb 2017 12:48:45 -0700 +Subject: [PATCH 044/103] fpga zynq: Use the scatterlist interface + +This allows the driver to avoid a high order coherent DMA allocation +and memory copy. With this patch it can DMA directly from the kernel +pages that the bitfile is stored in. + +Since this is now a gather DMA operation the driver uses the ISR +to feed the chips DMA queue with each entry from the SGL. + +Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/zynq-fpga.c | 174 ++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 135 insertions(+), 39 deletions(-) + +--- a/drivers/fpga/zynq-fpga.c ++++ b/drivers/fpga/zynq-fpga.c +@@ -30,6 +30,7 @@ + #include <linux/pm.h> + #include <linux/regmap.h> + #include <linux/string.h> ++#include <linux/scatterlist.h> + + /* Offsets into SLCR regmap */ + +@@ -80,6 +81,7 @@ + + /* FPGA init status */ + #define STATUS_DMA_Q_F BIT(31) ++#define STATUS_DMA_Q_E BIT(30) + #define STATUS_PCFG_INIT_MASK BIT(4) + + /* Interrupt Status/Mask Register Bit definitions */ +@@ -98,12 +100,16 @@ + #define DMA_INVALID_ADDRESS GENMASK(31, 0) + /* Used to unlock the dev */ + #define UNLOCK_MASK 0x757bdf0d +-/* Timeout for DMA to complete */ +-#define DMA_DONE_TIMEOUT msecs_to_jiffies(1000) + /* Timeout for polling reset bits */ + #define INIT_POLL_TIMEOUT 2500000 + /* Delay for polling reset bits */ + #define INIT_POLL_DELAY 20 ++/* Signal this is the last DMA transfer, wait for the AXI and PCAP before ++ * interrupting ++ */ ++#define DMA_SRC_LAST_TRANSFER 1 ++/* Timeout for DMA completion */ ++#define DMA_TIMEOUT_MS 5000 + + /* Masks for controlling stuff in SLCR */ + /* Disable all Level shifters */ +@@ -124,6 +130,11 @@ struct zynq_fpga_priv { + void __iomem *io_base; + struct regmap *slcr; + ++ spinlock_t dma_lock; ++ unsigned int dma_elm; ++ unsigned int dma_nelms; ++ struct scatterlist *cur_sg; ++ + struct completion dma_done; + }; + +@@ -149,13 +160,80 @@ static inline void zynq_fpga_set_irq(str + zynq_fpga_write(priv, INT_MASK_OFFSET, ~enable); + } + ++/* Must be called with dma_lock held */ ++static void zynq_step_dma(struct zynq_fpga_priv *priv) ++{ ++ u32 addr; ++ u32 len; ++ bool first; ++ ++ first = priv->dma_elm == 0; ++ while (priv->cur_sg) { ++ /* Feed the DMA queue until it is full. */ ++ if (zynq_fpga_read(priv, STATUS_OFFSET) & STATUS_DMA_Q_F) ++ break; ++ ++ addr = sg_dma_address(priv->cur_sg); ++ len = sg_dma_len(priv->cur_sg); ++ if (priv->dma_elm + 1 == priv->dma_nelms) { ++ /* The last transfer waits for the PCAP to finish too, ++ * notice this also changes the irq_mask to ignore ++ * IXR_DMA_DONE_MASK which ensures we do not trigger ++ * the completion too early. ++ */ ++ addr |= DMA_SRC_LAST_TRANSFER; ++ priv->cur_sg = NULL; ++ } else { ++ priv->cur_sg = sg_next(priv->cur_sg); ++ priv->dma_elm++; ++ } ++ ++ zynq_fpga_write(priv, DMA_SRC_ADDR_OFFSET, addr); ++ zynq_fpga_write(priv, DMA_DST_ADDR_OFFSET, DMA_INVALID_ADDRESS); ++ zynq_fpga_write(priv, DMA_SRC_LEN_OFFSET, len / 4); ++ zynq_fpga_write(priv, DMA_DEST_LEN_OFFSET, 0); ++ } ++ ++ /* Once the first transfer is queued we can turn on the ISR, future ++ * calls to zynq_step_dma will happen from the ISR context. The ++ * dma_lock spinlock guarentees this handover is done coherently, the ++ * ISR enable is put at the end to avoid another CPU spinning in the ++ * ISR on this lock. ++ */ ++ if (first && priv->cur_sg) { ++ zynq_fpga_set_irq(priv, ++ IXR_DMA_DONE_MASK | IXR_ERROR_FLAGS_MASK); ++ } else if (!priv->cur_sg) { ++ /* The last transfer changes to DMA & PCAP mode since we do ++ * not want to continue until everything has been flushed into ++ * the PCAP. ++ */ ++ zynq_fpga_set_irq(priv, ++ IXR_D_P_DONE_MASK | IXR_ERROR_FLAGS_MASK); ++ } ++} ++ + static irqreturn_t zynq_fpga_isr(int irq, void *data) + { + struct zynq_fpga_priv *priv = data; ++ u32 intr_status; + +- /* disable DMA and error IRQs */ +- zynq_fpga_set_irq(priv, 0); ++ /* If anything other than DMA completion is reported stop and hand ++ * control back to zynq_fpga_ops_write, something went wrong, ++ * otherwise progress the DMA. ++ */ ++ spin_lock(&priv->dma_lock); ++ intr_status = zynq_fpga_read(priv, INT_STS_OFFSET); ++ if (!(intr_status & IXR_ERROR_FLAGS_MASK) && ++ (intr_status & IXR_DMA_DONE_MASK) && priv->cur_sg) { ++ zynq_fpga_write(priv, INT_STS_OFFSET, IXR_DMA_DONE_MASK); ++ zynq_step_dma(priv); ++ spin_unlock(&priv->dma_lock); ++ return IRQ_HANDLED; ++ } ++ spin_unlock(&priv->dma_lock); + ++ zynq_fpga_set_irq(priv, 0); + complete(&priv->dma_done); + + return IRQ_HANDLED; +@@ -266,10 +344,11 @@ static int zynq_fpga_ops_write_init(stru + zynq_fpga_write(priv, CTRL_OFFSET, + (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK | ctrl)); + +- /* check that we have room in the command queue */ ++ /* We expect that the command queue is empty right now. */ + status = zynq_fpga_read(priv, STATUS_OFFSET); +- if (status & STATUS_DMA_Q_F) { +- dev_err(&mgr->dev, "DMA command queue full\n"); ++ if ((status & STATUS_DMA_Q_F) || ++ (status & STATUS_DMA_Q_E) != STATUS_DMA_Q_E) { ++ dev_err(&mgr->dev, "DMA command queue not right\n"); + err = -EBUSY; + goto out_err; + } +@@ -288,27 +367,36 @@ out_err: + return err; + } + +-static int zynq_fpga_ops_write(struct fpga_manager *mgr, +- const char *buf, size_t count) ++static int zynq_fpga_ops_write(struct fpga_manager *mgr, struct sg_table *sgt) + { + struct zynq_fpga_priv *priv; + const char *why; + int err; +- char *kbuf; +- size_t in_count; +- dma_addr_t dma_addr; +- u32 transfer_length; + u32 intr_status; ++ unsigned long timeout; ++ unsigned long flags; ++ struct scatterlist *sg; ++ int i; + +- in_count = count; + priv = mgr->priv; + +- kbuf = +- dma_alloc_coherent(mgr->dev.parent, count, &dma_addr, GFP_KERNEL); +- if (!kbuf) +- return -ENOMEM; ++ /* The hardware can only DMA multiples of 4 bytes, and it requires the ++ * starting addresses to be aligned to 64 bits (UG585 pg 212). ++ */ ++ for_each_sg(sgt->sgl, sg, sgt->nents, i) { ++ if ((sg->offset % 8) || (sg->length % 4)) { ++ dev_err(&mgr->dev, ++ "Invalid bitstream, chunks must be aligned\n"); ++ return -EINVAL; ++ } ++ } + +- memcpy(kbuf, buf, count); ++ priv->dma_nelms = ++ dma_map_sg(mgr->dev.parent, sgt->sgl, sgt->nents, DMA_TO_DEVICE); ++ if (priv->dma_nelms == 0) { ++ dev_err(&mgr->dev, "Unable to DMA map (TO_DEVICE)\n"); ++ return -ENOMEM; ++ } + + /* enable clock */ + err = clk_enable(priv->clk); +@@ -316,28 +404,31 @@ static int zynq_fpga_ops_write(struct fp + goto out_free; + + zynq_fpga_write(priv, INT_STS_OFFSET, IXR_ALL_MASK); +- + reinit_completion(&priv->dma_done); + +- /* enable DMA and error IRQs */ +- zynq_fpga_set_irq(priv, IXR_D_P_DONE_MASK | IXR_ERROR_FLAGS_MASK); +- +- /* the +1 in the src addr is used to hold off on DMA_DONE IRQ +- * until both AXI and PCAP are done ... +- */ +- zynq_fpga_write(priv, DMA_SRC_ADDR_OFFSET, (u32)(dma_addr) + 1); +- zynq_fpga_write(priv, DMA_DST_ADDR_OFFSET, (u32)DMA_INVALID_ADDRESS); +- +- /* convert #bytes to #words */ +- transfer_length = (count + 3) / 4; ++ /* zynq_step_dma will turn on interrupts */ ++ spin_lock_irqsave(&priv->dma_lock, flags); ++ priv->dma_elm = 0; ++ priv->cur_sg = sgt->sgl; ++ zynq_step_dma(priv); ++ spin_unlock_irqrestore(&priv->dma_lock, flags); + +- zynq_fpga_write(priv, DMA_SRC_LEN_OFFSET, transfer_length); +- zynq_fpga_write(priv, DMA_DEST_LEN_OFFSET, 0); ++ timeout = wait_for_completion_timeout(&priv->dma_done, ++ msecs_to_jiffies(DMA_TIMEOUT_MS)); + +- wait_for_completion(&priv->dma_done); ++ spin_lock_irqsave(&priv->dma_lock, flags); ++ zynq_fpga_set_irq(priv, 0); ++ priv->cur_sg = NULL; ++ spin_unlock_irqrestore(&priv->dma_lock, flags); + + intr_status = zynq_fpga_read(priv, INT_STS_OFFSET); +- zynq_fpga_write(priv, INT_STS_OFFSET, intr_status); ++ zynq_fpga_write(priv, INT_STS_OFFSET, IXR_ALL_MASK); ++ ++ /* There doesn't seem to be a way to force cancel any DMA, so if ++ * something went wrong we are relying on the hardware to have halted ++ * the DMA before we get here, if there was we could use ++ * wait_for_completion_interruptible too. ++ */ + + if (intr_status & IXR_ERROR_FLAGS_MASK) { + why = "DMA reported error"; +@@ -345,8 +436,12 @@ static int zynq_fpga_ops_write(struct fp + goto out_report; + } + +- if (!((intr_status & IXR_D_P_DONE_MASK) == IXR_D_P_DONE_MASK)) { +- why = "DMA did not complete"; ++ if (priv->cur_sg || ++ !((intr_status & IXR_D_P_DONE_MASK) == IXR_D_P_DONE_MASK)) { ++ if (timeout == 0) ++ why = "DMA timed out"; ++ else ++ why = "DMA did not complete"; + err = -EIO; + goto out_report; + } +@@ -369,7 +464,7 @@ out_clk: + clk_disable(priv->clk); + + out_free: +- dma_free_coherent(mgr->dev.parent, count, kbuf, dma_addr); ++ dma_unmap_sg(mgr->dev.parent, sgt->sgl, sgt->nents, DMA_TO_DEVICE); + return err; + } + +@@ -433,7 +528,7 @@ static const struct fpga_manager_ops zyn + .initial_header_size = 128, + .state = zynq_fpga_ops_state, + .write_init = zynq_fpga_ops_write_init, +- .write = zynq_fpga_ops_write, ++ .write_sg = zynq_fpga_ops_write, + .write_complete = zynq_fpga_ops_write_complete, + }; + +@@ -447,6 +542,7 @@ static int zynq_fpga_probe(struct platfo + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; ++ spin_lock_init(&priv->dma_lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->io_base = devm_ioremap_resource(dev, res); diff --git a/patches.socfpga/0045-fpga-fix-sparse-warnings-in-fpga-mgr-and-fpga-bridge.patch b/patches.socfpga/0045-fpga-fix-sparse-warnings-in-fpga-mgr-and-fpga-bridge.patch new file mode 100644 index 00000000000000..8c9fde3740934f --- /dev/null +++ b/patches.socfpga/0045-fpga-fix-sparse-warnings-in-fpga-mgr-and-fpga-bridge.patch @@ -0,0 +1,41 @@ +From e465a0699c040d68ea3790af91f6e73cd4797ea7 Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Mon, 27 Feb 2017 09:18:59 -0600 +Subject: [PATCH 045/103] fpga: fix sparse warnings in fpga-mgr and fpga-bridge + +Fix up these sparse warnings: + +drivers/fpga/fpga-mgr.c:189:21: warning: symbol '__fpga_mgr_get' was not declared. Should it be static? +drivers/fpga/fpga-bridge.c:30:12: warning: symbol 'bridge_list_lock' was not declared. Should it be static? + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +Acked-by: Moritz Fischer <mdf@kernel.org> +Signed-off-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/fpga-bridge.c | 2 +- + drivers/fpga/fpga-mgr.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/fpga/fpga-bridge.c ++++ b/drivers/fpga/fpga-bridge.c +@@ -27,7 +27,7 @@ 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 spinlock_t bridge_list_lock; + + static int fpga_bridge_of_node_match(struct device *dev, const void *data) + { +--- a/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c +@@ -361,7 +361,7 @@ static struct attribute *fpga_mgr_attrs[ + }; + ATTRIBUTE_GROUPS(fpga_mgr); + +-struct fpga_manager *__fpga_mgr_get(struct device *dev) ++static struct fpga_manager *__fpga_mgr_get(struct device *dev) + { + struct fpga_manager *mgr; + int ret = -ENODEV; diff --git a/patches.socfpga/0046-fpga-Add-flag-to-indicate-bitstream-needs-decrypting.patch b/patches.socfpga/0046-fpga-Add-flag-to-indicate-bitstream-needs-decrypting.patch new file mode 100644 index 00000000000000..f2327b0ac2f078 --- /dev/null +++ b/patches.socfpga/0046-fpga-Add-flag-to-indicate-bitstream-needs-decrypting.patch @@ -0,0 +1,29 @@ +From 52ae233165163bb6c71e8be8ee703a1eb0fa3e25 Mon Sep 17 00:00:00 2001 +From: Moritz Fischer <mdf@kernel.org> +Date: Mon, 27 Feb 2017 09:19:00 -0600 +Subject: [PATCH 046/103] fpga: Add flag to indicate bitstream needs decrypting + +Add a flag that is passed to the write_init() callback, indicating +that the bitstream is encrypted. + +The low-level driver will deal with the flag, or return an error, +if encrypted bitstreams are not supported. + +Signed-off-by: Moritz Fischer <mdf@kernel.org> +Acked-by: Michal Simek <michal.simek@xilinx.com> +Signed-off-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + include/linux/fpga/fpga-mgr.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h +@@ -70,6 +70,7 @@ enum fpga_mgr_states { + */ + #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + #define FPGA_MGR_EXTERNAL_CONFIG BIT(1) ++#define FPGA_MGR_ENCRYPTED_BITSTREAM BIT(2) + + /** + * struct fpga_image_info - information specific to a FPGA image diff --git a/patches.socfpga/0047-fpga-zynq-Add-support-for-encrypted-bitstreams.patch b/patches.socfpga/0047-fpga-zynq-Add-support-for-encrypted-bitstreams.patch new file mode 100644 index 00000000000000..db09d001f49ea9 --- /dev/null +++ b/patches.socfpga/0047-fpga-zynq-Add-support-for-encrypted-bitstreams.patch @@ -0,0 +1,73 @@ +From 478e30d8b329c3c6212e903e6ba68997e2f0582a Mon Sep 17 00:00:00 2001 +From: Moritz Fischer <mdf@kernel.org> +Date: Mon, 27 Feb 2017 09:19:01 -0600 +Subject: [PATCH 047/103] fpga: zynq: Add support for encrypted bitstreams + +Add support for encrypted bitstreams. For this to work the system +must be booted in secure mode. + +In order for on-the-fly decryption to work, the PCAP clock rate +needs to be lowered via the PCAP_RATE_EN bit. + +Signed-off-by: Moritz Fischer <mdf@kernel.org> +Acked-by: Michal Simek <michal.simek@xilinx.com> +Signed-off-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/zynq-fpga.c | 28 +++++++++++++++++++++++++--- + 1 file changed, 25 insertions(+), 3 deletions(-) + +--- a/drivers/fpga/zynq-fpga.c ++++ b/drivers/fpga/zynq-fpga.c +@@ -72,6 +72,10 @@ + #define CTRL_PCAP_PR_MASK BIT(27) + /* Enable PCAP */ + #define CTRL_PCAP_MODE_MASK BIT(26) ++/* Lower rate to allow decrypt on the fly */ ++#define CTRL_PCAP_RATE_EN_MASK BIT(25) ++/* System booted in secure mode */ ++#define CTRL_SEC_EN_MASK BIT(7) + + /* Miscellaneous Control Register bit definitions */ + /* Internal PCAP loopback */ +@@ -266,6 +270,17 @@ static int zynq_fpga_ops_write_init(stru + if (err) + return err; + ++ /* check if bitstream is encrypted & and system's still secure */ ++ if (info->flags & FPGA_MGR_ENCRYPTED_BITSTREAM) { ++ ctrl = zynq_fpga_read(priv, CTRL_OFFSET); ++ if (!(ctrl & CTRL_SEC_EN_MASK)) { ++ dev_err(&mgr->dev, ++ "System not secure, can't use crypted bitstreams\n"); ++ err = -EINVAL; ++ goto out_err; ++ } ++ } ++ + /* don't globally reset PL if we're doing partial reconfig */ + if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { + if (!zynq_fpga_has_sync(buf, count)) { +@@ -337,12 +352,19 @@ static int zynq_fpga_ops_write_init(stru + + /* set configuration register with following options: + * - enable PCAP interface +- * - set throughput for maximum speed ++ * - set throughput for maximum speed (if bistream not crypted) + * - set CPU in user mode + */ + ctrl = zynq_fpga_read(priv, CTRL_OFFSET); +- zynq_fpga_write(priv, CTRL_OFFSET, +- (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK | ctrl)); ++ if (info->flags & FPGA_MGR_ENCRYPTED_BITSTREAM) ++ zynq_fpga_write(priv, CTRL_OFFSET, ++ (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK ++ | CTRL_PCAP_RATE_EN_MASK | ctrl)); ++ else ++ zynq_fpga_write(priv, CTRL_OFFSET, ++ (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK ++ | ctrl)); ++ + + /* We expect that the command queue is empty right now. */ + status = zynq_fpga_read(priv, STATUS_OFFSET); diff --git a/patches.socfpga/0048-fpga-region-Add-fpga-region-property-encrypted-fpga-.patch b/patches.socfpga/0048-fpga-region-Add-fpga-region-property-encrypted-fpga-.patch new file mode 100644 index 00000000000000..2b425ec38a57e7 --- /dev/null +++ b/patches.socfpga/0048-fpga-region-Add-fpga-region-property-encrypted-fpga-.patch @@ -0,0 +1,52 @@ +From 273c66a75fbbc3ca0afc73fc39c36932da94b37f Mon Sep 17 00:00:00 2001 +From: Moritz Fischer <mdf@kernel.org> +Date: Mon, 27 Feb 2017 09:19:02 -0600 +Subject: [PATCH 048/103] fpga: region: Add fpga-region property + 'encrypted-fpga-config' + +Add fpga-region property to allow passing the fact that the bitstream is +encrypted to the fpga-region and ultimately to the low-level driver. + +Signed-off-by: Moritz Fischer <mdf@kernel.org> +Acked-by: Michal Simek <michal.simek@xilinx.com> +Signed-off-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + Documentation/devicetree/bindings/fpga/fpga-region.txt | 1 + + drivers/fpga/fpga-region.c | 8 ++++++-- + 2 files changed, 7 insertions(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/fpga/fpga-region.txt ++++ b/Documentation/devicetree/bindings/fpga/fpga-region.txt +@@ -186,6 +186,7 @@ Optional properties: + otherwise full reconfiguration is done. + - external-fpga-config : boolean, set if the FPGA has already been configured + prior to OS boot up. ++- encrypted-fpga-config : boolean, set if the bitstream is encrypted + - region-unfreeze-timeout-us : The maximum time in microseconds to wait for + bridges to successfully become enabled after the region has been + programmed. +--- a/drivers/fpga/fpga-region.c ++++ b/drivers/fpga/fpga-region.c +@@ -337,8 +337,9 @@ static int child_regions_with_firmware(s + * The overlay must add either firmware-name or external-fpga-config property + * to the FPGA Region. + * +- * firmware-name : program the FPGA +- * external-fpga-config : FPGA is already programmed ++ * firmware-name : program the FPGA ++ * external-fpga-config : FPGA is already programmed ++ * encrypted-fpga-config : FPGA bitstream is encrypted + * + * The overlay can add other FPGA regions, but child FPGA regions cannot have a + * firmware-name property since those regions don't exist yet. +@@ -373,6 +374,9 @@ static int fpga_region_notify_pre_apply( + if (of_property_read_bool(nd->overlay, "external-fpga-config")) + info->flags |= FPGA_MGR_EXTERNAL_CONFIG; + ++ if (of_property_read_bool(nd->overlay, "encrypted-fpga-config")) ++ info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM; ++ + of_property_read_string(nd->overlay, "firmware-name", &firmware_name); + + of_property_read_u32(nd->overlay, "region-unfreeze-timeout-us", diff --git a/patches.socfpga/0049-FPGA-Add-TS-7300-FPGA-manager.patch b/patches.socfpga/0049-FPGA-Add-TS-7300-FPGA-manager.patch new file mode 100644 index 00000000000000..6dbc86a5629fc5 --- /dev/null +++ b/patches.socfpga/0049-FPGA-Add-TS-7300-FPGA-manager.patch @@ -0,0 +1,211 @@ +From bed35874b4fe30165188c479341d04fdb7d74230 Mon Sep 17 00:00:00 2001 +From: Florian Fainelli <f.fainelli@gmail.com> +Date: Mon, 27 Feb 2017 16:14:22 -0600 +Subject: [PATCH 049/103] FPGA: Add TS-7300 FPGA manager + +Add support for loading bitstreams on the Altera Cyclone II FPGA +populated on the TS-7300 board. This is done through the configuration +and data registers offered through a memory interface between the EP93xx +SoC and the FPGA via an intermediate CPLD device. + +The EP93xx SoC on the TS-7300 does not have direct means of configuring +the on-board FPGA other than by using the special memory mapped +interface to the CPLD. No other entity on the system can control the +FPGA bitstream. + +Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 7 ++ + drivers/fpga/Makefile | 1 + drivers/fpga/ts73xx-fpga.c | 156 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 164 insertions(+) + create mode 100644 drivers/fpga/ts73xx-fpga.c + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -33,6 +33,13 @@ config FPGA_MGR_SOCFPGA_A10 + help + FPGA manager driver support for Altera Arria10 SoCFPGA. + ++config FPGA_MGR_TS73XX ++ tristate "Technologic Systems TS-73xx SBC FPGA Manager" ++ depends on ARCH_EP93XX && MACH_TS72XX ++ help ++ FPGA manager driver support for the Altera Cyclone II FPGA ++ present on the TS-73xx SBC boards. ++ + config FPGA_MGR_ZYNQ_FPGA + tristate "Xilinx Zynq FPGA" + depends on ARCH_ZYNQ || COMPILE_TEST +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -8,6 +8,7 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o + # FPGA Manager Drivers + obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o + obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o ++obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o + obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o + + # FPGA Bridge Drivers +--- /dev/null ++++ b/drivers/fpga/ts73xx-fpga.c +@@ -0,0 +1,156 @@ ++/* ++ * Technologic Systems TS-73xx SBC FPGA loader ++ * ++ * Copyright (C) 2016 Florian Fainelli <f.fainelli@gmail.com> ++ * ++ * FPGA Manager Driver for the on-board Altera Cyclone II FPGA found on ++ * TS-7300, heavily based on load_fpga.c in their vendor tree. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/string.h> ++#include <linux/iopoll.h> ++#include <linux/fpga/fpga-mgr.h> ++ ++#define TS73XX_FPGA_DATA_REG 0 ++#define TS73XX_FPGA_CONFIG_REG 1 ++ ++#define TS73XX_FPGA_WRITE_DONE 0x1 ++#define TS73XX_FPGA_WRITE_DONE_TIMEOUT 1000 /* us */ ++#define TS73XX_FPGA_RESET 0x2 ++#define TS73XX_FPGA_RESET_LOW_DELAY 30 /* us */ ++#define TS73XX_FPGA_RESET_HIGH_DELAY 80 /* us */ ++#define TS73XX_FPGA_LOAD_OK 0x4 ++#define TS73XX_FPGA_CONFIG_LOAD 0x8 ++ ++struct ts73xx_fpga_priv { ++ void __iomem *io_base; ++ struct device *dev; ++}; ++ ++static enum fpga_mgr_states ts73xx_fpga_state(struct fpga_manager *mgr) ++{ ++ return FPGA_MGR_STATE_UNKNOWN; ++} ++ ++static int ts73xx_fpga_write_init(struct fpga_manager *mgr, ++ struct fpga_image_info *info, ++ const char *buf, size_t count) ++{ ++ struct ts73xx_fpga_priv *priv = mgr->priv; ++ ++ /* Reset the FPGA */ ++ writeb(0, priv->io_base + TS73XX_FPGA_CONFIG_REG); ++ udelay(TS73XX_FPGA_RESET_LOW_DELAY); ++ writeb(TS73XX_FPGA_RESET, priv->io_base + TS73XX_FPGA_CONFIG_REG); ++ udelay(TS73XX_FPGA_RESET_HIGH_DELAY); ++ ++ return 0; ++} ++ ++static int ts73xx_fpga_write(struct fpga_manager *mgr, const char *buf, ++ size_t count) ++{ ++ struct ts73xx_fpga_priv *priv = mgr->priv; ++ size_t i = 0; ++ int ret; ++ u8 reg; ++ ++ while (count--) { ++ ret = readb_poll_timeout(priv->io_base + TS73XX_FPGA_CONFIG_REG, ++ reg, !(reg & TS73XX_FPGA_WRITE_DONE), ++ 1, TS73XX_FPGA_WRITE_DONE_TIMEOUT); ++ if (ret < 0) ++ return ret; ++ ++ writeb(buf[i], priv->io_base + TS73XX_FPGA_DATA_REG); ++ i++; ++ } ++ ++ return 0; ++} ++ ++static int ts73xx_fpga_write_complete(struct fpga_manager *mgr, ++ struct fpga_image_info *info) ++{ ++ struct ts73xx_fpga_priv *priv = mgr->priv; ++ u8 reg; ++ ++ usleep_range(1000, 2000); ++ reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG); ++ reg |= TS73XX_FPGA_CONFIG_LOAD; ++ writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG); ++ ++ usleep_range(1000, 2000); ++ reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG); ++ reg &= ~TS73XX_FPGA_CONFIG_LOAD; ++ writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG); ++ ++ reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG); ++ if ((reg & TS73XX_FPGA_LOAD_OK) != TS73XX_FPGA_LOAD_OK) ++ return -ETIMEDOUT; ++ ++ return 0; ++} ++ ++static const struct fpga_manager_ops ts73xx_fpga_ops = { ++ .state = ts73xx_fpga_state, ++ .write_init = ts73xx_fpga_write_init, ++ .write = ts73xx_fpga_write, ++ .write_complete = ts73xx_fpga_write_complete, ++}; ++ ++static int ts73xx_fpga_probe(struct platform_device *pdev) ++{ ++ struct device *kdev = &pdev->dev; ++ struct ts73xx_fpga_priv *priv; ++ struct resource *res; ++ ++ priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = kdev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->io_base = devm_ioremap_resource(kdev, res); ++ if (IS_ERR(priv->io_base)) { ++ dev_err(kdev, "unable to remap registers\n"); ++ return PTR_ERR(priv->io_base); ++ } ++ ++ return fpga_mgr_register(kdev, "TS-73xx FPGA Manager", ++ &ts73xx_fpga_ops, priv); ++} ++ ++static int ts73xx_fpga_remove(struct platform_device *pdev) ++{ ++ fpga_mgr_unregister(&pdev->dev); ++ ++ return 0; ++} ++ ++static struct platform_driver ts73xx_fpga_driver = { ++ .driver = { ++ .name = "ts73xx-fpga-mgr", ++ }, ++ .probe = ts73xx_fpga_probe, ++ .remove = ts73xx_fpga_remove, ++}; ++module_platform_driver(ts73xx_fpga_driver); ++ ++MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>"); ++MODULE_DESCRIPTION("TS-73xx FPGA Manager driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/patches.socfpga/0050-Documentation-Add-binding-document-for-Lattice-iCE40.patch b/patches.socfpga/0050-Documentation-Add-binding-document-for-Lattice-iCE40.patch new file mode 100644 index 00000000000000..c933e57f6ce25f --- /dev/null +++ b/patches.socfpga/0050-Documentation-Add-binding-document-for-Lattice-iCE40.patch @@ -0,0 +1,44 @@ +From 17e3c8974a87f231c91825ff809988797a001f35 Mon Sep 17 00:00:00 2001 +From: Joel Holdsworth <joel@airwebreathe.org.uk> +Date: Mon, 27 Feb 2017 16:14:25 -0600 +Subject: [PATCH 050/103] Documentation: Add binding document for Lattice iCE40 + FPGA manager + +This adds documentation of the device tree bindings of the Lattice iCE40 +FPGA driver for the FPGA manager framework. + +Signed-off-by: Joel Holdsworth <joel@airwebreathe.org.uk> +Acked-by: Rob Herring <robh@kernel.org> +Acked-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Acked-by: Marek Vasut <marex@denx.de> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + Documentation/devicetree/bindings/fpga/lattice-ice40-fpga-mgr.txt | 21 ++++++++++ + 1 file changed, 21 insertions(+) + create mode 100644 Documentation/devicetree/bindings/fpga/lattice-ice40-fpga-mgr.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/fpga/lattice-ice40-fpga-mgr.txt +@@ -0,0 +1,21 @@ ++Lattice iCE40 FPGA Manager ++ ++Required properties: ++- compatible: Should contain "lattice,ice40-fpga-mgr" ++- reg: SPI chip select ++- spi-max-frequency: Maximum SPI frequency (>=1000000, <=25000000) ++- cdone-gpios: GPIO input connected to CDONE pin ++- reset-gpios: Active-low GPIO output connected to CRESET_B pin. Note ++ that unless the GPIO is held low during startup, the ++ FPGA will enter Master SPI mode and drive SCK with a ++ clock signal potentially jamming other devices on the ++ bus until the firmware is loaded. ++ ++Example: ++ fpga: fpga@0 { ++ compatible = "lattice,ice40-fpga-mgr"; ++ reg = <0>; ++ spi-max-frequency = <1000000>; ++ cdone-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&gpio 22 GPIO_ACTIVE_LOW>; ++ }; diff --git a/patches.socfpga/0051-fpga-Add-support-for-Lattice-iCE40-FPGAs.patch b/patches.socfpga/0051-fpga-Add-support-for-Lattice-iCE40-FPGAs.patch new file mode 100644 index 00000000000000..afe02a501f2687 --- /dev/null +++ b/patches.socfpga/0051-fpga-Add-support-for-Lattice-iCE40-FPGAs.patch @@ -0,0 +1,256 @@ +From dea9de651d978f61922c8cebd01a3089c0acfd04 Mon Sep 17 00:00:00 2001 +From: Joel Holdsworth <joel@airwebreathe.org.uk> +Date: Mon, 27 Feb 2017 16:14:26 -0600 +Subject: [PATCH 051/103] fpga: Add support for Lattice iCE40 FPGAs + +This patch adds support to the FPGA manager for configuring the SRAM of +iCE40LM, iCE40LP, iCE40HX, iCE40 Ultra, iCE40 UltraLite and iCE40 +UltraPlus devices, through slave SPI. + +Signed-off-by: Joel Holdsworth <joel@airwebreathe.org.uk> +Reviewed-by: Marek Vasut <marex@denx.de> +Reviewed-by: Moritz Fischer <moritz.fischer@ettus.com> +Acked-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 6 + + drivers/fpga/Makefile | 1 + drivers/fpga/ice40-spi.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 214 insertions(+) + create mode 100644 drivers/fpga/ice40-spi.c + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -20,6 +20,12 @@ config FPGA_REGION + FPGA Regions allow loading FPGA images under control of + the Device Tree. + ++config FPGA_MGR_ICE40_SPI ++ tristate "Lattice iCE40 SPI" ++ depends on OF && SPI ++ help ++ FPGA manager driver support for Lattice iCE40 FPGAs over SPI. ++ + config FPGA_MGR_SOCFPGA + tristate "Altera SOCFPGA FPGA Manager" + depends on ARCH_SOCFPGA || COMPILE_TEST +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -6,6 +6,7 @@ + obj-$(CONFIG_FPGA) += fpga-mgr.o + + # FPGA Manager Drivers ++obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o + obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o + obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o + obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o +--- /dev/null ++++ b/drivers/fpga/ice40-spi.c +@@ -0,0 +1,207 @@ ++/* ++ * FPGA Manager Driver for Lattice iCE40. ++ * ++ * Copyright (c) 2016 Joel Holdsworth ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This driver adds support to the FPGA manager for configuring the SRAM of ++ * Lattice iCE40 FPGAs through slave SPI. ++ */ ++ ++#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/stringify.h> ++ ++#define ICE40_SPI_MAX_SPEED 25000000 /* Hz */ ++#define ICE40_SPI_MIN_SPEED 1000000 /* Hz */ ++ ++#define ICE40_SPI_RESET_DELAY 1 /* us (>200ns) */ ++#define ICE40_SPI_HOUSEKEEPING_DELAY 1200 /* us */ ++ ++#define ICE40_SPI_NUM_ACTIVATION_BYTES DIV_ROUND_UP(49, 8) ++ ++struct ice40_fpga_priv { ++ struct spi_device *dev; ++ struct gpio_desc *reset; ++ struct gpio_desc *cdone; ++}; ++ ++static enum fpga_mgr_states ice40_fpga_ops_state(struct fpga_manager *mgr) ++{ ++ struct ice40_fpga_priv *priv = mgr->priv; ++ ++ return gpiod_get_value(priv->cdone) ? FPGA_MGR_STATE_OPERATING : ++ FPGA_MGR_STATE_UNKNOWN; ++} ++ ++static int ice40_fpga_ops_write_init(struct fpga_manager *mgr, ++ struct fpga_image_info *info, ++ const char *buf, size_t count) ++{ ++ struct ice40_fpga_priv *priv = mgr->priv; ++ struct spi_device *dev = priv->dev; ++ struct spi_message message; ++ struct spi_transfer assert_cs_then_reset_delay = { ++ .cs_change = 1, ++ .delay_usecs = ICE40_SPI_RESET_DELAY ++ }; ++ struct spi_transfer housekeeping_delay_then_release_cs = { ++ .delay_usecs = ICE40_SPI_HOUSEKEEPING_DELAY ++ }; ++ int ret; ++ ++ if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { ++ dev_err(&dev->dev, ++ "Partial reconfiguration is not supported\n"); ++ return -ENOTSUPP; ++ } ++ ++ /* Lock the bus, assert CRESET_B and SS_B and delay >200ns */ ++ spi_bus_lock(dev->master); ++ ++ gpiod_set_value(priv->reset, 1); ++ ++ spi_message_init(&message); ++ spi_message_add_tail(&assert_cs_then_reset_delay, &message); ++ ret = spi_sync_locked(dev, &message); ++ ++ /* Come out of reset */ ++ gpiod_set_value(priv->reset, 0); ++ ++ /* Abort if the chip-select failed */ ++ if (ret) ++ goto fail; ++ ++ /* Check CDONE is de-asserted i.e. the FPGA is reset */ ++ if (gpiod_get_value(priv->cdone)) { ++ dev_err(&dev->dev, "Device reset failed, CDONE is asserted\n"); ++ ret = -EIO; ++ goto fail; ++ } ++ ++ /* Wait for the housekeeping to complete, and release SS_B */ ++ spi_message_init(&message); ++ spi_message_add_tail(&housekeeping_delay_then_release_cs, &message); ++ ret = spi_sync_locked(dev, &message); ++ ++fail: ++ spi_bus_unlock(dev->master); ++ ++ return ret; ++} ++ ++static int ice40_fpga_ops_write(struct fpga_manager *mgr, ++ const char *buf, size_t count) ++{ ++ struct ice40_fpga_priv *priv = mgr->priv; ++ ++ return spi_write(priv->dev, buf, count); ++} ++ ++static int ice40_fpga_ops_write_complete(struct fpga_manager *mgr, ++ struct fpga_image_info *info) ++{ ++ struct ice40_fpga_priv *priv = mgr->priv; ++ struct spi_device *dev = priv->dev; ++ const u8 padding[ICE40_SPI_NUM_ACTIVATION_BYTES] = {0}; ++ ++ /* Check CDONE is asserted */ ++ if (!gpiod_get_value(priv->cdone)) { ++ dev_err(&dev->dev, ++ "CDONE was not asserted after firmware transfer\n"); ++ return -EIO; ++ } ++ ++ /* Send of zero-padding to activate the firmware */ ++ return spi_write(dev, padding, sizeof(padding)); ++} ++ ++static const struct fpga_manager_ops ice40_fpga_ops = { ++ .state = ice40_fpga_ops_state, ++ .write_init = ice40_fpga_ops_write_init, ++ .write = ice40_fpga_ops_write, ++ .write_complete = ice40_fpga_ops_write_complete, ++}; ++ ++static int ice40_fpga_probe(struct spi_device *spi) ++{ ++ struct device *dev = &spi->dev; ++ struct ice40_fpga_priv *priv; ++ int ret; ++ ++ priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = spi; ++ ++ /* Check board setup data. */ ++ if (spi->max_speed_hz > ICE40_SPI_MAX_SPEED) { ++ dev_err(dev, "SPI speed is too high, maximum speed is " ++ __stringify(ICE40_SPI_MAX_SPEED) "\n"); ++ return -EINVAL; ++ } ++ ++ if (spi->max_speed_hz < ICE40_SPI_MIN_SPEED) { ++ dev_err(dev, "SPI speed is too low, minimum speed is " ++ __stringify(ICE40_SPI_MIN_SPEED) "\n"); ++ return -EINVAL; ++ } ++ ++ if (spi->mode & SPI_CPHA) { ++ dev_err(dev, "Bad SPI mode, CPHA not supported\n"); ++ return -EINVAL; ++ } ++ ++ /* Set up the GPIOs */ ++ priv->cdone = devm_gpiod_get(dev, "cdone", GPIOD_IN); ++ if (IS_ERR(priv->cdone)) { ++ ret = PTR_ERR(priv->cdone); ++ dev_err(dev, "Failed to get CDONE GPIO: %d\n", ret); ++ return ret; ++ } ++ ++ priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); ++ if (IS_ERR(priv->reset)) { ++ ret = PTR_ERR(priv->reset); ++ dev_err(dev, "Failed to get CRESET_B GPIO: %d\n", ret); ++ return ret; ++ } ++ ++ /* Register with the FPGA manager */ ++ return fpga_mgr_register(dev, "Lattice iCE40 FPGA Manager", ++ &ice40_fpga_ops, priv); ++} ++ ++static int ice40_fpga_remove(struct spi_device *spi) ++{ ++ fpga_mgr_unregister(&spi->dev); ++ return 0; ++} ++ ++static const struct of_device_id ice40_fpga_of_match[] = { ++ { .compatible = "lattice,ice40-fpga-mgr", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ice40_fpga_of_match); ++ ++static struct spi_driver ice40_fpga_driver = { ++ .probe = ice40_fpga_probe, ++ .remove = ice40_fpga_remove, ++ .driver = { ++ .name = "ice40spi", ++ .of_match_table = of_match_ptr(ice40_fpga_of_match), ++ }, ++}; ++ ++module_spi_driver(ice40_fpga_driver); ++ ++MODULE_AUTHOR("Joel Holdsworth <joel@airwebreathe.org.uk>"); ++MODULE_DESCRIPTION("Lattice iCE40 FPGA Manager"); ++MODULE_LICENSE("GPL v2"); diff --git a/patches.socfpga/0052-fpga-bridge-Replace-open-coded-list_for_each-list_en.patch b/patches.socfpga/0052-fpga-bridge-Replace-open-coded-list_for_each-list_en.patch new file mode 100644 index 00000000000000..a218c13f57d425 --- /dev/null +++ b/patches.socfpga/0052-fpga-bridge-Replace-open-coded-list_for_each-list_en.patch @@ -0,0 +1,62 @@ +From 65107537be49563835a6accd0a7ef0dd078020cb Mon Sep 17 00:00:00 2001 +From: Moritz Fischer <mdf@kernel.org> +Date: Fri, 10 Mar 2017 12:47:11 -0800 +Subject: [PATCH 052/103] fpga: bridge: Replace open-coded list_for_each + + list_entry + +Replaces open-coded list_for_each() + list_entry() with macro +list_for_each_entry() + +Signed-off-by: Moritz Fischer <mdf@kernel.org> +Cc: linux-fpga@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Acked-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/fpga-bridge.c | 15 ++++----------- + 1 file changed, 4 insertions(+), 11 deletions(-) + +--- a/drivers/fpga/fpga-bridge.c ++++ b/drivers/fpga/fpga-bridge.c +@@ -146,11 +146,9 @@ EXPORT_SYMBOL_GPL(fpga_bridge_put); + 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); ++ list_for_each_entry(bridge, bridge_list, node) { + ret = fpga_bridge_enable(bridge); + if (ret) + return ret; +@@ -172,11 +170,9 @@ EXPORT_SYMBOL_GPL(fpga_bridges_enable); + 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); ++ list_for_each_entry(bridge, bridge_list, node) { + ret = fpga_bridge_disable(bridge); + if (ret) + return ret; +@@ -196,13 +192,10 @@ EXPORT_SYMBOL_GPL(fpga_bridges_disable); + */ + void fpga_bridges_put(struct list_head *bridge_list) + { +- struct fpga_bridge *bridge; +- struct list_head *node, *next; ++ struct fpga_bridge *bridge, *next; + unsigned long flags; + +- list_for_each_safe(node, next, bridge_list) { +- bridge = list_entry(node, struct fpga_bridge, node); +- ++ list_for_each_entry_safe(bridge, next, bridge_list, node) { + fpga_bridge_put(bridge); + + spin_lock_irqsave(&bridge_list_lock, flags); diff --git a/patches.socfpga/0053-fpga-altera_freeze_bridge-Constify-ops.patch b/patches.socfpga/0053-fpga-altera_freeze_bridge-Constify-ops.patch new file mode 100644 index 00000000000000..2747428eae44fc --- /dev/null +++ b/patches.socfpga/0053-fpga-altera_freeze_bridge-Constify-ops.patch @@ -0,0 +1,28 @@ +From a55d3c2ff9848a13ccd78a45551bd38c390426fb Mon Sep 17 00:00:00 2001 +From: Moritz Fischer <mdf@kernel.org> +Date: Thu, 23 Mar 2017 19:34:24 -0500 +Subject: [PATCH 053/103] fpga: altera_freeze_bridge: Constify ops + +The ops are not changing, make them const. + +Signed-off-by: Moritz Fischer <mdf@kernel.org> +Cc: Alan Tull <atull@kernel.org> +Cc: linux-kernel@vger.kernel.org +Cc: linux-fpga@vger.kernel.org +Acked-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/altera-freeze-bridge.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/fpga/altera-freeze-bridge.c ++++ b/drivers/fpga/altera-freeze-bridge.c +@@ -203,7 +203,7 @@ static int altera_freeze_br_enable_show( + return priv->enable; + } + +-static struct fpga_bridge_ops altera_freeze_br_br_ops = { ++static const struct fpga_bridge_ops altera_freeze_br_br_ops = { + .enable_set = altera_freeze_br_enable_set, + .enable_show = altera_freeze_br_enable_show, + }; diff --git a/patches.socfpga/0054-dt-bindings-fpga-add-xilinx-slave-serial-binding-des.patch b/patches.socfpga/0054-dt-bindings-fpga-add-xilinx-slave-serial-binding-des.patch new file mode 100644 index 00000000000000..1c4bcc622e2f77 --- /dev/null +++ b/patches.socfpga/0054-dt-bindings-fpga-add-xilinx-slave-serial-binding-des.patch @@ -0,0 +1,67 @@ +From bad33a7dfec8bc8eb393519a9b2348d009a2fa6d Mon Sep 17 00:00:00 2001 +From: Anatolij Gustschin <agust@denx.de> +Date: Thu, 23 Mar 2017 19:34:25 -0500 +Subject: [PATCH 054/103] dt: bindings: fpga: add xilinx slave-serial binding + description + +Add dt binding documentation details for Xilinx FPGA configuration +over slave serial interface. + +Signed-off-by: Anatolij Gustschin <agust@denx.de> +Acked-by: Moritz Fischer <mdf@kernel.org> +Acked-by: Rob Herring <robh@kernel.org> +Acked-by: Michal Simek <michal.simek@xilinx.com> +Acked-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + Documentation/devicetree/bindings/fpga/xilinx-slave-serial.txt | 44 ++++++++++ + 1 file changed, 44 insertions(+) + create mode 100644 Documentation/devicetree/bindings/fpga/xilinx-slave-serial.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/fpga/xilinx-slave-serial.txt +@@ -0,0 +1,44 @@ ++Xilinx Slave Serial SPI FPGA Manager ++ ++Xilinx Spartan-6 FPGAs support a method of loading the bitstream over ++what is referred to as "slave serial" interface. ++The slave 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.xilinx.com/support/documentation/user_guides/ug380.pdf ++ ++Required properties: ++- compatible: should contain "xlnx,fpga-slave-serial" ++- reg: spi chip select of the FPGA ++- prog_b-gpios: config pin (referred to as PROGRAM_B in the manual) ++- done-gpios: config status pin (referred to as DONE in the manual) ++ ++Example for full FPGA configuration: ++ ++ fpga-region0 { ++ compatible = "fpga-region"; ++ fpga-mgr = <&fpga_mgr_spi>; ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ }; ++ ++ spi1: spi@10680 { ++ compatible = "marvell,armada-xp-spi", "marvell,orion-spi"; ++ pinctrl-0 = <&spi0_pins>; ++ pinctrl-names = "default"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ cell-index = <1>; ++ interrupts = <92>; ++ clocks = <&coreclk 0>; ++ status = "okay"; ++ ++ fpga_mgr_spi: fpga-mgr@0 { ++ compatible = "xlnx,fpga-slave-serial"; ++ spi-max-frequency = <60000000>; ++ spi-cpha; ++ reg = <0>; ++ done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; ++ prog_b-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; ++ }; ++ }; diff --git a/patches.socfpga/0055-fpga-manager-Add-Xilinx-slave-serial-SPI-driver.patch b/patches.socfpga/0055-fpga-manager-Add-Xilinx-slave-serial-SPI-driver.patch new file mode 100644 index 00000000000000..0f10393c3f504d --- /dev/null +++ b/patches.socfpga/0055-fpga-manager-Add-Xilinx-slave-serial-SPI-driver.patch @@ -0,0 +1,247 @@ +From d4cd4955c34d18b9849d52ddfe6ca83f9f04e5a5 Mon Sep 17 00:00:00 2001 +From: Anatolij Gustschin <agust@denx.de> +Date: Thu, 23 Mar 2017 19:34:26 -0500 +Subject: [PATCH 055/103] fpga manager: Add Xilinx slave serial SPI driver + +The driver loads FPGA firmware over SPI, using the "slave serial" +configuration interface on Xilinx FPGAs. + +Signed-off-by: Anatolij Gustschin <agust@denx.de> +Acked-by: Michal Simek <michal.simek@xilinx.com> +Reviewed-by: Moritz Fischer <mdf@kernel.org> +Acked-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 7 + + drivers/fpga/Makefile | 1 + drivers/fpga/xilinx-spi.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 206 insertions(+) + create mode 100644 drivers/fpga/xilinx-spi.c + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -46,6 +46,13 @@ config FPGA_MGR_TS73XX + FPGA manager driver support for the Altera Cyclone II FPGA + present on the TS-73xx SBC boards. + ++config FPGA_MGR_XILINX_SPI ++ tristate "Xilinx Configuration over Slave Serial (SPI)" ++ depends on SPI ++ help ++ FPGA manager driver support for Xilinx FPGA configuration ++ over slave serial interface. ++ + config FPGA_MGR_ZYNQ_FPGA + tristate "Xilinx Zynq FPGA" + depends on ARCH_ZYNQ || COMPILE_TEST +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice4 + obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o + obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o + obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o ++obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o + obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o + + # FPGA Bridge Drivers +--- /dev/null ++++ b/drivers/fpga/xilinx-spi.c +@@ -0,0 +1,198 @@ ++/* ++ * Xilinx Spartan6 Slave Serial SPI Driver ++ * ++ * Copyright (C) 2017 DENX Software Engineering ++ * ++ * Anatolij Gustschin <agust@denx.de> ++ * ++ * 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. ++ * ++ * Manage Xilinx FPGA firmware that is loaded over SPI using ++ * the slave serial configuration interface. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/fpga/fpga-mgr.h> ++#include <linux/gpio/consumer.h> ++#include <linux/module.h> ++#include <linux/mod_devicetable.h> ++#include <linux/of.h> ++#include <linux/spi/spi.h> ++#include <linux/sizes.h> ++ ++struct xilinx_spi_conf { ++ struct spi_device *spi; ++ struct gpio_desc *prog_b; ++ struct gpio_desc *done; ++}; ++ ++static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr) ++{ ++ struct xilinx_spi_conf *conf = mgr->priv; ++ ++ if (!gpiod_get_value(conf->done)) ++ return FPGA_MGR_STATE_RESET; ++ ++ return FPGA_MGR_STATE_UNKNOWN; ++} ++ ++static int xilinx_spi_write_init(struct fpga_manager *mgr, ++ struct fpga_image_info *info, ++ const char *buf, size_t count) ++{ ++ struct xilinx_spi_conf *conf = mgr->priv; ++ const size_t prog_latency_7500us = 7500; ++ const size_t prog_pulse_1us = 1; ++ ++ if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { ++ dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); ++ return -EINVAL; ++ } ++ ++ gpiod_set_value(conf->prog_b, 1); ++ ++ udelay(prog_pulse_1us); /* min is 500 ns */ ++ ++ gpiod_set_value(conf->prog_b, 0); ++ ++ if (gpiod_get_value(conf->done)) { ++ dev_err(&mgr->dev, "Unexpected DONE pin state...\n"); ++ return -EIO; ++ } ++ ++ /* program latency */ ++ usleep_range(prog_latency_7500us, prog_latency_7500us + 100); ++ return 0; ++} ++ ++static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf, ++ size_t count) ++{ ++ struct xilinx_spi_conf *conf = mgr->priv; ++ const char *fw_data = buf; ++ const char *fw_data_end = fw_data + count; ++ ++ while (fw_data < fw_data_end) { ++ size_t remaining, stride; ++ int ret; ++ ++ remaining = fw_data_end - fw_data; ++ stride = min_t(size_t, remaining, SZ_4K); ++ ++ 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 xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf) ++{ ++ struct spi_device *spi = conf->spi; ++ const u8 din_data[1] = { 0xff }; ++ int ret; ++ ++ ret = spi_write(conf->spi, din_data, sizeof(din_data)); ++ if (ret) ++ dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static int xilinx_spi_write_complete(struct fpga_manager *mgr, ++ struct fpga_image_info *info) ++{ ++ struct xilinx_spi_conf *conf = mgr->priv; ++ unsigned long timeout; ++ int ret; ++ ++ if (gpiod_get_value(conf->done)) ++ return xilinx_spi_apply_cclk_cycles(conf); ++ ++ timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us); ++ ++ while (time_before(jiffies, timeout)) { ++ ++ ret = xilinx_spi_apply_cclk_cycles(conf); ++ if (ret) ++ return ret; ++ ++ if (gpiod_get_value(conf->done)) ++ return xilinx_spi_apply_cclk_cycles(conf); ++ } ++ ++ dev_err(&mgr->dev, "Timeout after config data transfer.\n"); ++ return -ETIMEDOUT; ++} ++ ++static const struct fpga_manager_ops xilinx_spi_ops = { ++ .state = xilinx_spi_state, ++ .write_init = xilinx_spi_write_init, ++ .write = xilinx_spi_write, ++ .write_complete = xilinx_spi_write_complete, ++}; ++ ++static int xilinx_spi_probe(struct spi_device *spi) ++{ ++ struct xilinx_spi_conf *conf; ++ ++ conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); ++ if (!conf) ++ return -ENOMEM; ++ ++ conf->spi = spi; ++ ++ /* PROGRAM_B is active low */ ++ conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW); ++ if (IS_ERR(conf->prog_b)) { ++ dev_err(&spi->dev, "Failed to get PROGRAM_B gpio: %ld\n", ++ PTR_ERR(conf->prog_b)); ++ return PTR_ERR(conf->prog_b); ++ } ++ ++ conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN); ++ if (IS_ERR(conf->done)) { ++ dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n", ++ PTR_ERR(conf->done)); ++ return PTR_ERR(conf->done); ++ } ++ ++ return fpga_mgr_register(&spi->dev, "Xilinx Slave Serial FPGA Manager", ++ &xilinx_spi_ops, conf); ++} ++ ++static int xilinx_spi_remove(struct spi_device *spi) ++{ ++ fpga_mgr_unregister(&spi->dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id xlnx_spi_of_match[] = { ++ { .compatible = "xlnx,fpga-slave-serial", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, xlnx_spi_of_match); ++ ++static struct spi_driver xilinx_slave_spi_driver = { ++ .driver = { ++ .name = "xlnx-slave-spi", ++ .of_match_table = of_match_ptr(xlnx_spi_of_match), ++ }, ++ .probe = xilinx_spi_probe, ++ .remove = xilinx_spi_remove, ++}; ++ ++module_spi_driver(xilinx_slave_spi_driver) ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); ++MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SPI"); diff --git a/patches.socfpga/0056-ARM-socfpga-add-bindings-document-for-fpga-bridge-dr.patch b/patches.socfpga/0056-ARM-socfpga-add-bindings-document-for-fpga-bridge-dr.patch new file mode 100644 index 00000000000000..36657182d49ae7 --- /dev/null +++ b/patches.socfpga/0056-ARM-socfpga-add-bindings-document-for-fpga-bridge-dr.patch @@ -0,0 +1,85 @@ +From be625b6c7234e180a34bcee690d64bfd52ae116d Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 12 Jul 2016 14:36:41 -0500 +Subject: [PATCH 056/103] ARM: socfpga: add bindings document for fpga bridge + drivers + +Add bindings documentation for Altera SOCFPGA bridges: + * fpga2sdram + * fpga2hps + * hps2fpga + * lwhps2fpga + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Matthew Gerlach <mgerlach@altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +Acked-by: Rob Herring <robh@kernel.org> +Signed-off-by: Rob Herring <robh@kernel.org> +--- + Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt | 16 ++++ + Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt | 39 ++++++++++ + 2 files changed, 55 insertions(+) + create mode 100644 Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt + create mode 100644 Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt +@@ -0,0 +1,16 @@ ++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: ++ fpga_bridge3: fpga-bridge@ffc25080 { ++ compatible = "altr,socfpga-fpga2sdram-bridge"; ++ reg = <0xffc25080 0x4>; ++ bridge-enable = <0>; ++ }; +--- /dev/null ++++ b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt +@@ -0,0 +1,39 @@ ++Altera FPGA/HPS Bridge Driver ++ ++Required properties: ++- regs : base address and size for AXI bridge module ++- compatible : Should contain one of: ++ "altr,socfpga-lwhps2fpga-bridge", ++ "altr,socfpga-hps2fpga-bridge", or ++ "altr,socfpga-fpga2hps-bridge" ++- resets : Phandle and reset specifier for this bridge's reset ++- 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: ++ fpga_bridge0: fpga-bridge@ff400000 { ++ compatible = "altr,socfpga-lwhps2fpga-bridge"; ++ reg = <0xff400000 0x100000>; ++ resets = <&rst LWHPS2FPGA_RESET>; ++ clocks = <&l4_main_clk>; ++ bridge-enable = <0>; ++ }; ++ ++ fpga_bridge1: fpga-bridge@ff500000 { ++ compatible = "altr,socfpga-hps2fpga-bridge"; ++ reg = <0xff500000 0x10000>; ++ resets = <&rst HPS2FPGA_RESET>; ++ clocks = <&l4_main_clk>; ++ bridge-enable = <1>; ++ }; ++ ++ fpga_bridge2: fpga-bridge@ff600000 { ++ compatible = "altr,socfpga-fpga2hps-bridge"; ++ reg = <0xff600000 0x100000>; ++ resets = <&rst FPGA2HPS_RESET>; ++ clocks = <&l4_main_clk>; ++ }; diff --git a/patches.socfpga/0057-ARM-socfpga-add-bindings-doc-for-arria10-fpga-manage.patch b/patches.socfpga/0057-ARM-socfpga-add-bindings-doc-for-arria10-fpga-manage.patch new file mode 100644 index 00000000000000..a7a2904bc33bfb --- /dev/null +++ b/patches.socfpga/0057-ARM-socfpga-add-bindings-doc-for-arria10-fpga-manage.patch @@ -0,0 +1,40 @@ +From 94068d8c8be80b81e019683b4997a46627e3dd86 Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 12 Jul 2016 14:07:08 -0500 +Subject: [PATCH 057/103] ARM: socfpga: add bindings doc for arria10 fpga + manager + +Add a device tree bindings document for the SoCFPGA Arria10 +FPGA Manager driver. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Acked-by: Rob Herring <robh@kernel.org> +Acked-By: Moritz Fischer <moritz.fischer@ettus.com> +Signed-off-by: Rob Herring <robh@kernel.org> +--- + Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt | 19 ++++++++++ + 1 file changed, 19 insertions(+) + create mode 100644 Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt +@@ -0,0 +1,19 @@ ++Altera SOCFPGA Arria10 FPGA Manager ++ ++Required properties: ++- compatible : should contain "altr,socfpga-a10-fpga-mgr" ++- reg : base address and size for memory mapped io. ++ - The first index is for FPGA manager register access. ++ - The second index is for writing FPGA configuration data. ++- resets : Phandle and reset specifier for the device's reset. ++- clocks : Clocks used by the device. ++ ++Example: ++ ++ fpga_mgr: fpga-mgr@ffd03000 { ++ compatible = "altr,socfpga-a10-fpga-mgr"; ++ reg = <0xffd03000 0x100 ++ 0xffcfe400 0x20>; ++ clocks = <&l4_mp_clk>; ++ resets = <&rst FPGAMGR_RESET>; ++ }; diff --git a/patches.socfpga/0058-add-bindings-document-for-altera-freeze-bridge.patch b/patches.socfpga/0058-add-bindings-document-for-altera-freeze-bridge.patch new file mode 100644 index 00000000000000..8863758a0c5ca0 --- /dev/null +++ b/patches.socfpga/0058-add-bindings-document-for-altera-freeze-bridge.patch @@ -0,0 +1,45 @@ +From 48e56f16d7bc13665e037dc17935a23dc440e0df Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Mon, 17 Oct 2016 11:09:34 -0500 +Subject: [PATCH 058/103] add bindings document for altera freeze bridge + +Add bindings document for the Altera Freeze Bridge. A Freeze +Bridge is used to gate traffic to/from a region of a FPGA +such that that region can be reprogrammed. The Freeze Bridge +exist in FPGA fabric that is not currently being reconfigured. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Matthew Gerlach <mgerlach@opensource.altera.com> +Acked-by: Rob Herring <robh@kernel.org> +Signed-off-by: Rob Herring <robh@kernel.org> +--- + Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt | 23 ++++++++++ + 1 file changed, 23 insertions(+) + create mode 100644 Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt +@@ -0,0 +1,23 @@ ++Altera Freeze Bridge Controller Driver ++ ++The Altera Freeze Bridge Controller manages one or more freeze bridges. ++The controller can freeze/disable the bridges which prevents signal ++changes from passing through the bridge. The controller can also ++unfreeze/enable the bridges which allows traffic to pass through the ++bridge normally. ++ ++Required properties: ++- compatible : Should contain "altr,freeze-bridge-controller" ++- regs : base address and size for freeze bridge 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 current state. ++ ++Example: ++ freeze-controller@100000450 { ++ compatible = "altr,freeze-bridge-controller"; ++ regs = <0x1000 0x10>; ++ bridge-enable = <0>; ++ }; diff --git a/patches.socfpga/0059-MAINTAINERS-add-git-url-for-fpga.patch b/patches.socfpga/0059-MAINTAINERS-add-git-url-for-fpga.patch new file mode 100644 index 00000000000000..e7a92866f8beb4 --- /dev/null +++ b/patches.socfpga/0059-MAINTAINERS-add-git-url-for-fpga.patch @@ -0,0 +1,22 @@ +From c642ff14e89edf9cb54008765c97e75e505545b7 Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Tue, 29 Nov 2016 15:15:45 -0600 +Subject: [PATCH 059/103] MAINTAINERS: add git url for fpga + +Add git url for fpga stuff. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +--- + MAINTAINERS | 1 + + 1 file changed, 1 insertion(+) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4959,6 +4959,7 @@ FPGA MANAGER FRAMEWORK + M: Alan Tull <atull@opensource.altera.com> + R: Moritz Fischer <moritz.fischer@ettus.com> + S: Maintained ++T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git + F: drivers/fpga/ + F: include/linux/fpga/fpga-mgr.h + W: http://www.rocketboards.org diff --git a/patches.socfpga/0060-ARM-dts-socfpga-add-base-fpga-region-and-fpga-bridge.patch b/patches.socfpga/0060-ARM-dts-socfpga-add-base-fpga-region-and-fpga-bridge.patch new file mode 100644 index 00000000000000..704a2dc20006cf --- /dev/null +++ b/patches.socfpga/0060-ARM-dts-socfpga-add-base-fpga-region-and-fpga-bridge.patch @@ -0,0 +1,68 @@ +From d063b52520c412dccb99b0737b5e2b462d83dd8a Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Fri, 26 Feb 2016 14:21:04 -0600 +Subject: [PATCH 060/103] ARM: dts: socfpga: add base fpga region and fpga + bridges + +Add h2f and lwh2f bridges. +Add base FPGA Region to support DT overlays for FPGA programming. +Add l3regs. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- +v2: removed fpga-bridges, ranges, and reset-names +--- + arch/arm/boot/dts/socfpga.dtsi | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +--- a/arch/arm/boot/dts/socfpga.dtsi ++++ b/arch/arm/boot/dts/socfpga.dtsi +@@ -93,6 +93,14 @@ + }; + }; + ++ base_fpga_region { ++ compatible = "fpga-region"; ++ fpga-mgr = <&fpgamgr0>; ++ ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ }; ++ + can0: can@ffc00000 { + compatible = "bosch,d_can"; + reg = <0xffc00000 0x1000>; +@@ -513,6 +521,20 @@ + }; + }; + ++ fpga_bridge0: fpga_bridge@ff400000 { ++ compatible = "altr,socfpga-lwhps2fpga-bridge"; ++ reg = <0xff400000 0x100000>; ++ resets = <&rst LWHPS2FPGA_RESET>; ++ clocks = <&l4_main_clk>; ++ }; ++ ++ fpga_bridge1: fpga_bridge@ff500000 { ++ compatible = "altr,socfpga-hps2fpga-bridge"; ++ reg = <0xff500000 0x10000>; ++ resets = <&rst HPS2FPGA_RESET>; ++ clocks = <&l4_main_clk>; ++ }; ++ + fpgamgr0: fpgamgr@ff706000 { + compatible = "altr,socfpga-fpga-mgr"; + reg = <0xff706000 0x1000 +@@ -689,6 +711,11 @@ + arm,shared-override; + }; + ++ l3regs@0xff800000 { ++ compatible = "altr,l3regs", "syscon"; ++ reg = <0xff800000 0x1000>; ++ }; ++ + mmc: dwmmc0@ff704000 { + compatible = "altr,socfpga-dw-mshc"; + reg = <0xff704000 0x1000>; diff --git a/patches.socfpga/0061-fpga-add-config-complete-timeout.patch b/patches.socfpga/0061-fpga-add-config-complete-timeout.patch new file mode 100644 index 00000000000000..b3594a46e98e5b --- /dev/null +++ b/patches.socfpga/0061-fpga-add-config-complete-timeout.patch @@ -0,0 +1,44 @@ +From 3871c39c6683965dbafdedc7b9f9b558cf620f0f Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Thu, 23 Mar 2017 19:34:27 -0500 +Subject: [PATCH 061/103] fpga: add config complete timeout + +Adding timeout for maximum allowed time for FPGA to go to +operating mode after a FPGA region has been programmed. + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/fpga-region.c | 3 +++ + include/linux/fpga/fpga-mgr.h | 3 +++ + 2 files changed, 6 insertions(+) + +--- a/drivers/fpga/fpga-region.c ++++ b/drivers/fpga/fpga-region.c +@@ -385,6 +385,9 @@ static int fpga_region_notify_pre_apply( + of_property_read_u32(nd->overlay, "region-freeze-timeout-us", + &info->disable_timeout_us); + ++ of_property_read_u32(nd->overlay, "config-complete-timeout-us", ++ &info->config_complete_timeout_us); ++ + /* If FPGA was externally programmed, don't specify firmware */ + if ((info->flags & FPGA_MGR_EXTERNAL_CONFIG) && firmware_name) { + pr_err("error: specified firmware and external-fpga-config"); +--- a/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h +@@ -77,11 +77,14 @@ enum fpga_mgr_states { + * @flags: boolean flags as defined above + * @enable_timeout_us: maximum time to enable traffic through bridge (uSec) + * @disable_timeout_us: maximum time to disable traffic through bridge (uSec) ++ * @config_complete_timeout_us: maximum time for FPGA to switch to operating ++ * status in the write_complete op. + */ + struct fpga_image_info { + u32 flags; + u32 enable_timeout_us; + u32 disable_timeout_us; ++ u32 config_complete_timeout_us; + }; + + /** diff --git a/patches.socfpga/0062-MAINTAINERS-Add-file-patterns-for-fpga-device-tree-b.patch b/patches.socfpga/0062-MAINTAINERS-Add-file-patterns-for-fpga-device-tree-b.patch new file mode 100644 index 00000000000000..5180d45b407e83 --- /dev/null +++ b/patches.socfpga/0062-MAINTAINERS-Add-file-patterns-for-fpga-device-tree-b.patch @@ -0,0 +1,30 @@ +From f2e9e7db072f6445f9fea325f93f3406b78edc11 Mon Sep 17 00:00:00 2001 +From: Geert Uytterhoeven <geert@linux-m68k.org> +Date: Thu, 23 Mar 2017 19:34:31 -0500 +Subject: [PATCH 062/103] MAINTAINERS: Add file patterns for fpga device tree + bindings + +Submitters of device tree binding documentation may forget to CC +the subsystem maintainer if this is missing. + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +Acked-by: Moritz Fischer <moritz.fischer@ettus.com> +Cc: Alan Tull <atull@opensource.altera.com> +Cc: Moritz Fischer <moritz.fischer@ettus.com> +Cc: linux-fpga@vger.kernel.org +Acked-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + MAINTAINERS | 1 + + 1 file changed, 1 insertion(+) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4960,6 +4960,7 @@ M: Alan Tull <atull@opensource.altera.co + R: Moritz Fischer <moritz.fischer@ettus.com> + S: Maintained + T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git ++F: Documentation/devicetree/bindings/fpga/ + F: drivers/fpga/ + F: include/linux/fpga/fpga-mgr.h + W: http://www.rocketboards.org diff --git a/patches.socfpga/0063-MAINTAINERS-fpga-update-email-and-directory-paths.patch b/patches.socfpga/0063-MAINTAINERS-fpga-update-email-and-directory-paths.patch new file mode 100644 index 00000000000000..499db058492d88 --- /dev/null +++ b/patches.socfpga/0063-MAINTAINERS-fpga-update-email-and-directory-paths.patch @@ -0,0 +1,35 @@ +From efcf802e63e2d545f6695ed386a3737ed9f1d77e Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@kernel.org> +Date: Thu, 30 Mar 2017 13:23:12 -0500 +Subject: [PATCH 063/103] MAINTAINERS: fpga: update email and directory paths + +A few updates: +* Updating my email address +* Adding another docs directory: Documentation/fpga +* Making the include path not specific to fpga-mgr.h only + +Signed-off-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + MAINTAINERS | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4956,13 +4956,14 @@ F: include/linux/ipmi-fru.h + K: fmc_d.*register + + FPGA MANAGER FRAMEWORK +-M: Alan Tull <atull@opensource.altera.com> ++M: Alan Tull <atull@kernel.org> + R: Moritz Fischer <moritz.fischer@ettus.com> + S: Maintained + T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git ++F: Documentation/fpga/ + F: Documentation/devicetree/bindings/fpga/ + F: drivers/fpga/ +-F: include/linux/fpga/fpga-mgr.h ++F: include/linux/fpga/ + W: http://www.rocketboards.org + + FPU EMULATOR diff --git a/patches.socfpga/0064-spi-Add-Flag-to-Enable-Slave-Select-with-GPIO-Chip-S.patch b/patches.socfpga/0064-spi-Add-Flag-to-Enable-Slave-Select-with-GPIO-Chip-S.patch new file mode 100644 index 00000000000000..b64e9d522758a8 --- /dev/null +++ b/patches.socfpga/0064-spi-Add-Flag-to-Enable-Slave-Select-with-GPIO-Chip-S.patch @@ -0,0 +1,56 @@ +From d500a6439c32092db46195c550ef617ce3a3ffc2 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <tthayer@opensource.altera.com> +Date: Mon, 10 Oct 2016 09:25:24 -0500 +Subject: [PATCH 064/103] spi: Add Flag to Enable Slave Select with GPIO Chip + Select. + +Some SPI masters require slave selection before the transfer +can begin [1]. The SPI framework currently selects the chip using +either 1) the internal CS mechanism or 2) the GPIO CS, but not both. + +This patch adds a new master->flags define to indicate both the GPIO +CS and the internal chip select mechanism should be used. + +Tested On: + Altera CycloneV development kit + Compile tested for build errors on x86_64 (allyesconfigs) + +[1] DesignWare dw_apb_ssi Databook, Version 3.20a (page 39) + +Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> +Signed-off-by: Mark Brown <broonie@kernel.org> +--- + drivers/spi/spi.c | 9 +++++++-- + include/linux/spi/spi.h | 1 + + 2 files changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -699,10 +699,15 @@ static void spi_set_cs(struct spi_device + if (spi->mode & SPI_CS_HIGH) + enable = !enable; + +- if (gpio_is_valid(spi->cs_gpio)) ++ if (gpio_is_valid(spi->cs_gpio)) { + gpio_set_value(spi->cs_gpio, !enable); +- else if (spi->master->set_cs) ++ /* Some SPI masters need both GPIO CS & slave_select */ ++ if ((spi->master->flags & SPI_MASTER_GPIO_SS) && ++ spi->master->set_cs) ++ spi->master->set_cs(spi, !enable); ++ } else if (spi->master->set_cs) { + spi->master->set_cs(spi, !enable); ++ } + } + + #ifdef CONFIG_HAS_DMA +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -442,6 +442,7 @@ struct spi_master { + #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ + #define SPI_MASTER_MUST_RX BIT(3) /* requires rx */ + #define SPI_MASTER_MUST_TX BIT(4) /* requires tx */ ++#define SPI_MASTER_GPIO_SS BIT(5) /* GPIO CS must select slave */ + + /* + * on some hardware transfer / message size may be constrained diff --git a/patches.socfpga/0065-spi-dw-Set-GPIO_SS-flag-to-toggle-Slave-Select-on-GP.patch b/patches.socfpga/0065-spi-dw-Set-GPIO_SS-flag-to-toggle-Slave-Select-on-GP.patch new file mode 100644 index 00000000000000..861baed53ef160 --- /dev/null +++ b/patches.socfpga/0065-spi-dw-Set-GPIO_SS-flag-to-toggle-Slave-Select-on-GP.patch @@ -0,0 +1,34 @@ +From 1d1b6b573a601464ca8ec40ace560a30fa00bdf4 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <tthayer@opensource.altera.com> +Date: Mon, 10 Oct 2016 09:25:25 -0500 +Subject: [PATCH 065/103] spi: dw: Set GPIO_SS flag to toggle Slave Select on + GPIO CS + +The Designware SPI master requires slave selection before the transfer +can begin [1]. + +This patch uses the new master flag to indicate both the GPIO CS and +the internal chip select should be used. + +Tested On: + Altera CycloneV development kit + Compile tested for build errors on x86_64 (allyesconfigs) + +[1] DesignWare dw_apb_ssi Databook, Version 3.20a (page 39) + +Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> +Signed-off-by: Mark Brown <broonie@kernel.org> +--- + drivers/spi/spi-dw.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/spi/spi-dw.c ++++ b/drivers/spi/spi-dw.c +@@ -502,6 +502,7 @@ int dw_spi_add_host(struct device *dev, + master->handle_err = dw_spi_handle_err; + master->max_speed_hz = dws->max_freq; + master->dev.of_node = dev->of_node; ++ master->flags = SPI_MASTER_GPIO_SS; + + /* Basic HW init */ + spi_hw_init(dev, dws); diff --git a/patches.socfpga/0066-ARM-dts-socfpga-Add-SPI-Master1-for-Arria10-SR-chip.patch b/patches.socfpga/0066-ARM-dts-socfpga-Add-SPI-Master1-for-Arria10-SR-chip.patch new file mode 100644 index 00000000000000..a6a2449a4e97c4 --- /dev/null +++ b/patches.socfpga/0066-ARM-dts-socfpga-Add-SPI-Master1-for-Arria10-SR-chip.patch @@ -0,0 +1,39 @@ +From 591692b01bed97f524daa7623e58543276e32abd Mon Sep 17 00:00:00 2001 +From: Thor Thayer <tthayer@opensource.altera.com> +Date: Thu, 2 Jun 2016 17:52:25 +0000 +Subject: [PATCH 066/103] ARM: dts: socfpga: Add SPI Master1 for Arria10 SR + chip + +Add the Altera Arria10 SPI Master Node in preparation for +the A10SR MFD node. + +Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga_arria10.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10.dtsi +@@ -579,6 +579,21 @@ + status = "disabled"; + }; + ++ spi1: spi@ffda5000 { ++ compatible = "snps,dw-apb-ssi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0xffda5000 0x100>; ++ interrupts = <0 102 4>; ++ num-chipselect = <4>; ++ bus-num = <0>; ++ /*32bit_access;*/ ++ tx-dma-channel = <&pdma 16>; ++ rx-dma-channel = <&pdma 17>; ++ clocks = <&spi_m_clk>; ++ status = "disabled"; ++ }; ++ + sdr: sdr@ffc25000 { + compatible = "altr,sdr-ctl", "syscon"; + reg = <0xffcfb100 0x80>; diff --git a/patches.socfpga/0067-ARM-dts-socfpga-Add-Devkit-A10-SR-fields-for-Arria10.patch b/patches.socfpga/0067-ARM-dts-socfpga-Add-Devkit-A10-SR-fields-for-Arria10.patch new file mode 100644 index 00000000000000..4797dfc4096e83 --- /dev/null +++ b/patches.socfpga/0067-ARM-dts-socfpga-Add-Devkit-A10-SR-fields-for-Arria10.patch @@ -0,0 +1,45 @@ +From dd696cdcf4973ec6ba54ed24283548c1e57948cf Mon Sep 17 00:00:00 2001 +From: Thor Thayer <tthayer@opensource.altera.com> +Date: Thu, 2 Jun 2016 17:52:26 +0000 +Subject: [PATCH 067/103] ARM: dts: socfpga: Add Devkit A10-SR fields for + Arria10 + +Add the Altera Arria10 System Resource node. This is a Multi-Function +device with GPIO expander support. + +Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga_arria10_socdk.dtsi | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +@@ -75,6 +75,27 @@ + status = "okay"; + }; + ++&spi1 { ++ status = "okay"; ++ ++ resource-manager@0 { ++ compatible = "altr,a10sr"; ++ reg = <0>; ++ spi-max-frequency = <100000>; ++ /* low-level active IRQ at GPIO1_5 */ ++ interrupt-parent = <&portb>; ++ interrupts = <5 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ ++ a10sr_gpio: gpio-controller { ++ compatible = "altr,a10sr-gpio"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++}; ++ + &i2c1 { + speed-mode = <0>; + status = "okay"; diff --git a/patches.socfpga/0068-ARM-dts-socfpga-Enable-GPIO-parent-for-Arria10-SR-ch.patch b/patches.socfpga/0068-ARM-dts-socfpga-Enable-GPIO-parent-for-Arria10-SR-ch.patch new file mode 100644 index 00000000000000..d24d027ded66ae --- /dev/null +++ b/patches.socfpga/0068-ARM-dts-socfpga-Enable-GPIO-parent-for-Arria10-SR-ch.patch @@ -0,0 +1,27 @@ +From a672d36e350129ca4b0d5fd127d2672c6484100d Mon Sep 17 00:00:00 2001 +From: Thor Thayer <tthayer@opensource.altera.com> +Date: Thu, 2 Jun 2016 17:52:27 +0000 +Subject: [PATCH 068/103] ARM: dts: socfpga: Enable GPIO parent for Arria10 SR + chip + +Enable the Altera Arria10 GPIO parent for MFD operation. + +Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga_arria10_socdk.dtsi | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +@@ -75,6 +75,10 @@ + status = "okay"; + }; + ++&gpio1 { ++ status = "okay"; ++}; ++ + &spi1 { + status = "okay"; + diff --git a/patches.socfpga/0069-ARM-dts-socfpga-Add-LED-framework-to-A10-SR-GPIO.patch b/patches.socfpga/0069-ARM-dts-socfpga-Add-LED-framework-to-A10-SR-GPIO.patch new file mode 100644 index 00000000000000..0a3341b0d97ba1 --- /dev/null +++ b/patches.socfpga/0069-ARM-dts-socfpga-Add-LED-framework-to-A10-SR-GPIO.patch @@ -0,0 +1,46 @@ +From 40c6c417eabe97c7a3364f418880e00e9da7b420 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <tthayer@opensource.altera.com> +Date: Thu, 2 Jun 2016 17:52:28 +0000 +Subject: [PATCH 069/103] ARM: dts: socfpga: Add LED framework to A10-SR GPIO + +Add the LED framework to the Arria10 System Resource chip GPIO hooks. + +Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga_arria10_socdk.dtsi | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +@@ -36,6 +36,30 @@ + reg = <0x0 0x40000000>; /* 1GB */ + }; + ++ a10leds { ++ compatible = "gpio-leds"; ++ ++ a10sr_led0 { ++ label = "a10sr-led0"; ++ gpios = <&a10sr_gpio 0 1>; ++ }; ++ ++ a10sr_led1 { ++ label = "a10sr-led1"; ++ gpios = <&a10sr_gpio 1 1>; ++ }; ++ ++ a10sr_led2 { ++ label = "a10sr-led2"; ++ gpios = <&a10sr_gpio 2 1>; ++ }; ++ ++ a10sr_led3 { ++ label = "a10sr-led3"; ++ gpios = <&a10sr_gpio 3 1>; ++ }; ++ }; ++ + soc { + clkmgr@ffd04000 { + clocks { diff --git a/patches.socfpga/0070-EDAC-altera-Disable-IRQs-while-injecting-SDRAM-error.patch b/patches.socfpga/0070-EDAC-altera-Disable-IRQs-while-injecting-SDRAM-error.patch new file mode 100644 index 00000000000000..6edb8831857602 --- /dev/null +++ b/patches.socfpga/0070-EDAC-altera-Disable-IRQs-while-injecting-SDRAM-error.patch @@ -0,0 +1,40 @@ +From ea62c7b1bf6a7fa765bddfc710a279e233ead67c Mon Sep 17 00:00:00 2001 +From: Thor Thayer <tthayer@opensource.altera.com> +Date: Wed, 19 Oct 2016 14:53:47 -0500 +Subject: [PATCH 070/103] EDAC, altera: Disable IRQs while injecting SDRAM + errors + +Disable IRQs while injecting SDRAM errors. The RT patches exposed +a spinlock deadlock where the spinlock taken for the regmap write +deadlocked with the IRQ clear regmap write. + +Error injection is not normally enabled for ECC but only for testing. + +Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> +Cc: linux-edac <linux-edac@vger.kernel.org> +Link: http://lkml.kernel.org/r/1476906827-9412-1-git-send-email-tthayer@opensource.altera.com +Signed-off-by: Borislav Petkov <bp@suse.de> +--- + drivers/edac/altera_edac.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -153,13 +153,17 @@ static ssize_t altr_sdr_mc_err_inject_wr + if (count == 3) { + edac_printk(KERN_ALERT, EDAC_MC, + "Inject Double bit error\n"); ++ local_irq_disable(); + regmap_write(drvdata->mc_vbase, priv->ce_ue_trgr_offset, + (read_reg | priv->ue_set_mask)); ++ local_irq_enable(); + } else { + edac_printk(KERN_ALERT, EDAC_MC, + "Inject Single bit error\n"); ++ local_irq_disable(); + regmap_write(drvdata->mc_vbase, priv->ce_ue_trgr_offset, + (read_reg | priv->ce_set_mask)); ++ local_irq_enable(); + } + + ptemp[0] = 0x5A5A5A5A; diff --git a/patches.socfpga/0071-gpio-altera-a10sr-Add-A10-System-Resource-Chip-GPIO-.patch b/patches.socfpga/0071-gpio-altera-a10sr-Add-A10-System-Resource-Chip-GPIO-.patch new file mode 100644 index 00000000000000..29332fa707cd7d --- /dev/null +++ b/patches.socfpga/0071-gpio-altera-a10sr-Add-A10-System-Resource-Chip-GPIO-.patch @@ -0,0 +1,190 @@ +From 26b18f6bff88d437c9949a2251c5bc62de427311 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <tthayer@opensource.altera.com> +Date: Thu, 2 Jun 2016 12:52:24 -0500 +Subject: [PATCH 071/103] gpio: altera-a10sr: Add A10 System Resource Chip GPIO + support. + +Add the GPIO functionality for the Altera Arria10 MAX5 System Resource +Chip. The A10 MAX5 has 12 bits of GPIO assigned to switches, buttons, +and LEDs as a GPIO extender on the SPI bus. + +Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> +Acked-by: Linus Walleij <linus.walleij@linaro.org>i +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/gpio/Kconfig | 8 ++ + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-altera-a10sr.c | 140 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 149 insertions(+) + create mode 100644 drivers/gpio/gpio-altera-a10sr.c + +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -814,6 +814,14 @@ config GPIO_ADP5520 + This option enables support for on-chip GPIO found + on Analog Devices ADP5520 PMICs. + ++config GPIO_ALTERA_A10SR ++ tristate "Altera Arria10 System Resource GPIO" ++ depends on MFD_ALTERA_A10SR ++ help ++ Driver for Arria10 Development Kit GPIO expansion which ++ includes reads of pushbuttons and DIP switches as well ++ as writes to LEDs. ++ + config GPIO_ARIZONA + tristate "Wolfson Microelectronics Arizona class devices" + depends on MFD_ARIZONA +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -24,6 +24,7 @@ obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o + obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o + obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o + obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o ++obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o + obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o + obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o + obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +--- /dev/null ++++ b/drivers/gpio/gpio-altera-a10sr.c +@@ -0,0 +1,140 @@ ++/* ++ * Copyright Intel Corporation (C) 2014-2016. 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/>. ++ * ++ * GPIO driver for Altera Arria10 MAX5 System Resource Chip ++ * ++ * Adapted from gpio-tps65910.c ++ */ ++ ++#include <linux/gpio/driver.h> ++#include <linux/mfd/altera-a10sr.h> ++#include <linux/module.h> ++ ++/** ++ * struct altr_a10sr_gpio - Altera Max5 GPIO device private data structure ++ * @gp: : instance of the gpio_chip ++ * @regmap: the regmap from the parent device. ++ */ ++struct altr_a10sr_gpio { ++ struct gpio_chip gp; ++ struct regmap *regmap; ++}; ++ ++static int altr_a10sr_gpio_get(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct altr_a10sr_gpio *gpio = gpiochip_get_data(chip); ++ int ret, val; ++ ++ ret = regmap_read(gpio->regmap, ALTR_A10SR_PBDSW_REG, &val); ++ if (ret < 0) ++ return ret; ++ ++ return !!(val & BIT(offset - ALTR_A10SR_LED_VALID_SHIFT)); ++} ++ ++static void altr_a10sr_gpio_set(struct gpio_chip *chip, unsigned int offset, ++ int value) ++{ ++ struct altr_a10sr_gpio *gpio = gpiochip_get_data(chip); ++ ++ regmap_update_bits(gpio->regmap, ALTR_A10SR_LED_REG, ++ BIT(ALTR_A10SR_LED_VALID_SHIFT + offset), ++ value ? BIT(ALTR_A10SR_LED_VALID_SHIFT + offset) ++ : 0); ++} ++ ++static int altr_a10sr_gpio_direction_input(struct gpio_chip *gc, ++ unsigned int nr) ++{ ++ if (nr >= (ALTR_A10SR_IN_VALID_RANGE_LO - ALTR_A10SR_LED_VALID_SHIFT)) ++ return 0; ++ return -EINVAL; ++} ++ ++static int altr_a10sr_gpio_direction_output(struct gpio_chip *gc, ++ unsigned int nr, int value) ++{ ++ if (nr <= (ALTR_A10SR_OUT_VALID_RANGE_HI - ALTR_A10SR_LED_VALID_SHIFT)) ++ return 0; ++ return -EINVAL; ++} ++ ++static struct gpio_chip altr_a10sr_gc = { ++ .label = "altr_a10sr_gpio", ++ .owner = THIS_MODULE, ++ .get = altr_a10sr_gpio_get, ++ .set = altr_a10sr_gpio_set, ++ .direction_input = altr_a10sr_gpio_direction_input, ++ .direction_output = altr_a10sr_gpio_direction_output, ++ .can_sleep = true, ++ .ngpio = 12, ++ .base = -1, ++}; ++ ++static int altr_a10sr_gpio_probe(struct platform_device *pdev) ++{ ++ struct altr_a10sr_gpio *gpio; ++ int ret; ++ struct altr_a10sr *a10sr = dev_get_drvdata(pdev->dev.parent); ++ ++ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); ++ if (!gpio) ++ return -ENOMEM; ++ ++ gpio->regmap = a10sr->regmap; ++ ++ gpio->gp = altr_a10sr_gc; ++ ++ gpio->gp.of_node = pdev->dev.of_node; ++ ++ ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, gpio); ++ ++ return 0; ++} ++ ++static int altr_a10sr_gpio_remove(struct platform_device *pdev) ++{ ++ struct altr_a10sr_gpio *gpio = platform_get_drvdata(pdev); ++ ++ gpiochip_remove(&gpio->gp); ++ ++ return 0; ++} ++ ++static const struct of_device_id altr_a10sr_gpio_of_match[] = { ++ { .compatible = "altr,a10sr-gpio" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, altr_a10sr_gpio_of_match); ++ ++static struct platform_driver altr_a10sr_gpio_driver = { ++ .probe = altr_a10sr_gpio_probe, ++ .remove = altr_a10sr_gpio_remove, ++ .driver = { ++ .name = "altr_a10sr_gpio", ++ .of_match_table = of_match_ptr(altr_a10sr_gpio_of_match), ++ }, ++}; ++module_platform_driver(altr_a10sr_gpio_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Thor Thayer <tthayer@opensource.altera.com>"); ++MODULE_DESCRIPTION("Altera Arria10 System Resource Chip GPIO"); diff --git a/patches.socfpga/0072-dt-bindings-mfd-Add-Altera-Arria10-System-Resource-C.patch b/patches.socfpga/0072-dt-bindings-mfd-Add-Altera-Arria10-System-Resource-C.patch new file mode 100644 index 00000000000000..48faa04dfee82c --- /dev/null +++ b/patches.socfpga/0072-dt-bindings-mfd-Add-Altera-Arria10-System-Resource-C.patch @@ -0,0 +1,67 @@ +From e9ea91f657e4f88cbedf1e93a19176d45d47548e Mon Sep 17 00:00:00 2001 +From: Thor Thayer <tthayer@opensource.altera.com> +Date: Thu, 2 Jun 2016 12:52:21 -0500 +Subject: [PATCH 072/103] dt-bindings: mfd: Add Altera Arria10 System Resource + Chip bindings + +The Altera Arria10 Devkit System Resource chip is a Multi-Function +Device with a GPIO expander. + +This patch adds documentation for the Altera A10-SR DT bindings. + +Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> +Signed-off-by: Lee Jones <lee.jones@linaro.org> +--- + Documentation/devicetree/bindings/mfd/altera-a10sr.txt | 46 +++++++++++++++++ + 1 file changed, 46 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mfd/altera-a10sr.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mfd/altera-a10sr.txt +@@ -0,0 +1,46 @@ ++* Altera Arria10 Development Kit System Resource Chip ++ ++Required parent device properties: ++- compatible : "altr,a10sr" ++- spi-max-frequency : Maximum SPI frequency. ++- reg : The SPI Chip Select address for the Arria10 ++ System Resource chip ++- interrupt-parent : The parent interrupt controller. ++- interrupts : The interrupt line the device is connected to. ++- interrupt-controller : Marks the device node as an interrupt controller. ++- #interrupt-cells : The number of cells to describe an IRQ, should be 2. ++ The first cell is the IRQ number. ++ The second cell is the flags, encoded as trigger ++ masks from ../interrupt-controller/interrupts.txt. ++ ++The A10SR consists of these sub-devices: ++ ++Device Description ++------ ---------- ++a10sr_gpio GPIO Controller ++ ++Arria10 GPIO ++Required Properties: ++- compatible : Should be "altr,a10sr-gpio" ++- gpio-controller : Marks the device node as a GPIO Controller. ++- #gpio-cells : Should be two. The first cell is the pin number and ++ the second cell is used to specify flags. ++ See ../gpio/gpio.txt for more information. ++ ++Example: ++ ++ resource-manager@0 { ++ compatible = "altr,a10sr"; ++ reg = <0>; ++ spi-max-frequency = <100000>; ++ interrupt-parent = <&portb>; ++ interrupts = <5 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ ++ a10sr_gpio: gpio-controller { ++ compatible = "altr,a10sr-gpio"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; diff --git a/patches.socfpga/0073-ARM-dts-Add-EMAC-AXI-settings-for-Arria10.patch b/patches.socfpga/0073-ARM-dts-Add-EMAC-AXI-settings-for-Arria10.patch new file mode 100644 index 00000000000000..a721ede04dedde --- /dev/null +++ b/patches.socfpga/0073-ARM-dts-Add-EMAC-AXI-settings-for-Arria10.patch @@ -0,0 +1,53 @@ +From 0484444cbff352dc6c1882ed5a6f9ac502875ad7 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <thor.thayer@linux.intel.com> +Date: Thu, 2 Feb 2017 16:05:21 -0600 +Subject: [PATCH 073/103] ARM: dts: Add EMAC AXI settings for Arria10 + +Add the device tree entries needed to support the EMAC AXI +bus settings on the Arria10 SoCFPGA chip. + +Signed-off-by: Thor Thayer <thor.thayer@linux.intel.com> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_arria10.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10.dtsi +@@ -408,6 +408,12 @@ + }; + }; + ++ socfpga_axi_setup: stmmac-axi-config { ++ snps,wr_osr_lmt = <0xf>; ++ snps,rd_osr_lmt = <0xf>; ++ snps,blen = <0 0 0 0 16 0 0>; ++ }; ++ + gmac0: ethernet@ff800000 { + compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac"; + altr,sysmgr-syscon = <&sysmgr 0x44 0>; +@@ -424,6 +430,7 @@ + clock-names = "stmmaceth"; + resets = <&rst EMAC0_RESET>; + reset-names = "stmmaceth"; ++ snps,axi-config = <&socfpga_axi_setup>; + status = "disabled"; + }; + +@@ -443,6 +450,7 @@ + clock-names = "stmmaceth"; + resets = <&rst EMAC1_RESET>; + reset-names = "stmmaceth"; ++ snps,axi-config = <&socfpga_axi_setup>; + status = "disabled"; + }; + +@@ -460,6 +468,7 @@ + rx-fifo-depth = <16384>; + clocks = <&l4_mp_clk>; + clock-names = "stmmaceth"; ++ snps,axi-config = <&socfpga_axi_setup>; + status = "disabled"; + }; + diff --git a/patches.socfpga/0074-MAINTAINERS-EDAC-Update-email-for-Thor-Thayer.patch b/patches.socfpga/0074-MAINTAINERS-EDAC-Update-email-for-Thor-Thayer.patch new file mode 100644 index 00000000000000..2a20ff53b526d1 --- /dev/null +++ b/patches.socfpga/0074-MAINTAINERS-EDAC-Update-email-for-Thor-Thayer.patch @@ -0,0 +1,36 @@ +From 46436c057d4b2210fe487f76a51fdfe7eb9c3d15 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <thor.thayer@linux.intel.com> +Date: Mon, 13 Feb 2017 13:30:41 -0600 +Subject: [PATCH 074/103] MAINTAINERS, EDAC: Update email for Thor Thayer + +My opensource.altera.com email will be going away soon. Switch to new +email address (linux.intel.com). + +Signed-off-by: Thor Thayer <thor.thayer@linux.intel.com> +Cc: linux-edac <linux-edac@vger.kernel.org> +Link: http://lkml.kernel.org/r/1487014241-3771-1-git-send-email-thor.thayer@linux.intel.com +Signed-off-by: Borislav Petkov <bp@suse.de> +--- + MAINTAINERS | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -628,7 +628,7 @@ S: Maintained + F: drivers/gpio/gpio-altera.c + + ALTERA SYSTEM RESOURCE DRIVER FOR ARRIA10 DEVKIT +-M: Thor Thayer <tthayer@opensource.altera.com> ++M: Thor Thayer <thor.thayer@linux.intel.com> + S: Maintained + F: drivers/gpio/gpio-altera-a10sr.c + F: drivers/mfd/altera-a10sr.c +@@ -1766,7 +1766,7 @@ S: Maintained + F: drivers/clk/socfpga/ + + ARM/SOCFPGA EDAC SUPPORT +-M: Thor Thayer <tthayer@opensource.altera.com> ++M: Thor Thayer <thor.thayer@linux.intel.com> + S: Maintained + F: drivers/edac/altera_edac. + diff --git a/patches.socfpga/0075-gpio-altera-a10sr-Set-gpio_chip-parent-property.patch b/patches.socfpga/0075-gpio-altera-a10sr-Set-gpio_chip-parent-property.patch new file mode 100644 index 00000000000000..22a0a2e79a0de8 --- /dev/null +++ b/patches.socfpga/0075-gpio-altera-a10sr-Set-gpio_chip-parent-property.patch @@ -0,0 +1,25 @@ +From 53c9bf5edfe4359a3baa2e42da49dabcc25d789a Mon Sep 17 00:00:00 2001 +From: Thor Thayer <thor.thayer@linux.intel.com> +Date: Mon, 13 Feb 2017 13:49:58 -0600 +Subject: [PATCH 075/103] gpio: altera-a10sr: Set gpio_chip parent property + +Set the gpio_chip parent property since some recent functions +such as devprop_gpiochip_set_names() can use it. + +Signed-off-by: Thor Thayer <thor.thayer@linux.intel.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/gpio/gpio-altera-a10sr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpio/gpio-altera-a10sr.c ++++ b/drivers/gpio/gpio-altera-a10sr.c +@@ -96,7 +96,7 @@ static int altr_a10sr_gpio_probe(struct + gpio->regmap = a10sr->regmap; + + gpio->gp = altr_a10sr_gc; +- ++ gpio->gp.parent = pdev->dev.parent; + gpio->gp.of_node = pdev->dev.of_node; + + ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio); diff --git a/patches.socfpga/0076-dt-bindings-reset-a10sr-Add-Arria10-SR-Reset-Control.patch b/patches.socfpga/0076-dt-bindings-reset-a10sr-Add-Arria10-SR-Reset-Control.patch new file mode 100644 index 00000000000000..343c5d36a23124 --- /dev/null +++ b/patches.socfpga/0076-dt-bindings-reset-a10sr-Add-Arria10-SR-Reset-Control.patch @@ -0,0 +1,64 @@ +From 472534014030a4dc7abfa55952e6fdcb60d12f55 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <thor.thayer@linux.intel.com> +Date: Wed, 22 Feb 2017 11:10:16 -0600 +Subject: [PATCH 076/103] dt-bindings: reset: a10sr: Add Arria10 SR Reset + Controller offsets + +The Arria10 System Resource Chip reset controller handles the +Arria10 peripheral PHYs. This patch adds the offsets for +these PHYs. + +Signed-off-by: Thor Thayer <thor.thayer@linux.intel.com> +Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> +--- + MAINTAINERS | 1 + include/dt-bindings/reset/altr,rst-mgr-a10sr.h | 33 +++++++++++++++++++++++++ + 2 files changed, 34 insertions(+) + create mode 100644 include/dt-bindings/reset/altr,rst-mgr-a10sr.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -633,6 +633,7 @@ S: Maintained + F: drivers/gpio/gpio-altera-a10sr.c + F: drivers/mfd/altera-a10sr.c + F: include/linux/mfd/altera-a10sr.h ++F: include/dt-bindings/reset/altr,rst-mgr-a10sr.h + + ALTERA TRIPLE SPEED ETHERNET DRIVER + M: Vince Bridgers <vbridger@opensource.altera.com> +--- /dev/null ++++ b/include/dt-bindings/reset/altr,rst-mgr-a10sr.h +@@ -0,0 +1,33 @@ ++/* ++ * Copyright Intel Corporation (C) 2017. 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/>. ++ * ++ * Reset binding definitions for Altera Arria10 MAX5 System Resource Chip ++ * ++ * Adapted from altr,rst-mgr-a10.h ++ */ ++ ++#ifndef _DT_BINDINGS_RESET_ALTR_RST_MGR_A10SR_H ++#define _DT_BINDINGS_RESET_ALTR_RST_MGR_A10SR_H ++ ++/* Peripheral PHY resets */ ++#define A10SR_RESET_ENET_HPS 0 ++#define A10SR_RESET_PCIE 1 ++#define A10SR_RESET_FILE 2 ++#define A10SR_RESET_BQSPI 3 ++#define A10SR_RESET_USB 4 ++ ++#define A10SR_RESET_NUM 5 ++ ++#endif diff --git a/patches.socfpga/0077-reset-Add-Altera-Arria10-SR-Reset-Controller.patch b/patches.socfpga/0077-reset-Add-Altera-Arria10-SR-Reset-Controller.patch new file mode 100644 index 00000000000000..e845232369dd3f --- /dev/null +++ b/patches.socfpga/0077-reset-Add-Altera-Arria10-SR-Reset-Controller.patch @@ -0,0 +1,199 @@ +From 5d4c070628323b330cd36b4013d373ed0433a4eb Mon Sep 17 00:00:00 2001 +From: Thor Thayer <thor.thayer@linux.intel.com> +Date: Wed, 22 Feb 2017 11:10:17 -0600 +Subject: [PATCH 077/103] reset: Add Altera Arria10 SR Reset Controller + +This patch adds the reset controller functionality for +Peripheral PHYs to the Arria10 System Resource Chip. + +Signed-off-by: Thor Thayer <thor.thayer@linux.intel.com> +Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> + +Conflicts: + + drivers/reset/Makefile +--- + MAINTAINERS | 1 + drivers/reset/Kconfig | 7 ++ + drivers/reset/Makefile | 1 + drivers/reset/reset-a10sr.c | 138 ++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 147 insertions(+) + create mode 100644 drivers/reset/reset-a10sr.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -632,6 +632,7 @@ M: Thor Thayer <thor.thayer@linux.intel. + S: Maintained + F: drivers/gpio/gpio-altera-a10sr.c + F: drivers/mfd/altera-a10sr.c ++F: drivers/reset/reset-a10sr.c + F: include/linux/mfd/altera-a10sr.h + F: include/dt-bindings/reset/altr,rst-mgr-a10sr.h + +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -14,6 +14,13 @@ menuconfig RESET_CONTROLLER + + if RESET_CONTROLLER + ++config RESET_A10SR ++ tristate "Altera Arria10 System Resource Reset" ++ depends on MFD_ALTERA_A10SR ++ help ++ This option enables support for the external reset functions for ++ peripheral PHYs on the Altera Arria10 System Resource Chip. ++ + config RESET_ATH79 + bool "AR71xx Reset Driver" if COMPILE_TEST + default ATH79 +--- a/drivers/reset/Makefile ++++ b/drivers/reset/Makefile +@@ -1,6 +1,7 @@ + obj-y += core.o + obj-y += hisilicon/ + obj-$(CONFIG_ARCH_STI) += sti/ ++obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o + obj-$(CONFIG_RESET_ATH79) += reset-ath79.o + obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o + obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o +--- /dev/null ++++ b/drivers/reset/reset-a10sr.c +@@ -0,0 +1,138 @@ ++/* ++ * Copyright Intel Corporation (C) 2017. 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/>. ++ * ++ * Reset driver for Altera Arria10 MAX5 System Resource Chip ++ * ++ * Adapted from reset-socfpga.c ++ */ ++ ++#include <linux/err.h> ++#include <linux/mfd/altera-a10sr.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/reset-controller.h> ++ ++#include <dt-bindings/reset/altr,rst-mgr-a10sr.h> ++ ++struct a10sr_reset { ++ struct reset_controller_dev rcdev; ++ struct regmap *regmap; ++}; ++ ++static inline struct a10sr_reset *to_a10sr_rst(struct reset_controller_dev *rc) ++{ ++ return container_of(rc, struct a10sr_reset, rcdev); ++} ++ ++static inline int a10sr_reset_shift(unsigned long id) ++{ ++ switch (id) { ++ case A10SR_RESET_ENET_HPS: ++ return 1; ++ case A10SR_RESET_PCIE: ++ case A10SR_RESET_FILE: ++ case A10SR_RESET_BQSPI: ++ case A10SR_RESET_USB: ++ return id + 11; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int a10sr_reset_update(struct reset_controller_dev *rcdev, ++ unsigned long id, bool assert) ++{ ++ struct a10sr_reset *a10r = to_a10sr_rst(rcdev); ++ int offset = a10sr_reset_shift(id); ++ u8 mask = ALTR_A10SR_REG_BIT_MASK(offset); ++ int index = ALTR_A10SR_HPS_RST_REG + ALTR_A10SR_REG_OFFSET(offset); ++ ++ return regmap_update_bits(a10r->regmap, index, mask, assert ? 0 : mask); ++} ++ ++static int a10sr_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return a10sr_reset_update(rcdev, id, true); ++} ++ ++static int a10sr_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return a10sr_reset_update(rcdev, id, false); ++} ++ ++static int a10sr_reset_status(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ int ret; ++ struct a10sr_reset *a10r = to_a10sr_rst(rcdev); ++ int offset = a10sr_reset_shift(id); ++ u8 mask = ALTR_A10SR_REG_BIT_MASK(offset); ++ int index = ALTR_A10SR_HPS_RST_REG + ALTR_A10SR_REG_OFFSET(offset); ++ unsigned int value; ++ ++ ret = regmap_read(a10r->regmap, index, &value); ++ if (ret < 0) ++ return ret; ++ ++ return !!(value & mask); ++} ++ ++static const struct reset_control_ops a10sr_reset_ops = { ++ .assert = a10sr_reset_assert, ++ .deassert = a10sr_reset_deassert, ++ .status = a10sr_reset_status, ++}; ++ ++static int a10sr_reset_probe(struct platform_device *pdev) ++{ ++ struct altr_a10sr *a10sr = dev_get_drvdata(pdev->dev.parent); ++ struct a10sr_reset *a10r; ++ ++ a10r = devm_kzalloc(&pdev->dev, sizeof(struct a10sr_reset), ++ GFP_KERNEL); ++ if (!a10r) ++ return -ENOMEM; ++ ++ a10r->rcdev.owner = THIS_MODULE; ++ a10r->rcdev.nr_resets = A10SR_RESET_NUM; ++ a10r->rcdev.ops = &a10sr_reset_ops; ++ a10r->rcdev.of_node = pdev->dev.of_node; ++ a10r->regmap = a10sr->regmap; ++ ++ platform_set_drvdata(pdev, a10r); ++ ++ return devm_reset_controller_register(&pdev->dev, &a10r->rcdev); ++} ++ ++static const struct of_device_id a10sr_reset_of_match[] = { ++ { .compatible = "altr,a10sr-reset" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, a10sr_reset_of_match); ++ ++static struct platform_driver a10sr_reset_driver = { ++ .probe = a10sr_reset_probe, ++ .driver = { ++ .name = "altr_a10sr_reset", ++ }, ++}; ++module_platform_driver(a10sr_reset_driver); ++ ++MODULE_AUTHOR("Thor Thayer <thor.thayer@linux.intel.com>"); ++MODULE_DESCRIPTION("Altera Arria10 System Resource Reset Controller Driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/patches.socfpga/0078-ARM-dts-socfpga-Add-Devkit-A10-SR-Reset-Controller.patch b/patches.socfpga/0078-ARM-dts-socfpga-Add-Devkit-A10-SR-Reset-Controller.patch new file mode 100644 index 00000000000000..bbbafba61f42ba --- /dev/null +++ b/patches.socfpga/0078-ARM-dts-socfpga-Add-Devkit-A10-SR-Reset-Controller.patch @@ -0,0 +1,29 @@ +From c948058fb2a34b35c935b947f4c4f07c3d3e7d24 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <thor.thayer@linux.intel.com> +Date: Thu, 16 Mar 2017 07:57:16 -0500 +Subject: [PATCH 078/103] ARM: dts: socfpga: Add Devkit A10-SR Reset Controller + +Add the Altera Arria10 System Resource Reset Controller to the MFD + +Signed-off-by: Thor Thayer <thor.thayer@linux.intel.com> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- +v2 change commit header to ARM: dts: socfpga. +--- + arch/arm/boot/dts/socfpga_arria10_socdk.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +@@ -121,6 +121,11 @@ + gpio-controller; + #gpio-cells = <2>; + }; ++ ++ a10sr_rst: reset-controller { ++ compatible = "altr,a10sr-reset"; ++ #reset-cells = <1>; ++ }; + }; + }; + diff --git a/patches.socfpga/0079-EDAC-altera-Fix-peripheral-warnings-for-Cyclone5.patch b/patches.socfpga/0079-EDAC-altera-Fix-peripheral-warnings-for-Cyclone5.patch new file mode 100644 index 00000000000000..7f6e80c1bf5f1c --- /dev/null +++ b/patches.socfpga/0079-EDAC-altera-Fix-peripheral-warnings-for-Cyclone5.patch @@ -0,0 +1,61 @@ +From 5a77f16dd47f75102d12d86a6ad7bb230b256077 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <thor.thayer@linux.intel.com> +Date: Wed, 5 Apr 2017 13:01:02 -0500 +Subject: [PATCH 079/103] EDAC, altera: Fix peripheral warnings for Cyclone5 + +The peripherals' RAS functionality only exist on the Arria10 SoCFPGA. +The Cyclone5 initialization generates EDAC warnings when the peripherals +aren't found in the device tree. Fix by checking for Arria10 in the init +functions. + +Signed-off-by: Thor Thayer <thor.thayer@linux.intel.com> +Cc: linux-edac <linux-edac@vger.kernel.org> +Link: http://lkml.kernel.org/r/1491415262-5018-1-git-send-email-thor.thayer@linux.intel.com +Signed-off-by: Borislav Petkov <bp@suse.de> +--- + drivers/edac/altera_edac.c | 22 ++++++++++++++++++---- + 1 file changed, 18 insertions(+), 4 deletions(-) + +--- a/drivers/edac/altera_edac.c ++++ b/drivers/edac/altera_edac.c +@@ -1024,13 +1024,23 @@ out: + return ret; + } + ++static int socfpga_is_a10(void) ++{ ++ return of_machine_is_compatible("altr,socfpga-arria10"); ++} ++ + static int validate_parent_available(struct device_node *np); + static const struct of_device_id altr_edac_a10_device_of_match[]; + static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat) + { + int irq; +- struct device_node *child, *np = of_find_compatible_node(NULL, NULL, +- "altr,socfpga-a10-ecc-manager"); ++ struct device_node *child, *np; ++ ++ if (!socfpga_is_a10()) ++ return -ENODEV; ++ ++ np = of_find_compatible_node(NULL, NULL, ++ "altr,socfpga-a10-ecc-manager"); + if (!np) { + edac_printk(KERN_ERR, EDAC_DEVICE, "ECC Manager not found\n"); + return -ENODEV; +@@ -1546,8 +1556,12 @@ static const struct edac_device_prv_data + static int __init socfpga_init_sdmmc_ecc(void) + { + int rc = -ENODEV; +- struct device_node *child = of_find_compatible_node(NULL, NULL, +- "altr,socfpga-sdmmc-ecc"); ++ struct device_node *child; ++ ++ if (!socfpga_is_a10()) ++ return -ENODEV; ++ ++ child = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc"); + if (!child) { + edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n"); + return -ENODEV; diff --git a/patches.socfpga/0080-mfd-altr_a10sr-Add-Arria10-DevKit-Reset-Controller.patch b/patches.socfpga/0080-mfd-altr_a10sr-Add-Arria10-DevKit-Reset-Controller.patch new file mode 100644 index 00000000000000..8da8b04d0cb386 --- /dev/null +++ b/patches.socfpga/0080-mfd-altr_a10sr-Add-Arria10-DevKit-Reset-Controller.patch @@ -0,0 +1,27 @@ +From 3c7b3fce2cf21f284518116f77bff9d6c7f4b327 Mon Sep 17 00:00:00 2001 +From: Thor Thayer <thor.thayer@linux.intel.com> +Date: Wed, 22 Feb 2017 11:10:18 -0600 +Subject: [PATCH 080/103] mfd: altr_a10sr: Add Arria10 DevKit Reset Controller + +Add Peripheral PHY Reset Controller to the Arria10 +Development Kit System Resource Chip's MFD. + +Signed-off-by: Thor Thayer <thor.thayer@linux.intel.com> +Signed-off-by: Lee Jones <lee.jones@linaro.org> +--- + drivers/mfd/altera-a10sr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mfd/altera-a10sr.c ++++ b/drivers/mfd/altera-a10sr.c +@@ -33,6 +33,10 @@ static const struct mfd_cell altr_a10sr_ + .name = "altr_a10sr_gpio", + .of_compatible = "altr,a10sr-gpio", + }, ++ { ++ .name = "altr_a10sr_reset", ++ .of_compatible = "altr,a10sr-reset", ++ }, + }; + + static bool altr_a10sr_reg_readable(struct device *dev, unsigned int reg) diff --git a/patches.socfpga/0081-dt-bindings-mfd-Add-Altera-Arria10-SR-Reset-Controll.patch b/patches.socfpga/0081-dt-bindings-mfd-Add-Altera-Arria10-SR-Reset-Controll.patch new file mode 100644 index 00000000000000..2541f56a8da66a --- /dev/null +++ b/patches.socfpga/0081-dt-bindings-mfd-Add-Altera-Arria10-SR-Reset-Controll.patch @@ -0,0 +1,48 @@ +From f12e2e73318394511538aa49c150a864d4f1a91a Mon Sep 17 00:00:00 2001 +From: Thor Thayer <thor.thayer@linux.intel.com> +Date: Wed, 22 Feb 2017 11:10:15 -0600 +Subject: [PATCH 081/103] dt-bindings: mfd: Add Altera Arria10 SR Reset + Controller bindings + +This patch adds documentation for the Altera A10-SR Reset +Controller DT bindings. + +Signed-off-by: Thor Thayer <thor.thayer@linux.intel.com> +Acked-by: Rob Herring <robh@kernel.org> +Signed-off-by: Lee Jones <lee.jones@linaro.org> +--- + Documentation/devicetree/bindings/mfd/altera-a10sr.txt | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/Documentation/devicetree/bindings/mfd/altera-a10sr.txt ++++ b/Documentation/devicetree/bindings/mfd/altera-a10sr.txt +@@ -18,6 +18,7 @@ The A10SR consists of these sub-devices: + Device Description + ------ ---------- + a10sr_gpio GPIO Controller ++a10sr_rst Reset Controller + + Arria10 GPIO + Required Properties: +@@ -27,6 +28,11 @@ Required Properties: + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + ++Arria10 Peripheral PHY Reset ++Required Properties: ++- compatible : Should be "altr,a10sr-reset" ++- #reset-cells : Should be one. ++ + Example: + + resource-manager@0 { +@@ -43,4 +49,9 @@ Example: + gpio-controller; + #gpio-cells = <2>; + }; ++ ++ a10sr_rst: reset-controller { ++ compatible = "altr,a10sr-reset"; ++ #reset-cells = <1>; ++ }; + }; diff --git a/patches.socfpga/0082-ARM-socfpga-defconfig-enable-qspi.patch b/patches.socfpga/0082-ARM-socfpga-defconfig-enable-qspi.patch new file mode 100644 index 00000000000000..406f4072673e75 --- /dev/null +++ b/patches.socfpga/0082-ARM-socfpga-defconfig-enable-qspi.patch @@ -0,0 +1,23 @@ +From fa54ece4ad77749237745ea23796f8a2a368cbfc Mon Sep 17 00:00:00 2001 +From: Steffen Trumtrar <s.trumtrar@pengutronix.de> +Date: Tue, 18 Oct 2016 07:43:04 +0000 +Subject: [PATCH 082/103] ARM: socfpga: defconfig: enable qspi + +Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/configs/socfpga_defconfig | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/arm/configs/socfpga_defconfig ++++ b/arch/arm/configs/socfpga_defconfig +@@ -51,6 +51,9 @@ CONFIG_CAN_DEBUG_DEVICES=y + CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" + CONFIG_DEVTMPFS=y + CONFIG_DEVTMPFS_MOUNT=y ++CONFIG_MTD=y ++CONFIG_MTD_SPI_NOR=y ++CONFIG_SPI_CADENCE_QUADSPI=y + CONFIG_BLK_DEV_RAM=y + CONFIG_BLK_DEV_RAM_COUNT=2 + CONFIG_BLK_DEV_RAM_SIZE=8192 diff --git a/patches.socfpga/0083-ARM-socfpga-updates-for-socfpga_defconfig.patch b/patches.socfpga/0083-ARM-socfpga-updates-for-socfpga_defconfig.patch new file mode 100644 index 00000000000000..3fc4ef2288e72d --- /dev/null +++ b/patches.socfpga/0083-ARM-socfpga-updates-for-socfpga_defconfig.patch @@ -0,0 +1,58 @@ +From b7e82058125354c24224ef475ffed4a8f30d025c Mon Sep 17 00:00:00 2001 +From: Alan Tull <atull@opensource.altera.com> +Date: Wed, 2 Nov 2016 16:22:36 -0500 +Subject: [PATCH 083/103] ARM: socfpga: updates for socfpga_defconfig + +This patch enables the following in the +socfpga_defconfig: + ++CONFIG_OF_OVERLAY=y + Enable support for Device Tree Overlays + ++CONFIG_FPGA_REGION=y + Enable device tree overlay support for FPGA + programming + ++CONFIG_FPGA_MGR_SOCFPGA_A10=y + Enable partial reconfiguration for Altera + Arria 10 FPGA + ++CONFIG_FPGA_BRIDGE=y + Enable the FPGA Bridges framework + ++CONFIG_SOCFPGA_FPGA_BRIDGE=y + Enable support for SoCFPGA hardware + bridges + ++CONFIG_ALTERA_FREEZE_BRIDGE=y + Enable support for the Altera Soft IP + Freeze bridges + +Signed-off-by: Alan Tull <atull@opensource.altera.com> +--- + arch/arm/configs/socfpga_defconfig | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/arch/arm/configs/socfpga_defconfig ++++ b/arch/arm/configs/socfpga_defconfig +@@ -54,6 +54,7 @@ CONFIG_DEVTMPFS_MOUNT=y + CONFIG_MTD=y + CONFIG_MTD_SPI_NOR=y + CONFIG_SPI_CADENCE_QUADSPI=y ++CONFIG_OF_OVERLAY=y + CONFIG_BLK_DEV_RAM=y + CONFIG_BLK_DEV_RAM_COUNT=2 + CONFIG_BLK_DEV_RAM_SIZE=8192 +@@ -105,7 +106,12 @@ CONFIG_DMADEVICES=y + CONFIG_PL330_DMA=y + CONFIG_DMATEST=m + CONFIG_FPGA=y ++CONFIG_FPGA_REGION=y + CONFIG_FPGA_MGR_SOCFPGA=y ++CONFIG_FPGA_MGR_SOCFPGA_A10=y ++CONFIG_FPGA_BRIDGE=y ++CONFIG_SOCFPGA_FPGA_BRIDGE=y ++CONFIG_ALTERA_FREEZE_BRIDGE=y + CONFIG_EXT2_FS=y + CONFIG_EXT2_FS_XATTR=y + CONFIG_EXT2_FS_POSIX_ACL=y diff --git a/patches.socfpga/0084-ARM-socfpga_defconfig-update-defconfig-for-SoCFPGA.patch b/patches.socfpga/0084-ARM-socfpga_defconfig-update-defconfig-for-SoCFPGA.patch new file mode 100644 index 00000000000000..89303586e3d4d4 --- /dev/null +++ b/patches.socfpga/0084-ARM-socfpga_defconfig-update-defconfig-for-SoCFPGA.patch @@ -0,0 +1,112 @@ +From b0068141c565214d7682a9fa95c1673648ab159d Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Wed, 14 Dec 2016 04:25:54 -0600 +Subject: [PATCH 084/103] ARM: socfpga_defconfig: update defconfig for SoCFPGA + +MARVELL_PHY - support for the Marvell PHY that is on most of the devkits +EEPROM_AT24 - support for I2C EEPROMs on the devkits +GPIO_ALTERA - support for Altera's GPIO driver +NAND - support for the Denali NAND controller along with MTD subsystem +SPI_DESIGNWARE - support for SPI that is on SoCFPGA +SPI_DW_MMIO - support for the memory-mapped io interface for the DW SPI core +OF_CONFIGFS - SoCFPGA makes use of DT overlays using configfs, enable it +GPIO_ALTERA_A10SR - support for the newly added Altera HWMON driver +LEDS - support for the GPIO LEDs on the SoCFPGA devkits +RTC - support for the DS1307 RTC +JFFS2_FS - support for the JFFS2 filesystem +NFS_V4 - supports for v4 NFS +FUNCTION_TRACER - supports debug function tracing + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/configs/socfpga_defconfig | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +--- a/arch/arm/configs/socfpga_defconfig ++++ b/arch/arm/configs/socfpga_defconfig +@@ -52,14 +52,20 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug + CONFIG_DEVTMPFS=y + CONFIG_DEVTMPFS_MOUNT=y + CONFIG_MTD=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_M25P80=y ++CONFIG_MTD_NAND=y ++CONFIG_MTD_NAND_DENALI_DT=y + CONFIG_MTD_SPI_NOR=y + CONFIG_SPI_CADENCE_QUADSPI=y + CONFIG_OF_OVERLAY=y ++CONFIG_OF_CONFIGFS=y + CONFIG_BLK_DEV_RAM=y + CONFIG_BLK_DEV_RAM_COUNT=2 + CONFIG_BLK_DEV_RAM_SIZE=8192 + CONFIG_BLK_DEV_NVME=m + CONFIG_SRAM=y ++CONFIG_EEPROM_AT24=y + CONFIG_SCSI=y + # CONFIG_SCSI_PROC_FS is not set + CONFIG_BLK_DEV_SD=y +@@ -69,6 +75,7 @@ CONFIG_E1000E=m + CONFIG_IGB=m + CONFIG_IXGBE=m + CONFIG_STMMAC_ETH=y ++CONFIG_MARVELL_PHY=y + CONFIG_MICREL_PHY=y + CONFIG_INPUT_EVDEV=y + CONFIG_INPUT_TOUCHSCREEN=y +@@ -84,14 +91,22 @@ CONFIG_SERIAL_8250_DW=y + CONFIG_I2C=y + CONFIG_I2C_CHARDEV=y + CONFIG_I2C_DESIGNWARE_PLATFORM=y ++CONFIG_SPI=y ++CONFIG_SPI_DESIGNWARE=y ++CONFIG_SPI_DW_MMIO=y ++CONFIG_SPI_SPIDEV=y + CONFIG_GPIOLIB=y + CONFIG_GPIO_SYSFS=y ++CONFIG_GPIO_ALTERA=y + CONFIG_GPIO_DWAPB=y ++CONFIG_GPIO_ALTERA_A10SR=y ++CONFIG_SENSORS_MAX1619=y + CONFIG_PMBUS=y + CONFIG_SENSORS_LTC2978=y + CONFIG_SENSORS_LTC2978_REGULATOR=y + CONFIG_WATCHDOG=y + CONFIG_DW_WATCHDOG=y ++CONFIG_MFD_ALTERA_A10SR=y + CONFIG_MFD_STMPE=y + CONFIG_REGULATOR=y + CONFIG_REGULATOR_FIXED_VOLTAGE=y +@@ -102,6 +117,14 @@ CONFIG_NOP_USB_XCEIV=y + CONFIG_USB_GADGET=y + CONFIG_MMC=y + CONFIG_MMC_DW=y ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y ++CONFIG_LEDS_TRIGGER_TIMER=y ++CONFIG_LEDS_TRIGGER_CPU=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_DRV_DS1307=y + CONFIG_DMADEVICES=y + CONFIG_PL330_DMA=y + CONFIG_DMATEST=m +@@ -121,9 +144,10 @@ CONFIG_VFAT_FS=y + CONFIG_NTFS_FS=y + CONFIG_NTFS_RW=y + CONFIG_TMPFS=y +-CONFIG_CONFIGFS_FS=y ++CONFIG_JFFS2_FS=y + CONFIG_NFS_FS=y + CONFIG_NFS_V3_ACL=y ++CONFIG_NFS_V4=y + CONFIG_ROOT_NFS=y + CONFIG_NFSD=y + CONFIG_NFSD_V3_ACL=y +@@ -135,5 +159,5 @@ CONFIG_DEBUG_INFO=y + CONFIG_MAGIC_SYSRQ=y + CONFIG_DETECT_HUNG_TASK=y + # CONFIG_SCHED_DEBUG is not set +-CONFIG_ENABLE_DEFAULT_TRACERS=y ++CONFIG_FUNCTION_TRACER=y + CONFIG_DEBUG_USER=y diff --git a/patches.socfpga/0085-ARM-socfpga-updates-for-socfpga_defconfig.patch b/patches.socfpga/0085-ARM-socfpga-updates-for-socfpga_defconfig.patch new file mode 100644 index 00000000000000..022150af48be64 --- /dev/null +++ b/patches.socfpga/0085-ARM-socfpga-updates-for-socfpga_defconfig.patch @@ -0,0 +1,23 @@ +From 6dd0a8c7a2e167fd63ef04f038b0e1cbf6e33188 Mon Sep 17 00:00:00 2001 +From: Jia Jie Ho <ho.jia.jie@intel.com> +Date: Thu, 16 Mar 2017 08:05:46 -0500 +Subject: [PATCH 085/103] ARM: socfpga: updates for socfpga_defconfig + +This patch enables Altera TSE support in socfpga_defconfig + +Signed-off-by: Jia Jie Ho <ho.jia.jie@intel.com> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/configs/socfpga_defconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/configs/socfpga_defconfig ++++ b/arch/arm/configs/socfpga_defconfig +@@ -71,6 +71,7 @@ CONFIG_SCSI=y + CONFIG_BLK_DEV_SD=y + # CONFIG_SCSI_LOWLEVEL is not set + CONFIG_NETDEVICES=y ++CONFIG_ALTERA_TSE=m + CONFIG_E1000E=m + CONFIG_IGB=m + CONFIG_IXGBE=m diff --git a/patches.socfpga/0086-ARM-dts-socfpga-Add-new-MCVEVK-manufacturer-compat.patch b/patches.socfpga/0086-ARM-dts-socfpga-Add-new-MCVEVK-manufacturer-compat.patch new file mode 100644 index 00000000000000..f5c7e4e37c8d4a --- /dev/null +++ b/patches.socfpga/0086-ARM-dts-socfpga-Add-new-MCVEVK-manufacturer-compat.patch @@ -0,0 +1,37 @@ +From 3bf20e590278aeae0493d36dead11207a5a3b6d7 Mon Sep 17 00:00:00 2001 +From: Marek Vasut <marex@denx.de> +Date: Mon, 19 Sep 2016 21:40:43 +0000 +Subject: [PATCH 086/103] ARM: dts: socfpga: Add new MCVEVK manufacturer compat + +The board is now manufactured by Aries Embedded GmbH, update compat string. + +Signed-off-by: Marek Vasut <marex@denx.de> +Cc: Dinh Nguyen <dinguyen@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi ++++ b/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi +@@ -18,7 +18,7 @@ + #include "socfpga_cyclone5.dtsi" + + / { +- model = "DENX MCV"; ++ model = "Aries/DENX MCV"; + compatible = "altr,socfpga-cyclone5", "altr,socfpga"; + + memory { +--- a/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts +@@ -18,7 +18,7 @@ + #include "socfpga_cyclone5_mcv.dtsi" + + / { +- model = "DENX MCV EVK"; ++ model = "Aries/DENX MCV EVK"; + compatible = "altr,socfpga-cyclone5", "altr,socfpga"; + + aliases { diff --git a/patches.socfpga/0087-ARM-dts-socfpga-Add-Macnica-sodia-board.patch b/patches.socfpga/0087-ARM-dts-socfpga-Add-Macnica-sodia-board.patch new file mode 100644 index 00000000000000..f004121699f14f --- /dev/null +++ b/patches.socfpga/0087-ARM-dts-socfpga-Add-Macnica-sodia-board.patch @@ -0,0 +1,162 @@ +From 3cd00779ac5363f30cccb685ae6ca56990d363b1 Mon Sep 17 00:00:00 2001 +From: Nobuhiro Iwamatsu <iwamatsu@nigauri.org> +Date: Sat, 24 Sep 2016 23:59:45 +0000 +Subject: [PATCH 087/103] ARM: dts: socfpga: Add Macnica sodia board + +Add support for board based on the Altera Cyclone V SoC. +This board has the following functions: + - 1 GiB of DRAM + - 1 Gigabit ethernet + - 1 SD card slot + - 1 USB gadget port + - QSPI NOR Flash + - I2C EEPROMs and I2C RTC + - DVI output + - Audio port + +This commit supports without QSPI, DVI and Audio. + +Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/socfpga_cyclone5_sodia.dts | 123 +++++++++++++++++++++++++++ + 2 files changed, 124 insertions(+) + create mode 100644 arch/arm/boot/dts/socfpga_cyclone5_sodia.dts + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -700,6 +700,7 @@ dtb-$(CONFIG_ARCH_SOCFPGA) += \ + socfpga_cyclone5_de0_sockit.dtb \ + socfpga_cyclone5_sockit.dtb \ + socfpga_cyclone5_socrates.dtb \ ++ socfpga_cyclone5_sodia.dtb \ + socfpga_cyclone5_vining_fpga.dtb \ + socfpga_vt.dtb + dtb-$(CONFIG_ARCH_SPEAR13XX) += \ +--- /dev/null ++++ b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts +@@ -0,0 +1,123 @@ ++/* ++ * Copyright (C) 2016 Nobuhiro Iwamatsu <iwamatsu@nigauri.org> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * 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 "socfpga_cyclone5.dtsi" ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/input/input.h> ++ ++/ { ++ model = "Altera SOCFPGA Cyclone V SoC Macnica Sodia board"; ++ compatible = "altr,socfpga-cyclone5", "altr,socfpga"; ++ ++ chosen { ++ bootargs = "earlyprintk"; ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory { ++ name = "memory"; ++ device_type = "memory"; ++ reg = <0x0 0x40000000>; ++ }; ++ ++ aliases { ++ ethernet0 = &gmac1; ++ }; ++ ++ regulator_3_3v: 3-3-v-regulator { ++ compatible = "regulator-fixed"; ++ regulator-name = "3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ leds: gpio-leds { ++ compatible = "gpio-leds"; ++ ++ hps_led0 { ++ label = "hps:green:led0"; ++ gpios = <&portb 12 GPIO_ACTIVE_LOW>; ++ }; ++ ++ hps_led1 { ++ label = "hps:green:led1"; ++ gpios = <&portb 13 GPIO_ACTIVE_LOW>; ++ }; ++ ++ hps_led2 { ++ label = "hps:green:led2"; ++ gpios = <&portb 14 GPIO_ACTIVE_LOW>; ++ }; ++ ++ hps_led3 { ++ label = "hps:green:led3"; ++ gpios = <&portb 15 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++}; ++ ++&gmac1 { ++ status = "okay"; ++ phy-mode = "rgmii"; ++ phy = <&phy0>; ++ ++ mdio0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ phy0: ethernet-phy@0 { ++ reg = <0>; ++ rxd0-skew-ps = <0>; ++ rxd1-skew-ps = <0>; ++ rxd2-skew-ps = <0>; ++ rxd3-skew-ps = <0>; ++ rxdv-skew-ps = <0>; ++ rxc-skew-ps = <3000>; ++ txen-skew-ps = <0>; ++ txc-skew-ps = <3000>; ++ }; ++ }; ++}; ++ ++&gpio1 { ++ status = "okay"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ eeprom@51 { ++ compatible = "atmel,24c32"; ++ reg = <0x51>; ++ pagesize = <32>; ++ }; ++ ++ rtc@68 { ++ compatible = "dallas,ds1339"; ++ reg = <0x68>; ++ }; ++}; ++ ++&mmc0 { ++ cd-gpios = <&portb 18 0>; ++ vmmc-supply = <®ulator_3_3v>; ++ vqmmc-supply = <®ulator_3_3v>; ++ status = "okay"; ++}; ++ ++&usb1 { ++ status = "okay"; ++}; diff --git a/patches.socfpga/0088-ARM-dts-socfpga-add-specific-compatible-strings-for-.patch b/patches.socfpga/0088-ARM-dts-socfpga-add-specific-compatible-strings-for-.patch new file mode 100644 index 00000000000000..4a87d3bbb77c85 --- /dev/null +++ b/patches.socfpga/0088-ARM-dts-socfpga-add-specific-compatible-strings-for-.patch @@ -0,0 +1,89 @@ +From d5b1b034ae10a0fcbd24a3af638558c93e17ca4a Mon Sep 17 00:00:00 2001 +From: Dinh Nguyen <dinguyen@kernel.org> +Date: Tue, 1 Nov 2016 09:57:06 -0500 +Subject: [PATCH 088/103] ARM: dts: socfpga: add specific compatible strings + for boards + +Add a more specific board compatible entry for all of the SOCFPGA +Cyclone 5 based boards. + +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- +v3: Be a bit more specific with the c5 dk and sockit, use + "altr,socfpga-cyclone5-socdk" and "terasic,socfpga-cyclone5-sockit" +v2: remove extra space and add a comma between compatible entries +--- + arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_sockit.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_sodia.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts | 2 +- + 6 files changed, 6 insertions(+), 6 deletions(-) + +--- a/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts +@@ -18,7 +18,7 @@ + + / { + model = "Terasic DE-0(Atlas)"; +- compatible = "altr,socfpga-cyclone5", "altr,socfpga"; ++ compatible = "terasic,de0-atlas", "altr,socfpga-cyclone5", "altr,socfpga"; + + chosen { + bootargs = "earlyprintk"; +--- a/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_mcvevk.dts +@@ -19,7 +19,7 @@ + + / { + model = "Aries/DENX MCV EVK"; +- compatible = "altr,socfpga-cyclone5", "altr,socfpga"; ++ compatible = "denx,mcvevk", "altr,socfpga-cyclone5", "altr,socfpga"; + + aliases { + ethernet0 = &gmac0; +--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +@@ -19,7 +19,7 @@ + + / { + model = "Altera SOCFPGA Cyclone V SoC Development Kit"; +- compatible = "altr,socfpga-cyclone5", "altr,socfpga"; ++ compatible = "altr,socfpga-cyclone5-socdk", "altr,socfpga-cyclone5", "altr,socfpga"; + + chosen { + bootargs = "earlyprintk"; +--- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts +@@ -19,7 +19,7 @@ + + / { + model = "Terasic SoCkit"; +- compatible = "altr,socfpga-cyclone5", "altr,socfpga"; ++ compatible = "terasic,socfpga-cyclone5-sockit", "altr,socfpga-cyclone5", "altr,socfpga"; + + chosen { + bootargs = "earlyprintk"; +--- a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts +@@ -21,7 +21,7 @@ + + / { + model = "Altera SOCFPGA Cyclone V SoC Macnica Sodia board"; +- compatible = "altr,socfpga-cyclone5", "altr,socfpga"; ++ compatible = "macnica,sodia", "altr,socfpga-cyclone5", "altr,socfpga"; + + chosen { + bootargs = "earlyprintk"; +--- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts +@@ -51,7 +51,7 @@ + + / { + model = "samtec VIN|ING FPGA"; +- compatible = "altr,socfpga-cyclone5", "altr,socfpga"; ++ compatible = "samtec,vining", "altr,socfpga-cyclone5", "altr,socfpga"; + + chosen { + bootargs = "console=ttyS0,115200"; diff --git a/patches.socfpga/0089-ARM-dts-socfpga-Add-unit-name-to-memory-nodes.patch b/patches.socfpga/0089-ARM-dts-socfpga-Add-unit-name-to-memory-nodes.patch new file mode 100644 index 00000000000000..c89c1521defa55 --- /dev/null +++ b/patches.socfpga/0089-ARM-dts-socfpga-Add-unit-name-to-memory-nodes.patch @@ -0,0 +1,138 @@ +From 053c4886aa63bf59091841b2a7635ce14921fb37 Mon Sep 17 00:00:00 2001 +From: Florian Vaussard <florian.vaussard@gmail.com> +Date: Mon, 27 Feb 2017 10:38:39 -0600 +Subject: [PATCH 089/103] ARM: dts: socfpga: Add unit name to memory nodes + +Memory nodes in Arria5, Cyclone5 and Arria10 do not have a unit name. +This will trigger several warnings like this one (when compiled with +W=1): + +Node /memory has a reg or ranges property, but no unit name + +Add the corresponding unit name to each node. + +Signed-off-by: Florian Vaussard <florian.vaussard@heig-vd.ch> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_arria10_socdk.dtsi | 2 +- + arch/arm/boot/dts/socfpga_arria5_socdk.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_sockit.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_socrates.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_sodia.dts | 2 +- + arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts | 2 +- + arch/arm/boot/dts/socfpga_vt.dts | 2 +- + 10 files changed, 10 insertions(+), 10 deletions(-) + +--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi +@@ -30,7 +30,7 @@ + stdout-path = "serial0:115200n8"; + }; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1GB */ +--- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts +@@ -26,7 +26,7 @@ + stdout-path = "serial0:115200n8"; + }; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1GB */ +--- a/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_de0_sockit.dts +@@ -25,7 +25,7 @@ + stdout-path = "serial0:115200n8"; + }; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1GB */ +--- a/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi ++++ b/arch/arm/boot/dts/socfpga_cyclone5_mcv.dtsi +@@ -21,7 +21,7 @@ + model = "Aries/DENX MCV"; + compatible = "altr,socfpga-cyclone5", "altr,socfpga"; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1 GiB */ +--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +@@ -26,7 +26,7 @@ + stdout-path = "serial0:115200n8"; + }; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1GB */ +--- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts +@@ -26,7 +26,7 @@ + stdout-path = "serial0:115200n8"; + }; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1GB */ +--- a/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_socrates.dts +@@ -25,7 +25,7 @@ + bootargs = "console=ttyS0,115200"; + }; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1GB */ +--- a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts +@@ -28,7 +28,7 @@ + stdout-path = "serial0:115200n8"; + }; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; +--- a/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts +@@ -57,7 +57,7 @@ + bootargs = "console=ttyS0,115200"; + }; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1GB */ +--- a/arch/arm/boot/dts/socfpga_vt.dts ++++ b/arch/arm/boot/dts/socfpga_vt.dts +@@ -26,7 +26,7 @@ + bootargs = "console=ttyS0,57600"; + }; + +- memory { ++ memory@0 { + name = "memory"; + device_type = "memory"; + reg = <0x0 0x40000000>; /* 1 GB */ diff --git a/patches.socfpga/0090-ARM-dts-socfpga-sodia-enable-qspi.patch b/patches.socfpga/0090-ARM-dts-socfpga-sodia-enable-qspi.patch new file mode 100644 index 00000000000000..9d3cdf35d287ad --- /dev/null +++ b/patches.socfpga/0090-ARM-dts-socfpga-sodia-enable-qspi.patch @@ -0,0 +1,41 @@ +From d59a294e24214c1d45314e38eac346256973f389 Mon Sep 17 00:00:00 2001 +From: Nobuhiro Iwamatsu <iwamatsu@nigauri.org> +Date: Fri, 10 Feb 2017 11:21:33 -0600 +Subject: [PATCH 090/103] ARM: dts: socfpga: sodia: enable qspi + +Enable the qspi controller on sodia board and add the flash chip +(n25q512a). + +Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- + arch/arm/boot/dts/socfpga_cyclone5_sodia.dts | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +--- a/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts ++++ b/arch/arm/boot/dts/socfpga_cyclone5_sodia.dts +@@ -121,3 +121,24 @@ + &usb1 { + status = "okay"; + }; ++ ++&qspi { ++ status = "okay"; ++ ++ flash0: n25q512a@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "n25q512a"; ++ reg = <0>; ++ spi-max-frequency = <100000000>; ++ ++ m25p,fast-read; ++ cdns,page-size = <256>; ++ cdns,block-size = <16>; ++ cdns,read-delay = <4>; ++ cdns,tshsl-ns = <50>; ++ cdns,tsd2d-ns = <50>; ++ cdns,tchsh-ns = <4>; ++ cdns,tslch-ns = <4>; ++ }; ++}; diff --git a/patches.socfpga/0091-ARM-dts-socfpga-add-qspi-node.patch b/patches.socfpga/0091-ARM-dts-socfpga-add-qspi-node.patch new file mode 100644 index 00000000000000..f07477c406f3a7 --- /dev/null +++ b/patches.socfpga/0091-ARM-dts-socfpga-add-qspi-node.patch @@ -0,0 +1,36 @@ +From 5420a09156d6bc2cb61aad87b1277c6c9e3ba788 Mon Sep 17 00:00:00 2001 +From: Steffen Trumtrar <s.trumtrar@pengutronix.de> +Date: Tue, 18 Oct 2016 07:43:02 +0000 +Subject: [PATCH 091/103] ARM: dts: socfpga: add qspi node + +Add the qspi node to the socfpga dtsi file. + +Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> +Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com> +--- + arch/arm/boot/dts/socfpga.dtsi | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/arch/arm/boot/dts/socfpga.dtsi ++++ b/arch/arm/boot/dts/socfpga.dtsi +@@ -733,6 +733,20 @@ + reg = <0xffff0000 0x10000>; + }; + ++ qspi: spi@ff705000 { ++ compatible = "cdns,qspi-nor"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0xff705000 0x1000>, ++ <0xffa00000 0x1000>; ++ interrupts = <0 151 4>; ++ cdns,fifo-depth = <128>; ++ cdns,fifo-width = <4>; ++ cdns,trigger-address = <0x00000000>; ++ clocks = <&qspi_clk>; ++ status = "disabled"; ++ }; ++ + rst: rstmgr@ffd05000 { + #reset-cells = <1>; + compatible = "altr,rst-mgr"; diff --git a/patches.socfpga/0092-fpga-pr-ip-Core-driver-support-for-Altera-Partial-Re.patch b/patches.socfpga/0092-fpga-pr-ip-Core-driver-support-for-Altera-Partial-Re.patch new file mode 100644 index 00000000000000..6d6a33500d45b9 --- /dev/null +++ b/patches.socfpga/0092-fpga-pr-ip-Core-driver-support-for-Altera-Partial-Re.patch @@ -0,0 +1,302 @@ +From dee4f9e2e4dd5ee90ad2910be5546ff32f42aa55 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach <matthew.gerlach@linux.intel.com> +Date: Thu, 23 Mar 2017 19:34:28 -0500 +Subject: [PATCH 092/103] fpga pr ip: Core driver support for Altera Partial + Reconfiguration IP. + +Adding the core functions necessary for a fpga-mgr driver +for the Altera Partial IP component. It is intended for +these functions to be used by the various bus implementations +like the platform bus or the PCIe bus. + +Signed-off-by: Matthew Gerlach <matthew.gerlach@linux.intel.com> +Acked-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 5 + drivers/fpga/Makefile | 1 + drivers/fpga/altera-pr-ip-core.c | 220 +++++++++++++++++++++++++++++++++ + include/linux/fpga/altera-pr-ip-core.h | 29 ++++ + 4 files changed, 255 insertions(+) + create mode 100644 drivers/fpga/altera-pr-ip-core.c + create mode 100644 include/linux/fpga/altera-pr-ip-core.h + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -83,6 +83,11 @@ config ALTERA_FREEZE_BRIDGE + isolate one region of the FPGA from the busses while that + region is being reprogrammed. + ++config ALTERA_PR_IP_CORE ++ tristate "Altera Partial Reconfiguration IP Core" ++ help ++ Core driver support for Altera Partial Reconfiguration IP component ++ + endif # FPGA + + endmenu +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += so + obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o + obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o + obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o ++obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o + + # FPGA Bridge Drivers + obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o +--- /dev/null ++++ b/drivers/fpga/altera-pr-ip-core.c +@@ -0,0 +1,220 @@ ++/* ++ * Driver for Altera Partial Reconfiguration IP Core ++ * ++ * Copyright (C) 2016-2017 Intel Corporation ++ * ++ * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation ++ * by Alan Tull <atull@opensource.altera.com> ++ * ++ * 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/delay.h> ++#include <linux/fpga/altera-pr-ip-core.h> ++#include <linux/fpga/fpga-mgr.h> ++#include <linux/module.h> ++ ++#define ALT_PR_DATA_OFST 0x00 ++#define ALT_PR_CSR_OFST 0x04 ++ ++#define ALT_PR_CSR_PR_START BIT(0) ++#define ALT_PR_CSR_STATUS_SFT 2 ++#define ALT_PR_CSR_STATUS_MSK (7 << ALT_PR_CSR_STATUS_SFT) ++#define ALT_PR_CSR_STATUS_NRESET (0 << ALT_PR_CSR_STATUS_SFT) ++#define ALT_PR_CSR_STATUS_PR_ERR (1 << ALT_PR_CSR_STATUS_SFT) ++#define ALT_PR_CSR_STATUS_CRC_ERR (2 << ALT_PR_CSR_STATUS_SFT) ++#define ALT_PR_CSR_STATUS_BAD_BITS (3 << ALT_PR_CSR_STATUS_SFT) ++#define ALT_PR_CSR_STATUS_PR_IN_PROG (4 << ALT_PR_CSR_STATUS_SFT) ++#define ALT_PR_CSR_STATUS_PR_SUCCESS (5 << ALT_PR_CSR_STATUS_SFT) ++ ++struct alt_pr_priv { ++ void __iomem *reg_base; ++}; ++ ++static enum fpga_mgr_states alt_pr_fpga_state(struct fpga_manager *mgr) ++{ ++ struct alt_pr_priv *priv = mgr->priv; ++ const char *err = "unknown"; ++ enum fpga_mgr_states ret = FPGA_MGR_STATE_UNKNOWN; ++ u32 val; ++ ++ val = readl(priv->reg_base + ALT_PR_CSR_OFST); ++ ++ val &= ALT_PR_CSR_STATUS_MSK; ++ ++ switch (val) { ++ case ALT_PR_CSR_STATUS_NRESET: ++ return FPGA_MGR_STATE_RESET; ++ ++ case ALT_PR_CSR_STATUS_PR_ERR: ++ err = "pr error"; ++ ret = FPGA_MGR_STATE_WRITE_ERR; ++ break; ++ ++ case ALT_PR_CSR_STATUS_CRC_ERR: ++ err = "crc error"; ++ ret = FPGA_MGR_STATE_WRITE_ERR; ++ break; ++ ++ case ALT_PR_CSR_STATUS_BAD_BITS: ++ err = "bad bits"; ++ ret = FPGA_MGR_STATE_WRITE_ERR; ++ break; ++ ++ case ALT_PR_CSR_STATUS_PR_IN_PROG: ++ return FPGA_MGR_STATE_WRITE; ++ ++ case ALT_PR_CSR_STATUS_PR_SUCCESS: ++ return FPGA_MGR_STATE_OPERATING; ++ ++ default: ++ break; ++ } ++ ++ dev_err(&mgr->dev, "encountered error code %d (%s) in %s()\n", ++ val, err, __func__); ++ return ret; ++} ++ ++static int alt_pr_fpga_write_init(struct fpga_manager *mgr, ++ struct fpga_image_info *info, ++ const char *buf, size_t count) ++{ ++ struct alt_pr_priv *priv = mgr->priv; ++ u32 val; ++ ++ if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { ++ dev_err(&mgr->dev, "%s Partial Reconfiguration flag not set\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ val = readl(priv->reg_base + ALT_PR_CSR_OFST); ++ ++ if (val & ALT_PR_CSR_PR_START) { ++ dev_err(&mgr->dev, ++ "%s Partial Reconfiguration already started\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ writel(val | ALT_PR_CSR_PR_START, priv->reg_base + ALT_PR_CSR_OFST); ++ ++ return 0; ++} ++ ++static int alt_pr_fpga_write(struct fpga_manager *mgr, const char *buf, ++ size_t count) ++{ ++ struct alt_pr_priv *priv = mgr->priv; ++ u32 *buffer_32 = (u32 *)buf; ++ size_t i = 0; ++ ++ if (count <= 0) ++ return -EINVAL; ++ ++ /* Write out the complete 32-bit chunks */ ++ while (count >= sizeof(u32)) { ++ writel(buffer_32[i++], priv->reg_base); ++ count -= sizeof(u32); ++ } ++ ++ /* Write out remaining non 32-bit chunks */ ++ switch (count) { ++ case 3: ++ writel(buffer_32[i++] & 0x00ffffff, priv->reg_base); ++ break; ++ case 2: ++ writel(buffer_32[i++] & 0x0000ffff, priv->reg_base); ++ break; ++ case 1: ++ writel(buffer_32[i++] & 0x000000ff, priv->reg_base); ++ break; ++ case 0: ++ break; ++ default: ++ /* This will never happen */ ++ return -EFAULT; ++ } ++ ++ if (alt_pr_fpga_state(mgr) == FPGA_MGR_STATE_WRITE_ERR) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int alt_pr_fpga_write_complete(struct fpga_manager *mgr, ++ struct fpga_image_info *info) ++{ ++ u32 i = 0; ++ ++ do { ++ switch (alt_pr_fpga_state(mgr)) { ++ case FPGA_MGR_STATE_WRITE_ERR: ++ return -EIO; ++ ++ case FPGA_MGR_STATE_OPERATING: ++ dev_info(&mgr->dev, ++ "successful partial reconfiguration\n"); ++ return 0; ++ ++ default: ++ break; ++ } ++ udelay(1); ++ } while (info->config_complete_timeout_us > i++); ++ ++ dev_err(&mgr->dev, "timed out waiting for write to complete\n"); ++ return -ETIMEDOUT; ++} ++ ++static const struct fpga_manager_ops alt_pr_ops = { ++ .state = alt_pr_fpga_state, ++ .write_init = alt_pr_fpga_write_init, ++ .write = alt_pr_fpga_write, ++ .write_complete = alt_pr_fpga_write_complete, ++}; ++ ++int alt_pr_register(struct device *dev, void __iomem *reg_base) ++{ ++ struct alt_pr_priv *priv; ++ u32 val; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->reg_base = reg_base; ++ ++ val = readl(priv->reg_base + ALT_PR_CSR_OFST); ++ ++ dev_dbg(dev, "%s status=%d start=%d\n", __func__, ++ (val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT, ++ (int)(val & ALT_PR_CSR_PR_START)); ++ ++ return fpga_mgr_register(dev, dev_name(dev), &alt_pr_ops, priv); ++} ++EXPORT_SYMBOL_GPL(alt_pr_register); ++ ++int alt_pr_unregister(struct device *dev) ++{ ++ dev_dbg(dev, "%s\n", __func__); ++ ++ fpga_mgr_unregister(dev); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(alt_pr_unregister); ++ ++MODULE_AUTHOR("Matthew Gerlach <matthew.gerlach@linux.intel.com>"); ++MODULE_DESCRIPTION("Altera Partial Reconfiguration IP Core"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/include/linux/fpga/altera-pr-ip-core.h +@@ -0,0 +1,29 @@ ++/* ++ * Driver for Altera Partial Reconfiguration IP Core ++ * ++ * Copyright (C) 2016 Intel Corporation ++ * ++ * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation ++ * by Alan Tull <atull@opensource.altera.com> ++ * ++ * 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/>. ++ */ ++ ++#ifndef _ALT_PR_IP_CORE_H ++#define _ALT_PR_IP_CORE_H ++#include <linux/io.h> ++ ++int alt_pr_register(struct device *dev, void __iomem *reg_base); ++int alt_pr_unregister(struct device *dev); ++ ++#endif /* _ALT_PR_IP_CORE_H */ diff --git a/patches.socfpga/0093-fpga-dt-bindings-for-Altera-Partial-Reconfiguration-.patch b/patches.socfpga/0093-fpga-dt-bindings-for-Altera-Partial-Reconfiguration-.patch new file mode 100644 index 00000000000000..b394e1eb58125a --- /dev/null +++ b/patches.socfpga/0093-fpga-dt-bindings-for-Altera-Partial-Reconfiguration-.patch @@ -0,0 +1,32 @@ +From 4d9e84bcd82101758a0c21563d7740c1be578631 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach <matthew.gerlach@linux.intel.com> +Date: Thu, 23 Mar 2017 19:34:29 -0500 +Subject: [PATCH 093/103] fpga dt: bindings for Altera Partial Reconfiguration + IP. + +Device Tree bindings for Altera Partial Reconfiguration IP. + +Signed-off-by: Matthew Gerlach <matthew.gerlach@linux.intel.com> +Acked-by: Rob Herring <robh@kernel.org> +Acked-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + Documentation/devicetree/bindings/fpga/altera-pr-ip.txt | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + create mode 100644 Documentation/devicetree/bindings/fpga/altera-pr-ip.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/fpga/altera-pr-ip.txt +@@ -0,0 +1,12 @@ ++Altera Arria10 Partial Reconfiguration IP ++ ++Required properties: ++- compatible : should contain "altr,a10-pr-ip" ++- reg : base address and size for memory mapped io. ++ ++Example: ++ ++ fpga_mgr: fpga-mgr@ff20c000 { ++ compatible = "altr,a10-pr-ip"; ++ reg = <0xff20c000 0x10>; ++ }; diff --git a/patches.socfpga/0094-fpga-pr-ip-Platform-driver-for-Altera-Partial-Reconf.patch b/patches.socfpga/0094-fpga-pr-ip-Platform-driver-for-Altera-Partial-Reconf.patch new file mode 100644 index 00000000000000..0a1454748fe7de --- /dev/null +++ b/patches.socfpga/0094-fpga-pr-ip-Platform-driver-for-Altera-Partial-Reconf.patch @@ -0,0 +1,116 @@ +From 78ffcb1fd105ec0289d496df641c391d87e3c773 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach <matthew.gerlach@linux.intel.com> +Date: Thu, 23 Mar 2017 19:34:30 -0500 +Subject: [PATCH 094/103] fpga pr ip: Platform driver for Altera Partial + Reconfiguration IP. + +This adds a platform bus driver for a fpga-mgr driver +that uses the Altera Partial Reconfiguration IP component. + +Signed-off-by: Matthew Gerlach <matthew.gerlach@linux.intel.com> +Acked-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 7 +++ + drivers/fpga/Makefile | 1 + drivers/fpga/altera-pr-ip-core-plat.c | 68 ++++++++++++++++++++++++++++++++++ + 3 files changed, 76 insertions(+) + create mode 100644 drivers/fpga/altera-pr-ip-core-plat.c + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -88,6 +88,13 @@ config ALTERA_PR_IP_CORE + help + Core driver support for Altera Partial Reconfiguration IP component + ++config ALTERA_PR_IP_CORE_PLAT ++ tristate "Platform support of Altera Partial Reconfiguration IP Core" ++ depends on ALTERA_PR_IP_CORE && OF && HAS_IOMEM ++ help ++ Platform driver support for Altera Partial Reconfiguration IP ++ component ++ + endif # FPGA + + endmenu +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -13,6 +13,7 @@ obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx + obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o + obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o + obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o ++obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o + + # FPGA Bridge Drivers + obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o +--- /dev/null ++++ b/drivers/fpga/altera-pr-ip-core-plat.c +@@ -0,0 +1,68 @@ ++/* ++ * Driver for Altera Partial Reconfiguration IP Core ++ * ++ * Copyright (C) 2016-2017 Intel Corporation ++ * ++ * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation ++ * by Alan Tull <atull@opensource.altera.com> ++ * ++ * 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/altera-pr-ip-core.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++ ++static int alt_pr_platform_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ void __iomem *reg_base; ++ struct resource *res; ++ ++ /* First mmio base is for register access */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ reg_base = devm_ioremap_resource(dev, res); ++ ++ if (IS_ERR(reg_base)) ++ return PTR_ERR(reg_base); ++ ++ return alt_pr_register(dev, reg_base); ++} ++ ++static int alt_pr_platform_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ ++ return alt_pr_unregister(dev); ++} ++ ++static const struct of_device_id alt_pr_of_match[] = { ++ { .compatible = "altr,a10-pr-ip", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, alt_pr_of_match); ++ ++static struct platform_driver alt_pr_platform_driver = { ++ .probe = alt_pr_platform_probe, ++ .remove = alt_pr_platform_remove, ++ .driver = { ++ .name = "alt_a10_pr_ip", ++ .of_match_table = alt_pr_of_match, ++ }, ++}; ++ ++module_platform_driver(alt_pr_platform_driver); ++MODULE_AUTHOR("Matthew Gerlach <matthew.gerlach@linux.intel.com>"); ++MODULE_DESCRIPTION("Altera Partial Reconfiguration IP Platform Driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/patches.socfpga/0095-fpga-Add-support-for-Xilinx-LogiCORE-PR-Decoupler.patch b/patches.socfpga/0095-fpga-Add-support-for-Xilinx-LogiCORE-PR-Decoupler.patch new file mode 100644 index 00000000000000..496db77680c4af --- /dev/null +++ b/patches.socfpga/0095-fpga-Add-support-for-Xilinx-LogiCORE-PR-Decoupler.patch @@ -0,0 +1,219 @@ +From f978b7b1a45263dc1cfc46e6e0df91c608764910 Mon Sep 17 00:00:00 2001 +From: Moritz Fischer <mdf@kernel.org> +Date: Fri, 24 Mar 2017 10:33:21 -0500 +Subject: [PATCH 095/103] fpga: Add support for Xilinx LogiCORE PR Decoupler +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This adds support for the Xilinx LogiCORE PR Decoupler +soft-ip that does decoupling of PR regions in the FPGA +fabric during partial reconfiguration. + +Signed-off-by: Moritz Fischer <mdf@kernel.org> +Signed-off-by: Michal Simek <michal.simek@xilinx.com> +Cc: Sören Brinkmann <soren.brinkmann@xilinx.com> +Cc: linux-kernel@vger.kernel.org +Cc: devicetree@vger.kernel.org +Acked-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/Kconfig | 10 ++ + drivers/fpga/Makefile | 1 + drivers/fpga/xilinx-pr-decoupler.c | 161 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 172 insertions(+) + create mode 100644 drivers/fpga/xilinx-pr-decoupler.c + +--- a/drivers/fpga/Kconfig ++++ b/drivers/fpga/Kconfig +@@ -95,6 +95,16 @@ config ALTERA_PR_IP_CORE_PLAT + Platform driver support for Altera Partial Reconfiguration IP + component + ++config XILINX_PR_DECOUPLER ++ tristate "Xilinx LogiCORE PR Decoupler" ++ depends on FPGA_BRIDGE ++ depends on HAS_IOMEM ++ help ++ Say Y to enable drivers for Xilinx LogiCORE PR Decoupler. ++ The PR Decoupler exists in the FPGA fabric to isolate one ++ region of the FPGA from the busses while that region is ++ being reprogrammed during partial reconfig. ++ + endif # FPGA + + endmenu +--- a/drivers/fpga/Makefile ++++ b/drivers/fpga/Makefile +@@ -19,6 +19,7 @@ obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) + obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o + obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE) += altera-hps2fpga.o altera-fpga2sdram.o + obj-$(CONFIG_ALTERA_FREEZE_BRIDGE) += altera-freeze-bridge.o ++obj-$(CONFIG_XILINX_PR_DECOUPLER) += xilinx-pr-decoupler.o + + # High Level Interfaces + obj-$(CONFIG_FPGA_REGION) += fpga-region.o +--- /dev/null ++++ b/drivers/fpga/xilinx-pr-decoupler.c +@@ -0,0 +1,161 @@ ++/* ++ * Copyright (c) 2017, National Instruments Corp. ++ * Copyright (c) 2017, Xilix Inc ++ * ++ * FPGA Bridge Driver for the Xilinx LogiCORE Partial Reconfiguration ++ * Decoupler IP Core. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/of_device.h> ++#include <linux/module.h> ++#include <linux/fpga/fpga-bridge.h> ++ ++#define CTRL_CMD_DECOUPLE BIT(0) ++#define CTRL_CMD_COUPLE 0 ++#define CTRL_OFFSET 0 ++ ++struct xlnx_pr_decoupler_data { ++ void __iomem *io_base; ++ struct clk *clk; ++}; ++ ++static inline void xlnx_pr_decoupler_write(struct xlnx_pr_decoupler_data *d, ++ u32 offset, u32 val) ++{ ++ writel(val, d->io_base + offset); ++} ++ ++static inline u32 xlnx_pr_decouple_read(const struct xlnx_pr_decoupler_data *d, ++ u32 offset) ++{ ++ return readl(d->io_base + offset); ++} ++ ++static int xlnx_pr_decoupler_enable_set(struct fpga_bridge *bridge, bool enable) ++{ ++ int err; ++ struct xlnx_pr_decoupler_data *priv = bridge->priv; ++ ++ err = clk_enable(priv->clk); ++ if (err) ++ return err; ++ ++ if (enable) ++ xlnx_pr_decoupler_write(priv, CTRL_OFFSET, CTRL_CMD_COUPLE); ++ else ++ xlnx_pr_decoupler_write(priv, CTRL_OFFSET, CTRL_CMD_DECOUPLE); ++ ++ clk_disable(priv->clk); ++ ++ return 0; ++} ++ ++static int xlnx_pr_decoupler_enable_show(struct fpga_bridge *bridge) ++{ ++ const struct xlnx_pr_decoupler_data *priv = bridge->priv; ++ u32 status; ++ int err; ++ ++ err = clk_enable(priv->clk); ++ if (err) ++ return err; ++ ++ status = readl(priv->io_base); ++ ++ clk_disable(priv->clk); ++ ++ return !status; ++} ++ ++static struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { ++ .enable_set = xlnx_pr_decoupler_enable_set, ++ .enable_show = xlnx_pr_decoupler_enable_show, ++}; ++ ++static const struct of_device_id xlnx_pr_decoupler_of_match[] = { ++ { .compatible = "xlnx,pr-decoupler-1.00", }, ++ { .compatible = "xlnx,pr-decoupler", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match); ++ ++static int xlnx_pr_decoupler_probe(struct platform_device *pdev) ++{ ++ struct xlnx_pr_decoupler_data *priv; ++ int err; ++ struct resource *res; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->io_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(priv->io_base)) ++ return PTR_ERR(priv->io_base); ++ ++ priv->clk = devm_clk_get(&pdev->dev, "aclk"); ++ if (IS_ERR(priv->clk)) { ++ dev_err(&pdev->dev, "input clock not found\n"); ++ return PTR_ERR(priv->clk); ++ } ++ ++ err = clk_prepare_enable(priv->clk); ++ if (err) { ++ dev_err(&pdev->dev, "unable to enable clock\n"); ++ return err; ++ } ++ ++ clk_disable(priv->clk); ++ ++ err = fpga_bridge_register(&pdev->dev, "Xilinx PR Decoupler", ++ &xlnx_pr_decoupler_br_ops, priv); ++ ++ if (err) { ++ dev_err(&pdev->dev, "unable to register Xilinx PR Decoupler"); ++ clk_unprepare(priv->clk); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int xlnx_pr_decoupler_remove(struct platform_device *pdev) ++{ ++ struct fpga_bridge *bridge = platform_get_drvdata(pdev); ++ struct xlnx_pr_decoupler_data *p = bridge->priv; ++ ++ fpga_bridge_unregister(&pdev->dev); ++ ++ clk_unprepare(p->clk); ++ ++ return 0; ++} ++ ++static struct platform_driver xlnx_pr_decoupler_driver = { ++ .probe = xlnx_pr_decoupler_probe, ++ .remove = xlnx_pr_decoupler_remove, ++ .driver = { ++ .name = "xlnx_pr_decoupler", ++ .of_match_table = of_match_ptr(xlnx_pr_decoupler_of_match), ++ }, ++}; ++ ++module_platform_driver(xlnx_pr_decoupler_driver); ++ ++MODULE_DESCRIPTION("Xilinx Partial Reconfiguration Decoupler"); ++MODULE_AUTHOR("Moritz Fischer <mdf@kernel.org>"); ++MODULE_AUTHOR("Michal Simek <michal.simek@xilinx.com>"); ++MODULE_LICENSE("GPL v2"); diff --git a/patches.socfpga/0096-fpga-altera-hps2fpga-disable-unprepare-clock-on-erro.patch b/patches.socfpga/0096-fpga-altera-hps2fpga-disable-unprepare-clock-on-erro.patch new file mode 100644 index 00000000000000..d117a939a23417 --- /dev/null +++ b/patches.socfpga/0096-fpga-altera-hps2fpga-disable-unprepare-clock-on-erro.patch @@ -0,0 +1,51 @@ +From fa2e7c7a675e9523bd558009e966661e0ba50ddd Mon Sep 17 00:00:00 2001 +From: Tobias Klauser <tklauser@distanz.ch> +Date: Mon, 24 Apr 2017 16:34:20 -0500 +Subject: [PATCH 096/103] fpga altera-hps2fpga: disable/unprepare clock on + error in alt_fpga_bridge_probe() + +If either _alt_hps2fpga_enable_set() or fpga_bridge_register() fail in +alt_fpga_bridge_probe(), the clock remains enabled and prepared. Also, +in the error path for _alt_hps2fpga_enable_set() a call to +fpga_bridge_unregister() is made even though the bridge was not +registered yet. + +Remove the unnecessary call to fpga_bridge_unregister() and call +clk_disable_unprepare() in both error paths in order to make sure the +clock gets properly disabled and unprepared. + +Signed-off-by: Tobias Klauser <tklauser@distanz.ch> +Acked-by: Moritz Fischer <mdf@kernel.org> +Signed-off-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/altera-hps2fpga.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +--- a/drivers/fpga/altera-hps2fpga.c ++++ b/drivers/fpga/altera-hps2fpga.c +@@ -181,15 +181,18 @@ static int alt_fpga_bridge_probe(struct + (enable ? "enabling" : "disabling")); + + ret = _alt_hps2fpga_enable_set(priv, enable); +- if (ret) { +- fpga_bridge_unregister(&pdev->dev); +- return ret; +- } ++ if (ret) ++ goto err; + } + } + +- return fpga_bridge_register(dev, priv->name, &altera_hps2fpga_br_ops, +- priv); ++ ret = fpga_bridge_register(dev, priv->name, &altera_hps2fpga_br_ops, ++ priv); ++err: ++ if (ret) ++ clk_disable_unprepare(priv->clk); ++ ++ return ret; + } + + static int alt_fpga_bridge_remove(struct platform_device *pdev) diff --git a/patches.socfpga/0097-fpga-region-release-FPGA-region-reference-in-error-p.patch b/patches.socfpga/0097-fpga-region-release-FPGA-region-reference-in-error-p.patch new file mode 100644 index 00000000000000..44666661629fe3 --- /dev/null +++ b/patches.socfpga/0097-fpga-region-release-FPGA-region-reference-in-error-p.patch @@ -0,0 +1,40 @@ +From d5363219287e11386f82638a6bd4ad78a8ba7071 Mon Sep 17 00:00:00 2001 +From: Tobias Klauser <tklauser@distanz.ch> +Date: Mon, 24 Apr 2017 16:34:21 -0500 +Subject: [PATCH 097/103] fpga: region: release FPGA region reference in error + path + +If fpga_region_get_manager() fails in fpga_region_program_fpga(), a +reference to the fpga_manager instance previously acquired through +fpga_region_get() is retained. Make sure to properly release it in the +error case by using a separate jump label which will call +fpga_region_put() in before returning. + +Signed-off-by: Tobias Klauser <tklauser@distanz.ch> +Acked-by: Moritz Fischer <mdf@kernel.org> +Signed-off-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/fpga-region.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/fpga/fpga-region.c ++++ b/drivers/fpga/fpga-region.c +@@ -245,7 +245,8 @@ static int fpga_region_program_fpga(stru + mgr = fpga_region_get_manager(region); + if (IS_ERR(mgr)) { + pr_err("failed to get fpga region manager\n"); +- return PTR_ERR(mgr); ++ ret = PTR_ERR(mgr); ++ goto err_put_region; + } + + ret = fpga_region_get_bridges(region, overlay); +@@ -281,6 +282,7 @@ err_put_br: + fpga_bridges_put(®ion->bridge_list); + err_put_mgr: + fpga_mgr_put(mgr); ++err_put_region: + fpga_region_put(region); + + return ret; diff --git a/patches.socfpga/0098-fpga-fr-br-update-supported-version-numbers.patch b/patches.socfpga/0098-fpga-fr-br-update-supported-version-numbers.patch new file mode 100644 index 00000000000000..13a32098d13b87 --- /dev/null +++ b/patches.socfpga/0098-fpga-fr-br-update-supported-version-numbers.patch @@ -0,0 +1,82 @@ +From 1ac2b755e3a514fb74fbe7574042364c97a8e572 Mon Sep 17 00:00:00 2001 +From: Matthew Gerlach <matthew.gerlach@linux.intel.com> +Date: Mon, 24 Apr 2017 16:34:22 -0500 +Subject: [PATCH 098/103] fpga fr br: update supported version numbers + +The value in the version register of the altera freeze bridge +controller changed from the beta value of 2 to the +value of 0xad000003 in the official release of the IP. +This patch supports the old and new version numbers, and the +driver's probe function will fail if neither of the supported +versions is found. + +Signed-off-by: Matthew Gerlach <matthew.gerlach@linux.intel.com> +Reviewed-by: Moritz Fischer <mdf@kernel.org> +Signed-off-by: Alan Tull <atull@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/fpga/altera-freeze-bridge.c | 30 +++++++++++++++++++----------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +--- a/drivers/fpga/altera-freeze-bridge.c ++++ b/drivers/fpga/altera-freeze-bridge.c +@@ -28,6 +28,7 @@ + #define FREEZE_CSR_REG_VERSION 12 + + #define FREEZE_CSR_SUPPORTED_VERSION 2 ++#define FREEZE_CSR_OFFICIAL_VERSION 0xad000003 + + #define FREEZE_CSR_STATUS_FREEZE_REQ_DONE BIT(0) + #define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE BIT(1) +@@ -218,6 +219,7 @@ static int altera_freeze_br_probe(struct + { + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; ++ void __iomem *base_addr; + struct altera_freeze_br_data *priv; + struct resource *res; + u32 status, revision; +@@ -225,26 +227,32 @@ static int altera_freeze_br_probe(struct + if (!np) + return -ENODEV; + ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base_addr = devm_ioremap_resource(dev, res); ++ if (IS_ERR(base_addr)) ++ return PTR_ERR(base_addr); ++ ++ revision = readl(base_addr + FREEZE_CSR_REG_VERSION); ++ if ((revision != FREEZE_CSR_SUPPORTED_VERSION) && ++ (revision != FREEZE_CSR_OFFICIAL_VERSION)) { ++ dev_err(dev, ++ "%s unexpected revision 0x%x != 0x%x != 0x%x\n", ++ __func__, revision, FREEZE_CSR_SUPPORTED_VERSION, ++ FREEZE_CSR_OFFICIAL_VERSION); ++ return -EINVAL; ++ } ++ + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- priv->base_addr = devm_ioremap_resource(dev, res); +- if (IS_ERR(priv->base_addr)) +- return PTR_ERR(priv->base_addr); +- +- status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); ++ status = readl(base_addr + FREEZE_CSR_STATUS_OFFSET); + if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) + priv->enable = 1; + +- revision = readl(priv->base_addr + FREEZE_CSR_REG_VERSION); +- if (revision != FREEZE_CSR_SUPPORTED_VERSION) +- dev_warn(dev, +- "%s Freeze Controller unexpected revision %d != %d\n", +- __func__, revision, FREEZE_CSR_SUPPORTED_VERSION); ++ priv->base_addr = base_addr; + + return fpga_bridge_register(dev, FREEZE_BRIDGE_NAME, + &altera_freeze_br_br_ops, priv); diff --git a/patches.socfpga/0099-ARM-dts-socfpga-Add-NAND-device-tree-for-Arria10.patch b/patches.socfpga/0099-ARM-dts-socfpga-Add-NAND-device-tree-for-Arria10.patch new file mode 100644 index 00000000000000..b0255ad6c9108b --- /dev/null +++ b/patches.socfpga/0099-ARM-dts-socfpga-Add-NAND-device-tree-for-Arria10.patch @@ -0,0 +1,84 @@ +From 969f7218e1e460db033b6c1c04300a47c0cab279 Mon Sep 17 00:00:00 2001 +From: Graham Moore <grmoore@opensource.altera.com> +Date: Tue, 7 Jul 2015 09:58:36 -0500 +Subject: [PATCH 099/103] ARM: dts: socfpga: Add NAND device tree for Arria10 + +Add socfpga_arria10_socdk_nand.dts board file for supporting NAND. + +Signed-off-by: Graham Moore <grmoore@opensource.altera.com> +Signed-off-by: Dinh Nguyen <dinguyen@kernel.org> +--- +v2: move nand dts node to socfpga_arria10.dtsi +--- + arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/socfpga_arria10.dtsi | 13 +++++++++ + arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts | 31 +++++++++++++++++++++++ + 3 files changed, 45 insertions(+) + create mode 100644 arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -693,6 +693,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \ + sh73a0-kzm9g.dtb + dtb-$(CONFIG_ARCH_SOCFPGA) += \ + socfpga_arria5_socdk.dtb \ ++ socfpga_arria10_socdk_nand.dtb \ + socfpga_arria10_socdk_qspi.dtb \ + socfpga_arria10_socdk_sdmmc.dtb \ + socfpga_cyclone5_mcvevk.dtb \ +--- a/arch/arm/boot/dts/socfpga_arria10.dtsi ++++ b/arch/arm/boot/dts/socfpga_arria10.dtsi +@@ -631,6 +631,19 @@ + status = "disabled"; + }; + ++ nand: nand@ffb90000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "denali,denali-nand-dt", "altr,socfpga-denali-nand"; ++ reg = <0xffb90000 0x72000>, ++ <0xffb80000 0x10000>; ++ reg-names = "nand_data", "denali_reg"; ++ interrupts = <0 99 4>; ++ dma-mask = <0xffffffff>; ++ clocks = <&nand_clk>; ++ status = "disabled"; ++ }; ++ + ocram: sram@ffe00000 { + compatible = "mmio-sram"; + reg = <0xffe00000 0x40000>; +--- /dev/null ++++ b/arch/arm/boot/dts/socfpga_arria10_socdk_nand.dts +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 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/>. ++ */ ++ ++/dts-v1/; ++#include "socfpga_arria10_socdk.dtsi" ++ ++&nand { ++ status = "okay"; ++ ++ partition@nand-boot { ++ label = "Boot and fpga data"; ++ reg = <0x0 0x1C00000>; ++ }; ++ partition@nand-rootfs { ++ label = "Root Filesystem - JFFS2"; ++ reg = <0x1C00000 0x6400000>; ++ }; ++}; diff --git a/patches.socfpga/0100-dt-bindings-reset-Add-reset-manager-offsets-for-Stra.patch b/patches.socfpga/0100-dt-bindings-reset-Add-reset-manager-offsets-for-Stra.patch new file mode 100644 index 00000000000000..899840650b03c2 --- /dev/null +++ b/patches.socfpga/0100-dt-bindings-reset-Add-reset-manager-offsets-for-Stra.patch @@ -0,0 +1,127 @@ +From 5cfbeefdedaa7850b4e4cd121df2352947af0556 Mon Sep 17 00:00:00 2001 +From: Richard Gong <richard.gong@intel.com> +Date: Thu, 1 Jun 2017 09:23:59 -0500 +Subject: [PATCH 100/103] dt-bindings: reset: Add reset manager offsets for + Stratix10 + +There are several changes in reset manager offsets from Arria10 to +Stratix10. This patch is based on one from Arria10 and adds offset +updates for Stratix10 + +Signed-off-by: Richard Gong <richard.gong@intel.com> +--- + include/dt-bindings/reset/altr,rst-mgr-s10.h | 108 +++++++++++++++++++++++++++ + 1 file changed, 108 insertions(+) + create mode 100644 include/dt-bindings/reset/altr,rst-mgr-s10.h + +--- /dev/null ++++ b/include/dt-bindings/reset/altr,rst-mgr-s10.h +@@ -0,0 +1,108 @@ ++/* ++ * Copyright (C) 2016 Intel Corporation. All rights reserved ++ * Copyright (C) 2016 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/>. ++ * ++ * derived from Steffen Trumtrar's "altr,rst-mgr-a10.h" ++ */ ++ ++#ifndef _DT_BINDINGS_RESET_ALTR_RST_MGR_S10_H ++#define _DT_BINDINGS_RESET_ALTR_RST_MGR_S10_H ++ ++/* MPUMODRST */ ++#define CPU0_RESET 0 ++#define CPU1_RESET 1 ++#define CPU2_RESET 2 ++#define CPU3_RESET 3 ++ ++/* PER0MODRST */ ++#define EMAC0_RESET 32 ++#define EMAC1_RESET 33 ++#define EMAC2_RESET 34 ++#define USB0_RESET 35 ++#define USB1_RESET 36 ++#define NAND_RESET 37 ++/* 38 is empty */ ++#define SDMMC_RESET 39 ++#define EMAC0_OCP_RESET 40 ++#define EMAC1_OCP_RESET 41 ++#define EMAC2_OCP_RESET 42 ++#define USB0_OCP_RESET 43 ++#define USB1_OCP_RESET 44 ++#define NAND_OCP_RESET 45 ++/* 46 is empty */ ++#define SDMMC_OCP_RESET 47 ++#define DMA_RESET 48 ++#define SPIM0_RESET 49 ++#define SPIM1_RESET 50 ++#define SPIS0_RESET 51 ++#define SPIS1_RESET 52 ++#define DMA_OCP_RESET 53 ++#define EMAC_PTP_RESET 54 ++/* 55 is empty*/ ++#define DMAIF0_RESET 56 ++#define DMAIF1_RESET 57 ++#define DMAIF2_RESET 58 ++#define DMAIF3_RESET 59 ++#define DMAIF4_RESET 60 ++#define DMAIF5_RESET 61 ++#define DMAIF6_RESET 62 ++#define DMAIF7_RESET 63 ++ ++/* PER1MODRST */ ++#define WATCHDOG0_RESET 64 ++#define WATCHDOG1_RESET 65 ++#define WATCHDOG2_RESET 66 ++#define WATCHDOG3_RESET 67 ++#define L4SYSTIMER0_RESET 68 ++#define L4SYSTIMER1_RESET 69 ++#define SPTIMER0_RESET 70 ++#define SPTIMER1_RESET 71 ++#define I2C0_RESET 72 ++#define I2C1_RESET 73 ++#define I2C2_RESET 74 ++#define I2C3_RESET 75 ++#define I2C4_RESET 76 ++/* 77-79 is empty */ ++#define UART0_RESET 80 ++#define UART1_RESET 81 ++/* 82-87 is empty */ ++#define GPIO0_RESET 88 ++#define GPIO1_RESET 89 ++ ++/* BRGMODRST */ ++#define SOC2FPGA_RESET 96 ++#define LWHPS2FPGA_RESET 97 ++#define FPGA2SOC_RESET 98 ++#define F2SSDRAM0_RESET 99 ++#define F2SSDRAM1_RESET 100 ++#define F2SSDRAM2_RESET 101 ++#define DDRSCH_RESET 102 ++ ++/* COLDMODRST */ ++#define CPUPO0_RESET 160 ++#define CPUPO1_RESET 161 ++#define CPUPO2_RESET 162 ++#define CPUPO3_RESET 163 ++/* 164-167 is empty */ ++#define L2_RESET 168 ++ ++/* DBGMODRST */ ++#define DBG_RESET 224 ++#define CSDAP_RESET 225 ++ ++/* TAPMODRST */ ++#define TAP_RESET 256 ++ ++#endif diff --git a/patches.socfpga/0101-nios2-add-screen_info.patch b/patches.socfpga/0101-nios2-add-screen_info.patch new file mode 100644 index 00000000000000..6e33cf1129ccb3 --- /dev/null +++ b/patches.socfpga/0101-nios2-add-screen_info.patch @@ -0,0 +1,35 @@ +From b3e0ba2525523283d68e8a8f7a464faf8662a632 Mon Sep 17 00:00:00 2001 +From: Ley Foon Tan <ley.foon.tan@intel.com> +Date: Wed, 7 Dec 2016 15:44:19 +0800 +Subject: [PATCH 101/103] nios2: add screen_info + +Fix build error when enable VGA console. + +drivers/video/console/vgacon.c:586: undefined reference to `screen_info' + +Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com> +--- + arch/nios2/kernel/setup.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/nios2/kernel/setup.c ++++ b/arch/nios2/kernel/setup.c +@@ -18,6 +18,7 @@ + #include <linux/bootmem.h> + #include <linux/initrd.h> + #include <linux/of_fdt.h> ++#include <linux/screen_info.h> + + #include <asm/mmu_context.h> + #include <asm/sections.h> +@@ -36,6 +37,10 @@ static struct pt_regs fake_regs = { 0, 0 + 0, 0, 0, 0, 0, 0, + 0}; + ++#ifdef CONFIG_VT ++struct screen_info screen_info; ++#endif ++ + /* Copy a short hook instruction sequence to the exception address */ + static inline void copy_exception_handler(unsigned int addr) + { diff --git a/patches.socfpga/0102-nios2-switch-to-RAW_COPY_USER.patch b/patches.socfpga/0102-nios2-switch-to-RAW_COPY_USER.patch new file mode 100644 index 00000000000000..09391d9a83682a --- /dev/null +++ b/patches.socfpga/0102-nios2-switch-to-RAW_COPY_USER.patch @@ -0,0 +1,108 @@ +From 0b5d6273491a3b5dc69b794b0e6c678884f68157 Mon Sep 17 00:00:00 2001 +From: Al Viro <viro@zeniv.linux.org.uk> +Date: Wed, 22 Mar 2017 13:08:32 -0400 +Subject: [PATCH 102/103] nios2: switch to RAW_COPY_USER + +Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> +--- + arch/nios2/Kconfig | 1 + + arch/nios2/include/asm/uaccess.h | 31 ++++++------------------------- + arch/nios2/mm/uaccess.c | 16 ++++++++-------- + 3 files changed, 15 insertions(+), 33 deletions(-) + +--- a/arch/nios2/Kconfig ++++ b/arch/nios2/Kconfig +@@ -16,6 +16,7 @@ config NIOS2 + select SPARSE_IRQ + select USB_ARCH_HAS_HCD if USB_SUPPORT + select CPU_NO_EFFICIENT_FFS ++ select ARCH_HAS_RAW_COPY_USER + + config GENERIC_CSUM + def_bool y +--- a/arch/nios2/include/asm/uaccess.h ++++ b/arch/nios2/include/asm/uaccess.h +@@ -95,36 +95,17 @@ static inline unsigned long __must_check + return __clear_user(to, n); + } + +-extern long __copy_from_user(void *to, const void __user *from, +- unsigned long n); +-extern long __copy_to_user(void __user *to, const void *from, unsigned long n); +- +-static inline long copy_from_user(void *to, const void __user *from, +- unsigned long n) +-{ +- unsigned long res = n; +- if (access_ok(VERIFY_READ, from, n)) +- res = __copy_from_user(to, from, n); +- if (unlikely(res)) +- memset(to + (n - res), 0, res); +- return res; +-} +- +-static inline long copy_to_user(void __user *to, const void *from, +- unsigned long n) +-{ +- if (!access_ok(VERIFY_WRITE, to, n)) +- return n; +- return __copy_to_user(to, from, n); +-} ++extern unsigned long ++raw_copy_from_user(void *to, const void __user *from, unsigned long n); ++extern unsigned long ++raw_copy_to_user(void __user *to, const void *from, unsigned long n); ++#define INLINE_COPY_FROM_USER ++#define INLINE_COPY_TO_USER + + extern long strncpy_from_user(char *__to, const char __user *__from, + long __len); + extern long strnlen_user(const char __user *s, long n); + +-#define __copy_from_user_inatomic __copy_from_user +-#define __copy_to_user_inatomic __copy_to_user +- + /* Optimized macros */ + #define __get_user_asm(val, insn, addr, err) \ + { \ +--- a/arch/nios2/mm/uaccess.c ++++ b/arch/nios2/mm/uaccess.c +@@ -10,9 +10,9 @@ + #include <linux/export.h> + #include <linux/uaccess.h> + +-asm(".global __copy_from_user\n" +- " .type __copy_from_user, @function\n" +- "__copy_from_user:\n" ++asm(".global raw_copy_from_user\n" ++ " .type raw_copy_from_user, @function\n" ++ "raw_copy_from_user:\n" + " movi r2,7\n" + " mov r3,r4\n" + " bge r2,r6,1f\n" +@@ -65,12 +65,12 @@ asm(".global __copy_from_user\n" + ".word 7b,13b\n" + ".previous\n" + ); +-EXPORT_SYMBOL(__copy_from_user); ++EXPORT_SYMBOL(raw_copy_from_user); + + asm( +- " .global __copy_to_user\n" +- " .type __copy_to_user, @function\n" +- "__copy_to_user:\n" ++ " .global raw_copy_to_user\n" ++ " .type raw_copy_to_user, @function\n" ++ "raw_copy_to_user:\n" + " movi r2,7\n" + " mov r3,r4\n" + " bge r2,r6,1f\n" +@@ -127,7 +127,7 @@ asm( + ".word 11b,13b\n" + ".word 12b,13b\n" + ".previous\n"); +-EXPORT_SYMBOL(__copy_to_user); ++EXPORT_SYMBOL(raw_copy_to_user); + + long strncpy_from_user(char *__to, const char __user *__from, long __len) + { diff --git a/patches.socfpga/0103-nios2-use-generic-strncpy_from_user-and-strnlen_user.patch b/patches.socfpga/0103-nios2-use-generic-strncpy_from_user-and-strnlen_user.patch new file mode 100644 index 00000000000000..8701cfaacfbd3b --- /dev/null +++ b/patches.socfpga/0103-nios2-use-generic-strncpy_from_user-and-strnlen_user.patch @@ -0,0 +1,88 @@ +From 1e114cbc9496ee8376e0ad899890a1eff7e58230 Mon Sep 17 00:00:00 2001 +From: Ley Foon Tan <ley.foon.tan@intel.com> +Date: Mon, 8 May 2017 17:14:14 +0800 +Subject: [PATCH 103/103] nios2: use generic strncpy_from_user() and + strnlen_user() + +This change enables the generic strncpy_from_user() and strnlen_user() + +Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com> +--- + arch/nios2/Kconfig | 2 ++ + arch/nios2/include/asm/uaccess.h | 7 +++++-- + arch/nios2/mm/uaccess.c | 33 --------------------------------- + 3 files changed, 7 insertions(+), 35 deletions(-) + +--- a/arch/nios2/Kconfig ++++ b/arch/nios2/Kconfig +@@ -6,6 +6,8 @@ config NIOS2 + select GENERIC_CPU_DEVICES + select GENERIC_IRQ_PROBE + select GENERIC_IRQ_SHOW ++ select GENERIC_STRNCPY_FROM_USER ++ select GENERIC_STRNLEN_USER + select HAVE_ARCH_TRACEHOOK + select HAVE_ARCH_KGDB + select IRQ_DOMAIN +--- a/arch/nios2/include/asm/uaccess.h ++++ b/arch/nios2/include/asm/uaccess.h +@@ -64,6 +64,8 @@ extern int fixup_exception(struct pt_reg + + # define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" + ++#define user_addr_max() (uaccess_kernel() ? ~0UL : TASK_SIZE) ++ + /* + * Zero Userspace + */ +@@ -103,8 +105,9 @@ raw_copy_to_user(void __user *to, const + #define INLINE_COPY_TO_USER + + extern long strncpy_from_user(char *__to, const char __user *__from, +- long __len); +-extern long strnlen_user(const char __user *s, long n); ++ long __len); ++extern __must_check long strlen_user(const char __user *str); ++extern __must_check long strnlen_user(const char __user *s, long n); + + /* Optimized macros */ + #define __get_user_asm(val, insn, addr, err) \ +--- a/arch/nios2/mm/uaccess.c ++++ b/arch/nios2/mm/uaccess.c +@@ -128,36 +128,3 @@ asm( + ".word 12b,13b\n" + ".previous\n"); + EXPORT_SYMBOL(raw_copy_to_user); +- +-long strncpy_from_user(char *__to, const char __user *__from, long __len) +-{ +- int l = strnlen_user(__from, __len); +- int is_zt = 1; +- +- if (l > __len) { +- is_zt = 0; +- l = __len; +- } +- +- if (l == 0 || copy_from_user(__to, __from, l)) +- return -EFAULT; +- +- if (is_zt) +- l--; +- return l; +-} +- +-long strnlen_user(const char __user *s, long n) +-{ +- long i; +- +- for (i = 0; i < n; i++) { +- char c; +- +- if (get_user(c, s + i) == -EFAULT) +- return 0; +- if (c == 0) +- return i + 1; +- } +- return n + 1; +-} @@ -857,6 +857,112 @@ patches.renesas/0285-ARM-dts-r8a7790-Drop-_clk-suffix-from-external-CAN-c.patch patches.renesas/0286-ARM-dts-r8a7791-Drop-_clk-suffix-from-external-CAN-c.patch ############################################################################# +# SoCFPGA patches +patches.socfpga/0001-ARM-dts-socfpga-enable-arm-shared-override-in-the-pl.patch +patches.socfpga/0002-ARM-socfpga_defconfig-Enable-HIGHMEM.patch +patches.socfpga/0003-ARM-dts-socfpga-enable-qspi-on-the-Cyclone5-devkit.patch +patches.socfpga/0004-ARM-dts-socfpga-Add-QSPI-node-for-the-Arria10.patch +patches.socfpga/0005-ARM-dts-socfpga-Enable-QSPI-in-Arria10-devkit.patch +patches.socfpga/0006-ARM-dts-socfpga-Enable-QSPI-on-the-Cyclone5-sockit.patch +patches.socfpga/0007-ARM-dts-socfpga-Enable-QSPI-on-the-Arria5-devkit.patch +patches.socfpga/0008-ARM-socfpga_defconfig-enable-FS-configs-to-support-A.patch +patches.socfpga/0009-dt-bindings-Add-Macnica-Americas-vendor-prefix.patch +patches.socfpga/0010-dt-bindings-Add-vendor-prefix-for-Terasic-Inc.patch +patches.socfpga/0011-dt-bindings-Add-vendor-prefix-for-Samtec.patch +patches.socfpga/0012-ARM-dts-socfpga-enable-GPIO-and-LEDs-for-Cyclone5-an.patch +patches.socfpga/0013-ARM-dts-socfpga-set-desired-i2c-clock-on-Cyclone5-an.patch +patches.socfpga/0014-ARM-dts-socfpga-Add-Rohm-DH2228FV-DAC.patch +patches.socfpga/0015-ARM-dts-socfpga-enable-CAN-on-Cyclone5-devkit.patch +patches.socfpga/0016-ARM-dts-socfpga-enable-watchdog-timer-on-Arria5-and-.patch +patches.socfpga/0017-ARM-dts-socfpga-add-the-LTC2977-power-monitor-on-Arr.patch +patches.socfpga/0018-ARM-dts-socfpga-add-fpga-manager-node-for-Arria10.patch +patches.socfpga/0019-ARM-dts-socfpga-fpga-manager-data-is-32-bits.patch +patches.socfpga/0020-ARM-dts-socfpga-add-fpga-region-support-on-Arria10.patch +patches.socfpga/0021-ARM-dts-socfpga-add-missing-compatible-string-for-SD.patch +patches.socfpga/0022-ARM-dts-watchdog0-cannot-reliably-trigger-reset.patch +patches.socfpga/0023-MAINTAINERS-socfpga-update-email-for-Dinh-Nguyen.patch +patches.socfpga/0024-of-overlay-add-of-overlay-notifications.patch +patches.socfpga/0025-fpga-add-method-to-get-fpga-manager-from-device.patch +patches.socfpga/0026-doc-fpga-mgr-add-fpga-image-info-to-api.patch +patches.socfpga/0027-fpga-add-bindings-document-for-fpga-region.patch +patches.socfpga/0028-fpga-mgr-add-fpga-image-information-struct.patch +patches.socfpga/0029-add-sysfs-document-for-fpga-bridge-class.patch +patches.socfpga/0030-fpga-add-fpga-bridge-framework.patch +patches.socfpga/0031-fpga-fpga-region-device-tree-control-for-FPGA.patch +patches.socfpga/0032-ARM-socfpga-fpga-bridge-driver-support.patch +patches.socfpga/0033-fpga-add-altera-freeze-bridge-support.patch +patches.socfpga/0034-fpga-manager-Add-Socfpga-Arria10-support.patch +patches.socfpga/0035-ARM-socfpga-checking-the-wrong-variable.patch +patches.socfpga/0036-fpga-Add-COMPILE_TEST-to-all-drivers.patch +patches.socfpga/0037-fpga-zynq-Add-missing-n-to-messages.patch +patches.socfpga/0038-fpga-zynq-Remove-priv-dev.patch +patches.socfpga/0039-fpga-zynq-Fix-incorrect-ISR-state-on-bootup.patch +patches.socfpga/0040-fpga-Clarify-how-write_init-works-streaming-modes.patch +patches.socfpga/0041-fpga-zynq-Check-for-errors-after-completing-DMA.patch +patches.socfpga/0042-fpga-zynq-Check-the-bitstream-for-validity.patch +patches.socfpga/0043-fpga-Add-scatterlist-based-programming.patch +patches.socfpga/0044-fpga-zynq-Use-the-scatterlist-interface.patch +patches.socfpga/0045-fpga-fix-sparse-warnings-in-fpga-mgr-and-fpga-bridge.patch +patches.socfpga/0046-fpga-Add-flag-to-indicate-bitstream-needs-decrypting.patch +patches.socfpga/0047-fpga-zynq-Add-support-for-encrypted-bitstreams.patch +patches.socfpga/0048-fpga-region-Add-fpga-region-property-encrypted-fpga-.patch +patches.socfpga/0049-FPGA-Add-TS-7300-FPGA-manager.patch +patches.socfpga/0050-Documentation-Add-binding-document-for-Lattice-iCE40.patch +patches.socfpga/0051-fpga-Add-support-for-Lattice-iCE40-FPGAs.patch +patches.socfpga/0052-fpga-bridge-Replace-open-coded-list_for_each-list_en.patch +patches.socfpga/0053-fpga-altera_freeze_bridge-Constify-ops.patch +patches.socfpga/0054-dt-bindings-fpga-add-xilinx-slave-serial-binding-des.patch +patches.socfpga/0055-fpga-manager-Add-Xilinx-slave-serial-SPI-driver.patch +patches.socfpga/0056-ARM-socfpga-add-bindings-document-for-fpga-bridge-dr.patch +patches.socfpga/0057-ARM-socfpga-add-bindings-doc-for-arria10-fpga-manage.patch +patches.socfpga/0058-add-bindings-document-for-altera-freeze-bridge.patch +patches.socfpga/0059-MAINTAINERS-add-git-url-for-fpga.patch +patches.socfpga/0060-ARM-dts-socfpga-add-base-fpga-region-and-fpga-bridge.patch +patches.socfpga/0061-fpga-add-config-complete-timeout.patch +patches.socfpga/0062-MAINTAINERS-Add-file-patterns-for-fpga-device-tree-b.patch +patches.socfpga/0063-MAINTAINERS-fpga-update-email-and-directory-paths.patch +patches.socfpga/0064-spi-Add-Flag-to-Enable-Slave-Select-with-GPIO-Chip-S.patch +patches.socfpga/0065-spi-dw-Set-GPIO_SS-flag-to-toggle-Slave-Select-on-GP.patch +patches.socfpga/0066-ARM-dts-socfpga-Add-SPI-Master1-for-Arria10-SR-chip.patch +patches.socfpga/0067-ARM-dts-socfpga-Add-Devkit-A10-SR-fields-for-Arria10.patch +patches.socfpga/0068-ARM-dts-socfpga-Enable-GPIO-parent-for-Arria10-SR-ch.patch +patches.socfpga/0069-ARM-dts-socfpga-Add-LED-framework-to-A10-SR-GPIO.patch +patches.socfpga/0070-EDAC-altera-Disable-IRQs-while-injecting-SDRAM-error.patch +patches.socfpga/0071-gpio-altera-a10sr-Add-A10-System-Resource-Chip-GPIO-.patch +patches.socfpga/0072-dt-bindings-mfd-Add-Altera-Arria10-System-Resource-C.patch +patches.socfpga/0073-ARM-dts-Add-EMAC-AXI-settings-for-Arria10.patch +patches.socfpga/0074-MAINTAINERS-EDAC-Update-email-for-Thor-Thayer.patch +patches.socfpga/0075-gpio-altera-a10sr-Set-gpio_chip-parent-property.patch +patches.socfpga/0076-dt-bindings-reset-a10sr-Add-Arria10-SR-Reset-Control.patch +patches.socfpga/0077-reset-Add-Altera-Arria10-SR-Reset-Controller.patch +patches.socfpga/0078-ARM-dts-socfpga-Add-Devkit-A10-SR-Reset-Controller.patch +patches.socfpga/0079-EDAC-altera-Fix-peripheral-warnings-for-Cyclone5.patch +patches.socfpga/0080-mfd-altr_a10sr-Add-Arria10-DevKit-Reset-Controller.patch +patches.socfpga/0081-dt-bindings-mfd-Add-Altera-Arria10-SR-Reset-Controll.patch +patches.socfpga/0082-ARM-socfpga-defconfig-enable-qspi.patch +patches.socfpga/0083-ARM-socfpga-updates-for-socfpga_defconfig.patch +patches.socfpga/0084-ARM-socfpga_defconfig-update-defconfig-for-SoCFPGA.patch +patches.socfpga/0085-ARM-socfpga-updates-for-socfpga_defconfig.patch +patches.socfpga/0086-ARM-dts-socfpga-Add-new-MCVEVK-manufacturer-compat.patch +patches.socfpga/0087-ARM-dts-socfpga-Add-Macnica-sodia-board.patch +patches.socfpga/0088-ARM-dts-socfpga-add-specific-compatible-strings-for-.patch +patches.socfpga/0089-ARM-dts-socfpga-Add-unit-name-to-memory-nodes.patch +patches.socfpga/0090-ARM-dts-socfpga-sodia-enable-qspi.patch +patches.socfpga/0091-ARM-dts-socfpga-add-qspi-node.patch +patches.socfpga/0092-fpga-pr-ip-Core-driver-support-for-Altera-Partial-Re.patch +patches.socfpga/0093-fpga-dt-bindings-for-Altera-Partial-Reconfiguration-.patch +patches.socfpga/0094-fpga-pr-ip-Platform-driver-for-Altera-Partial-Reconf.patch +patches.socfpga/0095-fpga-Add-support-for-Xilinx-LogiCORE-PR-Decoupler.patch +patches.socfpga/0096-fpga-altera-hps2fpga-disable-unprepare-clock-on-erro.patch +patches.socfpga/0097-fpga-region-release-FPGA-region-reference-in-error-p.patch +patches.socfpga/0098-fpga-fr-br-update-supported-version-numbers.patch +patches.socfpga/0099-ARM-dts-socfpga-Add-NAND-device-tree-for-Arria10.patch +patches.socfpga/0100-dt-bindings-reset-Add-reset-manager-offsets-for-Stra.patch +patches.socfpga/0101-nios2-add-screen_info.patch +patches.socfpga/0102-nios2-switch-to-RAW_COPY_USER.patch +patches.socfpga/0103-nios2-use-generic-strncpy_from_user-and-strnlen_user.patch + +############################################################################# # Misc patches ############################################################################## |