diff --git a/cores/axis_rp_adc_v1_0/core_config.tcl b/cores/axis_rp_adc_v1_0/core_config.tcl
index c61fb615ceb8d23657ddcf52b43bf52e5fa3b70b..7b59ee3efed5d773344bb5fe2866051db7f7de42 100644
--- a/cores/axis_rp_adc_v1_0/core_config.tcl
+++ b/cores/axis_rp_adc_v1_0/core_config.tcl
@@ -1,4 +1,4 @@
-set display_name {AXI4-Stream Red Pitaya ADC}
+set display_name {AXI4-Stream Red Pitaya ADC v1.0}
set core [ipx::current_core]
diff --git a/cores/axis_rp_adc_v3_0/core_config.tcl b/cores/axis_rp_adc_v3_0/core_config.tcl
index c61fb615ceb8d23657ddcf52b43bf52e5fa3b70b..e01ad25776f5d08985e89ed780d049c99981bb10 100644
--- a/cores/axis_rp_adc_v3_0/core_config.tcl
+++ b/cores/axis_rp_adc_v3_0/core_config.tcl
@@ -1,4 +1,4 @@
-set display_name {AXI4-Stream Red Pitaya ADC}
+set display_name {AXI4-Stream Red Pitaya ADC v3.0}
set core [ipx::current_core]
diff --git a/patches/cma.c b/patches/cma.c
new file mode 100644
index 0000000000000000000000000000000000000000..621210743df0156c7261ffba1f64744bc7a0f0e4
--- /dev/null
+++ b/patches/cma.c
@@ -0,0 +1,96 @@
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-map-ops.h>
+
+#define CMA_ALLOC _IOWR('Z', 0, u32)
+
+static struct device *dma_device = NULL;
+static size_t dma_size = 0;
+static void *cpu_addr = NULL;
+static dma_addr_t dma_addr;
+
+static void cma_free(void)
+{
+ if(!cpu_addr) return;
+ dma_free_coherent(dma_device, dma_size, cpu_addr, dma_addr);
+ cpu_addr = NULL;
+}
+
+static long cma_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long rc;
+ u32 buffer;
+
+ if(cmd != CMA_ALLOC) return -ENOTTY;
+
+ rc = copy_from_user(&buffer, (void __user *)arg, sizeof(buffer));
+ if(rc) return rc;
+
+ cma_free();
+
+ dma_size = buffer;
+ cpu_addr = dma_alloc_coherent(dma_device, dma_size, &dma_addr, GFP_KERNEL);
+
+ if(IS_ERR_OR_NULL(cpu_addr))
+ {
+ rc = PTR_ERR(cpu_addr);
+ if(rc == 0) rc = -ENOMEM;
+ cpu_addr = NULL;
+ return rc;
+ }
+
+ buffer = dma_addr;
+ return copy_to_user((void __user *)arg, &buffer, sizeof(buffer));
+}
+
+static int cma_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return dma_mmap_coherent(dma_device, vma, cpu_addr, dma_addr, dma_size);
+}
+
+static int cma_release(struct inode *inode, struct file *file)
+{
+ cma_free();
+ return 0;
+}
+
+static struct file_operations cma_fops =
+{
+ .unlocked_ioctl = cma_ioctl,
+ .mmap = cma_mmap,
+ .release = cma_release
+};
+
+struct miscdevice cma_device =
+{
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "cma",
+ .fops = &cma_fops
+};
+
+static int __init cma_init(void)
+{
+ int rc;
+
+ rc = misc_register(&cma_device);
+ if(rc) return rc;
+
+ dma_device = cma_device.this_device;
+
+ dma_device->dma_ops = &arm_coherent_dma_ops;
+ dma_device->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ return 0;
+}
+
+static void __exit cma_exit(void)
+{
+ cma_free();
+ misc_deregister(&cma_device);
+}
+
+module_init(cma_init);
+module_exit(cma_exit);
+MODULE_LICENSE("MIT");
diff --git a/patches/devicetree.patch b/patches/devicetree.patch
new file mode 100644
index 0000000000000000000000000000000000000000..fc16466a0c4bfdde90d537e80901fbe747e8173e
--- /dev/null
+++ b/patches/devicetree.patch
@@ -0,0 +1,147 @@
+diff -rupN pl.dtsi.old pl.dtsi
+--- pl.dtsi.old
++++ pl.dtsi
+@@ -15,7 +15,7 @@
+ #interrupt-cells = <2>;
+ clock-names = "s_axi_aclk";
+ clocks = <&misc_clk_0>;
+- compatible = "xlnx,axi-intc-4.1", "xlnx,xps-intc-1.00.a";
++ compatible = "generic-uio";
+ interrupt-controller ;
+ interrupt-names = "irq";
+ interrupt-parent = <&intc>;
+@@ -32,19 +32,19 @@
+ cfg_0: axi_cfg_register@40001000 {
+ clock-names = "aclk";
+ clocks = <&misc_clk_0>;
+- compatible = "xlnx,axi-cfg-register-1.0";
++ compatible = "generic-uio";
+ reg = <0x40001000 0x1000>;
+ };
+ sts_0: axi_sts_register@40002000 {
+ clock-names = "aclk";
+ clocks = <&misc_clk_0>;
+- compatible = "xlnx,axi-sts-register-1.0";
++ compatible = "generic-uio";
+ reg = <0x40002000 0x1000>;
+ };
+ xadc_wiz_0: xadc_wiz@40003000 {
+ clock-names = "s_axi_aclk";
+ clocks = <&misc_clk_0>;
+- compatible = "xlnx,xadc-wiz-3.3", "xlnx,axi-xadc-1.00.a";
++ compatible = "generic-uio";
+ reg = <0x40003000 0x1000>;
+ xlnx,alarm-limit-r0 = <0xb5ed>;
+ xlnx,alarm-limit-r1 = <0x57e4>;
+@@ -126,5 +126,17 @@
+ xlnx,vaux8 = <0x1>;
+ xlnx,vaux9 = <0x1>;
+ };
+- };
++ hst0_reader_0: axi_bram_reader@40010000 {
++ clock-names = "aclk";
++ clocks = <&misc_clk_0>;
++ compatible = "generic-uio";
++ reg = <0x40010000 0x10000>;
++ };
++ hst1_reader_1: axi_bram_reader@40020000 {
++ clock-names = "aclk";
++ clocks = <&misc_clk_0>;
++ compatible = "generic-uio";
++ reg = <0x40020000 0x10000>;
++ };
++ };
+ };
+diff -rupN pcw.dtsi.old pcw.dtsi
+--- pcw.dtsi.old
++++ pcw.dtsi
+@@ -26,6 +26,19 @@
+ clock-frequency = <400000>;
+ status = "okay";
+ };
++&i2c0 {
++ eep@50 {
++ compatible = "24c64";
++ size = <8192>;
++ pagesize = <32>;
++ reg = <0x50>;
++ };
++ bmp180@77{
++ compatible = "bosch,bmp280";
++ reg = <0x77>;
++ status = "okay";
++ };
++};
+ &intc {
+ num_cpus = <2>;
+ num_interrupts = <96>;
+@@ -45,6 +51,11 @@
+ is-decoded-cs = <0>;
+ num-cs = <1>;
+ status = "okay";
++ spidev@0 {
++ compatible = "spidev";
++ reg = <0x0>;
++ spi-max-frequency = <10000000>;
++ };
+ };
+ &uart0 {
+ device_type = "serial";
+@@ -57,11 +68,33 @@
+ status = "okay";
+ };
+ &usb0 {
++ dr_mode = "host";
+- phy_type = "ulpi";
++ usb-phy = <&usb_phy0>;
+ status = "okay";
+- usb-reset = <&gpio0 48 0>;
++ xlnx,phy-reset-gpio = <&gpio0 48 0>;
+ };
+ &clkc {
+ fclk-enable = <0x0>;
+ ps-clk-frequency = <33333333>;
+ };
++&adc {
++ xlnx,channels {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ channel@0 {
++ reg = <0>;
++ };
++ channel@1 {
++ reg = <1>;
++ };
++ channel@2 {
++ reg = <2>;
++ };
++ channel@9 {
++ reg = <9>;
++ };
++ channel@10 {
++ reg = <10>;
++ };
++ };
++};
+diff -rupN system-top.dts.old system-top.dts
+--- system-top.dts.old
++++ system-top.dts
+@@ -14,6 +14,18 @@
+ bootargs = "console=ttyPS0,115200 earlyprintk earlycon";
+ stdout-path = "serial0:115200n8";
+ };
++ usb_phy0: phy0 {
++ #phy-cells = <0>;
++ compatible = "ulpi-phy";
++ reg = <0xe0002000 0x1000>;
++ view-port = <0x0170>;
++ drv-vbus;
++ };
++ pps {
++ compatible = "pps-gpio";
++ gpios = <&gpio0 54 0>;
++ capture-clear;
++ };
+ aliases {
+ ethernet0 = &gem0;
+ i2c0 = &i2c0;
diff --git a/patches/linux-5.10.patch b/patches/linux-5.10.patch
new file mode 100644
index 0000000000000000000000000000000000000000..f37550adb0d9daa8bbb5ba74dd6b79a316365496
--- /dev/null
+++ b/patches/linux-5.10.patch
@@ -0,0 +1,494 @@
+diff -rupN old/linux-5.10/arch/arm/mach-zynq/common.c linux-5.10/arch/arm/mach-zynq/common.c
+--- old/linux-5.10/arch/arm/mach-zynq/common.c
++++ linux-5.10/arch/arm/mach-zynq/common.c
+@@ -95,6 +95,7 @@ static void __init zynq_init_late(void)
+ {
+ zynq_core_pm_init();
+ zynq_pm_late_init();
++ zynq_prefetch_init();
+ }
+
+ /**
+@@ -186,8 +187,13 @@ static const char * const zynq_dt_match[
+
+ DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
+ /* 64KB way size, 8-way associativity, parity disabled */
+- .l2c_aux_val = 0x00400000,
++#ifdef CONFIG_XILINX_PREFETCH
++ .l2c_aux_val = 0x30400000,
++ .l2c_aux_mask = 0xcfbfffff,
++#else
++ .l2c_aux_val = 0x00400000,
+ .l2c_aux_mask = 0xffbfffff,
++#endif
+ .smp = smp_ops(zynq_smp_ops),
+ .map_io = zynq_map_io,
+ .init_irq = zynq_irq_init,
+diff -rupN old/linux-5.10/arch/arm/mach-zynq/common.h linux-5.10/arch/arm/mach-zynq/common.h
+--- old/linux-5.10/arch/arm/mach-zynq/common.h
++++ linux-5.10/arch/arm/mach-zynq/common.h
+@@ -15,6 +15,7 @@ extern void zynq_slcr_cpu_stop(int cpu);
+ extern void zynq_slcr_cpu_start(int cpu);
+ extern bool zynq_slcr_cpu_state_read(int cpu);
+ extern void zynq_slcr_cpu_state_write(int cpu, bool die);
++extern u32 zynq_slcr_get_ocm_config(void);
+ extern u32 zynq_slcr_get_device_id(void);
+
+ #ifdef CONFIG_SMP
+@@ -29,6 +30,22 @@ extern void __iomem *zynq_scu_base;
+
+ void zynq_pm_late_init(void);
+
++static inline void zynq_prefetch_init(void)
++{
++ /*
++ * Enable prefetching in aux control register. L2 prefetch must
++ * only be enabled if the slave supports it (PL310 does)
++ */
++ asm volatile ("mrc p15, 0, r1, c1, c0, 1\n"
++#ifdef CONFIG_XILINX_PREFETCH
++ "orr r1, r1, #6\n"
++#else
++ "bic r1, r1, #6\n"
++#endif
++ "mcr p15, 0, r1, c1, c0, 1\n"
++ : : : "r1");
++}
++
+ static inline void zynq_core_pm_init(void)
+ {
+ /* A9 clock gating */
+diff -rupN old/linux-5.10/arch/arm/mach-zynq/Kconfig linux-5.10/arch/arm/mach-zynq/Kconfig
+--- old/linux-5.10/arch/arm/mach-zynq/Kconfig
++++ linux-5.10/arch/arm/mach-zynq/Kconfig
+@@ -16,3 +16,19 @@ config ARCH_ZYNQ
+ select SOC_BUS
+ help
+ Support for Xilinx Zynq ARM Cortex A9 Platform
++
++if ARCH_ZYNQ
++
++menu "Xilinx Specific Options"
++
++config XILINX_PREFETCH
++ bool "Cache Prefetch"
++ default y
++ help
++ This option turns on L1 & L2 cache prefetching to get the best performance
++ in many cases. This may not always be the best performance depending on
++ the usage.
++
++endmenu
++
++endif
+diff -rupN old/linux-5.10/arch/arm/mach-zynq/Makefile linux-5.10/arch/arm/mach-zynq/Makefile
+--- old/linux-5.10/arch/arm/mach-zynq/Makefile
++++ linux-5.10/arch/arm/mach-zynq/Makefile
+@@ -4,5 +4,5 @@
+ #
+
+ # Common support
+-obj-y := common.o slcr.o pm.o
++obj-y := common.o slcr.o zynq_ocm.o pm.o
+ obj-$(CONFIG_SMP) += headsmp.o platsmp.o
+diff -rupN old/linux-5.10/arch/arm/mach-zynq/platsmp.c linux-5.10/arch/arm/mach-zynq/platsmp.c
+--- old/linux-5.10/arch/arm/mach-zynq/platsmp.c
++++ linux-5.10/arch/arm/mach-zynq/platsmp.c
+@@ -115,6 +115,7 @@ static void __init zynq_smp_prepare_cpus
+ static void zynq_secondary_init(unsigned int cpu)
+ {
+ zynq_core_pm_init();
++ zynq_prefetch_init();
+ }
+
+ #ifdef CONFIG_HOTPLUG_CPU
+diff -rupN old/linux-5.10/arch/arm/mach-zynq/slcr.c linux-5.10/arch/arm/mach-zynq/slcr.c
+--- old/linux-5.10/arch/arm/mach-zynq/slcr.c
++++ linux-5.10/arch/arm/mach-zynq/slcr.c
+@@ -20,6 +20,7 @@
+ #define SLCR_REBOOT_STATUS_OFFSET 0x258 /* PS Reboot Status */
+ #define SLCR_PSS_IDCODE 0x530 /* PS IDCODE */
+ #define SLCR_L2C_RAM 0xA1C /* L2C_RAM in AR#54190 */
++#define SLCR_OCM_CFG_OFFSET 0x910 /* OCM Address Mapping */
+
+ #define SLCR_UNLOCK_MAGIC 0xDF0D
+ #define SLCR_A9_CPU_CLKSTOP 0x10
+@@ -116,6 +117,19 @@ static struct notifier_block zynq_slcr_r
+ };
+
+ /**
++ * zynq_slcr_get_ocm_config - Get SLCR OCM config
++ *
++ * return: OCM config bits
++ */
++u32 zynq_slcr_get_ocm_config(void)
++{
++ u32 ret;
++
++ zynq_slcr_read(&ret, SLCR_OCM_CFG_OFFSET);
++ return ret;
++}
++
++/**
+ * zynq_slcr_cpu_start - Start cpu
+ * @cpu: cpu number
+ */
+diff -rupN old/linux-5.10/drivers/char/Kconfig linux-5.10/drivers/char/Kconfig
+--- old/linux-5.10/drivers/char/Kconfig
++++ linux-5.10/drivers/char/Kconfig
+@@ -471,6 +471,14 @@ config ADI
+ and SSM (Silicon Secured Memory). Intended consumers of this
+ driver include crash and makedumpfile.
+
++config DEVCMA
++ bool "/dev/cma virtual device support"
++ default y
++
++config XILINX_DEVCFG
++ tristate "Xilinx Device Configuration"
++ depends on ARCH_ZYNQ
++
+ endmenu
+
+ config RANDOM_TRUST_CPU
+diff -rupN old/linux-5.10/drivers/char/Makefile linux-5.10/drivers/char/Makefile
+--- old/linux-5.10/drivers/char/Makefile
++++ linux-5.10/drivers/char/Makefile
+@@ -47,3 +47,5 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o
+ obj-$(CONFIG_XILLYBUS) += xillybus/
+ obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
+ obj-$(CONFIG_ADI) += adi.o
++obj-$(CONFIG_DEVCMA) += cma.o
++obj-$(CONFIG_XILINX_DEVCFG) += xilinx_devcfg.o
+diff -rupN old/linux-5.10/drivers/net/phy/intel-xway.c linux-5.10/drivers/net/phy/intel-xway.c
+--- old/linux-5.10/drivers/net/phy/intel-xway.c
++++ linux-5.10/drivers/net/phy/intel-xway.c
+@@ -180,6 +180,12 @@ static int xway_gphy_config_init(struct
+ if (err)
+ return err;
+
++ /* Set SGMII RX & TX timing skew to 2 ns & 2.5 ns respectively. */
++ /* Set MII power supply to 2V5. */
++ err = phy_write(phydev, 0x17, 0x4D00);
++ if (err)
++ return err;
++
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDCH,
+ XWAY_MMD_LEDCH_NACS_NONE |
+ XWAY_MMD_LEDCH_SBF_F02HZ |
+@@ -189,20 +195,16 @@ static int xway_gphy_config_init(struct
+ XWAY_MMD_LEDCH_SCAN_NONE);
+
+ /**
+- * In most cases only one LED is connected to this phy, so
+- * configure them all to constant on and pulse mode. LED3 is
+- * only available in some packages, leave it in its reset
+- * configuration.
++ * Set LED0 blinking on RX/TX.
++ * Set LED1 blinking on link speed: slow=10M, fast=100M, on=1G.
+ */
+- ledxh = XWAY_MMD_LEDxH_BLINKF_NONE | XWAY_MMD_LEDxH_CON_LINK10XX;
+- ledxl = XWAY_MMD_LEDxL_PULSE_TXACT | XWAY_MMD_LEDxL_PULSE_RXACT |
+- XWAY_MMD_LEDxL_BLINKS_NONE;
+- phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0H, ledxh);
++ ledxl = XWAY_MMD_LEDxL_PULSE_TXACT | XWAY_MMD_LEDxL_PULSE_RXACT;
++ phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0H, 0);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED0L, ledxl);
++ ledxh = XWAY_MMD_LEDxH_CON_LINK1000 | XWAY_MMD_LEDxH_BLINKF_LINK100;
++ ledxl = XWAY_MMD_LEDxH_CON_LINK10;
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1H, ledxh);
+ phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED1L, ledxl);
+- phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh);
+- phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl);
+
+ return 0;
+ }
+diff -rupN old/linux-5.10/drivers/net/wireless/realtek/Kconfig linux-5.10/drivers/net/wireless/realtek/Kconfig
+--- old/linux-5.10/drivers/net/wireless/realtek/Kconfig
++++ linux-5.10/drivers/net/wireless/realtek/Kconfig
+@@ -13,8 +13,9 @@ config WLAN_VENDOR_REALTEK
+ if WLAN_VENDOR_REALTEK
+
+ source "drivers/net/wireless/realtek/rtl818x/Kconfig"
+-source "drivers/net/wireless/realtek/rtlwifi/Kconfig"
+ source "drivers/net/wireless/realtek/rtl8xxxu/Kconfig"
+ source "drivers/net/wireless/realtek/rtw88/Kconfig"
++source "drivers/net/wireless/realtek/rtl8188eu/Kconfig"
++source "drivers/net/wireless/realtek/rtl8192cu/Kconfig"
+
+ endif # WLAN_VENDOR_REALTEK
+diff -rupN old/linux-5.10/drivers/net/wireless/realtek/Makefile linux-5.10/drivers/net/wireless/realtek/Makefile
+--- old/linux-5.10/drivers/net/wireless/realtek/Makefile
++++ linux-5.10/drivers/net/wireless/realtek/Makefile
+@@ -5,7 +5,8 @@
+
+ obj-$(CONFIG_RTL8180) += rtl818x/
+ obj-$(CONFIG_RTL8187) += rtl818x/
+-obj-$(CONFIG_RTLWIFI) += rtlwifi/
+ obj-$(CONFIG_RTL8XXXU) += rtl8xxxu/
+ obj-$(CONFIG_RTW88) += rtw88/
++obj-$(CONFIG_RTL8188EU) += rtl8188eu/
++obj-$(CONFIG_RTL8192CU) += rtl8192cu/
+
+diff -rupN old/linux-5.10/drivers/net/wireless/realtek/rtl8188eu/Kconfig linux-5.10/drivers/net/wireless/realtek/rtl8188eu/Kconfig
+--- old/linux-5.10/drivers/net/wireless/realtek/rtl8188eu/Kconfig
++++ linux-5.10/drivers/net/wireless/realtek/rtl8188eu/Kconfig
+@@ -1,6 +1,6 @@
+ config RTL8188EU
+ tristate "Realtek 8188E USB WiFi"
+ depends on USB
+- ---help---
++ help
+ Help message of RTL8188EU
+
+diff -rupN old/linux-5.10/drivers/net/wireless/realtek/rtl8192cu/Kconfig linux-5.10/drivers/net/wireless/realtek/rtl8192cu/Kconfig
+--- old/linux-5.10/drivers/net/wireless/realtek/rtl8192cu/Kconfig 1970-01-01 00:00:00.000000000 +0000
++++ linux-5.10/drivers/net/wireless/realtek/rtl8192cu/Kconfig
+@@ -0,0 +1,9 @@
++config RTL8192CU
++ tristate "Realtek 8192CU USB WiFi"
++ depends on MAC80211 && USB
++ select CFG80211_WEXT
++ select WIRELESS_EXT
++ select WEXT_PRIV
++ help
++ This option adds the Realtek RTL8192CU USB device.
++
+diff -rupN old/linux-5.10/drivers/pps/clients/pps-gpio.c linux-5.10/drivers/pps/clients/pps-gpio.c
+--- old/linux-5.10/drivers/pps/clients/pps-gpio.c
++++ linux-5.10/drivers/pps/clients/pps-gpio.c
+@@ -145,6 +145,8 @@ static int pps_gpio_setup(struct platfor
+
+ if (of_property_read_bool(np, "assert-falling-edge"))
+ data->assert_falling_edge = true;
++ if (of_get_property(np, "capture-clear", NULL))
++ data->capture_clear = true;
+ return 0;
+ }
+
+diff -rupN old/linux-5.10/drivers/usb/chipidea/ci_hdrc_usb2.c linux-5.10/drivers/usb/chipidea/ci_hdrc_usb2.c
+--- old/linux-5.10/drivers/usb/chipidea/ci_hdrc_usb2.c
++++ linux-5.10/drivers/usb/chipidea/ci_hdrc_usb2.c
+@@ -30,6 +30,7 @@ static const struct ci_hdrc_platform_dat
+
+ static const struct ci_hdrc_platform_data ci_zynq_pdata = {
+ .capoffset = DEF_CAPOFFSET,
++ .flags = CI_HDRC_PHY_VBUS_CONTROL,
+ };
+
+ static const struct ci_hdrc_platform_data ci_zevio_pdata = {
+@@ -64,6 +65,9 @@ static int ci_hdrc_usb2_probe(struct pla
+ if (match && match->data) {
+ /* struct copy */
+ *ci_pdata = *(struct ci_hdrc_platform_data *)match->data;
++ ci_pdata->usb_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
++ if (IS_ERR(ci_pdata->usb_phy))
++ return PTR_ERR(ci_pdata->usb_phy);
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+diff -rupN old/linux-5.10/drivers/usb/chipidea/host.c linux-5.10/drivers/usb/chipidea/host.c
+--- old/linux-5.10/drivers/usb/chipidea/host.c
++++ linux-5.10/drivers/usb/chipidea/host.c
+@@ -57,6 +57,14 @@ static int ehci_ci_portpower(struct usb_
+ priv->enabled = enable;
+ }
+
++ if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL &&
++ ci->usb_phy && ci->usb_phy->set_vbus) {
++ if (enable)
++ ci->usb_phy->set_vbus(ci->usb_phy, 1);
++ else
++ ci->usb_phy->set_vbus(ci->usb_phy, 0);
++ }
++
+ if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) {
+ /*
+ * Marvell 28nm HSIC PHY requires forcing the port to HS mode.
+diff -rupN old/linux-5.10/drivers/usb/chipidea/otg_fsm.c linux-5.10/drivers/usb/chipidea/otg_fsm.c
+--- old/linux-5.10/drivers/usb/chipidea/otg_fsm.c
++++ linux-5.10/drivers/usb/chipidea/otg_fsm.c
+@@ -471,6 +471,11 @@ static void ci_otg_drv_vbus(struct otg_f
+ return;
+ }
+ }
++
++ if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL &&
++ ci->usb_phy && ci->usb_phy->set_vbus)
++ ci->usb_phy->set_vbus(ci->usb_phy, 1);
++
+ /* Disable data pulse irq */
+ hw_write_otgsc(ci, OTGSC_DPIE, 0);
+
+@@ -480,6 +485,10 @@ static void ci_otg_drv_vbus(struct otg_f
+ if (ci->platdata->reg_vbus)
+ regulator_disable(ci->platdata->reg_vbus);
+
++ if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL &&
++ ci->usb_phy && ci->usb_phy->set_vbus)
++ ci->usb_phy->set_vbus(ci->usb_phy, 0);
++
+ fsm->a_bus_drop = 1;
+ fsm->a_bus_req = 0;
+ }
+diff -rupN old/linux-5.10/drivers/usb/phy/phy-ulpi.c linux-5.10/drivers/usb/phy/phy-ulpi.c
+--- old/linux-5.10/drivers/usb/phy/phy-ulpi.c
++++ linux-5.10/drivers/usb/phy/phy-ulpi.c
+@@ -13,9 +13,16 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/export.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/io.h>
++#include <linux/of_address.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
+ #include <linux/usb.h>
+ #include <linux/usb/otg.h>
+ #include <linux/usb/ulpi.h>
++#include <linux/usb/phy.h>
+
+
+ struct ulpi_info {
+@@ -39,6 +46,13 @@ static struct ulpi_info ulpi_ids[] = {
+ ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"),
+ };
+
++struct ulpi_phy {
++ struct usb_phy *usb_phy;
++ void __iomem *regs;
++ unsigned int vp_offset;
++ unsigned int flags;
++};
++
+ static int ulpi_set_otg_flags(struct usb_phy *phy)
+ {
+ unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
+@@ -240,6 +254,23 @@ static int ulpi_set_vbus(struct usb_otg
+ return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
+ }
+
++static int usbphy_set_vbus(struct usb_phy *phy, int on)
++{
++ unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
++
++ flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
++
++ if (on) {
++ if (phy->flags & ULPI_OTG_DRVVBUS)
++ flags |= ULPI_OTG_CTRL_DRVVBUS;
++
++ if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
++ flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
++ }
++
++ return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
++}
++
+ static void otg_ulpi_init(struct usb_phy *phy, struct usb_otg *otg,
+ struct usb_phy_io_ops *ops,
+ unsigned int flags)
+@@ -249,6 +280,7 @@ static void otg_ulpi_init(struct usb_phy
+ phy->io_ops = ops;
+ phy->otg = otg;
+ phy->init = ulpi_init;
++ phy->set_vbus = usbphy_set_vbus;
+
+ otg->usb_phy = phy;
+ otg->set_host = ulpi_set_host;
+@@ -301,3 +333,83 @@ devm_otg_ulpi_create(struct device *dev,
+ return phy;
+ }
+ EXPORT_SYMBOL_GPL(devm_otg_ulpi_create);
++
++static int ulpi_phy_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct resource *res;
++ struct ulpi_phy *uphy;
++ bool flag;
++ int ret;
++
++ uphy = devm_kzalloc(&pdev->dev, sizeof(*uphy), GFP_KERNEL);
++ if (!uphy)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
++ return -ENODEV;
++ }
++
++ uphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
++ if (!uphy->regs) {
++ dev_err(&pdev->dev, "failed to map phy I/O memory\n");
++ return -EFAULT;
++ }
++
++ if (IS_ERR(uphy->regs))
++ return PTR_ERR(uphy->regs);
++
++ if (of_property_read_u32(np, "view-port", &uphy->vp_offset))
++ dev_dbg(&pdev->dev, "Missing view-port property\n");
++
++ if (IS_ERR(uphy->regs)) {
++ dev_err(&pdev->dev, "view-port register not specified\n");
++ return PTR_ERR(uphy->regs);
++ }
++
++ flag = of_property_read_bool(np, "drv-vbus");
++ if (flag)
++ uphy->flags |= ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT;
++
++ uphy->usb_phy = otg_ulpi_create(&ulpi_viewport_access_ops, uphy->flags);
++
++ uphy->usb_phy->dev = &pdev->dev;
++
++ uphy->usb_phy->io_priv = uphy->regs + uphy->vp_offset;
++
++ ret = usb_add_phy_dev(uphy->usb_phy);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static int ulpi_phy_remove(struct platform_device *pdev)
++{
++ struct ulpi_phy *uphy = platform_get_drvdata(pdev);
++
++ usb_remove_phy(uphy->usb_phy);
++
++ return 0;
++}
++
++static const struct of_device_id ulpi_phy_table[] = {
++ { .compatible = "ulpi-phy" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, ulpi_phy_table);
++
++static struct platform_driver ulpi_phy_driver = {
++ .probe = ulpi_phy_probe,
++ .remove = ulpi_phy_remove,
++ .driver = {
++ .name = "ulpi-phy",
++ .of_match_table = ulpi_phy_table,
++ },
++};
++module_platform_driver(ulpi_phy_driver);
++
++MODULE_DESCRIPTION("ULPI PHY driver");
++MODULE_LICENSE("GPL v2");
+diff -rupN old/linux-5.10/include/linux/usb/chipidea.h linux-5.10/include/linux/usb/chipidea.h
+--- old/linux-5.10/include/linux/usb/chipidea.h
++++ linux-5.10/include/linux/usb/chipidea.h
+@@ -62,6 +62,7 @@ struct ci_hdrc_platform_data {
+ #define CI_HDRC_REQUIRES_ALIGNED_DMA BIT(13)
+ #define CI_HDRC_IMX_IS_HSIC BIT(14)
+ #define CI_HDRC_PMQOS BIT(15)
++#define CI_HDRC_PHY_VBUS_CONTROL BIT(16)
+ enum usb_dr_mode dr_mode;
+ #define CI_HDRC_CONTROLLER_RESET_EVENT 0
+ #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1
diff --git a/patches/u-boot-2021.04.patch b/patches/u-boot-2021.04.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c9223599e86eb6b4f48407080ca17a51b89424d3
--- /dev/null
+++ b/patches/u-boot-2021.04.patch
@@ -0,0 +1,43 @@
+diff -rupN old/u-boot-2021.04/arch/arm/dts/Makefile u-boot-2021.04/arch/arm/dts/Makefile
+--- old/u-boot-2021.04/arch/arm/dts/Makefile
++++ u-boot-2021.04/arch/arm/dts/Makefile
+@@ -286,7 +286,8 @@ dtb-$(CONFIG_ARCH_ZYNQ) += \
+ zynq-zturn.dtb \
+ zynq-zturn-v5.dtb \
+ zynq-zybo.dtb \
+- zynq-zybo-z7.dtb
++ zynq-zybo-z7.dtb \
++ zynq-red-pitaya.dtb
+ dtb-$(CONFIG_ARCH_ZYNQMP) += \
+ avnet-ultra96-rev1.dtb \
+ avnet-ultrazedev-cc-v1.0-ultrazedev-som-v1.0.dtb \
+diff -rupN old/u-boot-2021.04/board/xilinx/zynq/board.c u-boot-2021.04/board/xilinx/zynq/board.c
+--- old/u-boot-2021.04/board/xilinx/zynq/board.c
++++ u-boot-2021.04/board/xilinx/zynq/board.c
+@@ -37,12 +37,12 @@ int board_late_init(void)
+ const char *mode;
+ char *new_targets;
+ char *env_targets;
+-
++/*
+ if (!(gd->flags & GD_FLG_ENV_DEFAULT)) {
+ debug("Saved variables - Skipping\n");
+ return 0;
+ }
+-
++*/
+ if (!CONFIG_IS_ENABLED(ENV_VARS_UBOOT_RUNTIME_CONFIG))
+ return 0;
+
+diff -rupN old/u-boot-2021.04/common/main.c u-boot-2021.04/common/main.c
+--- old/u-boot-2021.04/common/main.c
++++ u-boot-2021.04/common/main.c
+@@ -61,6 +61,8 @@ void main_loop(void)
+ if (cli_process_fdt(&s))
+ cli_secure_boot_cmd(s);
+
++ env_set("sdboot", "echo Importing environment from SD... && mmcinfo && load mmc 0 0x2000000 uEnv.txt && env import -t 0x2000000 ${filesize} && boot");
++
+ autoboot_command(s);
+
+ cli_loop();
diff --git a/patches/xilinx_devcfg.c b/patches/xilinx_devcfg.c
new file mode 100644
index 0000000000000000000000000000000000000000..ea36195621022c59a3f49ba02d4ea3e672489d56
--- /dev/null
+++ b/patches/xilinx_devcfg.c
@@ -0,0 +1,2160 @@
+/*
+ * Xilinx Zynq Device Config driver
+ *
+ * Copyright (c) 2011 - 2013 Xilinx Inc.
+ *
+ * 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.
+ */
+
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sysctl.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define DRIVER_NAME "xdevcfg"
+#define XDEVCFG_DEVICES 1
+
+/* An array, which is set to true when the device is registered. */
+static DEFINE_MUTEX(xdevcfg_mutex);
+
+/* Constant Definitions */
+#define XDCFG_CTRL_OFFSET 0x00 /* Control Register */
+#define XDCFG_LOCK_OFFSET 0x04 /* Lock Register */
+#define XDCFG_INT_STS_OFFSET 0x0C /* Interrupt Status Register */
+#define XDCFG_INT_MASK_OFFSET 0x10 /* Interrupt Mask Register */
+#define XDCFG_STATUS_OFFSET 0x14 /* Status Register */
+#define XDCFG_DMA_SRC_ADDR_OFFSET 0x18 /* DMA Source Address Register */
+#define XDCFG_DMA_DEST_ADDR_OFFSET 0x1C /* DMA Destination Address Reg */
+#define XDCFG_DMA_SRC_LEN_OFFSET 0x20 /* DMA Source Transfer Length */
+#define XDCFG_DMA_DEST_LEN_OFFSET 0x24 /* DMA Destination Transfer */
+#define XDCFG_UNLOCK_OFFSET 0x34 /* Unlock Register */
+#define XDCFG_MCTRL_OFFSET 0x80 /* Misc. Control Register */
+
+/* Control Register Bit definitions */
+#define XDCFG_CTRL_PCFG_PROG_B_MASK 0x40000000 /* Program signal to
+ * Reset FPGA
+ */
+#define XDCFG_CTRL_PCAP_PR_MASK 0x08000000 /* Enable PCAP for PR */
+#define XDCFG_CTRL_PCAP_MODE_MASK 0x04000000 /* Enable PCAP */
+#define XDCFG_CTRL_PCAP_RATE_EN_MASK 0x02000000 /* Enable PCAP Quad Rate */
+#define XDCFG_CTRL_PCFG_AES_EN_MASK 0x00000E00 /* AES Enable Mask */
+#define XDCFG_CTRL_SEU_EN_MASK 0x00000100 /* SEU Enable Mask */
+#define XDCFG_CTRL_SPNIDEN_MASK 0x00000040 /* Secure Non Invasive
+ * Debug Enable
+ */
+#define XDCFG_CTRL_SPIDEN_MASK 0x00000020 /* Secure Invasive
+ * Debug Enable
+ */
+#define XDCFG_CTRL_NIDEN_MASK 0x00000010 /* Non-Invasive Debug
+ * Enable
+ */
+#define XDCFG_CTRL_DBGEN_MASK 0x00000008 /* Invasive Debug
+ * Enable
+ */
+#define XDCFG_CTRL_DAP_EN_MASK 0x00000007 /* DAP Enable Mask */
+
+/* Lock register bit definitions */
+
+#define XDCFG_LOCK_AES_EN_MASK 0x00000008 /* Lock AES_EN update */
+#define XDCFG_LOCK_SEU_MASK 0x00000004 /* Lock SEU_En update */
+#define XDCFG_LOCK_DBG_MASK 0x00000001 /* This bit locks
+ * security config
+ * including: DAP_En,
+ * DBGEN,NIDEN, SPNIEN
+ */
+
+/* Miscellaneous Control Register bit definitions */
+#define XDCFG_MCTRL_PCAP_LPBK_MASK 0x00000010 /* Internal PCAP loopback */
+
+/* Status register bit definitions */
+#define XDCFG_STATUS_PCFG_INIT_MASK 0x00000010 /* FPGA init status */
+
+/* Interrupt Status/Mask Register Bit definitions */
+#define XDCFG_IXR_DMA_DONE_MASK 0x00002000 /* DMA Command Done */
+#define XDCFG_IXR_D_P_DONE_MASK 0x00001000 /* DMA and PCAP Cmd Done */
+#define XDCFG_IXR_PCFG_DONE_MASK 0x00000004 /* FPGA programmed */
+#define XDCFG_IXR_ERROR_FLAGS_MASK 0x00F0F860
+#define XDCFG_IXR_ALL_MASK 0xF8F7F87F
+/* Miscellaneous constant values */
+#define XDCFG_DMA_INVALID_ADDRESS 0xFFFFFFFF /* Invalid DMA address */
+
+static const char * const fclk_name[] = {
+ "fclk0",
+ "fclk1",
+ "fclk2",
+ "fclk3"
+};
+#define NUMFCLKS ARRAY_SIZE(fclk_name)
+
+/**
+ * struct xdevcfg_drvdata - Device Configuration driver structure
+ *
+ * @dev: Pointer to the device structure
+ * @cdev: Instance of the cdev structure
+ * @devt: Pointer to the dev_t structure
+ * @class: Pointer to device class
+ * @fclk_class: Pointer to fclk device class
+ * @dma_done: The dma_done status bit for the DMA command completion
+ * @error_status: The error status captured during the DMA transfer
+ * @irq: Interrupt number
+ * @clk: Peripheral clock for devcfg
+ * @fclk: Array holding references to the FPGA clocks
+ * @fclk_exported: Flag inidcating whether an FPGA clock is exported
+ * @is_open: The status bit to indicate whether the device is opened
+ * @sem: Instance for the mutex
+ * @lock: Instance of spinlock
+ * @base_address: The virtual device base address of the device registers
+ * @ep107: Flags is used to identify the platform
+ * @endian_swap: Flags is used to identify the endianness format
+ * @residue_buf: Array holding stragglers from last time (0 to 3 bytes)
+ * @residue_len: stragglers length in bytes
+ * @is_partial_bitstream: Status bit to indicate partial/full bitstream
+ */
+struct xdevcfg_drvdata {
+ struct device *dev;
+ struct cdev cdev;
+ dev_t devt;
+ struct class *class;
+ struct class *fclk_class;
+ int irq;
+ struct clk *clk;
+ struct clk *fclk[NUMFCLKS];
+ u8 fclk_exported[NUMFCLKS];
+ bool dma_done;
+ int error_status;
+ bool is_open;
+ struct mutex sem;
+ spinlock_t lock;
+ void __iomem *base_address;
+ int ep107;
+ bool is_partial_bitstream;
+ bool endian_swap;
+ char residue_buf[3];
+ int residue_len;
+};
+
+/**
+ * struct fclk_data - FPGA clock data
+ * @clk: Pointer to clock
+ * @enabled: Flag indicating enable status of the clock
+ * @rate_rnd: Rate to be rounded for round rate operation
+ */
+struct fclk_data {
+ struct clk *clk;
+ int enabled;
+ unsigned long rate_rnd;
+};
+
+/* Register read/write access routines */
+#define xdevcfg_writereg(offset, val) __raw_writel(val, offset)
+#define xdevcfg_readreg(offset) __raw_readl(offset)
+
+#define SLCR_FPGA_RST_CTRL_OFFSET 0x240 /* FPGA Software Reset Control */
+#define SLCR_LVL_SHFTR_EN_OFFSET 0x900 /* Level Shifters Enable */
+
+static struct regmap *zynq_slcr_regmap;
+
+/**
+ * zynq_slcr_write - Write to a register in SLCR block
+ *
+ * @val: Value to write to the register
+ * @offset: Register offset in SLCR block
+ *
+ * Return: a negative value on error, 0 on success
+ */
+static int zynq_slcr_write(u32 val, u32 offset)
+{
+ return regmap_write(zynq_slcr_regmap, offset, val);
+}
+
+/**
+ * zynq_slcr_init_preload_fpga - Disable communication from the PL to PS.
+ */
+static void zynq_slcr_init_preload_fpga(void)
+{
+ /* Assert FPGA top level output resets */
+ zynq_slcr_write(0xF, SLCR_FPGA_RST_CTRL_OFFSET);
+
+ /* Disable level shifters */
+ zynq_slcr_write(0, SLCR_LVL_SHFTR_EN_OFFSET);
+
+ /* Enable output level shifters */
+ zynq_slcr_write(0xA, SLCR_LVL_SHFTR_EN_OFFSET);
+}
+
+/**
+ * zynq_slcr_init_postload_fpga - Re-enable communication from the PL to PS.
+ */
+static void zynq_slcr_init_postload_fpga(void)
+{
+ /* Enable level shifters */
+ zynq_slcr_write(0xf, SLCR_LVL_SHFTR_EN_OFFSET);
+
+ /* Deassert AXI interface resets */
+ zynq_slcr_write(0, SLCR_FPGA_RST_CTRL_OFFSET);
+}
+
+/**
+ * xdevcfg_reset_pl - Reset the programmable logic.
+ * @base_address: The base address of the device.
+ *
+ * Must be called with PCAP clock enabled
+ */
+static void xdevcfg_reset_pl(void __iomem *base_address)
+{
+ /*
+ * Create a rising edge on PCFG_INIT. PCFG_INIT follows PCFG_PROG_B,
+ * so we need to * poll it after setting PCFG_PROG_B to make sure that
+ * the rising edge happens.
+ */
+ xdevcfg_writereg(base_address + XDCFG_CTRL_OFFSET,
+ (xdevcfg_readreg(base_address + XDCFG_CTRL_OFFSET) &
+ ~XDCFG_CTRL_PCFG_PROG_B_MASK));
+ while (xdevcfg_readreg(base_address + XDCFG_STATUS_OFFSET) &
+ XDCFG_STATUS_PCFG_INIT_MASK)
+ ;
+
+ usleep_range(5000, 5100);
+ xdevcfg_writereg(base_address + XDCFG_CTRL_OFFSET,
+ (xdevcfg_readreg(base_address + XDCFG_CTRL_OFFSET) |
+ XDCFG_CTRL_PCFG_PROG_B_MASK));
+ while (!(xdevcfg_readreg(base_address + XDCFG_STATUS_OFFSET) &
+ XDCFG_STATUS_PCFG_INIT_MASK))
+ ;
+}
+
+/**
+ * xdevcfg_irq - The main interrupt handler.
+ * @irq: The interrupt number.
+ * @data: Pointer to the driver data structure.
+ * returns: IRQ_HANDLED after the interrupt is handled.
+ **/
+static irqreturn_t xdevcfg_irq(int irq, void *data)
+{
+ u32 intr_status;
+ struct xdevcfg_drvdata *drvdata = data;
+
+ spin_lock(&drvdata->lock);
+
+ intr_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_INT_STS_OFFSET);
+
+ /* Clear the interrupts */
+ xdevcfg_writereg(drvdata->base_address + XDCFG_INT_STS_OFFSET,
+ intr_status);
+
+ if ((intr_status & XDCFG_IXR_D_P_DONE_MASK) ==
+ XDCFG_IXR_D_P_DONE_MASK)
+ drvdata->dma_done = 1;
+
+ if ((intr_status & XDCFG_IXR_ERROR_FLAGS_MASK) ==
+ XDCFG_IXR_ERROR_FLAGS_MASK)
+ drvdata->error_status = 1;
+
+ spin_unlock(&drvdata->lock);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * xdevcfg_write - The is the driver write function.
+ *
+ * @file: Pointer to the file structure.
+ * @buf: Pointer to the bitstream location.
+ * @count: The number of bytes to be written.
+ * @ppos: Pointer to the offset value
+ * returns: Success or error status.
+ **/
+static ssize_t
+xdevcfg_write(struct file *file, const char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ char *kbuf;
+ int status;
+ unsigned long timeout;
+ u32 intr_reg, dma_len;
+ dma_addr_t dma_addr;
+ u32 transfer_length = 0;
+ struct xdevcfg_drvdata *drvdata = file->private_data;
+ size_t user_count = count;
+ int i;
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ status = mutex_lock_interruptible(&drvdata->sem);
+
+ if (status)
+ goto err_clk;
+
+ dma_len = count + drvdata->residue_len;
+ kbuf = dma_alloc_coherent(drvdata->dev, dma_len, &dma_addr, GFP_KERNEL);
+ if (!kbuf) {
+ status = -ENOMEM;
+ goto err_unlock;
+ }
+
+ /* Collect stragglers from last time (0 to 3 bytes) */
+ memcpy(kbuf, drvdata->residue_buf, drvdata->residue_len);
+
+ /* Fetch user data, appending to stragglers */
+ if (copy_from_user(kbuf + drvdata->residue_len, buf, count)) {
+ status = -EFAULT;
+ goto error;
+ }
+
+ /* Include stragglers in total bytes to be handled */
+ count += drvdata->residue_len;
+
+ /* First block contains a header */
+ if (*ppos == 0 && count > 4) {
+ /* Look for sync word */
+ for (i = 0; i < count - 4; i++) {
+ if (memcmp(kbuf + i, "\x66\x55\x99\xAA", 4) == 0) {
+ pr_debug("Found normal sync word\n");
+ drvdata->endian_swap = 0;
+ break;
+ }
+ if (memcmp(kbuf + i, "\xAA\x99\x55\x66", 4) == 0) {
+ pr_debug("Found swapped sync word\n");
+ drvdata->endian_swap = 1;
+ break;
+ }
+ }
+ /* Remove the header, aligning the data on word boundary */
+ if (i != count - 4) {
+ count -= i;
+ memmove(kbuf, kbuf + i, count);
+ }
+ }
+
+ /* Save stragglers for next time */
+ drvdata->residue_len = count % 4;
+ count -= drvdata->residue_len;
+ memcpy(drvdata->residue_buf, kbuf + count, drvdata->residue_len);
+
+ /* Fixup endianess of the data */
+ if (drvdata->endian_swap) {
+ for (i = 0; i < count; i += 4) {
+ u32 *p = (u32 *)&kbuf[i];
+ *p = swab32(*p);
+ }
+ }
+
+ /* Enable DMA and error interrupts */
+ xdevcfg_writereg(drvdata->base_address + XDCFG_INT_STS_OFFSET,
+ XDCFG_IXR_ALL_MASK);
+
+
+ xdevcfg_writereg(drvdata->base_address + XDCFG_INT_MASK_OFFSET,
+ (u32) (~(XDCFG_IXR_D_P_DONE_MASK |
+ XDCFG_IXR_ERROR_FLAGS_MASK)));
+
+ drvdata->dma_done = 0;
+ drvdata->error_status = 0;
+
+ /* Initiate DMA write command */
+ if (count < 0x1000)
+ xdevcfg_writereg(drvdata->base_address +
+ XDCFG_DMA_SRC_ADDR_OFFSET, (u32)(dma_addr + 1));
+ else
+ xdevcfg_writereg(drvdata->base_address +
+ XDCFG_DMA_SRC_ADDR_OFFSET, (u32) dma_addr);
+
+ xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_DEST_ADDR_OFFSET,
+ (u32)XDCFG_DMA_INVALID_ADDRESS);
+ /* Convert number of bytes to number of words. */
+ if (count % 4)
+ transfer_length = (count / 4 + 1);
+ else
+ transfer_length = count / 4;
+ xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_SRC_LEN_OFFSET,
+ transfer_length);
+ xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_DEST_LEN_OFFSET, 0);
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+
+ while (!READ_ONCE(drvdata->dma_done)) {
+ if (time_after(jiffies, timeout)) {
+ status = -ETIMEDOUT;
+ goto error;
+ }
+ }
+
+ if (READ_ONCE(drvdata->error_status))
+ status = drvdata->error_status;
+
+ /* Disable the DMA and error interrupts */
+ intr_reg = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_INT_MASK_OFFSET);
+ xdevcfg_writereg(drvdata->base_address + XDCFG_INT_MASK_OFFSET,
+ intr_reg | (XDCFG_IXR_D_P_DONE_MASK |
+ XDCFG_IXR_ERROR_FLAGS_MASK));
+
+ /* If we didn't write correctly, then bail out. */
+ if (status) {
+ status = -EFAULT;
+ goto error;
+ }
+
+ *ppos += user_count;
+ status = user_count;
+
+error:
+ dma_free_coherent(drvdata->dev, dma_len, kbuf, dma_addr);
+err_unlock:
+ mutex_unlock(&drvdata->sem);
+err_clk:
+ clk_disable(drvdata->clk);
+ return status;
+}
+
+
+/**
+ * xdevcfg_read - The is the driver read function.
+ * @file: Pointer to the file structure.
+ * @buf: Pointer to the bitstream location.
+ * @count: The number of bytes read.
+ * @ppos: Pointer to the offsetvalue
+ * returns: Success or error status.
+ */
+static ssize_t
+xdevcfg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+ u32 *kbuf;
+ int status;
+ unsigned long timeout;
+ dma_addr_t dma_addr;
+ struct xdevcfg_drvdata *drvdata = file->private_data;
+ u32 intr_reg;
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ status = mutex_lock_interruptible(&drvdata->sem);
+ if (status)
+ goto err_clk;
+
+ /* Get new data from the ICAP, and return was requested. */
+ kbuf = dma_alloc_coherent(drvdata->dev, count, &dma_addr, GFP_KERNEL);
+ if (!kbuf) {
+ status = -ENOMEM;
+ goto err_unlock;
+ }
+
+ drvdata->dma_done = 0;
+ drvdata->error_status = 0;
+
+ /* Enable DMA and error interrupts */
+ xdevcfg_writereg(drvdata->base_address + XDCFG_INT_STS_OFFSET,
+ XDCFG_IXR_ALL_MASK);
+
+ xdevcfg_writereg(drvdata->base_address + XDCFG_INT_MASK_OFFSET,
+ (u32) (~(XDCFG_IXR_D_P_DONE_MASK |
+ XDCFG_IXR_ERROR_FLAGS_MASK)));
+ /* Initiate DMA read command */
+ xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_SRC_ADDR_OFFSET,
+ (u32)XDCFG_DMA_INVALID_ADDRESS);
+ xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_DEST_ADDR_OFFSET,
+ (u32)dma_addr);
+ xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_SRC_LEN_OFFSET, 0);
+ xdevcfg_writereg(drvdata->base_address + XDCFG_DMA_DEST_LEN_OFFSET,
+ count / 4);
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+
+ while (!drvdata->dma_done) {
+ if (time_after(jiffies, timeout)) {
+ status = -ETIMEDOUT;
+ goto error;
+ }
+ }
+
+ if (drvdata->error_status)
+ status = drvdata->error_status;
+
+ /* Disable and clear DMA and error interrupts */
+ intr_reg = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_INT_MASK_OFFSET);
+ xdevcfg_writereg(drvdata->base_address + XDCFG_INT_MASK_OFFSET,
+ intr_reg | (XDCFG_IXR_D_P_DONE_MASK |
+ XDCFG_IXR_ERROR_FLAGS_MASK));
+
+
+ /* If we didn't read correctly, then bail out. */
+ if (status) {
+ status = -EFAULT;
+ goto error;
+ }
+
+ /* If we fail to return the data to the user, then bail out. */
+ if (copy_to_user(buf, kbuf, count)) {
+ status = -EFAULT;
+ goto error;
+ }
+
+ status = count;
+error:
+ dma_free_coherent(drvdata->dev, count, kbuf, dma_addr);
+err_unlock:
+ mutex_unlock(&drvdata->sem);
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+static void xdevcfg_enable_partial(struct xdevcfg_drvdata *drvdata)
+{
+ u32 reg = xdevcfg_readreg(drvdata->base_address + XDCFG_CTRL_OFFSET);
+
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ reg | XDCFG_CTRL_PCAP_PR_MASK);
+}
+
+static void xdevcfg_disable_partial(struct xdevcfg_drvdata *drvdata)
+{
+ u32 reg = xdevcfg_readreg(drvdata->base_address + XDCFG_CTRL_OFFSET);
+
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ reg & ~XDCFG_CTRL_PCAP_PR_MASK);
+}
+
+/**
+ * xdevcfg_open - The is the driver open function.
+ * @inode: Pointer to the inode structure of this device.
+ * @file: Pointer to the file structure.
+ * returns: Success or error status.
+ */
+static int xdevcfg_open(struct inode *inode, struct file *file)
+{
+ struct xdevcfg_drvdata *drvdata;
+ int status;
+
+ drvdata = container_of(inode->i_cdev, struct xdevcfg_drvdata, cdev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ status = mutex_lock_interruptible(&drvdata->sem);
+ if (status)
+ goto err_clk;
+
+ if (drvdata->is_open) {
+ status = -EBUSY;
+ goto error;
+ }
+
+ file->private_data = drvdata;
+ drvdata->is_open = 1;
+ drvdata->endian_swap = 0;
+ drvdata->residue_len = 0;
+
+ /*
+ * If is_partial_bitstream is set, then PROG_B is not asserted
+ * (xdevcfg_reset_pl function) and also zynq_slcr_init_preload_fpga and
+ * zynq_slcr_init_postload_fpga functions are not invoked.
+ */
+ if (drvdata->is_partial_bitstream)
+ xdevcfg_enable_partial(drvdata);
+ else
+ zynq_slcr_init_preload_fpga();
+
+ /*
+ * Only do the reset of the PL for Zynq as it causes problems on the
+ * EP107 and the issue is not understood, but not worth investigating
+ * as the emulation platform is very different than silicon and not a
+ * complete implementation. Also, do not reset if it is a partial
+ * bitstream.
+ */
+ if ((!drvdata->ep107) && (!drvdata->is_partial_bitstream))
+ xdevcfg_reset_pl(drvdata->base_address);
+
+ xdevcfg_writereg(drvdata->base_address + XDCFG_INT_STS_OFFSET,
+ XDCFG_IXR_PCFG_DONE_MASK);
+
+error:
+ mutex_unlock(&drvdata->sem);
+err_clk:
+ clk_disable(drvdata->clk);
+ return status;
+}
+
+/**
+ * xdevcfg_release - The is the driver release function.
+ * @inode: Pointer to the inode structure of this device.
+ * @file: Pointer to the file structure.
+ * returns: Success.
+ */
+static int xdevcfg_release(struct inode *inode, struct file *file)
+{
+ struct xdevcfg_drvdata *drvdata = file->private_data;
+
+ if (drvdata->is_partial_bitstream)
+ xdevcfg_disable_partial(drvdata);
+ else
+ zynq_slcr_init_postload_fpga();
+
+ if (drvdata->residue_len)
+ dev_info(drvdata->dev, "Did not transfer last %d bytes\n",
+ drvdata->residue_len);
+
+ drvdata->is_open = 0;
+
+ return 0;
+}
+
+static const struct file_operations xdevcfg_fops = {
+ .owner = THIS_MODULE,
+ .write = xdevcfg_write,
+ .read = xdevcfg_read,
+ .open = xdevcfg_open,
+ .release = xdevcfg_release,
+};
+
+/*
+ * The following functions are the routines provided to the user to
+ * set/get the status bit value in the control/lock registers.
+ */
+
+/**
+ * xdevcfg_set_dap_en - This function sets the DAP bits in the
+ * control register with the given value.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: negative error if the string could not be converted
+ * or the size of the buffer.
+ */
+static ssize_t xdevcfg_set_dap_en(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 ctrl_reg_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ int status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ ctrl_reg_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET);
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ goto err_unlock;
+
+ if (mask_bit > 7) {
+ status = -EINVAL;
+ goto err_unlock;
+ }
+
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status |
+ (((u32)mask_bit) & XDCFG_CTRL_DAP_EN_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_unlock:
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_dap_en_status - The function returns the DAP_EN bits status in
+ * the control register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: Size of the buffer.
+ */
+static ssize_t xdevcfg_show_dap_en_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 dap_en_status;
+ int status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ dap_en_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET) & XDCFG_CTRL_DAP_EN_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", dap_en_status);
+
+ return status;
+}
+
+static DEVICE_ATTR(enable_dap, 0644, xdevcfg_show_dap_en_status,
+ xdevcfg_set_dap_en);
+
+/**
+ * xdevcfg_set_dbgen - This function sets the DBGEN bit in the
+ * control register with the given value.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or size
+ */
+static ssize_t xdevcfg_set_dbgen(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 ctrl_reg_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ int status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ ctrl_reg_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET);
+
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ goto err_clk;
+
+ if (mask_bit > 1) {
+ status = -EINVAL;
+ goto err_clk;
+ }
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ if (mask_bit)
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status | XDCFG_CTRL_DBGEN_MASK));
+ else
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status & (~XDCFG_CTRL_DBGEN_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_dbgen_status - The function returns the DBGEN bit status in
+ * the control register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: Size of the buffer.
+ */
+static ssize_t xdevcfg_show_dbgen_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 dbgen_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ dbgen_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET) & XDCFG_CTRL_DBGEN_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", (dbgen_status >> 3));
+
+ return status;
+}
+
+static DEVICE_ATTR(enable_dbg_in, 0644, xdevcfg_show_dbgen_status,
+ xdevcfg_set_dbgen);
+
+/**
+ * xdevcfg_set_niden - This function sets the NIDEN bit in the
+ * control register with the given value.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or size
+ */
+static ssize_t xdevcfg_set_niden(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 ctrl_reg_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ int status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ ctrl_reg_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET);
+
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ goto err_clk;
+
+ if (mask_bit > 1) {
+ status = -EINVAL;
+ goto err_clk;
+ }
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ if (mask_bit)
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status | XDCFG_CTRL_NIDEN_MASK));
+ else
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status & (~XDCFG_CTRL_NIDEN_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_niden_status - The function returns the NIDEN bit status in
+ * the control register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: Size of the buffer.
+ */
+static ssize_t xdevcfg_show_niden_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 niden_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ niden_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET) & XDCFG_CTRL_NIDEN_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", (niden_status >> 4));
+
+ return status;
+}
+
+static DEVICE_ATTR(enable_dbg_nonin, 0644, xdevcfg_show_niden_status,
+ xdevcfg_set_niden);
+
+/**
+ * xdevcfg_set_spiden - This function sets the SPIDEN bit in the
+ * control register with the given value.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or size
+ */
+static ssize_t xdevcfg_set_spiden(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 ctrl_reg_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ int status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ ctrl_reg_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET);
+
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ goto err_clk;
+
+ if (mask_bit > 1) {
+ status = -EINVAL;
+ goto err_clk;
+ }
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ if (mask_bit)
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status | XDCFG_CTRL_SPIDEN_MASK));
+ else
+
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status & (~XDCFG_CTRL_SPIDEN_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_spiden_status - The function returns the SPIDEN bit status in
+ * the control register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: Size of the buffer.
+ */
+static ssize_t xdevcfg_show_spiden_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 spiden_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ spiden_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET) & XDCFG_CTRL_SPIDEN_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", (spiden_status >> 5));
+
+ return status;
+}
+
+static DEVICE_ATTR(enable_sec_dbg_in, 0644, xdevcfg_show_spiden_status,
+ xdevcfg_set_spiden);
+
+/**
+ * xdevcfg_set_spniden - This function sets the SPNIDEN bit in the
+ * control register with the given value.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or the size of buffer
+ */
+static ssize_t xdevcfg_set_spniden(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 ctrl_reg_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ ctrl_reg_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET);
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ goto err_clk;
+
+ if (mask_bit > 1) {
+ status = -EINVAL;
+ goto err_clk;
+ }
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ if (mask_bit)
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status | XDCFG_CTRL_SPNIDEN_MASK));
+ else
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status & (~XDCFG_CTRL_SPNIDEN_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_spniden_status - The function returns the SPNIDEN bit status
+ * in the control register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: Size of the buffer.
+ */
+static ssize_t xdevcfg_show_spniden_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 spniden_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ spniden_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET) & XDCFG_CTRL_SPNIDEN_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", (spniden_status >> 6));
+
+ return status;
+}
+
+static DEVICE_ATTR(enable_sec_dbg_nonin, 0644, xdevcfg_show_spniden_status,
+ xdevcfg_set_spniden);
+
+/**
+ * xdevcfg_set_seu - This function sets the SEU_EN bit in the
+ * control register with the given value
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or size
+ */
+static ssize_t xdevcfg_set_seu(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 ctrl_reg_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ ctrl_reg_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET);
+
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ goto err_clk;
+
+ if (mask_bit > 1) {
+ status = -EINVAL;
+ goto err_clk;
+ }
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ if (mask_bit)
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status | XDCFG_CTRL_SEU_EN_MASK));
+ else
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status & (~XDCFG_CTRL_SEU_EN_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_seu_status - The function returns the SEU_EN bit status
+ * in the control register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: size of the buffer.
+ */
+static ssize_t xdevcfg_show_seu_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 seu_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ seu_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET) & XDCFG_CTRL_SEU_EN_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", (seu_status > 8));
+
+ return status;
+}
+
+static DEVICE_ATTR(enable_seu, 0644, xdevcfg_show_seu_status, xdevcfg_set_seu);
+
+/**
+ * xdevcfg_set_aes - This function sets the AES_EN bits in the
+ * control register with either all 1s or all 0s.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or size
+ *
+ * The user must send only one bit in the buffer to notify whether he wants to
+ * either set or reset these bits.
+ */
+static ssize_t xdevcfg_set_aes(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 ctrl_reg_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ int status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ ctrl_reg_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET);
+
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status < 0)
+ goto err_clk;
+
+ if (mask_bit > 1) {
+ status = -EINVAL;
+ goto err_clk;
+ }
+
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ if (mask_bit)
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status |
+ XDCFG_CTRL_PCFG_AES_EN_MASK |
+ XDCFG_CTRL_PCAP_RATE_EN_MASK));
+ else
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET,
+ (ctrl_reg_status &
+ ~(XDCFG_CTRL_PCFG_AES_EN_MASK |
+ XDCFG_CTRL_PCAP_RATE_EN_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_aes_status - The function returns the AES_EN bit status
+ * in the control register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: size of the buffer.
+ */
+static ssize_t xdevcfg_show_aes_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 aes_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ aes_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_CTRL_OFFSET) & XDCFG_CTRL_PCFG_AES_EN_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", (aes_status >> 9));
+
+ return status;
+}
+
+static DEVICE_ATTR(enable_aes, 0644, xdevcfg_show_aes_status, xdevcfg_set_aes);
+
+/**
+ * xdevcfg_set_aes_en_lock - This function sets the LOCK_AES_EN bit in the
+ * lock register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or size
+ */
+static ssize_t xdevcfg_set_aes_en_lock(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 aes_en_lock_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ aes_en_lock_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_LOCK_OFFSET);
+
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ goto err_clk;
+
+ if (mask_bit > 1) {
+ status = -EINVAL;
+ goto err_clk;
+ }
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ if (mask_bit)
+ xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET,
+ (aes_en_lock_status | XDCFG_LOCK_AES_EN_MASK));
+ else
+ xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET,
+ (aes_en_lock_status &
+ (~XDCFG_LOCK_AES_EN_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_aes_en_lock_status - The function returns the LOCK_AES_EN bit
+ * status in the lock register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: size of the buffer.
+ */
+static ssize_t xdevcfg_show_aes_en_lock_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 aes_en_lock_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ aes_en_lock_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_LOCK_OFFSET) & XDCFG_LOCK_AES_EN_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", (aes_en_lock_status >> 3));
+
+ return status;
+}
+
+static DEVICE_ATTR(aes_en_lock, 0644, xdevcfg_show_aes_en_lock_status,
+ xdevcfg_set_aes_en_lock);
+
+/**
+ * xdevcfg_set_seu_lock - This function sets the LOCK_SEU bit in the
+ * lock register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or size
+ */
+static ssize_t xdevcfg_set_seu_lock(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 seu_lock_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ seu_lock_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_LOCK_OFFSET);
+
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ goto err_clk;
+
+ if (mask_bit > 1) {
+ status = -EINVAL;
+ goto err_clk;
+ }
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ if (mask_bit)
+ xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET,
+ (seu_lock_status | XDCFG_LOCK_SEU_MASK));
+ else
+ xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET,
+ (seu_lock_status & (~XDCFG_LOCK_SEU_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_seu_lock_status - The function returns the LOCK_SEU bit
+ * status in the lock register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: size of the buffer.
+ */
+static ssize_t xdevcfg_show_seu_lock_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 seu_lock_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ seu_lock_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_LOCK_OFFSET) & XDCFG_LOCK_SEU_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", (seu_lock_status >> 2));
+
+ return status;
+}
+
+static DEVICE_ATTR(seu_lock, 0644, xdevcfg_show_seu_lock_status,
+ xdevcfg_set_seu_lock);
+
+/**
+ * xdevcfg_set_dbg_lock - This function sets the LOCK_DBG bit in the
+ * lock register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or size
+ */
+static ssize_t xdevcfg_set_dbg_lock(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ u32 lock_reg_status;
+ unsigned long flags;
+ unsigned long mask_bit;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ lock_reg_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_LOCK_OFFSET);
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ goto err_clk;
+
+ if (mask_bit > 1) {
+ status = -EINVAL;
+ goto err_clk;
+ }
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+
+ if (mask_bit)
+ xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET,
+ (lock_reg_status | XDCFG_LOCK_DBG_MASK));
+ else
+ xdevcfg_writereg(drvdata->base_address + XDCFG_LOCK_OFFSET,
+ (lock_reg_status & (~XDCFG_LOCK_DBG_MASK)));
+
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ clk_disable(drvdata->clk);
+
+ return size;
+
+err_clk:
+ clk_disable(drvdata->clk);
+
+ return status;
+}
+
+/**
+ * xdevcfg_show_dbg_lock_status - The function returns the LOCK_DBG bit
+ * status in the lock register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: size of the buffer.
+ */
+static ssize_t xdevcfg_show_dbg_lock_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 dbg_lock_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ dbg_lock_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_LOCK_OFFSET) & XDCFG_LOCK_DBG_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", dbg_lock_status);
+
+ return status;
+}
+
+static DEVICE_ATTR(dbg_lock, 0644, xdevcfg_show_dbg_lock_status,
+ xdevcfg_set_dbg_lock);
+
+/**
+ * xdevcfg_show_prog_done_status - The function returns the PROG_DONE bit
+ * status in the interrupt status register.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: size of the buffer.
+ */
+static ssize_t xdevcfg_show_prog_done_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 prog_done_status;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = clk_enable(drvdata->clk);
+ if (status)
+ return status;
+
+ prog_done_status = xdevcfg_readreg(drvdata->base_address +
+ XDCFG_INT_STS_OFFSET) & XDCFG_IXR_PCFG_DONE_MASK;
+
+ clk_disable(drvdata->clk);
+
+ status = sprintf(buf, "%d\n", (prog_done_status >> 2));
+
+ return status;
+}
+
+static DEVICE_ATTR(prog_done, 0644, xdevcfg_show_prog_done_status,
+ NULL);
+
+/**
+ * xdevcfg_set_is_partial_bitstream - This function sets the
+ * is_partial_bitstream variable. If is_partial_bitstream is set,
+ * then PROG_B is not asserted (xdevcfg_reset_pl) and also
+ * zynq_slcr_init_preload_fpga and zynq_slcr_init_postload_fpga functions
+ * are not invoked.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * @size: The number of bytes used from the buffer
+ * returns: -EINVAL if invalid parameter is sent or size
+ */
+static ssize_t xdevcfg_set_is_partial_bitstream(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ unsigned long mask_bit;
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = kstrtoul(buf, 10, &mask_bit);
+
+ if (status)
+ return status;
+
+ if (mask_bit > 1)
+ return -EINVAL;
+
+ if (mask_bit)
+ drvdata->is_partial_bitstream = 1;
+ else
+ drvdata->is_partial_bitstream = 0;
+
+ return size;
+}
+
+/**
+ * xdevcfg_show_is_partial_bitstream_status - The function returns the
+ * value of is_partial_bitstream variable.
+ * @dev: Pointer to the device structure.
+ * @attr: Pointer to the device attribute structure.
+ * @buf: Pointer to the buffer location for the configuration
+ * data.
+ * returns: size of the buffer.
+ */
+static ssize_t xdevcfg_show_is_partial_bitstream_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t status;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ status = sprintf(buf, "%d\n", drvdata->is_partial_bitstream);
+
+ return status;
+}
+
+static DEVICE_ATTR(is_partial_bitstream, 0644,
+ xdevcfg_show_is_partial_bitstream_status,
+ xdevcfg_set_is_partial_bitstream);
+
+static const struct attribute *xdevcfg_attrs[] = {
+ &dev_attr_prog_done.attr, /* PCFG_DONE bit in Intr Status register */
+ &dev_attr_dbg_lock.attr, /* Debug lock bit in Lock register */
+ &dev_attr_seu_lock.attr, /* SEU lock bit in Lock register */
+ &dev_attr_aes_en_lock.attr, /* AES EN lock bit in Lock register */
+ &dev_attr_enable_aes.attr, /* AES EN bit in Control register */
+ &dev_attr_enable_seu.attr, /* SEU EN bit in Control register */
+ &dev_attr_enable_sec_dbg_nonin.attr, /*SPNIDEN bit in Control register*/
+ &dev_attr_enable_sec_dbg_in.attr, /*SPIDEN bit in Control register */
+ &dev_attr_enable_dbg_nonin.attr, /* NIDEN bit in Control register */
+ &dev_attr_enable_dbg_in.attr, /* DBGEN bit in Control register */
+ &dev_attr_enable_dap.attr, /* DAP_EN bits in Control register */
+ &dev_attr_is_partial_bitstream.attr, /* Flag for partial bitstream */
+ NULL,
+};
+
+
+static const struct attribute_group xdevcfg_attr_group = {
+ .attrs = (struct attribute **) xdevcfg_attrs,
+};
+
+static ssize_t fclk_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fclk_data *pdata = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", pdata->enabled);
+}
+
+static ssize_t fclk_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long enable;
+ int ret;
+ struct fclk_data *pdata = dev_get_drvdata(dev);
+
+ ret = kstrtoul(buf, 0, &enable);
+ if (ret)
+ return -EINVAL;
+
+ enable = !!enable;
+ if (enable == pdata->enabled)
+ return count;
+
+ if (enable)
+ ret = clk_enable(pdata->clk);
+ else
+ clk_disable(pdata->clk);
+
+ if (ret)
+ return ret;
+
+ pdata->enabled = enable;
+ return count;
+}
+
+static DEVICE_ATTR(enable, 0644, fclk_enable_show, fclk_enable_store);
+
+static ssize_t fclk_set_rate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fclk_data *pdata = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%lu\n", clk_get_rate(pdata->clk));
+}
+
+static ssize_t fclk_set_rate_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret = 0;
+ unsigned long rate;
+ struct fclk_data *pdata = dev_get_drvdata(dev);
+
+ ret = kstrtoul(buf, 0, &rate);
+ if (ret)
+ return -EINVAL;
+
+ rate = clk_round_rate(pdata->clk, rate);
+ ret = clk_set_rate(pdata->clk, rate);
+
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(set_rate, 0644, fclk_set_rate_show, fclk_set_rate_store);
+
+static ssize_t fclk_round_rate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fclk_data *pdata = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%lu => %lu\n", pdata->rate_rnd,
+ clk_round_rate(pdata->clk, pdata->rate_rnd));
+}
+
+static ssize_t fclk_round_rate_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret = 0;
+ unsigned long rate;
+ struct fclk_data *pdata = dev_get_drvdata(dev);
+
+ ret = kstrtoul(buf, 0, &rate);
+ if (ret)
+ return -EINVAL;
+
+ pdata->rate_rnd = rate;
+
+ return count;
+}
+
+static DEVICE_ATTR(round_rate, 0644, fclk_round_rate_show,
+ fclk_round_rate_store);
+
+static const struct attribute *fclk_ctrl_attrs[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_set_rate.attr,
+ &dev_attr_round_rate.attr,
+ NULL,
+};
+
+static const struct attribute_group fclk_ctrl_attr_grp = {
+ .attrs = (struct attribute **)fclk_ctrl_attrs,
+};
+
+static ssize_t xdevcfg_fclk_export_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ int i, ret;
+ struct device *subdev;
+ struct fclk_data *fdata;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ for (i = 0; i < NUMFCLKS; i++) {
+ if (!strncmp(buf, fclk_name[i], strlen(fclk_name[i])))
+ break;
+ }
+
+ if (i < NUMFCLKS && !drvdata->fclk_exported[i]) {
+ drvdata->fclk_exported[i] = 1;
+ subdev = device_create(drvdata->fclk_class, dev, MKDEV(0, 0),
+ NULL, fclk_name[i]);
+ if (IS_ERR(subdev))
+ return PTR_ERR(subdev);
+ ret = clk_prepare(drvdata->fclk[i]);
+ if (ret)
+ return ret;
+ fdata = kzalloc(sizeof(*fdata), GFP_KERNEL);
+ if (!fdata) {
+ ret = -ENOMEM;
+ goto err_unprepare;
+ }
+ fdata->clk = drvdata->fclk[i];
+ dev_set_drvdata(subdev, fdata);
+ ret = sysfs_create_group(&subdev->kobj, &fclk_ctrl_attr_grp);
+ if (ret)
+ goto err_free;
+ } else {
+ return -EINVAL;
+ }
+
+ return size;
+
+err_free:
+ kfree(fdata);
+err_unprepare:
+ clk_unprepare(drvdata->fclk[i]);
+
+ return ret;
+}
+
+static ssize_t xdevcfg_fclk_export_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ ssize_t count = 0;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ for (i = 0; i < NUMFCLKS; i++) {
+ if (!drvdata->fclk_exported[i])
+ count += scnprintf(buf + count, PAGE_SIZE - count,
+ "%s\n", fclk_name[i]);
+ }
+ return count;
+}
+
+static DEVICE_ATTR(fclk_export, 0644, xdevcfg_fclk_export_show,
+ xdevcfg_fclk_export_store);
+
+static int match_fclk(struct device *dev, const void *data)
+{
+ struct fclk_data *fdata = dev_get_drvdata(dev);
+
+ return fdata->clk == data;
+}
+
+static ssize_t xdevcfg_fclk_unexport_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ int i;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ for (i = 0; i < NUMFCLKS; i++) {
+ if (!strncmp(buf, fclk_name[i], strlen(fclk_name[i])))
+ break;
+ }
+
+ if (i < NUMFCLKS && drvdata->fclk_exported[i]) {
+ struct fclk_data *fdata;
+ struct device *subdev;
+
+ drvdata->fclk_exported[i] = 0;
+ subdev = class_find_device(drvdata->fclk_class, NULL,
+ drvdata->fclk[i], match_fclk);
+ fdata = dev_get_drvdata(subdev);
+ if (fdata->enabled)
+ clk_disable(fdata->clk);
+ clk_unprepare(fdata->clk);
+ kfree(fdata);
+ device_unregister(subdev);
+ put_device(subdev);
+ } else {
+ return -EINVAL;
+ }
+
+ return size;
+}
+
+static ssize_t xdevcfg_fclk_unexport_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ ssize_t count = 0;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ for (i = 0; i < NUMFCLKS; i++) {
+ if (drvdata->fclk_exported[i])
+ count += scnprintf(buf + count, PAGE_SIZE - count,
+ "%s\n", fclk_name[i]);
+ }
+ return count;
+}
+
+static DEVICE_ATTR(fclk_unexport, 0644, xdevcfg_fclk_unexport_show,
+ xdevcfg_fclk_unexport_store);
+
+static const struct attribute *fclk_exp_attrs[] = {
+ &dev_attr_fclk_export.attr,
+ &dev_attr_fclk_unexport.attr,
+ NULL,
+};
+
+static const struct attribute_group fclk_exp_attr_grp = {
+ .attrs = (struct attribute **)fclk_exp_attrs,
+};
+
+static void xdevcfg_fclk_init(struct device *dev)
+{
+ int i;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ for (i = 0; i < NUMFCLKS; i++) {
+ drvdata->fclk[i] = clk_get(dev, fclk_name[i]);
+ if (IS_ERR(drvdata->fclk[i])) {
+ dev_warn(dev, "fclk not found\n");
+ return;
+ }
+ }
+
+ drvdata->fclk_class = class_create(THIS_MODULE, "fclk");
+ if (IS_ERR(drvdata->fclk_class)) {
+ dev_warn(dev, "failed to create fclk class\n");
+ return;
+ }
+
+ if (sysfs_create_group(&dev->kobj, &fclk_exp_attr_grp))
+ dev_warn(dev, "failed to create sysfs entries\n");
+}
+
+static void xdevcfg_fclk_remove(struct device *dev)
+{
+ int i;
+ struct xdevcfg_drvdata *drvdata = dev_get_drvdata(dev);
+
+ for (i = 0; i < NUMFCLKS; i++) {
+ if (drvdata->fclk_exported[i]) {
+ struct fclk_data *fdata;
+ struct device *subdev;
+
+ drvdata->fclk_exported[i] = 0;
+ subdev = class_find_device(drvdata->fclk_class, NULL,
+ drvdata->fclk[i], match_fclk);
+ fdata = dev_get_drvdata(subdev);
+ if (fdata->enabled)
+ clk_disable(fdata->clk);
+ clk_unprepare(fdata->clk);
+ kfree(fdata);
+ device_unregister(subdev);
+ put_device(subdev);
+
+ }
+ }
+
+ class_destroy(drvdata->fclk_class);
+ sysfs_remove_group(&dev->kobj, &fclk_exp_attr_grp);
+
+}
+
+/**
+ * xdevcfg_drv_probe - Probe call for the device.
+ *
+ * @pdev: handle to the platform device structure.
+ *
+ * Returns: 0 on success, negative error otherwise.
+ *
+ * It does all the memory allocation and registration for the device.
+ */
+static int xdevcfg_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct xdevcfg_drvdata *drvdata;
+ dev_t devt;
+ int retval;
+ u32 ctrlreg;
+ struct device_node *np;
+ const void *prop;
+ int size;
+ struct device *dev;
+
+ zynq_slcr_regmap = syscon_regmap_lookup_by_compatible("xlnx,zynq-slcr");
+ if (IS_ERR(zynq_slcr_regmap)) {
+ pr_err("%s: failed to find zynq-slcr\n", __func__);
+ return -ENODEV;
+ }
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ drvdata->base_address = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(drvdata->base_address))
+ return PTR_ERR(drvdata->base_address);
+
+ drvdata->irq = platform_get_irq(pdev, 0);
+ retval = devm_request_irq(&pdev->dev, drvdata->irq, &xdevcfg_irq,
+ 0, dev_name(&pdev->dev), drvdata);
+ if (retval) {
+ dev_err(&pdev->dev, "No IRQ available");
+ return retval;
+ }
+
+ platform_set_drvdata(pdev, drvdata);
+ spin_lock_init(&drvdata->lock);
+ mutex_init(&drvdata->sem);
+ drvdata->is_open = 0;
+ drvdata->is_partial_bitstream = 0;
+ drvdata->dma_done = 0;
+ drvdata->error_status = 0;
+ dev_info(&pdev->dev, "ioremap %pa to %p\n",
+ &res->start, drvdata->base_address);
+
+ drvdata->clk = devm_clk_get(&pdev->dev, "ref_clk");
+ if (IS_ERR(drvdata->clk)) {
+ dev_err(&pdev->dev, "input clock not found\n");
+ return PTR_ERR(drvdata->clk);
+ }
+
+ retval = clk_prepare_enable(drvdata->clk);
+ if (retval) {
+ dev_err(&pdev->dev, "unable to enable clock\n");
+ return retval;
+ }
+
+ /*
+ * Figure out from the device tree if this is running on the EP107
+ * emulation platform as it doesn't match the silicon exactly and the
+ * driver needs to work accordingly.
+ */
+ np = of_get_next_parent(pdev->dev.of_node);
+ np = of_get_next_parent(np);
+ prop = of_get_property(np, "compatible", &size);
+
+ if (prop != NULL) {
+ if ((strcmp((const char *)prop, "xlnx,zynq-ep107")) == 0)
+ drvdata->ep107 = 1;
+ else
+ drvdata->ep107 = 0;
+ }
+
+ /* Unlock the device */
+ xdevcfg_writereg(drvdata->base_address + XDCFG_UNLOCK_OFFSET,
+ 0x757BDF0D);
+
+ /*
+ * Set the configuration register with the following options
+ * - Reset FPGA
+ * - Enable the PCAP interface
+ * - Set the throughput rate for maximum speed
+ * - Set the CPU in user mode
+ */
+ ctrlreg = xdevcfg_readreg(drvdata->base_address + XDCFG_CTRL_OFFSET);
+ ctrlreg &= ~XDCFG_CTRL_PCAP_PR_MASK;
+ ctrlreg |= XDCFG_CTRL_PCFG_PROG_B_MASK | XDCFG_CTRL_PCAP_MODE_MASK;
+ xdevcfg_writereg(drvdata->base_address + XDCFG_CTRL_OFFSET, ctrlreg);
+
+ /* Ensure internal PCAP loopback is disabled */
+ ctrlreg = xdevcfg_readreg(drvdata->base_address + XDCFG_MCTRL_OFFSET);
+ xdevcfg_writereg(drvdata->base_address + XDCFG_MCTRL_OFFSET,
+ (~XDCFG_MCTRL_PCAP_LPBK_MASK &
+ ctrlreg));
+
+
+ retval = alloc_chrdev_region(&devt, 0, XDEVCFG_DEVICES, DRIVER_NAME);
+ if (retval < 0)
+ goto failed5;
+
+ drvdata->devt = devt;
+
+ cdev_init(&drvdata->cdev, &xdevcfg_fops);
+ drvdata->cdev.owner = THIS_MODULE;
+ retval = cdev_add(&drvdata->cdev, devt, 1);
+ if (retval) {
+ dev_err(&pdev->dev, "cdev_add() failed\n");
+ goto failed6;
+ }
+
+ drvdata->class = class_create(THIS_MODULE, DRIVER_NAME);
+ if (IS_ERR(drvdata->class)) {
+ dev_err(&pdev->dev, "failed to create class\n");
+ goto failed6;
+ }
+
+ dev = device_create(drvdata->class, &pdev->dev, devt, drvdata,
+ DRIVER_NAME);
+ if (IS_ERR(dev)) {
+ dev_err(&pdev->dev, "unable to create device\n");
+ goto failed7;
+ }
+
+ drvdata->dev = &pdev->dev;
+
+ /* create sysfs files for the device */
+ retval = sysfs_create_group(&(pdev->dev.kobj), &xdevcfg_attr_group);
+ if (retval) {
+ dev_err(&pdev->dev, "Failed to create sysfs attr group\n");
+ cdev_del(&drvdata->cdev);
+ goto failed8;
+ }
+
+ xdevcfg_fclk_init(&pdev->dev);
+
+ clk_disable(drvdata->clk);
+
+ return 0; /* Success */
+
+failed8:
+ device_destroy(drvdata->class, drvdata->devt);
+failed7:
+ class_destroy(drvdata->class);
+failed6:
+ /* Unregister char driver */
+ unregister_chrdev_region(devt, XDEVCFG_DEVICES);
+failed5:
+ clk_disable_unprepare(drvdata->clk);
+
+ return retval;
+}
+
+/**
+ * xdevcfg_drv_remove - Remove call for the device.
+ *
+ * @pdev: handle to the platform device structure.
+ *
+ * Returns: 0 or error status.
+ *
+ * Unregister the device after releasing the resources.
+ */
+static int xdevcfg_drv_remove(struct platform_device *pdev)
+{
+ struct xdevcfg_drvdata *drvdata;
+
+ drvdata = platform_get_drvdata(pdev);
+
+ if (!drvdata)
+ return -ENODEV;
+
+ unregister_chrdev_region(drvdata->devt, XDEVCFG_DEVICES);
+
+ sysfs_remove_group(&pdev->dev.kobj, &xdevcfg_attr_group);
+
+ xdevcfg_fclk_remove(&pdev->dev);
+ device_destroy(drvdata->class, drvdata->devt);
+ class_destroy(drvdata->class);
+ cdev_del(&drvdata->cdev);
+ clk_unprepare(drvdata->clk);
+
+ return 0; /* Success */
+}
+
+static const struct of_device_id xdevcfg_of_match[] = {
+ { .compatible = "xlnx,zynq-devcfg-1.0", },
+ { /* end of table */}
+};
+MODULE_DEVICE_TABLE(of, xdevcfg_of_match);
+
+/* Driver Structure */
+static struct platform_driver xdevcfg_platform_driver = {
+ .probe = xdevcfg_drv_probe,
+ .remove = xdevcfg_drv_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .of_match_table = xdevcfg_of_match,
+ },
+};
+
+module_platform_driver(xdevcfg_platform_driver);
+
+MODULE_AUTHOR("Xilinx, Inc");
+MODULE_DESCRIPTION("Xilinx Device Config Driver");
+MODULE_LICENSE("GPL");
diff --git a/patches/xilinx_zynq_defconfig b/patches/xilinx_zynq_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..72063935e48964cb82df90dff70144db9743ac8f
--- /dev/null
+++ b/patches/xilinx_zynq_defconfig
@@ -0,0 +1,396 @@
+CONFIG_LOCALVERSION="-xilinx"
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CGROUPS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BPF_SYSCALL=y
+# CONFIG_BUG is not set
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+CONFIG_SLAB=y
+CONFIG_ARCH_VEXPRESS=y
+CONFIG_ARCH_ZYNQ=y
+CONFIG_PL310_ERRATA_588369=y
+CONFIG_PL310_ERRATA_727915=y
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_ARM_ERRATA_754327=y
+CONFIG_ARM_ERRATA_764369=y
+CONFIG_ARM_ERRATA_775420=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_SCHED_SMT=y
+CONFIG_BIG_LITTLE=y
+CONFIG_BL_SWITCHER=y
+CONFIG_HIGHMEM=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_ARM_ZYNQ_CPUIDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_COMPACTION is not set
+CONFIG_CMA=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_SYN_COOKIES=y
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_CAN=y
+CONFIG_CAN_XILINXCAN=y
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCIE_XILINX=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_MTD_NAND_PL353=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_OF_OVERLAY=y
+CONFIG_OF_CONFIGFS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_XILINX_TRAFGEN=y
+CONFIG_EEPROM_AT24=y
+CONFIG_EEPROM_AT25=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_NETDEVICES=y
+CONFIG_MACB=y
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+CONFIG_E1000E=y
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+CONFIG_R8169=y
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_XILINX_EMACLITE=y
+CONFIG_XILINX_AXI_EMAC=y
+CONFIG_MARVELL_PHY=y
+CONFIG_VITESSE_PHY=y
+CONFIG_INTEL_XWAY_PHY=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_INPUT_SPARSEKMAP=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_GPIO_POLLED=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_XILINX_PS_UART=y
+CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_XILINX_DEVCFG=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_MUX_PCA954x=y
+CONFIG_I2C_CADENCE=y
+CONFIG_SPI=y
+CONFIG_SPI_CADENCE=y
+CONFIG_SPI_XILINX=y
+CONFIG_SPI_ZYNQ_QSPI=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_XILINX=y
+CONFIG_GPIO_ZYNQ=y
+CONFIG_PMBUS=y
+CONFIG_SENSORS_UCD9000=y
+CONFIG_SENSORS_UCD9200=y
+CONFIG_BMP280=y
+CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_XILINX_WATCHDOG=y
+CONFIG_CADENCE_WATCHDOG=y
+CONFIG_REGULATOR=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_XILINX=y
+CONFIG_VIDEO_XILINX_CFA=y
+CONFIG_VIDEO_XILINX_CRESAMPLE=y
+CONFIG_VIDEO_XILINX_REMAPPER=y
+CONFIG_VIDEO_XILINX_RGB2YUV=y
+CONFIG_VIDEO_XILINX_SCALER=y
+CONFIG_VIDEO_XILINX_SWITCH=y
+CONFIG_VIDEO_XILINX_TPG=y
+CONFIG_VIDEO_ADV7604=y
+CONFIG_DRM=y
+CONFIG_DRM_XLNX=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_ADI=y
+CONFIG_SND_SOC_ADI_AXI_I2S=y
+CONFIG_SND_SOC_ADI_AXI_SPDIF=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_STORAGE=y
+CONFIG_USB_UAS=m
+CONFIG_USB_CHIPIDEA=y
+CONFIG_USB_CHIPIDEA_UDC=y
+CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_ULPI=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_XILINX=y
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_ZERO=m
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_OF_ARASAN=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_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=y
+CONFIG_LEDS_TRIGGER_CAMERA=y
+CONFIG_EDAC=y
+CONFIG_EDAC_SYNOPSYS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PCF8563=y
+CONFIG_DMADEVICES=y
+CONFIG_PL330_DMA=y
+CONFIG_XILINX_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_PDRV_GENIRQ=y
+CONFIG_UIO_XILINX_APM=y
+CONFIG_COMMON_CLK_SI570=y
+CONFIG_REMOTEPROC=y
+CONFIG_ZYNQ_REMOTEPROC=m
+CONFIG_MEMORY=y
+CONFIG_IIO=y
+CONFIG_XILINX_XADC=y
+CONFIG_XILINX_INTC=y
+CONFIG_RAS=y
+CONFIG_EXT3_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DMA_CMA=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_FTRACE is not set
+CONFIG_OVERLAY_FS=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SYN_COOKIES=y
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=m
+CONFIG_MAC80211=m
+CONFIG_RTL8188EU=m
+CONFIG_RTL8192CU=m
+CONFIG_RT2X00=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+CONFIG_RT2800USB_UNKNOWN=y
+CONFIG_MT7601U=m
+CONFIG_ATH9K_HTC=m
+CONFIG_B43=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_USB=y
+CONFIG_PPP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_MBIM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_QMI_WWAN=m
+CONFIG_NAMESPACES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_NAT_IPV4=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_MACVLAN=m
+CONFIG_TUN=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_FB_DEFERRED_IO=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_UDL=m
+CONFIG_FUSE_FS=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_PPS_CLIENT_GPIO=m
+CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_USB_GPIO_VBUS=y
+CONFIG_USB_ULPI_BUS=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS2=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_ACL=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_STAGING=y
+CONFIG_FB_TFT=m
+CONFIG_FB_TFT_AGM1264K_FL=m
+CONFIG_FB_TFT_BD663474=m
+CONFIG_FB_TFT_HX8340BN=m
+CONFIG_FB_TFT_HX8347D=m
+CONFIG_FB_TFT_HX8353D=m
+CONFIG_FB_TFT_HX8357D=m
+CONFIG_FB_TFT_ILI9163=m
+CONFIG_FB_TFT_ILI9320=m
+CONFIG_FB_TFT_ILI9325=m
+CONFIG_FB_TFT_ILI9340=m
+CONFIG_FB_TFT_ILI9341=m
+CONFIG_FB_TFT_ILI9481=m
+CONFIG_FB_TFT_ILI9486=m
+CONFIG_FB_TFT_PCD8544=m
+CONFIG_FB_TFT_RA8875=m
+CONFIG_FB_TFT_S6D02A1=m
+CONFIG_FB_TFT_S6D1121=m
+CONFIG_FB_TFT_SSD1289=m
+CONFIG_FB_TFT_SSD1306=m
+CONFIG_FB_TFT_SSD1331=m
+CONFIG_FB_TFT_SSD1351=m
+CONFIG_FB_TFT_ST7735R=m
+CONFIG_FB_TFT_ST7789V=m
+CONFIG_FB_TFT_TINYLCD=m
+CONFIG_FB_TFT_TLS8204=m
+CONFIG_FB_TFT_UC1611=m
+CONFIG_FB_TFT_UC1701=m
+CONFIG_FB_TFT_UPD161704=m
+CONFIG_FB_TFT_WATTEROTT=m
+CONFIG_FB_FLEX=m
+CONFIG_FB_TFT_FBTFT_DEVICE=m
+CONFIG_USB_ACM=m
+CONFIG_USB_TMC=m
+CONFIG_VIDEOBUF2_VMALLOC=m
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=8
+CONFIG_U_SERIAL_CONSOLE=y
+CONFIG_USB_F_ACM=m
+CONFIG_USB_U_SERIAL=m
+CONFIG_USB_U_ETHER=m
+CONFIG_USB_F_SERIAL=m
+CONFIG_USB_F_OBEX=m
+CONFIG_USB_F_NCM=m
+CONFIG_USB_F_ECM=m
+CONFIG_USB_F_EEM=m
+CONFIG_USB_F_SUBSET=m
+CONFIG_USB_F_RNDIS=m
+CONFIG_USB_F_FS=m
+CONFIG_USB_F_UAC1=m
+CONFIG_USB_F_UAC2=m
+CONFIG_USB_F_UVC=m
+CONFIG_USB_F_MIDI=m
+CONFIG_USB_F_HID=m
+CONFIG_USB_F_PRINTER=m
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_UAC1=y
+CONFIG_USB_CONFIGFS_F_UAC2=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_UVC=y
+CONFIG_USB_CONFIGFS_F_PRINTER=y
+CONFIG_USB_AUDIO=m
+CONFIG_GADGET_UAC1=y
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_ETH_EEM=y
+CONFIG_USB_G_NCM=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FUNCTIONFS=m
+CONFIG_USB_FUNCTIONFS_ETH=y
+CONFIG_USB_FUNCTIONFS_RNDIS=y
+CONFIG_USB_FUNCTIONFS_GENERIC=y
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_MIDI_GADGET=m
+CONFIG_USB_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_ACM_MS=m
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_MULTI_RNDIS=y
+CONFIG_USB_G_MULTI_CDC=y
+CONFIG_USB_G_HID=m
+CONFIG_USB_G_WEBCAM=m
diff --git a/patches/zynq-red-pitaya.dts b/patches/zynq-red-pitaya.dts
new file mode 100644
index 0000000000000000000000000000000000000000..1c6ceb9dfd064193c954d9241b118a3c4f97370b
--- /dev/null
+++ b/patches/zynq-red-pitaya.dts
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2011 - 2015 Xilinx
+ * Copyright (C) 2012 National Instruments Corp.
+ */
+/dts-v1/;
+#include "zynq-7000.dtsi"
+
+/ {
+ model = "Red Pitaya Board";
+ compatible = "xlnx,zynq-red-pitaya", "xlnx,zynq-7000";
+
+ aliases {
+ ethernet0 = &gem0;
+ serial0 = &uart0;
+ mmc0 = &sdhci0;
+ };
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x20000000>;
+ };
+
+ chosen {
+ bootargs = "";
+ stdout-path = "serial0:115200n8";
+ };
+
+ usb_phy0: phy0 {
+ #phy-cells = <0>;
+ compatible = "usb-nop-xceiv";
+ };
+};
+
+&clkc {
+ ps-clk-frequency = <33333333>;
+};
+
+&gem0 {
+ status = "okay";
+ phy-mode = "rgmii-id";
+ phy-handle = <ðernet_phy>;
+
+ ethernet_phy: ethernet-phy@1 {
+ reg = <1>;
+ device_type = "ethernet-phy";
+ };
+};
+
+&i2c0 {
+ status = "okay";
+ clock-frequency = <400000>;
+ eeprom@50 {
+ compatible = "24c64";
+ reg = <0x50>;
+ };
+ bmp180@77{
+ compatible = "bosch,bmp280";
+ reg = <0x77>;
+ };
+};
+
+&sdhci0 {
+ u-boot,dm-pre-reloc;
+ status = "okay";
+};
+
+&uart0 {
+ u-boot,dm-pre-reloc;
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+ dr_mode = "host";
+ usb-phy = <&usb_phy0>;
+};
diff --git a/patches/zynq_ocm.c b/patches/zynq_ocm.c
new file mode 100644
index 0000000000000000000000000000000000000000..324b7c125bf5681ecff2bb5f6f090bcd293ffc44
--- /dev/null
+++ b/patches/zynq_ocm.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2013 Xilinx
+ *
+ * Based on "Generic on-chip SRAM allocation driver"
+ *
+ * Copyright (C) 2012 Philipp Zabel, Pengutronix
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/genalloc.h>
+
+#include "common.h"
+
+#define ZYNQ_OCM_HIGHADDR 0xfffc0000
+#define ZYNQ_OCM_LOWADDR 0x0
+#define ZYNQ_OCM_BLOCK_SIZE 0x10000
+#define ZYNQ_OCM_BLOCKS 4
+#define ZYNQ_OCM_GRANULARITY 32
+
+#define ZYNQ_OCM_PARITY_CTRL 0x0
+#define ZYNQ_OCM_PARITY_ENABLE 0x1e
+
+#define ZYNQ_OCM_PARITY_ERRADDRESS 0x4
+
+#define ZYNQ_OCM_IRQ_STS 0x8
+#define ZYNQ_OCM_IRQ_STS_ERR_MASK 0x7
+
+struct zynq_ocm_dev {
+ void __iomem *base;
+ int irq;
+ struct gen_pool *pool;
+ struct resource res[ZYNQ_OCM_BLOCKS];
+};
+
+/**
+ * zynq_ocm_irq_handler - Interrupt service routine of the OCM controller
+ * @irq: IRQ number
+ * @data: Pointer to the zynq_ocm_dev structure
+ *
+ * Return: IRQ_HANDLED when handled; IRQ_NONE otherwise.
+ */
+static irqreturn_t zynq_ocm_irq_handler(int irq, void *data)
+{
+ u32 sts;
+ u32 err_addr;
+ struct zynq_ocm_dev *zynq_ocm = data;
+
+ /* check status */
+ sts = readl(zynq_ocm->base + ZYNQ_OCM_IRQ_STS);
+ if (sts & ZYNQ_OCM_IRQ_STS_ERR_MASK) {
+ /* check error address */
+ err_addr = readl(zynq_ocm->base + ZYNQ_OCM_PARITY_ERRADDRESS);
+ pr_err("%s: OCM err intr generated at 0x%04x (stat: 0x%08x).",
+ __func__, err_addr, sts & ZYNQ_OCM_IRQ_STS_ERR_MASK);
+ return IRQ_HANDLED;
+ }
+ pr_warn("%s: Interrupt generated by OCM, but no error is found.",
+ __func__);
+
+ return IRQ_NONE;
+}
+
+/**
+ * zynq_ocm_probe - Probe method for the OCM driver
+ * @pdev: Pointer to the platform_device structure
+ *
+ * This function initializes the driver data structures and the hardware.
+ *
+ * Return: 0 on success and error value on failure
+ */
+static int zynq_ocm_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct zynq_ocm_dev *zynq_ocm;
+ u32 i, ocm_config, curr;
+ struct resource *res;
+
+ ocm_config = zynq_slcr_get_ocm_config();
+
+ zynq_ocm = devm_kzalloc(&pdev->dev, sizeof(*zynq_ocm), GFP_KERNEL);
+ if (!zynq_ocm)
+ return -ENOMEM;
+
+ zynq_ocm->pool = devm_gen_pool_create(&pdev->dev,
+ ilog2(ZYNQ_OCM_GRANULARITY),
+ NUMA_NO_NODE, NULL);
+ if (!zynq_ocm->pool)
+ return -ENOMEM;
+
+ curr = 0; /* For storing current struct resource for OCM */
+ for (i = 0; i < ZYNQ_OCM_BLOCKS; i++) {
+ u32 base, start, end;
+
+ /* Setup base address for 64kB OCM block */
+ if (ocm_config & BIT(i))
+ base = ZYNQ_OCM_HIGHADDR;
+ else
+ base = ZYNQ_OCM_LOWADDR;
+
+ /* Calculate start and end block addresses */
+ start = i * ZYNQ_OCM_BLOCK_SIZE + base;
+ end = start + (ZYNQ_OCM_BLOCK_SIZE - 1);
+
+ /* Concatenate OCM blocks together to get bigger pool */
+ if (i > 0 && start == (zynq_ocm->res[curr - 1].end + 1)) {
+ zynq_ocm->res[curr - 1].end = end;
+ } else {
+#ifdef CONFIG_SMP
+ /*
+ * OCM block if placed at 0x0 has special meaning
+ * for SMP because jump trampoline is added there.
+ * Ensure that this address won't be allocated.
+ */
+ if (!base) {
+ u32 trampoline_code_size =
+ &zynq_secondary_trampoline_end -
+ &zynq_secondary_trampoline;
+ dev_dbg(&pdev->dev,
+ "Allocate reset vector table %dB\n",
+ trampoline_code_size);
+ /* postpone start offset */
+ start += trampoline_code_size;
+ }
+#endif
+ /* First resource is always initialized */
+ zynq_ocm->res[curr].start = start;
+ zynq_ocm->res[curr].end = end;
+ zynq_ocm->res[curr].flags = IORESOURCE_MEM;
+ curr++; /* Increment curr value */
+ }
+ dev_dbg(&pdev->dev, "OCM block %d, start %x, end %x\n",
+ i, start, end);
+ }
+
+ /*
+ * Separate pool allocation from OCM block detection to ensure
+ * the biggest possible pool.
+ */
+ for (i = 0; i < ZYNQ_OCM_BLOCKS; i++) {
+ unsigned long size;
+ void __iomem *virt_base;
+
+ /* Skip all zero size resources */
+ if (zynq_ocm->res[i].end == 0)
+ break;
+ dev_dbg(&pdev->dev, "OCM resources %d, start %x, end %x\n",
+ i, zynq_ocm->res[i].start, zynq_ocm->res[i].end);
+ size = resource_size(&zynq_ocm->res[i]);
+ virt_base = devm_ioremap_resource(&pdev->dev,
+ &zynq_ocm->res[i]);
+ if (IS_ERR(virt_base))
+ return PTR_ERR(virt_base);
+
+ ret = gen_pool_add_virt(zynq_ocm->pool,
+ (unsigned long)virt_base,
+ zynq_ocm->res[i].start, size, -1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Gen pool failed\n");
+ return ret;
+ }
+ dev_info(&pdev->dev, "ZYNQ OCM pool: %ld KiB @ 0x%p\n",
+ size / 1024, virt_base);
+ }
+
+ /* Get OCM config space */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ zynq_ocm->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(zynq_ocm->base))
+ return PTR_ERR(zynq_ocm->base);
+
+ /* Allocate OCM parity IRQ */
+ zynq_ocm->irq = platform_get_irq(pdev, 0);
+ if (zynq_ocm->irq < 0) {
+ dev_err(&pdev->dev, "irq resource not found\n");
+ return zynq_ocm->irq;
+ }
+ ret = devm_request_irq(&pdev->dev, zynq_ocm->irq, zynq_ocm_irq_handler,
+ 0, pdev->name, zynq_ocm);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ return ret;
+ }
+
+ /* Enable parity errors */
+ writel(ZYNQ_OCM_PARITY_ENABLE, zynq_ocm->base + ZYNQ_OCM_PARITY_CTRL);
+
+ platform_set_drvdata(pdev, zynq_ocm);
+
+ return 0;
+}
+
+/**
+ * zynq_ocm_remove - Remove method for the OCM driver
+ * @pdev: Pointer to the platform_device structure
+ *
+ * This function is called if a device is physically removed from the system or
+ * if the driver module is being unloaded. It frees all resources allocated to
+ * the device.
+ *
+ * Return: 0 on success and error value on failure
+ */
+static int zynq_ocm_remove(struct platform_device *pdev)
+{
+ struct zynq_ocm_dev *zynq_ocm = platform_get_drvdata(pdev);
+
+ if (gen_pool_avail(zynq_ocm->pool) < gen_pool_size(zynq_ocm->pool))
+ dev_dbg(&pdev->dev, "removed while SRAM allocated\n");
+
+ return 0;
+}
+
+static struct of_device_id zynq_ocm_dt_ids[] = {
+ { .compatible = "xlnx,zynq-ocmc-1.0" },
+ { /* end of table */ }
+};
+
+static struct platform_driver zynq_ocm_driver = {
+ .driver = {
+ .name = "zynq-ocm",
+ .of_match_table = zynq_ocm_dt_ids,
+ },
+ .probe = zynq_ocm_probe,
+ .remove = zynq_ocm_remove,
+};
+
+static int __init zynq_ocm_init(void)
+{
+ return platform_driver_register(&zynq_ocm_driver);
+}
+
+arch_initcall(zynq_ocm_init);
diff --git a/patches/zynq_red_pitaya.h b/patches/zynq_red_pitaya.h
new file mode 100644
index 0000000000000000000000000000000000000000..2be3bd17d46527f12d4f8ec1e060f24d4272dac9
--- /dev/null
+++ b/patches/zynq_red_pitaya.h
@@ -0,0 +1,16 @@
+#ifndef __CONFIG_ZYNQ_RED_PITAYA_H
+#define __CONFIG_ZYNQ_RED_PITAYA_H
+
+#include <configs/zynq-common.h>
+
+#undef CONFIG_SYS_I2C_EEPROM_ADDR_LEN
+#undef CONFIG_SYS_I2C_EEPROM_ADDR
+#undef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS
+#undef CONFIG_SYS_EEPROM_SIZE
+
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
+#define CONFIG_SYS_I2C_EEPROM_ADDR 0x50
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 5
+#define CONFIG_SYS_EEPROM_SIZE 8192 /* Bytes */
+
+#endif /* __CONFIG_ZYNQ_RED_PITAYA_H */
diff --git a/patches/zynq_red_pitaya_defconfig b/patches/zynq_red_pitaya_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..6b6197b2750e68e1107a02975ebe6dad68af6955
--- /dev/null
+++ b/patches/zynq_red_pitaya_defconfig
@@ -0,0 +1,24 @@
+CONFIG_ARM=y
+CONFIG_ARCH_ZYNQ=y
+CONFIG_SYS_TEXT_BASE=0x4000000
+CONFIG_SYS_CUSTOM_LDSCRIPT=y
+CONFIG_SYS_LDSCRIPT="arch/arm/mach-zynq/u-boot.lds"
+CONFIG_DEFAULT_DEVICE_TREE="zynq-red-pitaya"
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_CMD_MMC=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_EEPROM=y
+CONFIG_ENV_OFFSET=0x1800
+CONFIG_ENV_SIZE=0x400
+CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_MISC=y
+CONFIG_I2C_EEPROM=y
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_CADENCE=y
+CONFIG_SYS_I2C_EEPROM_ADDR=0x50
+CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ZYNQ=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_ZYNQ_GEM=y
+CONFIG_ZYNQ_SERIAL=y