aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-zynqmp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-zynqmp')
-rw-r--r--arch/arm/mach-zynqmp/Kconfig206
-rw-r--r--arch/arm/mach-zynqmp/Makefile14
-rw-r--r--arch/arm/mach-zynqmp/aes.c58
-rw-r--r--arch/arm/mach-zynqmp/clk.c47
-rw-r--r--arch/arm/mach-zynqmp/cpu.c226
-rw-r--r--arch/arm/mach-zynqmp/ecc_spl_init.c162
-rw-r--r--arch/arm/mach-zynqmp/handoff.c106
-rw-r--r--arch/arm/mach-zynqmp/include/mach/clk.h12
-rw-r--r--arch/arm/mach-zynqmp/include/mach/ecc_spl_init.h13
-rw-r--r--arch/arm/mach-zynqmp/include/mach/hardware.h186
-rw-r--r--arch/arm/mach-zynqmp/include/mach/psu_init_gpl.h26
-rw-r--r--arch/arm/mach-zynqmp/include/mach/sys_proto.h57
-rw-r--r--arch/arm/mach-zynqmp/include/mach/zynqmp_aes.h34
-rwxr-xr-xarch/arm/mach-zynqmp/mkimage_fit_atf.sh240
-rw-r--r--arch/arm/mach-zynqmp/mp.c368
-rw-r--r--arch/arm/mach-zynqmp/psu_spl_init.c88
-rw-r--r--arch/arm/mach-zynqmp/spl.c141
-rw-r--r--arch/arm/mach-zynqmp/zynqmp.c431
18 files changed, 2415 insertions, 0 deletions
diff --git a/arch/arm/mach-zynqmp/Kconfig b/arch/arm/mach-zynqmp/Kconfig
new file mode 100644
index 00000000000..aea13622b68
--- /dev/null
+++ b/arch/arm/mach-zynqmp/Kconfig
@@ -0,0 +1,206 @@
+if ARCH_ZYNQMP
+
+config SYS_BOARD
+ string "Board name"
+ default "zynqmp"
+
+config SYS_VENDOR
+ string "Vendor name"
+ default "xilinx"
+
+config SYS_SOC
+ default "zynqmp"
+
+config SYS_MEM_RSVD_FOR_MMU
+ bool "Reserve memory for MMU Table"
+ help
+ If defined this option is used to setup different space for
+ MMU table than the one which will be allocated during
+ relocation.
+
+config BOOT_INIT_FILE
+ string "boot.bin init register filename"
+ depends on SPL
+ default ""
+ help
+ Add register writes to boot.bin format (max 256 pairs).
+ Expect a table of register-value pairs, e.g. "0x12345678 0x4321"
+
+config PMUFW_INIT_FILE
+ string "PMU firmware"
+ depends on SPL
+ default ""
+ help
+ Include external PMUFW (Platform Management Unit FirmWare) to
+ a Xilinx bootable image (boot.bin).
+
+config ZYNQMP_SPL_PM_CFG_OBJ_FILE
+ string "PMU firmware configuration object to load at runtime by SPL"
+ depends on SPL
+ help
+ Path to a binary PMU firmware configuration object to be linked
+ into U-Boot SPL and loaded at runtime into the PMU firmware.
+
+ The ZynqMP Power Management Unit (PMU) needs a configuration
+ object for most SoC peripherals to work. To have it loaded by
+ U-Boot SPL set here the file name (absolute path or relative to
+ the top source tree) of your configuration, which must be a
+ binary blob. It will be linked in the SPL binary and loaded
+ into the PMU firmware by U-Boot SPL during board
+ initialization.
+
+ Leave this option empty if your PMU firmware has a hard-coded
+ configuration object or you are loading it by any other means.
+
+config ZYNQMP_NO_DDR
+ bool "Disable DDR MMU mapping"
+ help
+ This option configures MMU with no DDR to avoid speculative
+ access to DDR memory where DDR is not present.
+
+config SPL_ZYNQMP_DRAM_ECC_INIT
+ bool "Initialize DRAM ECC"
+ depends on SPL
+ help
+ This option initializes all memory to 0xdeadbeef. Must be set if your
+ memory is of ECC type.
+
+config SPL_ZYNQMP_DRAM_BANK1_BASE
+ depends on SPL_ZYNQMP_DRAM_ECC_INIT
+ hex "DRAM Bank1 address"
+ default 0x00000000
+ help
+ Start address of DRAM ECC bank1
+
+config SPL_ZYNQMP_DRAM_BANK1_LEN
+ depends on SPL_ZYNQMP_DRAM_ECC_INIT
+ hex "DRAM Bank1 size"
+ default 0x80000000
+ help
+ Size in bytes of the DRAM ECC bank1
+
+config SPL_ZYNQMP_DRAM_BANK2_BASE
+ depends on SPL_ZYNQMP_DRAM_ECC_INIT
+ hex "DRAM Bank2 address"
+ default 0x800000000
+ help
+ Start address of DRAM ECC bank2
+
+config SPL_ZYNQMP_DRAM_BANK2_LEN
+ depends on SPL_ZYNQMP_DRAM_ECC_INIT
+ hex "DRAM Bank2 size"
+ default 0x0
+ help
+ Size in bytes of the DRAM ECC bank2. A null size takes no action.
+
+config SYS_MALLOC_F_LEN
+ default 0x600
+
+config DEFINE_TCM_OCM_MMAP
+ bool "Define TCM and OCM memory in MMU Table"
+ default y if MP
+ help
+ This option if enabled defines the TCM and OCM memory and its
+ memory attributes in MMU table entry.
+
+config ZYNQMP_PSU_INIT_ENABLED
+ bool "Include psu_init"
+ select BOARD_EARLY_INIT_F
+ help
+ Include psu_init to full u-boot.
+
+config SPL_ZYNQMP_PSU_INIT_ENABLED
+ bool "Include psu_init in SPL"
+ depends on SPL
+ default y
+ select BOARD_EARLY_INIT_F
+ help
+ Include psu_init by default in SPL.
+
+config SPL_ZYNQMP_ALT_BOOTMODE_ENABLED
+ bool "Overwrite SPL bootmode"
+ depends on SPL
+ help
+ Overwrite bootmode selected via boot mode pins to tell SPL what should
+ be the next boot device.
+
+config SPL_ZYNQMP_RESTORE_JTAG
+ bool "Restore JTAG"
+ depends on SPL
+ help
+ Booting SPL in secure mode causes the CSU to disable the JTAG interface
+ even if no eFuses were burnt. This option restores the interface if
+ possible.
+
+config ZYNQ_SDHCI_MAX_FREQ
+ default 200000000
+
+config SPL_ZYNQMP_ALT_BOOTMODE
+ hex
+ default 0x0 if JTAG_MODE
+ default 0x1 if QSPI_MODE_24BIT
+ default 0x2 if QSPI_MODE_32BIT
+ default 0x3 if SD_MODE
+ default 0x4 if NAND_MODE
+ default 0x5 if SD_MODE1
+ default 0x6 if EMMC_MODE
+ default 0x7 if USB_MODE
+ default 0xa if SW_USBHOST_MODE
+ default 0xb if SW_SATA_MODE
+ default 0xe if SD1_LSHFT_MODE
+
+choice
+ prompt "Boot mode"
+ depends on SPL_ZYNQMP_ALT_BOOTMODE_ENABLED
+ default JTAG_MODE
+
+config JTAG_MODE
+ bool "JTAG_MODE"
+
+config QSPI_MODE_24BIT
+ bool "QSPI_MODE_24BIT"
+
+config QSPI_MODE_32BIT
+ bool "QSPI_MODE_32BIT"
+
+config SD_MODE
+ bool "SD_MODE"
+
+config SD_MODE1
+ bool "SD_MODE1"
+
+config NAND_MODE
+ bool "NAND_MODE"
+
+config EMMC_MODE
+ bool "EMMC_MODE"
+
+config USB_MODE
+ bool "USB"
+
+config SW_USBHOST_MODE
+ bool "SW USBHOST_MODE"
+
+config SW_SATA_MODE
+ bool "SW SATA_MODE"
+
+config SD1_LSHFT_MODE
+ bool "SD1_LSHFT_MODE"
+
+endchoice
+
+config CMD_ZYNQMP
+ bool "Enable ZynqMP specific commands"
+ depends on ZYNQMP_FIRMWARE
+ default y
+ help
+ Enable ZynqMP specific commands like "zynqmp secure"
+ which is used for zynqmp secure image verification.
+ The secure image is a xilinx specific BOOT.BIN with
+ either authentication or encryption or both encryption
+ and authentication feature enabled while generating
+ BOOT.BIN using Xilinx bootgen tool.
+
+source "board/xilinx/Kconfig"
+
+endif
diff --git a/arch/arm/mach-zynqmp/Makefile b/arch/arm/mach-zynqmp/Makefile
new file mode 100644
index 00000000000..38be1627eeb
--- /dev/null
+++ b/arch/arm/mach-zynqmp/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2014 - 2015 Xilinx, Inc.
+# Michal Simek <michal.simek@amd.com>
+
+obj-y += aes.o clk.o cpu.o
+obj-$(CONFIG_MP) += mp.o
+obj-$(CONFIG_SPL_BUILD) += spl.o handoff.o psu_spl_init.o
+obj-$(CONFIG_SPL_ZYNQMP_DRAM_ECC_INIT) += ecc_spl_init.o
+obj-$(CONFIG_$(SPL_)ZYNQMP_PSU_INIT_ENABLED) += psu_spl_init.o
+
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_CMD_ZYNQMP) += zynqmp.o
+endif # !CONFIG_SPL_BUILD
diff --git a/arch/arm/mach-zynqmp/aes.c b/arch/arm/mach-zynqmp/aes.c
new file mode 100644
index 00000000000..9a05fbf9c11
--- /dev/null
+++ b/arch/arm/mach-zynqmp/aes.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018 Xilinx, Inc.
+ * Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
+ *
+ * Copyright (C) 2023 Weidmueller Interface GmbH & Co. KG <oss@weidmueller.com>
+ * Christian Taedcke <christian.taedcke@weidmueller.com>
+ */
+
+#include <mach/zynqmp_aes.h>
+#include <linux/errno.h>
+#include <asm/arch/sys_proto.h>
+#include <cpu_func.h>
+#include <memalign.h>
+#include <zynqmp_firmware.h>
+
+int zynqmp_aes_operation(struct zynqmp_aes *aes)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ if (zynqmp_firmware_version() <= PMUFW_V1_0)
+ return -ENOENT;
+
+ if (aes->srcaddr && aes->ivaddr && aes->dstaddr) {
+ flush_dcache_range(aes->srcaddr,
+ aes->srcaddr +
+ roundup(aes->len, ARCH_DMA_MINALIGN));
+ flush_dcache_range(aes->ivaddr,
+ aes->ivaddr +
+ roundup(IV_SIZE, ARCH_DMA_MINALIGN));
+ flush_dcache_range(aes->dstaddr,
+ aes->dstaddr +
+ roundup(aes->len, ARCH_DMA_MINALIGN));
+ }
+
+ if (aes->keysrc == 0) {
+ if (aes->keyaddr == 0)
+ return -EINVAL;
+
+ flush_dcache_range(aes->keyaddr,
+ aes->keyaddr +
+ roundup(KEY_PTR_LEN, ARCH_DMA_MINALIGN));
+ }
+
+ flush_dcache_range((ulong)aes, (ulong)(aes) +
+ roundup(sizeof(struct zynqmp_aes), ARCH_DMA_MINALIGN));
+
+ ret = xilinx_pm_request(PM_SECURE_AES, upper_32_bits((ulong)aes),
+ lower_32_bits((ulong)aes), 0, 0, ret_payload);
+ if (ret || ret_payload[1]) {
+ printf("Failed: AES op status:0x%x, errcode:0x%x\n",
+ ret, ret_payload[1]);
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/arch/arm/mach-zynqmp/clk.c b/arch/arm/mach-zynqmp/clk.c
new file mode 100644
index 00000000000..9b573b1746a
--- /dev/null
+++ b/arch/arm/mach-zynqmp/clk.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2014 - 2015 Xilinx, Inc.
+ * Michal Simek <michal.simek@amd.com>
+ */
+
+#include <init.h>
+#include <time.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+unsigned long zynqmp_get_system_timer_freq(void)
+{
+ u32 ver = zynqmp_get_silicon_version();
+
+ switch (ver) {
+ case ZYNQMP_CSU_VERSION_QEMU:
+ return 50000000;
+ }
+
+ return 100000000;
+}
+
+#ifdef CONFIG_CLOCKS
+/**
+ * set_cpu_clk_info() - Initialize clock framework
+ * Always returns zero.
+ *
+ * This function is called from common code after relocation and sets up the
+ * clock framework. The framework must not be used before this function had been
+ * called.
+ */
+int set_cpu_clk_info(void)
+{
+ gd->cpu_clk = get_tbclk();
+
+ gd->bd->bi_arm_freq = gd->cpu_clk / 1000000;
+
+ gd->bd->bi_dsp_freq = 0;
+
+ return 0;
+}
+#endif
diff --git a/arch/arm/mach-zynqmp/cpu.c b/arch/arm/mach-zynqmp/cpu.c
new file mode 100644
index 00000000000..07668c94689
--- /dev/null
+++ b/arch/arm/mach-zynqmp/cpu.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2014 - 2015 Xilinx, Inc.
+ * Michal Simek <michal.simek@amd.com>
+ */
+
+#include <init.h>
+#include <time.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/armv8/mmu.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <zynqmp_firmware.h>
+#include <asm/cache.h>
+#include <dm/platdata.h>
+
+#define ZYNQ_SILICON_VER_MASK 0xF000
+#define ZYNQ_SILICON_VER_SHIFT 12
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Number of filled static entries and also the first empty
+ * slot in zynqmp_mem_map.
+ */
+#define ZYNQMP_MEM_MAP_USED 4
+
+#if !defined(CONFIG_ZYNQMP_NO_DDR)
+#define DRAM_BANKS CONFIG_NR_DRAM_BANKS
+#else
+#define DRAM_BANKS 0
+#endif
+
+#if defined(CONFIG_DEFINE_TCM_OCM_MMAP)
+#define TCM_MAP 1
+#else
+#define TCM_MAP 0
+#endif
+
+/* +1 is end of list which needs to be empty */
+#define ZYNQMP_MEM_MAP_MAX (ZYNQMP_MEM_MAP_USED + DRAM_BANKS + TCM_MAP + 1)
+
+static struct mm_region zynqmp_mem_map[ZYNQMP_MEM_MAP_MAX] = {
+ {
+ .virt = 0x80000000UL,
+ .phys = 0x80000000UL,
+ .size = 0x70000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ .virt = 0xf8000000UL,
+ .phys = 0xf8000000UL,
+ .size = 0x07e00000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ .virt = 0x400000000UL,
+ .phys = 0x400000000UL,
+ .size = 0x400000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ .virt = 0x1000000000UL,
+ .phys = 0x1000000000UL,
+ .size = 0xf000000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }
+};
+
+void mem_map_fill(void)
+{
+ int banks = ZYNQMP_MEM_MAP_USED;
+
+#if defined(CONFIG_DEFINE_TCM_OCM_MMAP)
+ zynqmp_mem_map[banks].virt = 0xffe00000UL;
+ zynqmp_mem_map[banks].phys = 0xffe00000UL;
+ zynqmp_mem_map[banks].size = 0x00200000UL;
+ zynqmp_mem_map[banks].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE;
+ banks = banks + 1;
+#endif
+
+#if !defined(CONFIG_ZYNQMP_NO_DDR)
+ for (int i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ /* Zero size means no more DDR that's this is end */
+ if (!gd->bd->bi_dram[i].size)
+ break;
+
+ zynqmp_mem_map[banks].virt = gd->bd->bi_dram[i].start;
+ zynqmp_mem_map[banks].phys = gd->bd->bi_dram[i].start;
+ zynqmp_mem_map[banks].size = gd->bd->bi_dram[i].size;
+ zynqmp_mem_map[banks].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_INNER_SHARE;
+ banks = banks + 1;
+ }
+#endif
+}
+
+struct mm_region *mem_map = zynqmp_mem_map;
+
+u64 get_page_table_size(void)
+{
+ return 0x14000;
+}
+
+#if defined(CONFIG_SYS_MEM_RSVD_FOR_MMU) || defined(CONFIG_DEFINE_TCM_OCM_MMAP)
+void tcm_init(u8 mode)
+{
+ puts("WARNING: Initializing TCM overwrites TCM content\n");
+ initialize_tcm(mode);
+ memset((void *)ZYNQMP_TCM_BASE_ADDR, 0, ZYNQMP_TCM_SIZE);
+}
+#endif
+
+#ifdef CONFIG_SYS_MEM_RSVD_FOR_MMU
+int arm_reserve_mmu(void)
+{
+ tcm_init(TCM_LOCK);
+ gd->arch.tlb_size = PGTABLE_SIZE;
+ gd->arch.tlb_addr = ZYNQMP_TCM_BASE_ADDR;
+
+ return 0;
+}
+#endif
+
+static unsigned int zynqmp_get_silicon_version_secure(void)
+{
+ u32 ver;
+
+ ver = readl(&csu_base->version);
+ ver &= ZYNQMP_SILICON_VER_MASK;
+ ver >>= ZYNQMP_SILICON_VER_SHIFT;
+
+ return ver;
+}
+
+unsigned int zynqmp_get_silicon_version(void)
+{
+ if (current_el() == 3)
+ return zynqmp_get_silicon_version_secure();
+
+ gd->cpu_clk = get_tbclk();
+
+ switch (gd->cpu_clk) {
+ case 50000000:
+ return ZYNQMP_CSU_VERSION_QEMU;
+ }
+
+ return ZYNQMP_CSU_VERSION_SILICON;
+}
+
+static int zynqmp_mmio_rawwrite(const u32 address,
+ const u32 mask,
+ const u32 value)
+{
+ u32 data;
+ u32 value_local = value;
+ int ret;
+
+ ret = zynqmp_mmio_read(address, &data);
+ if (ret)
+ return ret;
+
+ data &= ~mask;
+ value_local &= mask;
+ value_local |= data;
+ writel(value_local, (ulong)address);
+ return 0;
+}
+
+static int zynqmp_mmio_rawread(const u32 address, u32 *value)
+{
+ *value = readl((ulong)address);
+ return 0;
+}
+
+int zynqmp_mmio_write(const u32 address,
+ const u32 mask,
+ const u32 value)
+{
+ if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3)
+ return zynqmp_mmio_rawwrite(address, mask, value);
+#if defined(CONFIG_ZYNQMP_FIRMWARE)
+ else
+ return xilinx_pm_request(PM_MMIO_WRITE, address, mask,
+ value, 0, NULL);
+#endif
+
+ return -EINVAL;
+}
+
+int zynqmp_mmio_read(const u32 address, u32 *value)
+{
+ u32 ret = -EINVAL;
+
+ if (!value)
+ return ret;
+
+ if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {
+ ret = zynqmp_mmio_rawread(address, value);
+ }
+#if defined(CONFIG_ZYNQMP_FIRMWARE)
+ else {
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ ret = xilinx_pm_request(PM_MMIO_READ, address, 0, 0,
+ 0, ret_payload);
+ *value = ret_payload[1];
+ }
+#endif
+
+ return ret;
+}
+
+U_BOOT_DRVINFO(soc_xilinx_zynqmp) = {
+ .name = "soc_xilinx_zynqmp",
+};
diff --git a/arch/arm/mach-zynqmp/ecc_spl_init.c b/arch/arm/mach-zynqmp/ecc_spl_init.c
new file mode 100644
index 00000000000..1eef1078951
--- /dev/null
+++ b/arch/arm/mach-zynqmp/ecc_spl_init.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2015 - 2020 Xilinx, Inc.
+ *
+ * Jorge Ramirez-Ortiz <jorge@foundries.io>
+ */
+
+#include <cpu_func.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/ecc_spl_init.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#define ZDMA_TRANSFER_MAX_LEN (0x3FFFFFFFU - 7U)
+#define ZDMA_CH_STATUS ((ADMA_CH0_BASEADDR) + 0x0000011CU)
+#define ZDMA_CH_STATUS_STATE_MASK 0x00000003U
+#define ZDMA_CH_STATUS_STATE_DONE 0x00000000U
+#define ZDMA_CH_STATUS_STATE_ERR 0x00000003U
+#define ZDMA_CH_CTRL0 ((ADMA_CH0_BASEADDR) + 0x00000110U)
+#define ZDMA_CH_CTRL0_POINT_TYPE_MASK (u32)0x00000040U
+#define ZDMA_CH_CTRL0_POINT_TYPE_NORMAL (u32)0x00000000U
+#define ZDMA_CH_CTRL0_MODE_MASK (u32)0x00000030U
+#define ZDMA_CH_CTRL0_MODE_WR_ONLY (u32)0x00000010U
+#define ZDMA_CH_CTRL0_TOTAL_BYTE_COUNT ((ADMA_CH0_BASEADDR) + 0x00000188U)
+#define ZDMA_CH_WR_ONLY_WORD0 ((ADMA_CH0_BASEADDR) + 0x00000148U)
+#define ZDMA_CH_WR_ONLY_WORD1 ((ADMA_CH0_BASEADDR) + 0x0000014CU)
+#define ZDMA_CH_WR_ONLY_WORD2 ((ADMA_CH0_BASEADDR) + 0x00000150U)
+#define ZDMA_CH_WR_ONLY_WORD3 ((ADMA_CH0_BASEADDR) + 0x00000154U)
+#define ZDMA_CH_DST_DSCR_WORD0 ((ADMA_CH0_BASEADDR) + 0x00000138U)
+#define ZDMA_CH_DST_DSCR_WORD0_LSB_MASK 0xFFFFFFFFU
+#define ZDMA_CH_DST_DSCR_WORD1 ((ADMA_CH0_BASEADDR) + 0x0000013CU)
+#define ZDMA_CH_DST_DSCR_WORD1_MSB_MASK 0x0001FFFFU
+#define ZDMA_CH_SRC_DSCR_WORD2 ((ADMA_CH0_BASEADDR) + 0x00000130U)
+#define ZDMA_CH_DST_DSCR_WORD2 ((ADMA_CH0_BASEADDR) + 0x00000140U)
+#define ZDMA_CH_CTRL2 ((ADMA_CH0_BASEADDR) + 0x00000200U)
+#define ZDMA_CH_CTRL2_EN_MASK 0x00000001U
+#define ZDMA_CH_ISR ((ADMA_CH0_BASEADDR) + 0x00000100U)
+#define ZDMA_CH_ISR_DMA_DONE_MASK 0x00000400U
+#define ECC_INIT_VAL_WORD 0xDEADBEEFU
+
+#define ZDMA_IDLE_TIMEOUT_USEC 1000000
+#define ZDMA_DONE_TIMEOUT_USEC 5000000
+
+static void ecc_zdma_restore(void)
+{
+ /* Restore reset values for the DMA registers used */
+ writel(ZDMA_CH_CTRL0, 0x00000080U);
+ writel(ZDMA_CH_WR_ONLY_WORD0, 0x00000000U);
+ writel(ZDMA_CH_WR_ONLY_WORD1, 0x00000000U);
+ writel(ZDMA_CH_WR_ONLY_WORD2, 0x00000000U);
+ writel(ZDMA_CH_WR_ONLY_WORD3, 0x00000000U);
+ writel(ZDMA_CH_DST_DSCR_WORD0, 0x00000000U);
+ writel(ZDMA_CH_DST_DSCR_WORD1, 0x00000000U);
+ writel(ZDMA_CH_SRC_DSCR_WORD2, 0x00000000U);
+ writel(ZDMA_CH_DST_DSCR_WORD2, 0x00000000U);
+ writel(ZDMA_CH_CTRL0_TOTAL_BYTE_COUNT, 0x00000000U);
+}
+
+static void ecc_dram_bank_init(u64 addr, u64 len)
+{
+ bool retry = true;
+ u32 timeout;
+ u64 bytes;
+ u32 size;
+ u64 src;
+ u32 reg;
+
+ if (!len)
+ return;
+retry:
+ bytes = len;
+ src = addr;
+ ecc_zdma_restore();
+ while (bytes > 0) {
+ size = bytes > ZDMA_TRANSFER_MAX_LEN ?
+ ZDMA_TRANSFER_MAX_LEN : (u32)bytes;
+
+ /* Wait until the DMA is in idle state */
+ timeout = ZDMA_IDLE_TIMEOUT_USEC;
+ do {
+ udelay(1);
+ reg = readl(ZDMA_CH_STATUS);
+ reg &= ZDMA_CH_STATUS_STATE_MASK;
+ if (!timeout--) {
+ puts("error, ECC DMA failed to idle\n");
+ goto done;
+ }
+
+ } while ((reg != ZDMA_CH_STATUS_STATE_DONE) &&
+ (reg != ZDMA_CH_STATUS_STATE_ERR));
+
+ /* Enable Simple (Write Only) Mode */
+ reg = readl(ZDMA_CH_CTRL0);
+ reg &= (ZDMA_CH_CTRL0_POINT_TYPE_MASK |
+ ZDMA_CH_CTRL0_MODE_MASK);
+ reg |= (ZDMA_CH_CTRL0_POINT_TYPE_NORMAL |
+ ZDMA_CH_CTRL0_MODE_WR_ONLY);
+ writel(reg, ZDMA_CH_CTRL0);
+
+ /* Fill in the data to be written */
+ writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD0);
+ writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD1);
+ writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD2);
+ writel(ECC_INIT_VAL_WORD, ZDMA_CH_WR_ONLY_WORD3);
+
+ /* Write Destination Address */
+ writel((u32)(src & ZDMA_CH_DST_DSCR_WORD0_LSB_MASK),
+ ZDMA_CH_DST_DSCR_WORD0);
+ writel((u32)((src >> 32) & ZDMA_CH_DST_DSCR_WORD1_MSB_MASK),
+ ZDMA_CH_DST_DSCR_WORD1);
+
+ /* Size to be Transferred. Recommended to set both src and dest sizes */
+ writel(size, ZDMA_CH_SRC_DSCR_WORD2);
+ writel(size, ZDMA_CH_DST_DSCR_WORD2);
+
+ /* DMA Enable */
+ reg = readl(ZDMA_CH_CTRL2);
+ reg |= ZDMA_CH_CTRL2_EN_MASK;
+ writel(reg, ZDMA_CH_CTRL2);
+
+ /* Check the status of the transfer by polling on DMA Done */
+ timeout = ZDMA_DONE_TIMEOUT_USEC;
+ do {
+ udelay(1);
+ reg = readl(ZDMA_CH_ISR);
+ reg &= ZDMA_CH_ISR_DMA_DONE_MASK;
+ if (!timeout--) {
+ puts("error, ECC DMA timeout\n");
+ goto done;
+ }
+ } while (reg != ZDMA_CH_ISR_DMA_DONE_MASK);
+
+ /* Clear DMA status */
+ reg = readl(ZDMA_CH_ISR);
+ reg |= ZDMA_CH_ISR_DMA_DONE_MASK;
+ writel(ZDMA_CH_ISR_DMA_DONE_MASK, ZDMA_CH_ISR);
+
+ /* Read the channel status for errors */
+ reg = readl(ZDMA_CH_STATUS);
+ if (reg == ZDMA_CH_STATUS_STATE_ERR) {
+ if (retry) {
+ retry = false;
+ goto retry;
+ }
+ puts("error, ECC DMA error\n");
+ break;
+ }
+
+ bytes -= size;
+ src += size;
+ }
+done:
+ ecc_zdma_restore();
+}
+
+void zynqmp_ecc_init(void)
+{
+ ecc_dram_bank_init(CONFIG_SPL_ZYNQMP_DRAM_BANK1_BASE,
+ CONFIG_SPL_ZYNQMP_DRAM_BANK1_LEN);
+ ecc_dram_bank_init(CONFIG_SPL_ZYNQMP_DRAM_BANK2_BASE,
+ CONFIG_SPL_ZYNQMP_DRAM_BANK2_LEN);
+}
diff --git a/arch/arm/mach-zynqmp/handoff.c b/arch/arm/mach-zynqmp/handoff.c
new file mode 100644
index 00000000000..b007307e1f3
--- /dev/null
+++ b/arch/arm/mach-zynqmp/handoff.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2016 - 2017 Xilinx, Inc.
+ *
+ * Michal Simek <michal.simek@amd.com>
+ */
+
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <spl.h>
+
+/*
+ * atfhandoffparams
+ * Parameter bitfield encoding
+ * -----------------------------------------------------------------------------
+ * Exec State 0 0 -> Aarch64, 1-> Aarch32
+ * endianness 1 0 -> LE, 1 -> BE
+ * secure (TZ) 2 0 -> Non secure, 1 -> secure
+ * EL 3:4 00 -> EL0, 01 -> EL1, 10 -> EL2, 11 -> EL3
+ * CPU# 5:6 00 -> A53_0, 01 -> A53_1, 10 -> A53_2, 11 -> A53_3
+ */
+
+#define FSBL_FLAGS_ESTATE_SHIFT 0
+#define FSBL_FLAGS_ESTATE_MASK (1 << FSBL_FLAGS_ESTATE_SHIFT)
+#define FSBL_FLAGS_ESTATE_A64 0
+#define FSBL_FLAGS_ESTATE_A32 1
+
+#define FSBL_FLAGS_ENDIAN_SHIFT 1
+#define FSBL_FLAGS_ENDIAN_MASK (1 << FSBL_FLAGS_ENDIAN_SHIFT)
+#define FSBL_FLAGS_ENDIAN_LE 0
+#define FSBL_FLAGS_ENDIAN_BE 1
+
+#define FSBL_FLAGS_TZ_SHIFT 2
+#define FSBL_FLAGS_TZ_MASK (1 << FSBL_FLAGS_TZ_SHIFT)
+#define FSBL_FLAGS_NON_SECURE 0
+#define FSBL_FLAGS_SECURE 1
+
+#define FSBL_FLAGS_EL_SHIFT 3
+#define FSBL_FLAGS_EL_MASK (3 << FSBL_FLAGS_EL_SHIFT)
+#define FSBL_FLAGS_EL0 0
+#define FSBL_FLAGS_EL1 1
+#define FSBL_FLAGS_EL2 2
+#define FSBL_FLAGS_EL3 3
+
+#define FSBL_FLAGS_CPU_SHIFT 5
+#define FSBL_FLAGS_CPU_MASK (3 << FSBL_FLAGS_CPU_SHIFT)
+#define FSBL_FLAGS_A53_0 0
+#define FSBL_FLAGS_A53_1 1
+#define FSBL_FLAGS_A53_2 2
+#define FSBL_FLAGS_A53_3 3
+
+#define FSBL_MAX_PARTITIONS 8
+
+/* Structure corresponding to each partition entry */
+struct xfsbl_partition {
+ uint64_t entry_point;
+ uint64_t flags;
+};
+
+/* Structure for handoff parameters to ARM Trusted Firmware (ATF) */
+struct xfsbl_atf_handoff_params {
+ uint8_t magic[4];
+ uint32_t num_entries;
+ struct xfsbl_partition partition[FSBL_MAX_PARTITIONS];
+};
+
+#ifdef CONFIG_SPL_ATF
+struct bl31_params *bl2_plat_get_bl31_params(uintptr_t bl32_entry,
+ uintptr_t bl33_entry,
+ uintptr_t fdt_addr)
+{
+ struct xfsbl_atf_handoff_params *atfhandoffparams;
+ u32 index = 0;
+
+ atfhandoffparams = (void *)CONFIG_SPL_TEXT_BASE;
+ atfhandoffparams->magic[0] = 'X';
+ atfhandoffparams->magic[1] = 'L';
+ atfhandoffparams->magic[2] = 'N';
+ atfhandoffparams->magic[3] = 'X';
+
+ debug("Creating handoff:\n");
+
+ if (bl32_entry) {
+ debug(" to BL32 at 0x%x EL-1, Secure\n", (u32)bl32_entry);
+ atfhandoffparams->partition[index].entry_point = bl32_entry;
+ atfhandoffparams->partition[index].flags = FSBL_FLAGS_EL1 << FSBL_FLAGS_EL_SHIFT |
+ FSBL_FLAGS_SECURE << FSBL_FLAGS_TZ_SHIFT;
+ index++;
+ }
+
+ if (bl33_entry) {
+ debug(" to BL33 at 0x%x EL-2\n", (u32)bl33_entry);
+ atfhandoffparams->partition[index].entry_point = bl33_entry;
+ atfhandoffparams->partition[index].flags = FSBL_FLAGS_EL2 <<
+ FSBL_FLAGS_EL_SHIFT;
+ index++;
+ }
+
+ atfhandoffparams->num_entries = index;
+
+ writel(CONFIG_SPL_TEXT_BASE, &pmu_base->gen_storage6);
+
+ return NULL;
+}
+#endif
diff --git a/arch/arm/mach-zynqmp/include/mach/clk.h b/arch/arm/mach-zynqmp/include/mach/clk.h
new file mode 100644
index 00000000000..9918d469122
--- /dev/null
+++ b/arch/arm/mach-zynqmp/include/mach/clk.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2014 - 2015 Xilinx, Inc.
+ * Michal Simek <michal.simek@amd.com>
+ */
+
+#ifndef _ASM_ARCH_CLK_H_
+#define _ASM_ARCH_CLK_H_
+
+unsigned long zynqmp_get_system_timer_freq(void);
+
+#endif /* _ASM_ARCH_CLK_H_ */
diff --git a/arch/arm/mach-zynqmp/include/mach/ecc_spl_init.h b/arch/arm/mach-zynqmp/include/mach/ecc_spl_init.h
new file mode 100644
index 00000000000..b4b6fcf53bc
--- /dev/null
+++ b/arch/arm/mach-zynqmp/include/mach/ecc_spl_init.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2015 - 2020 Xilinx, Inc.
+ *
+ * Jorge Ramirez-Ortiz <jorge@foundries.io>
+ */
+
+#ifndef __ARCH_ZYNQMP_ECC_INIT_H
+#define __ARCH_ZYNQMP_ECC_INIT_H
+
+void zynqmp_ecc_init(void);
+
+#endif
diff --git a/arch/arm/mach-zynqmp/include/mach/hardware.h b/arch/arm/mach-zynqmp/include/mach/hardware.h
new file mode 100644
index 00000000000..8cb6494e52c
--- /dev/null
+++ b/arch/arm/mach-zynqmp/include/mach/hardware.h
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2014 - 2015 Xilinx, Inc.
+ * Michal Simek <michal.simek@amd.com>
+ */
+
+#ifndef _ASM_ARCH_HARDWARE_H
+#define _ASM_ARCH_HARDWARE_H
+
+#ifndef __ASSEMBLY__
+#include <linux/bitops.h>
+#endif
+
+#define ZYNQMP_TCM_BASE_ADDR 0xFFE00000
+#define ZYNQMP_TCM_SIZE 0x40000
+
+#define ZYNQMP_CRL_APB_BASEADDR 0xFF5E0000
+#define ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT 0x1000000
+#define ZYNQMP_CRL_APB_BOOT_PIN_CTRL_OUT_EN_SHIFT 0
+#define ZYNQMP_CRL_APB_BOOT_PIN_CTRL_OUT_VAL_SHIFT 8
+
+#define ZYNQMP_AMS_PS_SYSMON_BASEADDR 0XFFA50800
+#define ZYNQMP_AMS_PS_SYSMON_ANALOG_BUS ((ZYNQMP_AMS_PS_SYSMON_BASEADDR) \
+ + 0x00000114)
+#define ZYNQMP_PS_SYSMON_ANALOG_BUS_VAL 0x00003210
+
+#define ADMA_CH0_BASEADDR 0xFFA80000
+
+#define PS_MODE0 BIT(0)
+#define PS_MODE1 BIT(1)
+#define PS_MODE2 BIT(2)
+#define PS_MODE3 BIT(3)
+
+#define RESET_REASON_DEBUG_SYS BIT(6)
+#define RESET_REASON_SOFT BIT(5)
+#define RESET_REASON_SRST BIT(4)
+#define RESET_REASON_PSONLY BIT(3)
+#define RESET_REASON_PMU BIT(2)
+#define RESET_REASON_INTERNAL BIT(1)
+#define RESET_REASON_EXTERNAL BIT(0)
+
+#define CRLAPB_DBG_LPD_CTRL_SETUP_CLK 0x01002002
+#define CRLAPB_RST_LPD_DBG_RESET 0
+
+struct crlapb_regs {
+ u32 reserved0[36];
+ u32 cpu_r5_ctrl; /* 0x90 */
+ u32 reserved1[7];
+ u32 dbg_lpd_ctrl; /* 0xB0 */
+ u32 reserved2[29];
+ u32 timestamp_ref_ctrl; /* 0x128 */
+ u32 reserved3[53];
+ u32 boot_mode; /* 0x200 */
+ u32 reserved4_0[7];
+ u32 reset_reason; /* 0x220 */
+ u32 reserved4_1[6];
+ u32 rst_lpd_top; /* 0x23C */
+ u32 rst_lpd_dbg; /* 0x240 */
+ u32 reserved5[3];
+ u32 boot_pin_ctrl; /* 0x250 */
+ u32 reserved6[21];
+};
+
+#define crlapb_base ((struct crlapb_regs *)ZYNQMP_CRL_APB_BASEADDR)
+
+#define ZYNQMP_IOU_SCNTR_SECURE 0xFF260000
+#define ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_EN 0x1
+#define ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_HDBG 0x2
+
+struct iou_scntr_secure {
+ u32 counter_control_register;
+ u32 reserved0[7];
+ u32 base_frequency_id_register;
+};
+
+#define iou_scntr_secure ((struct iou_scntr_secure *)ZYNQMP_IOU_SCNTR_SECURE)
+
+#define ZYNQMP_PS_VERSION 0xFFCA0044
+#define ZYNQMP_PS_VER_MASK GENMASK(1, 0)
+
+/* Bootmode setting values */
+#define BOOT_MODES_MASK 0x0000000F
+#define QSPI_MODE_24BIT 0x00000001
+#define QSPI_MODE_32BIT 0x00000002
+#define SD_MODE 0x00000003 /* sd 0 */
+#define SD_MODE1 0x00000005 /* sd 1 */
+#define NAND_MODE 0x00000004
+#define EMMC_MODE 0x00000006
+#define USB_MODE 0x00000007
+#define SD1_LSHFT_MODE 0x0000000E /* SD1 Level shifter */
+#define JTAG_MODE 0x00000000
+#define BOOT_MODE_USE_ALT 0x100
+#define BOOT_MODE_ALT_SHIFT 12
+/* SW secondary boot modes 0xa - 0xd */
+#define SW_USBHOST_MODE 0x0000000A
+#define SW_SATA_MODE 0x0000000B
+
+#define ZYNQMP_IOU_SLCR_BASEADDR 0xFF180000
+
+struct iou_slcr_regs {
+ u32 mio_pin[78];
+ u32 reserved[442];
+};
+
+#define slcr_base ((struct iou_slcr_regs *)ZYNQMP_IOU_SLCR_BASEADDR)
+
+#define ZYNQMP_RPU_BASEADDR 0xFF9A0000
+
+struct rpu_regs {
+ u32 rpu_glbl_ctrl;
+ u32 reserved0[63];
+ u32 rpu0_cfg; /* 0x100 */
+ u32 reserved1[63];
+ u32 rpu1_cfg; /* 0x200 */
+};
+
+#define rpu_base ((struct rpu_regs *)ZYNQMP_RPU_BASEADDR)
+
+#define ZYNQMP_CRF_APB_BASEADDR 0xFD1A0000
+
+struct crfapb_regs {
+ u32 reserved0[65];
+ u32 rst_fpd_apu; /* 0x104 */
+ u32 reserved1;
+};
+
+#define crfapb_base ((struct crfapb_regs *)ZYNQMP_CRF_APB_BASEADDR)
+
+#define ZYNQMP_APU_BASEADDR 0xFD5C0000
+
+struct apu_regs {
+ u32 reserved0[16];
+ u32 rvbar_addr0_l; /* 0x40 */
+ u32 rvbar_addr0_h; /* 0x44 */
+ u32 reserved1[20];
+};
+
+#define apu_base ((struct apu_regs *)ZYNQMP_APU_BASEADDR)
+
+/* Board version value */
+#define ZYNQMP_CSU_BASEADDR 0xFFCA0000
+#define ZYNQMP_CSU_VERSION_SILICON 0x0
+#define ZYNQMP_CSU_VERSION_QEMU 0x3
+
+#define ZYNQMP_CSU_VERSION_EMPTY_SHIFT 20
+
+#define ZYNQMP_SILICON_VER_MASK 0xF
+#define ZYNQMP_SILICON_VER_SHIFT 0
+
+#define CSU_JTAG_SEC_GATE_DISABLE GENMASK(7, 0)
+#define CSU_JTAG_DAP_ENABLE_DEBUG GENMASK(7, 0)
+#define CSU_JTAG_CHAIN_WR_SETUP GENMASK(1, 0)
+#define CSU_PCAP_PROG_RELEASE_PL BIT(0)
+
+#define ZYNQMP_CSU_STATUS_AUTHENTICATED BIT(0)
+#define ZYNQMP_CSU_STATUS_ENCRYPTED BIT(1)
+
+struct csu_regs {
+ u32 status;
+ u32 reserved0[3];
+ u32 multi_boot;
+ u32 reserved1[7];
+ u32 jtag_chain_status_wr;
+ u32 jtag_chain_status;
+ u32 jtag_sec;
+ u32 jtag_dap_cfg;
+ u32 idcode;
+ u32 version;
+ u32 reserved2[3054];
+ u32 pcap_prog;
+};
+
+#define csu_base ((struct csu_regs *)ZYNQMP_CSU_BASEADDR)
+
+#define ZYNQMP_PMU_BASEADDR 0xFFD80000
+
+struct pmu_regs {
+ u32 reserved0[16];
+ u32 gen_storage4; /* 0x40 */
+ u32 reserved1[1];
+ u32 gen_storage6; /* 0x48 */
+};
+
+#define pmu_base ((struct pmu_regs *)ZYNQMP_PMU_BASEADDR)
+
+#endif /* _ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-zynqmp/include/mach/psu_init_gpl.h b/arch/arm/mach-zynqmp/include/mach/psu_init_gpl.h
new file mode 100644
index 00000000000..783d7c45c7b
--- /dev/null
+++ b/arch/arm/mach-zynqmp/include/mach/psu_init_gpl.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _PSU_INIT_GPL_H_ /* prevent circular inclusions */
+#define _PSU_INIT_GPL_H_
+
+#include <asm/io.h>
+
+int mask_pollonvalue(unsigned long add, u32 mask, u32 value);
+
+int mask_poll(u32 add, u32 mask);
+
+u32 mask_read(u32 add, u32 mask);
+
+void mask_delay(u32 delay);
+
+void psu_mask_write(unsigned long offset, unsigned long mask,
+ unsigned long val);
+
+void prog_reg(unsigned long addr, unsigned long mask,
+ unsigned long shift, unsigned long value);
+
+int psu_init(void);
+unsigned long psu_post_config_data(void);
+int psu_uboot_init(void);
+
+#endif /* _PSU_INIT_GPL_H_ */
diff --git a/arch/arm/mach-zynqmp/include/mach/sys_proto.h b/arch/arm/mach-zynqmp/include/mach/sys_proto.h
new file mode 100644
index 00000000000..15b69e77712
--- /dev/null
+++ b/arch/arm/mach-zynqmp/include/mach/sys_proto.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2014 - 2015 Xilinx, Inc.
+ * Michal Simek <michal.simek@amd.com>
+ */
+
+#ifndef _ASM_ARCH_SYS_PROTO_H
+#define _ASM_ARCH_SYS_PROTO_H
+
+#define ZYNQMP_CSU_SILICON_VER_MASK 0xF
+#define KEY_PTR_LEN 32
+#define IV_SIZE 12
+#define RSA_KEY_SIZE 512
+#define MODULUS_LEN 512
+#define PRIV_EXPO_LEN 512
+#define PUB_EXPO_LEN 4
+
+#define ZYNQMP_SHA3_INIT 1
+#define ZYNQMP_SHA3_UPDATE 2
+#define ZYNQMP_SHA3_FINAL 4
+#define ZYNQMP_SHA3_SIZE 48
+
+#define ZYNQMP_FPGA_BIT_AUTH_DDR 1
+#define ZYNQMP_FPGA_BIT_AUTH_OCM 2
+#define ZYNQMP_FPGA_BIT_ENC_USR_KEY 3
+#define ZYNQMP_FPGA_BIT_ENC_DEV_KEY 4
+#define ZYNQMP_FPGA_BIT_NS 5
+
+#define ZYNQMP_FPGA_AUTH_DDR 1
+
+enum {
+ IDCODE,
+ VERSION,
+ IDCODE2,
+};
+
+enum {
+ ZYNQMP_SILICON_V1,
+ ZYNQMP_SILICON_V2,
+ ZYNQMP_SILICON_V3,
+ ZYNQMP_SILICON_V4,
+};
+
+enum {
+ TCM_LOCK,
+ TCM_SPLIT,
+};
+
+unsigned int zynqmp_get_silicon_version(void);
+
+void initialize_tcm(bool mode);
+void mem_map_fill(void);
+#if defined(CONFIG_SYS_MEM_RSVD_FOR_MMU) || defined(CONFIG_DEFINE_TCM_OCM_MMAP)
+void tcm_init(u8 mode);
+#endif
+
+#endif /* _ASM_ARCH_SYS_PROTO_H */
diff --git a/arch/arm/mach-zynqmp/include/mach/zynqmp_aes.h b/arch/arm/mach-zynqmp/include/mach/zynqmp_aes.h
new file mode 100644
index 00000000000..01a13d4c7c0
--- /dev/null
+++ b/arch/arm/mach-zynqmp/include/mach/zynqmp_aes.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 Weidmueller Interface GmbH & Co. KG <oss@weidmueller.com>
+ * Christian Taedcke <christian.taedcke@weidmueller.com>
+ *
+ * Declaration of AES operation functionality for ZynqMP.
+ */
+
+#ifndef ZYNQMP_AES_H
+#define ZYNQMP_AES_H
+
+#include <linux/types.h>
+
+struct zynqmp_aes {
+ u64 srcaddr;
+ u64 ivaddr;
+ u64 keyaddr;
+ u64 dstaddr;
+ u64 len;
+ u64 op;
+ u64 keysrc;
+};
+
+/**
+ * zynqmp_aes_operation() - Performs an aes operation using the pmu firmware
+ *
+ * @aes: The aes operation buffer that must have been allocated using
+ * ALLOC_CACHE_ALIGN_BUFFER(struct zynqmp_aes, aes, 1)
+ *
+ * Return: 0 in case of success, in case of an error any other value
+ */
+int zynqmp_aes_operation(struct zynqmp_aes *aes);
+
+#endif /* ZYNQMP_AES_H */
diff --git a/arch/arm/mach-zynqmp/mkimage_fit_atf.sh b/arch/arm/mach-zynqmp/mkimage_fit_atf.sh
new file mode 100755
index 00000000000..cdecb1c1d35
--- /dev/null
+++ b/arch/arm/mach-zynqmp/mkimage_fit_atf.sh
@@ -0,0 +1,240 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0+
+#
+# script to generate FIT image source for Xilinx ZynqMP boards with
+# ARM Trusted Firmware and multiple device trees (given on the command line)
+#
+# usage: $0 <dt_name> [<dt_name> [<dt_name] ...]
+
+BL33="u-boot-nodtb.bin"
+[ -z "$BL31" ] && BL31="bl31.bin"
+BL31_ELF="${BL31%.*}.elf"
+[ -f ${BL31_ELF} ] && ATF_LOAD_ADDR=`${CROSS_COMPILE}readelf -l "${BL31_ELF}" | \
+awk '/Entry point/ { print $3 }'`
+
+[ -z "$ATF_LOAD_ADDR" ] && ATF_LOAD_ADDR="0xfffea000"
+ATF_LOAD_ADDR_LOW=`printf 0x%x $((ATF_LOAD_ADDR & 0xffffffff))`
+ATF_LOAD_ADDR_HIGH=`printf 0x%x $((ATF_LOAD_ADDR >> 32))`
+
+[ -z "$BL32" ] && BL32="tee.bin"
+BL32_ELF="${BL32%.*}.elf"
+[ -f ${BL32_ELF} ] && TEE_LOAD_ADDR=`${CROSS_COMPILE}readelf -l "${BL32_ELF}" | \
+awk '/Entry point/ { print $3 }'`
+
+[ -z "$TEE_LOAD_ADDR" ] && TEE_LOAD_ADDR="0x60000000"
+TEE_LOAD_ADDR_LOW=`printf 0x%x $((TEE_LOAD_ADDR & 0xffffffff))`
+TEE_LOAD_ADDR_HIGH=`printf 0x%x $((TEE_LOAD_ADDR >> 32))`
+
+if [ -z "$BL33_LOAD_ADDR" ];then
+ BL33_LOAD_ADDR=`awk '/CONFIG_TEXT_BASE/ { print $3 }' include/generated/autoconf.h`
+fi
+BL33_LOAD_ADDR_LOW=`printf 0x%x $((BL33_LOAD_ADDR & 0xffffffff))`
+BL33_LOAD_ADDR_HIGH=`printf 0x%x $((BL33_LOAD_ADDR >> 32))`
+
+DTB_LOAD_ADDR=`awk '/CONFIG_XILINX_OF_BOARD_DTB_ADDR/ { print $3 }' include/generated/autoconf.h`
+if [ ! -z "$DTB_LOAD_ADDR" ]; then
+ DTB_LOAD_ADDR_LOW=`printf 0x%x $((DTB_LOAD_ADDR & 0xffffffff))`
+ DTB_LOAD_ADDR_HIGH=`printf 0x%x $((DTB_LOAD_ADDR >> 32))`
+ DTB_LOAD="load = <$DTB_LOAD_ADDR_HIGH $DTB_LOAD_ADDR_LOW>;"
+else
+ DTB_LOAD=""
+fi
+
+if [ -z "$*" ]; then
+ DT=arch/arm/dts/${DEVICE_TREE}.dtb
+else
+ DT=$*
+fi
+
+if [ ! -f $BL31 ]; then
+ echo "WARNING: BL31 file $BL31 NOT found, U-Boot will run in EL3" >&2
+ BL31=/dev/null
+fi
+
+cat << __HEADER_EOF
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+/dts-v1/;
+
+/ {
+ description = "Configuration for Xilinx ZynqMP SoC";
+
+ images {
+ uboot {
+ description = "U-Boot (64-bit)";
+ data = /incbin/("$BL33");
+ type = "firmware";
+ os = "u-boot";
+ arch = "arm64";
+ compression = "none";
+ load = <$BL33_LOAD_ADDR_HIGH $BL33_LOAD_ADDR_LOW>;
+ entry = <$BL33_LOAD_ADDR_HIGH $BL33_LOAD_ADDR_LOW>;
+ hash {
+ algo = "md5";
+ };
+ };
+__HEADER_EOF
+
+if [ -f $BL31 ]; then
+cat << __ATF
+ atf {
+ description = "Trusted Firmware-A";
+ data = /incbin/("$BL31");
+ type = "firmware";
+ os = "arm-trusted-firmware";
+ arch = "arm64";
+ compression = "none";
+ load = <$ATF_LOAD_ADDR_HIGH $ATF_LOAD_ADDR_LOW>;
+ entry = <$ATF_LOAD_ADDR_HIGH $ATF_LOAD_ADDR_LOW>;
+ hash {
+ algo = "md5";
+ };
+ };
+__ATF
+fi
+
+if [ -f $BL32 ]; then
+cat << __TEE
+ tee {
+ description = "TEE firmware";
+ data = /incbin/("$BL32");
+ type = "firmware";
+ os = "tee";
+ arch = "arm64";
+ compression = "none";
+ load = <$TEE_LOAD_ADDR_HIGH $TEE_LOAD_ADDR_LOW>;
+ entry = <$TEE_LOAD_ADDR_HIGH $TEE_LOAD_ADDR_LOW>;
+ hash {
+ algo = "md5";
+ };
+ };
+__TEE
+fi
+
+MULTI_DTB=`awk '/CONFIG_MULTI_DTB_FIT / { print $3 }' include/generated/autoconf.h`
+
+if [ 1"$MULTI_DTB" -eq 11 ]; then
+ cat << __FDT_IMAGE_EOF
+ fdt_1 {
+ description = "Multi DTB fit image";
+ data = /incbin/("fit-dtb.blob");
+ type = "flat_dt";
+ arch = "arm64";
+ compression = "none";
+ $DTB_LOAD
+ hash {
+ algo = "md5";
+ };
+ };
+ };
+ configurations {
+ default = "config_1";
+__FDT_IMAGE_EOF
+
+if [ ! -f $BL31 ]; then
+cat << __CONF_SECTION1_EOF
+ config_1 {
+ description = "Multi DTB without TF-A";
+ firmware = "uboot";
+ loadables = "fdt_1";
+ };
+__CONF_SECTION1_EOF
+else
+if [ -f $BL32 ]; then
+cat << __CONF_SECTION1_EOF
+ config_1 {
+ description = "Multi DTB with TF-A and TEE";
+ firmware = "atf";
+ loadables = "uboot", "tee", "fdt_1";
+ };
+__CONF_SECTION1_EOF
+else
+cat << __CONF_SECTION1_EOF
+ config_1 {
+ description = "Multi DTB with TF-A";
+ firmware = "atf";
+ loadables = "uboot", "fdt_1";
+ };
+__CONF_SECTION1_EOF
+fi
+fi
+
+cat << __ITS_EOF
+ };
+};
+__ITS_EOF
+
+else
+
+DEFAULT=1
+cnt=1
+for dtname in $DT
+do
+ cat << __FDT_IMAGE_EOF
+ fdt_$cnt {
+ description = "$(basename $dtname .dtb)";
+ data = /incbin/("$dtname");
+ type = "flat_dt";
+ arch = "arm64";
+ compression = "none";
+ $DTB_LOAD
+ hash {
+ algo = "md5";
+ };
+ };
+__FDT_IMAGE_EOF
+
+[ "x$(basename $dtname .dtb)" = "x${DEVICE_TREE}" ] && DEFAULT=$cnt
+
+cnt=$((cnt+1))
+done
+
+cat << __CONF_HEADER_EOF
+ };
+ configurations {
+ default = "config_$DEFAULT";
+
+__CONF_HEADER_EOF
+
+cnt=1
+for dtname in $DT
+do
+if [ ! -f $BL31 ]; then
+cat << __CONF_SECTION1_EOF
+ config_$cnt {
+ description = "$(basename $dtname .dtb)";
+ firmware = "uboot";
+ fdt = "fdt_$cnt";
+ };
+__CONF_SECTION1_EOF
+else
+if [ -f $BL32 ]; then
+cat << __CONF_SECTION1_EOF
+ config_$cnt {
+ description = "$(basename $dtname .dtb)";
+ firmware = "atf";
+ loadables = "uboot", "tee";
+ fdt = "fdt_$cnt";
+ };
+__CONF_SECTION1_EOF
+else
+cat << __CONF_SECTION1_EOF
+ config_$cnt {
+ description = "$(basename $dtname .dtb)";
+ firmware = "atf";
+ loadables = "uboot";
+ fdt = "fdt_$cnt";
+ };
+__CONF_SECTION1_EOF
+fi
+fi
+
+cnt=$((cnt+1))
+done
+
+cat << __ITS_EOF
+ };
+};
+__ITS_EOF
+
+fi
diff --git a/arch/arm/mach-zynqmp/mp.c b/arch/arm/mach-zynqmp/mp.c
new file mode 100644
index 00000000000..9b46a25a1cb
--- /dev/null
+++ b/arch/arm/mach-zynqmp/mp.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2014 - 2015 Xilinx, Inc.
+ * Michal Simek <michal.simek@amd.com>
+ */
+
+#include <config.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <vsprintf.h>
+#include <zynqmp_firmware.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+
+#define LOCK 0
+#define SPLIT 1
+
+#define HALT 0
+#define RELEASE 1
+
+#define ZYNQMP_BOOTADDR_HIGH_MASK 0xFFFFFFFF
+#define ZYNQMP_R5_HIVEC_ADDR 0xFFFF0000
+#define ZYNQMP_R5_LOVEC_ADDR 0x0
+#define ZYNQMP_RPU_CFG_CPU_HALT_MASK 0x01
+#define ZYNQMP_RPU_CFG_HIVEC_MASK 0x04
+#define ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK 0x08
+#define ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK 0x40
+#define ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK 0x10
+
+#define ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK 0x04
+#define ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK 0x01
+#define ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK 0x02
+#define ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK 0x1000000
+
+#define ZYNQMP_R5_0_TCM_START_ADDR 0xFFE00000
+#define ZYNQMP_R5_1_TCM_START_ADDR 0xFFE90000
+#define ZYNQMP_TCM_BOTH_SIZE 0x40000
+
+#define ZYNQMP_CORE_APU0 0
+#define ZYNQMP_CORE_APU3 3
+#define ZYNQMP_CORE_RPU0 4
+#define ZYNQMP_CORE_RPU1 5
+
+#define ZYNQMP_MAX_CORES 6
+
+#define ZYNQMP_RPU0_USE_MASK BIT(1)
+#define ZYNQMP_RPU1_USE_MASK BIT(2)
+
+int is_core_valid(unsigned int core)
+{
+ if (core < ZYNQMP_MAX_CORES)
+ return 1;
+
+ return 0;
+}
+
+int cpu_reset(u32 nr)
+{
+ puts("Feature is not implemented.\n");
+ return 0;
+}
+
+static void set_r5_halt_mode(u32 nr, u8 halt, u8 mode)
+{
+ u32 tmp;
+
+ if (mode == LOCK || nr == ZYNQMP_CORE_RPU0) {
+ tmp = readl(&rpu_base->rpu0_cfg);
+ if (halt == HALT)
+ tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
+ else
+ tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
+ writel(tmp, &rpu_base->rpu0_cfg);
+ }
+
+ if (mode == LOCK || nr == ZYNQMP_CORE_RPU1) {
+ tmp = readl(&rpu_base->rpu1_cfg);
+ if (halt == HALT)
+ tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK;
+ else
+ tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK;
+ writel(tmp, &rpu_base->rpu1_cfg);
+ }
+}
+
+static void set_r5_tcm_mode(u8 mode)
+{
+ u32 tmp;
+
+ tmp = readl(&rpu_base->rpu_glbl_ctrl);
+ if (mode == LOCK) {
+ tmp &= ~ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
+ tmp |= ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
+ ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK;
+ } else {
+ tmp |= ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK;
+ tmp &= ~(ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK |
+ ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK);
+ }
+
+ writel(tmp, &rpu_base->rpu_glbl_ctrl);
+}
+
+static void set_r5_reset(u32 nr, u8 mode)
+{
+ u32 tmp;
+
+ tmp = readl(&crlapb_base->rst_lpd_top);
+ if (mode == LOCK) {
+ tmp |= (ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
+ ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK |
+ ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK);
+ } else {
+ if (nr == ZYNQMP_CORE_RPU0) {
+ tmp |= ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK;
+ if (tmp & ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK)
+ tmp |= ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK;
+ } else {
+ tmp |= ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK;
+ if (tmp & ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK)
+ tmp |= ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK;
+ }
+ }
+
+ writel(tmp, &crlapb_base->rst_lpd_top);
+}
+
+static void release_r5_reset(u32 nr, u8 mode)
+{
+ u32 tmp;
+
+ tmp = readl(&crlapb_base->rst_lpd_top);
+ if (mode == LOCK || nr == ZYNQMP_CORE_RPU0)
+ tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
+ ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK);
+
+ if (mode == LOCK || nr == ZYNQMP_CORE_RPU1)
+ tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK |
+ ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK);
+
+ writel(tmp, &crlapb_base->rst_lpd_top);
+}
+
+static void enable_clock_r5(void)
+{
+ u32 tmp;
+
+ tmp = readl(&crlapb_base->cpu_r5_ctrl);
+ tmp |= ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK;
+ writel(tmp, &crlapb_base->cpu_r5_ctrl);
+
+ /* Give some delay for clock
+ * to propagate */
+ udelay(0x500);
+}
+
+static int check_r5_mode(void)
+{
+ u32 tmp;
+
+ tmp = readl(&rpu_base->rpu_glbl_ctrl);
+ if (tmp & ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK)
+ return SPLIT;
+
+ return LOCK;
+}
+
+int cpu_disable(u32 nr)
+{
+ if (nr <= ZYNQMP_CORE_APU3) {
+ u32 val = readl(&crfapb_base->rst_fpd_apu);
+ val |= 1 << nr;
+ writel(val, &crfapb_base->rst_fpd_apu);
+ } else {
+ set_r5_reset(nr, check_r5_mode());
+ }
+
+ return 0;
+}
+
+int cpu_status(u32 nr)
+{
+ if (nr <= ZYNQMP_CORE_APU3) {
+ u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
+ u32 addr_high = readl(((u8 *)&apu_base->rvbar_addr0_h) +
+ nr * 8);
+ u32 val = readl(&crfapb_base->rst_fpd_apu);
+ val &= 1 << nr;
+ printf("APU CPU%d %s - starting address HI: %x, LOW: %x\n",
+ nr, val ? "OFF" : "ON" , addr_high, addr_low);
+ } else {
+ u32 val = readl(&crlapb_base->rst_lpd_top);
+ val &= 1 << (nr - 4);
+ printf("RPU CPU%d %s\n", nr - 4, val ? "OFF" : "ON");
+ }
+
+ return 0;
+}
+
+static void set_r5_start(u8 high)
+{
+ u32 tmp;
+
+ tmp = readl(&rpu_base->rpu0_cfg);
+ if (high)
+ tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
+ else
+ tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
+ writel(tmp, &rpu_base->rpu0_cfg);
+
+ tmp = readl(&rpu_base->rpu1_cfg);
+ if (high)
+ tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK;
+ else
+ tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK;
+ writel(tmp, &rpu_base->rpu1_cfg);
+}
+
+static void write_tcm_boot_trampoline(u32 nr, u32 boot_addr)
+{
+ if (boot_addr) {
+ u64 tcm_start_addr = ZYNQMP_R5_0_TCM_START_ADDR;
+
+ if (nr == ZYNQMP_CORE_RPU1)
+ tcm_start_addr = ZYNQMP_R5_1_TCM_START_ADDR;
+
+ /*
+ * Boot trampoline is simple ASM code below.
+ *
+ * b over;
+ * label:
+ * .word 0
+ * over: ldr r0, =label
+ * ldr r1, [r0]
+ * bx r1
+ */
+ debug("Write boot trampoline for %x\n", boot_addr);
+ writel(0xea000000, tcm_start_addr);
+ writel(boot_addr, tcm_start_addr + 0x4);
+ writel(0xe59f0004, tcm_start_addr + 0x8);
+ writel(0xe5901000, tcm_start_addr + 0xc);
+ writel(0xe12fff11, tcm_start_addr + 0x10);
+ writel(0x00000004, tcm_start_addr + 0x14);
+ }
+}
+
+void initialize_tcm(bool mode)
+{
+ if (!mode) {
+ set_r5_tcm_mode(LOCK);
+ set_r5_halt_mode(ZYNQMP_CORE_RPU0, HALT, LOCK);
+ enable_clock_r5();
+ release_r5_reset(ZYNQMP_CORE_RPU0, LOCK);
+ } else {
+ set_r5_tcm_mode(SPLIT);
+ set_r5_halt_mode(ZYNQMP_CORE_RPU0, HALT, SPLIT);
+ set_r5_halt_mode(ZYNQMP_CORE_RPU1, HALT, SPLIT);
+ enable_clock_r5();
+ release_r5_reset(ZYNQMP_CORE_RPU0, SPLIT);
+ release_r5_reset(ZYNQMP_CORE_RPU1, SPLIT);
+ }
+}
+
+static void mark_r5_used(u32 nr, u8 mode)
+{
+ u32 mask = 0;
+
+ if (mode == LOCK) {
+ mask = ZYNQMP_RPU0_USE_MASK | ZYNQMP_RPU1_USE_MASK;
+ } else {
+ switch (nr) {
+ case ZYNQMP_CORE_RPU0:
+ mask = ZYNQMP_RPU0_USE_MASK;
+ break;
+ case ZYNQMP_CORE_RPU1:
+ mask = ZYNQMP_RPU1_USE_MASK;
+ break;
+ default:
+ return;
+ }
+ }
+ zynqmp_mmio_write((ulong)&pmu_base->gen_storage4, mask, mask);
+}
+
+int cpu_release(u32 nr, int argc, char *const argv[])
+{
+ if (nr <= ZYNQMP_CORE_APU3) {
+ u64 boot_addr = simple_strtoull(argv[0], NULL, 16);
+ /* HIGH */
+ writel((u32)(boot_addr >> 32),
+ ((u8 *)&apu_base->rvbar_addr0_h) + nr * 8);
+ /* LOW */
+ writel((u32)(boot_addr & ZYNQMP_BOOTADDR_HIGH_MASK),
+ ((u8 *)&apu_base->rvbar_addr0_l) + nr * 8);
+
+ u32 val = readl(&crfapb_base->rst_fpd_apu);
+ val &= ~(1 << nr);
+ writel(val, &crfapb_base->rst_fpd_apu);
+ } else {
+ if (argc != 2) {
+ printf("Invalid number of arguments to release.\n");
+ printf("<addr> <mode>-Start addr lockstep or split\n");
+ return 1;
+ }
+
+ u32 boot_addr = hextoul(argv[0], NULL);
+ u32 boot_addr_uniq = 0;
+ if (!(boot_addr == ZYNQMP_R5_LOVEC_ADDR ||
+ boot_addr == ZYNQMP_R5_HIVEC_ADDR)) {
+ printf("Using TCM jump trampoline for address 0x%x\n",
+ boot_addr);
+ /* Save boot address for later usage */
+ boot_addr_uniq = boot_addr;
+ /*
+ * R5 needs to start from LOVEC at TCM
+ * OCM will be probably occupied by ATF
+ */
+ boot_addr = ZYNQMP_R5_LOVEC_ADDR;
+ }
+
+ /*
+ * Since we don't know where the user may have loaded the image
+ * for an R5 we have to flush all the data cache to ensure
+ * the R5 sees it.
+ */
+ flush_dcache_all();
+
+ if (!strncmp(argv[1], "lockstep", 8)) {
+ if (nr != ZYNQMP_CORE_RPU0) {
+ printf("Lockstep mode should run on ZYNQMP_CORE_RPU0\n");
+ return 1;
+ }
+ printf("R5 lockstep mode\n");
+ set_r5_reset(nr, LOCK);
+ set_r5_tcm_mode(LOCK);
+ set_r5_halt_mode(nr, HALT, LOCK);
+ set_r5_start(boot_addr);
+ enable_clock_r5();
+ release_r5_reset(nr, LOCK);
+ dcache_disable();
+ write_tcm_boot_trampoline(nr, boot_addr_uniq);
+ dcache_enable();
+ set_r5_halt_mode(nr, RELEASE, LOCK);
+ mark_r5_used(nr, LOCK);
+ } else if (!strncmp(argv[1], "split", 5)) {
+ printf("R5 split mode\n");
+ set_r5_reset(nr, SPLIT);
+ set_r5_tcm_mode(SPLIT);
+ set_r5_halt_mode(nr, HALT, SPLIT);
+ set_r5_start(boot_addr);
+ enable_clock_r5();
+ release_r5_reset(nr, SPLIT);
+ dcache_disable();
+ write_tcm_boot_trampoline(nr, boot_addr_uniq);
+ dcache_enable();
+ set_r5_halt_mode(nr, RELEASE, SPLIT);
+ mark_r5_used(nr, SPLIT);
+ } else {
+ printf("Unsupported mode\n");
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/arch/arm/mach-zynqmp/psu_spl_init.c b/arch/arm/mach-zynqmp/psu_spl_init.c
new file mode 100644
index 00000000000..5b4d66359bf
--- /dev/null
+++ b/arch/arm/mach-zynqmp/psu_spl_init.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Xilinx, Inc.
+ *
+ * Michal Simek <michal.simek@amd.com>
+ */
+#include <asm/io.h>
+#include <asm/arch/psu_init_gpl.h>
+#include <linux/delay.h>
+
+#define PSU_MASK_POLL_TIME 1100000
+
+int __maybe_unused mask_pollonvalue(unsigned long add, u32 mask, u32 value)
+{
+ int i = 0;
+
+ while ((__raw_readl(add) & mask) != value) {
+ if (i == PSU_MASK_POLL_TIME)
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+__weak int mask_poll(u32 add, u32 mask)
+{
+ int i = 0;
+ unsigned long addr = add;
+
+ while (!(__raw_readl(addr) & mask)) {
+ if (i == PSU_MASK_POLL_TIME)
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+__weak u32 mask_read(u32 add, u32 mask)
+{
+ unsigned long addr = add;
+
+ return __raw_readl(addr) & mask;
+}
+
+__weak void mask_delay(u32 delay)
+{
+ udelay(delay);
+}
+
+__weak void psu_mask_write(unsigned long offset, unsigned long mask,
+ unsigned long val)
+{
+ unsigned long regval = 0;
+
+ regval = readl(offset);
+ regval &= ~(mask);
+ regval |= (val & mask);
+ writel(regval, offset);
+}
+
+__weak void prog_reg(unsigned long addr, unsigned long mask,
+ unsigned long shift, unsigned long value)
+{
+ int rdata = 0;
+
+ rdata = readl(addr);
+ rdata = rdata & (~mask);
+ rdata = rdata | (value << shift);
+ writel(rdata, addr);
+}
+
+__weak int psu_init(void)
+{
+ /*
+ * This function is overridden by the one in
+ * board/xilinx/zynqmp/(platform)/psu_init_gpl.c, if it exists.
+ */
+ return -1;
+}
+
+__weak unsigned long psu_post_config_data(void)
+{
+ /*
+ * This function is overridden by the one in
+ * board/xilinx/zynqmp/(platform)/psu_init_gpl.c, if it exists.
+ */
+ return 0;
+}
diff --git a/arch/arm/mach-zynqmp/spl.c b/arch/arm/mach-zynqmp/spl.c
new file mode 100644
index 00000000000..4a2d240abbb
--- /dev/null
+++ b/arch/arm/mach-zynqmp/spl.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015 - 2016 Xilinx, Inc.
+ *
+ * Michal Simek <michal.simek@amd.com>
+ */
+
+#include <image.h>
+#include <init.h>
+#include <log.h>
+#include <semihosting.h>
+#include <spl.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/spl.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/ecc_spl_init.h>
+#include <asm/arch/psu_init_gpl.h>
+#include <asm/arch/sys_proto.h>
+
+#if defined(CONFIG_DEBUG_UART_BOARD_INIT)
+void board_debug_uart_init(void)
+{
+ psu_uboot_init();
+}
+#endif
+
+void board_init_f(ulong dummy)
+{
+#if !defined(CONFIG_DEBUG_UART_BOARD_INIT)
+ psu_uboot_init();
+#endif
+
+ board_early_init_r();
+#ifdef CONFIG_SPL_ZYNQMP_DRAM_ECC_INIT
+ zynqmp_ecc_init();
+#endif
+}
+
+static void ps_mode_reset(ulong mode)
+{
+ writel(mode << ZYNQMP_CRL_APB_BOOT_PIN_CTRL_OUT_EN_SHIFT,
+ &crlapb_base->boot_pin_ctrl);
+ udelay(5);
+ writel(mode << ZYNQMP_CRL_APB_BOOT_PIN_CTRL_OUT_VAL_SHIFT |
+ mode << ZYNQMP_CRL_APB_BOOT_PIN_CTRL_OUT_EN_SHIFT,
+ &crlapb_base->boot_pin_ctrl);
+}
+
+/*
+ * Set default PS_MODE1 which is used for USB ULPI phy reset
+ * Also other resets can be connected to this certain pin
+ */
+#ifndef MODE_RESET
+# define MODE_RESET PS_MODE1
+#endif
+
+#ifdef CONFIG_SPL_SOC_INIT
+void spl_soc_init(void)
+{
+ preloader_console_init();
+ ps_mode_reset(MODE_RESET);
+ board_init();
+ psu_post_config_data();
+}
+#endif
+
+static u32 jtag_boot_device(void)
+{
+ return semihosting_enabled() ? BOOT_DEVICE_SMH : BOOT_DEVICE_RAM;
+}
+
+void board_boot_order(u32 *spl_boot_list)
+{
+ spl_boot_list[0] = spl_boot_device();
+
+ if (spl_boot_list[0] == BOOT_DEVICE_MMC1)
+ spl_boot_list[1] = BOOT_DEVICE_MMC2;
+ if (spl_boot_list[0] == BOOT_DEVICE_MMC2)
+ spl_boot_list[1] = BOOT_DEVICE_MMC1;
+
+ spl_boot_list[2] = jtag_boot_device();
+}
+
+u32 spl_boot_device(void)
+{
+ u32 reg = 0;
+ u8 bootmode;
+
+#if defined(CONFIG_SPL_ZYNQMP_ALT_BOOTMODE_ENABLED)
+ /* Change default boot mode at run-time */
+ reg = CONFIG_SPL_ZYNQMP_ALT_BOOTMODE;
+ writel(CONFIG_SPL_ZYNQMP_ALT_BOOTMODE << BOOT_MODE_ALT_SHIFT,
+ &crlapb_base->boot_mode);
+#else
+ reg = readl(&crlapb_base->boot_mode);
+ if (reg >> BOOT_MODE_ALT_SHIFT)
+ reg >>= BOOT_MODE_ALT_SHIFT;
+#endif
+
+ bootmode = reg & BOOT_MODES_MASK;
+
+ switch (bootmode) {
+ case JTAG_MODE:
+ return jtag_boot_device();
+#ifdef CONFIG_SPL_MMC
+ case SD_MODE1:
+ case SD1_LSHFT_MODE: /* not working on silicon v1 */
+ return BOOT_DEVICE_MMC2;
+ case SD_MODE:
+ case EMMC_MODE:
+ return BOOT_DEVICE_MMC1;
+#endif
+#ifdef CONFIG_SPL_DFU
+ case USB_MODE:
+ return BOOT_DEVICE_DFU;
+#endif
+#ifdef CONFIG_SPL_SATA
+ case SW_SATA_MODE:
+ return BOOT_DEVICE_SATA;
+#endif
+#ifdef CONFIG_SPL_SPI
+ case QSPI_MODE_24BIT:
+ case QSPI_MODE_32BIT:
+ return BOOT_DEVICE_SPI;
+#endif
+ default:
+ printf("Invalid Boot Mode:0x%x\n", bootmode);
+ break;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_SPL_OS_BOOT
+int spl_start_uboot(void)
+{
+ return 0;
+}
+#endif
diff --git a/arch/arm/mach-zynqmp/zynqmp.c b/arch/arm/mach-zynqmp/zynqmp.c
new file mode 100644
index 00000000000..bf39c5472ea
--- /dev/null
+++ b/arch/arm/mach-zynqmp/zynqmp.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018 Xilinx, Inc.
+ * Siva Durga Prasad Paladugu <siva.durga.prasad.paladugu@amd.com>>
+ */
+
+#include <command.h>
+#include <cpu_func.h>
+#include <env.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <vsprintf.h>
+#include <zynqmp_firmware.h>
+#include <linux/errno.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <mach/zynqmp_aes.h>
+
+static int do_zynqmp_verify_secure(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ u64 src_addr, addr;
+ u32 len, src_lo, src_hi;
+ u8 *key_ptr = NULL;
+ int ret;
+ u32 key_lo = 0;
+ u32 key_hi = 0;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+
+ if (argc < 4)
+ return CMD_RET_USAGE;
+
+ src_addr = simple_strtoull(argv[2], NULL, 16);
+ len = hextoul(argv[3], NULL);
+
+ if (argc == 5)
+ key_ptr = (uint8_t *)(uintptr_t)simple_strtoull(argv[4],
+ NULL, 16);
+
+ if ((ulong)src_addr != ALIGN((ulong)src_addr,
+ CONFIG_SYS_CACHELINE_SIZE)) {
+ printf("Failed: source address not aligned:%lx\n",
+ (ulong)src_addr);
+ return -EINVAL;
+ }
+
+ src_lo = lower_32_bits((ulong)src_addr);
+ src_hi = upper_32_bits((ulong)src_addr);
+ flush_dcache_range((ulong)src_addr, (ulong)(src_addr + len));
+
+ if (key_ptr) {
+ key_lo = lower_32_bits((ulong)key_ptr);
+ key_hi = upper_32_bits((ulong)key_ptr);
+ flush_dcache_range((ulong)key_ptr,
+ (ulong)(key_ptr + KEY_PTR_LEN));
+ }
+
+ ret = xilinx_pm_request(PM_SECURE_IMAGE, src_lo, src_hi,
+ key_lo, key_hi, ret_payload);
+ if (ret) {
+ printf("Failed: secure op status:0x%x\n", ret);
+ } else {
+ addr = (u64)ret_payload[1] << 32 | ret_payload[2];
+ printf("Verified image at 0x%llx\n", addr);
+ env_set_hex("zynqmp_verified_img_addr", addr);
+ }
+
+ return ret;
+}
+
+static int do_zynqmp_mmio_read(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ u32 read_val, addr;
+ int ret;
+
+ if (argc != cmdtp->maxargs)
+ return CMD_RET_USAGE;
+
+ addr = hextoul(argv[2], NULL);
+
+ ret = zynqmp_mmio_read(addr, &read_val);
+ if (!ret)
+ printf("mmio read value at 0x%x = 0x%x\n",
+ addr, read_val);
+ else
+ printf("Failed: mmio read\n");
+
+ return ret;
+}
+
+static int do_zynqmp_mmio_write(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ u32 addr, mask, val;
+ int ret;
+
+ if (argc != cmdtp->maxargs)
+ return CMD_RET_USAGE;
+
+ addr = hextoul(argv[2], NULL);
+ mask = hextoul(argv[3], NULL);
+ val = hextoul(argv[4], NULL);
+
+ ret = zynqmp_mmio_write(addr, mask, val);
+ if (ret != 0)
+ printf("Failed: mmio write\n");
+
+ return ret;
+}
+
+static int do_zynqmp_aes(struct cmd_tbl *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct zynqmp_aes, aes, 1);
+
+ if (zynqmp_firmware_version() <= PMUFW_V1_0) {
+ puts("ERR: PMUFW v1.0 or less is detected\n");
+ puts("ERR: Encrypt/Decrypt feature is not supported\n");
+ puts("ERR: Please upgrade PMUFW\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (argc < cmdtp->maxargs - 1)
+ return CMD_RET_USAGE;
+
+ aes->srcaddr = hextoul(argv[2], NULL);
+ aes->ivaddr = hextoul(argv[3], NULL);
+ aes->len = hextoul(argv[4], NULL);
+ aes->op = hextoul(argv[5], NULL);
+ aes->keysrc = hextoul(argv[6], NULL);
+ aes->dstaddr = hextoul(argv[7], NULL);
+
+ if (aes->keysrc == 0) {
+ if (argc < cmdtp->maxargs)
+ return CMD_RET_USAGE;
+
+ aes->keyaddr = hextoul(argv[8], NULL);
+ }
+
+ return zynqmp_aes_operation(aes);
+}
+
+#ifdef CONFIG_DEFINE_TCM_OCM_MMAP
+static int do_zynqmp_tcm_init(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ u8 mode;
+
+ if (argc != cmdtp->maxargs)
+ return CMD_RET_USAGE;
+
+ if (strcmp(argv[2], "lockstep") && strcmp(argv[2], "split")) {
+ printf("mode param should be lockstep or split\n");
+ return CMD_RET_FAILURE;
+ }
+
+ mode = hextoul(argv[2], NULL);
+ if (mode != TCM_LOCK && mode != TCM_SPLIT) {
+ printf("Mode should be either 0(lock)/1(split)\n");
+ return CMD_RET_FAILURE;
+ }
+
+ dcache_disable();
+ tcm_init(mode);
+ dcache_enable();
+
+ return CMD_RET_SUCCESS;
+}
+#endif
+
+static int do_zynqmp_pmufw(struct cmd_tbl *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ u32 addr, size;
+
+ if (argc != cmdtp->maxargs)
+ return CMD_RET_USAGE;
+
+ if (!strncmp(argv[2], "node", 4)) {
+ u32 id;
+ int ret;
+
+ if (!strncmp(argv[3], "close", 5))
+ return zynqmp_pmufw_config_close();
+
+ id = dectoul(argv[3], NULL);
+ if (!id) {
+ printf("Incorrect ID passed\n");
+ return CMD_RET_USAGE;
+ }
+
+ printf("Enable permission for node ID %d\n", id);
+
+ ret = zynqmp_pmufw_node(id);
+ if (ret == -ENODEV)
+ ret = 0;
+
+ return ret;
+ }
+
+ addr = hextoul(argv[2], NULL);
+ size = hextoul(argv[3], NULL);
+
+ zynqmp_pmufw_load_config_object((const void *)(uintptr_t)addr,
+ (size_t)size);
+
+ return 0;
+}
+
+static int do_zynqmp_rsa(struct cmd_tbl *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ u64 srcaddr, mod, exp;
+ u32 srclen, rsaop, size, ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ if (argc != cmdtp->maxargs)
+ return CMD_RET_USAGE;
+
+ if (zynqmp_firmware_version() <= PMUFW_V1_0) {
+ puts("ERR: PMUFW v1.0 or less is detected\n");
+ puts("ERR: Encrypt/Decrypt feature is not supported\n");
+ puts("ERR: Please upgrade PMUFW\n");
+ return CMD_RET_FAILURE;
+ }
+
+ srcaddr = hextoul(argv[2], NULL);
+ srclen = hextoul(argv[3], NULL);
+ if (srclen != RSA_KEY_SIZE) {
+ puts("ERR: srclen should be equal to 0x200(512 bytes)\n");
+ return CMD_RET_USAGE;
+ }
+
+ mod = hextoul(argv[4], NULL);
+ exp = hextoul(argv[5], NULL);
+ rsaop = hextoul(argv[6], NULL);
+ if (!(rsaop == 0 || rsaop == 1)) {
+ puts("ERR: rsaop should be either 0 or 1\n");
+ return CMD_RET_USAGE;
+ }
+
+ memcpy((void *)srcaddr + srclen, (void *)mod, MODULUS_LEN);
+
+ /*
+ * For encryption we load public exponent (key size 4096-bits),
+ * for decryption we load private exponent (32-bits)
+ */
+ if (rsaop) {
+ memcpy((void *)srcaddr + srclen + MODULUS_LEN,
+ (void *)exp, PUB_EXPO_LEN);
+ size = srclen + MODULUS_LEN + PUB_EXPO_LEN;
+ } else {
+ memcpy((void *)srcaddr + srclen + MODULUS_LEN,
+ (void *)exp, PRIV_EXPO_LEN);
+ size = srclen + MODULUS_LEN + PRIV_EXPO_LEN;
+ }
+
+ flush_dcache_range((ulong)srcaddr,
+ (ulong)(srcaddr) + roundup(size, ARCH_DMA_MINALIGN));
+
+ ret = xilinx_pm_request(PM_SECURE_RSA, upper_32_bits((ulong)srcaddr),
+ lower_32_bits((ulong)srcaddr), srclen, rsaop,
+ ret_payload);
+ if (ret || ret_payload[1]) {
+ printf("Failed: RSA status:0x%x, errcode:0x%x\n",
+ ret, ret_payload[1]);
+ return CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int do_zynqmp_sha3(struct cmd_tbl *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ u64 srcaddr, hashaddr;
+ u32 srclen, ret_payload[PAYLOAD_ARG_CNT];
+ int ret;
+
+ if (argc > cmdtp->maxargs || argc < (cmdtp->maxargs - 1))
+ return CMD_RET_USAGE;
+
+ if (zynqmp_firmware_version() <= PMUFW_V1_0) {
+ puts("ERR: PMUFW v1.0 or less is detected\n");
+ puts("ERR: Encrypt/Decrypt feature is not supported\n");
+ puts("ERR: Please upgrade PMUFW\n");
+ return CMD_RET_FAILURE;
+ }
+
+ srcaddr = hextoul(argv[2], NULL);
+ srclen = hextoul(argv[3], NULL);
+
+ if (argc == 5) {
+ hashaddr = hextoul(argv[4], NULL);
+ flush_dcache_range(hashaddr,
+ hashaddr + roundup(ZYNQMP_SHA3_SIZE,
+ ARCH_DMA_MINALIGN));
+ } else {
+ hashaddr = srcaddr;
+ }
+
+ /* Check srcaddr or srclen != 0 */
+ if (!srcaddr || !srclen) {
+ puts("ERR: srcaddr & srclen should not be 0\n");
+ return CMD_RET_USAGE;
+ }
+
+ flush_dcache_range(srcaddr,
+ srcaddr + roundup(srclen, ARCH_DMA_MINALIGN));
+
+ ret = xilinx_pm_request(PM_SECURE_SHA, 0, 0, 0,
+ ZYNQMP_SHA3_INIT, ret_payload);
+ if (ret || ret_payload[1]) {
+ printf("Failed: SHA INIT status:0x%x, errcode:0x%x\n",
+ ret, ret_payload[1]);
+ return CMD_RET_FAILURE;
+ }
+
+ ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)srcaddr),
+ lower_32_bits((ulong)srcaddr),
+ srclen, ZYNQMP_SHA3_UPDATE, ret_payload);
+ if (ret || ret_payload[1]) {
+ printf("Failed: SHA UPDATE status:0x%x, errcode:0x%x\n",
+ ret, ret_payload[1]);
+ return CMD_RET_FAILURE;
+ }
+
+ ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)hashaddr),
+ lower_32_bits((ulong)hashaddr),
+ ZYNQMP_SHA3_SIZE, ZYNQMP_SHA3_FINAL,
+ ret_payload);
+ if (ret || ret_payload[1]) {
+ printf("Failed: SHA FINAL status:0x%x, errcode:0x%x\n",
+ ret, ret_payload[1]);
+ return CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static struct cmd_tbl cmd_zynqmp_sub[] = {
+ U_BOOT_CMD_MKENT(secure, 5, 0, do_zynqmp_verify_secure, "", ""),
+ U_BOOT_CMD_MKENT(pmufw, 4, 0, do_zynqmp_pmufw, "", ""),
+ U_BOOT_CMD_MKENT(mmio_read, 3, 0, do_zynqmp_mmio_read, "", ""),
+ U_BOOT_CMD_MKENT(mmio_write, 5, 0, do_zynqmp_mmio_write, "", ""),
+ U_BOOT_CMD_MKENT(aes, 9, 0, do_zynqmp_aes, "", ""),
+ U_BOOT_CMD_MKENT(rsa, 7, 0, do_zynqmp_rsa, "", ""),
+ U_BOOT_CMD_MKENT(sha3, 5, 0, do_zynqmp_sha3, "", ""),
+#ifdef CONFIG_DEFINE_TCM_OCM_MMAP
+ U_BOOT_CMD_MKENT(tcminit, 3, 0, do_zynqmp_tcm_init, "", ""),
+#endif
+};
+
+/**
+ * do_zynqmp - Handle the "zynqmp" command-line command
+ * @cmdtp: Command data struct pointer
+ * @flag: Command flag
+ * @argc: Command-line argument count
+ * @argv: Array of command-line arguments
+ *
+ * Processes the zynqmp specific commands
+ *
+ * Return: return 0 on success and CMD_RET_USAGE incase of misuse and error
+ */
+static int do_zynqmp(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct cmd_tbl *c;
+ int ret = CMD_RET_USAGE;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ c = find_cmd_tbl(argv[1], &cmd_zynqmp_sub[0],
+ ARRAY_SIZE(cmd_zynqmp_sub));
+ if (c)
+ ret = c->cmd(c, flag, argc, argv);
+
+ return cmd_process_error(c, ret);
+}
+
+/***************************************************/
+U_BOOT_LONGHELP(zynqmp,
+ "secure src len [key_addr] - verifies secure images of $len bytes\n"
+ " long at address $src. Optional key_addr\n"
+ " can be specified if user key needs to\n"
+ " be used for decryption\n"
+ "zynqmp mmio_read address - read from address\n"
+ "zynqmp mmio_write address mask value - write value after masking to\n"
+ " address\n"
+ "zynqmp aes srcaddr ivaddr len aesop keysrc dstaddr [keyaddr] -\n"
+ " Encrypts or decrypts blob of data at src address and puts it\n"
+ " back to dstaddr using key and iv at keyaddr and ivaddr\n"
+ " respectively. keysrc value specifies from which source key\n"
+ " has to be used, it can be User/Device/PUF key. A value of 0\n"
+ " for KUP(user key),1 for DeviceKey and 2 for PUF key. The\n"
+ " aesop value specifies the operation which can be 0 for\n"
+ " decrypt and 1 for encrypt operation\n"
+#ifdef CONFIG_DEFINE_TCM_OCM_MMAP
+ "zynqmp tcminit mode - Initialize the TCM with zeros. TCM needs to be\n"
+ " initialized before accessing to avoid ECC\n"
+ " errors. mode specifies in which mode TCM has\n"
+ " to be initialized. Supported modes will be\n"
+ " lock(0)/split(1)\n"
+#endif
+ "zynqmp pmufw address size - load PMU FW configuration object\n"
+ "zynqmp pmufw node <id> - load PMU FW configuration object, <id> in dec\n"
+ "zynqmp pmufw node close - disable config object loading\n"
+ " node: keyword, id: NODE_ID in decimal format\n"
+ "zynqmp rsa srcaddr srclen mod exp rsaop -\n"
+ " Performs RSA encryption and RSA decryption on blob of data\n"
+ " at srcaddr and puts it back in srcaddr using modulus and\n"
+ " public or private exponent\n"
+ " srclen : must be key size(4096 bits)\n"
+ " exp : private key exponent for RSA decryption(4096 bits)\n"
+ " public key exponent for RSA encryption(32 bits)\n"
+ " rsaop : 0 for RSA Decryption, 1 for RSA Encryption\n"
+ "zynqmp sha3 srcaddr srclen [key_addr] -\n"
+ " Generates sha3 hash value for data blob at srcaddr and puts\n"
+ " 48 bytes hash value into srcaddr\n"
+ " Optional key_addr can be specified for saving sha3 hash value\n"
+ " Note: srcaddr/srclen should not be 0\n"
+ );
+
+U_BOOT_CMD(
+ zynqmp, 9, 1, do_zynqmp,
+ "ZynqMP sub-system",
+ zynqmp_help_text
+);