summaryrefslogtreecommitdiffstats
path: root/plat/xilinx/zynqmp/aarch64
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plat/xilinx/zynqmp/aarch64/zynqmp_common.c391
-rw-r--r--plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S86
2 files changed, 477 insertions, 0 deletions
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
new file mode 100644
index 0000000..3946e9b
--- /dev/null
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_sys.h"
+
+/*
+ * Table of regions to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * configure_mmu_elx() will give the available subset of that,
+ */
+const mmap_region_t plat_arm_mmap[] = {
+ { DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+ { DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+ { CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+ {0}
+};
+
+static uint32_t zynqmp_get_silicon_ver(void)
+{
+ static unsigned int ver;
+
+ if (!ver) {
+ ver = mmio_read_32(ZYNQMP_CSU_BASEADDR +
+ ZYNQMP_CSU_VERSION_OFFSET);
+ ver &= ZYNQMP_SILICON_VER_MASK;
+ ver >>= ZYNQMP_SILICON_VER_SHIFT;
+ }
+
+ return ver;
+}
+
+uint32_t zynqmp_get_uart_clk(void)
+{
+ unsigned int ver = zynqmp_get_silicon_ver();
+
+ if (ver == ZYNQMP_CSU_VERSION_QEMU) {
+ return 133000000;
+ } else {
+ return 100000000;
+ }
+}
+
+#if LOG_LEVEL >= LOG_LEVEL_NOTICE
+static const struct {
+ uint32_t id;
+ uint32_t ver;
+ char *name;
+ bool evexists;
+} zynqmp_devices[] = {
+ {
+ .id = 0x10,
+ .name = "XCZU3EG",
+ },
+ {
+ .id = 0x10,
+ .ver = 0x2c,
+ .name = "XCZU3CG",
+ },
+ {
+ .id = 0x11,
+ .name = "XCZU2EG",
+ },
+ {
+ .id = 0x11,
+ .ver = 0x2c,
+ .name = "XCZU2CG",
+ },
+ {
+ .id = 0x20,
+ .name = "XCZU5EV",
+ .evexists = true,
+ },
+ {
+ .id = 0x20,
+ .ver = 0x100,
+ .name = "XCZU5EG",
+ .evexists = true,
+ },
+ {
+ .id = 0x20,
+ .ver = 0x12c,
+ .name = "XCZU5CG",
+ },
+ {
+ .id = 0x21,
+ .name = "XCZU4EV",
+ .evexists = true,
+ },
+ {
+ .id = 0x21,
+ .ver = 0x100,
+ .name = "XCZU4EG",
+ .evexists = true,
+ },
+ {
+ .id = 0x21,
+ .ver = 0x12c,
+ .name = "XCZU4CG",
+ },
+ {
+ .id = 0x30,
+ .name = "XCZU7EV",
+ .evexists = true,
+ },
+ {
+ .id = 0x30,
+ .ver = 0x100,
+ .name = "XCZU7EG",
+ .evexists = true,
+ },
+ {
+ .id = 0x30,
+ .ver = 0x12c,
+ .name = "XCZU7CG",
+ },
+ {
+ .id = 0x38,
+ .name = "XCZU9EG",
+ },
+ {
+ .id = 0x38,
+ .ver = 0x2c,
+ .name = "XCZU9CG",
+ },
+ {
+ .id = 0x39,
+ .name = "XCZU6EG",
+ },
+ {
+ .id = 0x39,
+ .ver = 0x2c,
+ .name = "XCZU6CG",
+ },
+ {
+ .id = 0x40,
+ .name = "XCZU11EG",
+ },
+ {
+ .id = 0x50,
+ .name = "XCZU15EG",
+ },
+ {
+ .id = 0x58,
+ .name = "XCZU19EG",
+ },
+ {
+ .id = 0x59,
+ .name = "XCZU17EG",
+ },
+ {
+ .id = 0x60,
+ .name = "XCZU28DR",
+ },
+ {
+ .id = 0x61,
+ .name = "XCZU21DR",
+ },
+ {
+ .id = 0x62,
+ .name = "XCZU29DR",
+ },
+ {
+ .id = 0x63,
+ .name = "XCZU23DR",
+ },
+ {
+ .id = 0x64,
+ .name = "XCZU27DR",
+ },
+ {
+ .id = 0x65,
+ .name = "XCZU25DR",
+ },
+ {
+ .id = 0x66,
+ .name = "XCZU39DR",
+ },
+ {
+ .id = 0x7d,
+ .name = "XCZU43DR",
+ },
+ {
+ .id = 0x78,
+ .name = "XCZU46DR",
+ },
+ {
+ .id = 0x7f,
+ .name = "XCZU47DR",
+ },
+ {
+ .id = 0x7b,
+ .name = "XCZU48DR",
+ },
+ {
+ .id = 0x7e,
+ .name = "XCZU49DR",
+ },
+};
+
+#define ZYNQMP_PL_STATUS_BIT 9
+#define ZYNQMP_PL_STATUS_MASK BIT(ZYNQMP_PL_STATUS_BIT)
+#define ZYNQMP_CSU_VERSION_MASK ~(ZYNQMP_PL_STATUS_MASK)
+
+#define SILICON_ID_XCK24 0x4714093U
+#define SILICON_ID_XCK26 0x4724093U
+
+static char *zynqmp_get_silicon_idcode_name(void)
+{
+ uint32_t id, ver, chipid[2];
+ size_t i, j, len;
+ const char *name = "EG/EV";
+
+#ifdef IMAGE_BL32
+ /*
+ * For BL32, get the chip id info directly by reading corresponding
+ * registers instead of making pm call. This has limitation
+ * that these registers should be configured to have access
+ * from APU which is default case.
+ */
+ chipid[0] = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+ chipid[1] = mmio_read_32(EFUSE_BASEADDR + EFUSE_IPDISABLE_OFFSET);
+#else
+ if (pm_get_chipid(chipid) != PM_RET_SUCCESS) {
+ return "XCZUUNKN";
+ }
+#endif
+
+ id = chipid[0] & (ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
+ ZYNQMP_CSU_IDCODE_SVD_MASK);
+ id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
+ ver = chipid[1] >> ZYNQMP_EFUSE_IPDISABLE_SHIFT;
+
+ for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
+ if (zynqmp_devices[i].id == id &&
+ zynqmp_devices[i].ver == (ver & ZYNQMP_CSU_VERSION_MASK)) {
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(zynqmp_devices)) {
+ switch (chipid[0]) {
+ case SILICON_ID_XCK24:
+ return "XCK24";
+ case SILICON_ID_XCK26:
+ return "XCK26";
+ default:
+ return "XCZUUNKN";
+ }
+ }
+
+ if (!zynqmp_devices[i].evexists) {
+ return zynqmp_devices[i].name;
+ }
+
+ if ((ver & ZYNQMP_PL_STATUS_MASK) != 0U) {
+ return zynqmp_devices[i].name;
+ }
+
+ len = strlen(zynqmp_devices[i].name) - 2;
+ for (j = 0; j < strlen(name); j++) {
+ zynqmp_devices[i].name[len] = name[j];
+ len++;
+ }
+ zynqmp_devices[i].name[len] = '\0';
+
+ return zynqmp_devices[i].name;
+}
+
+static unsigned int zynqmp_get_rtl_ver(void)
+{
+ uint32_t ver;
+
+ ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
+ ver &= ZYNQMP_RTL_VER_MASK;
+ ver >>= ZYNQMP_RTL_VER_SHIFT;
+
+ return ver;
+}
+
+static char *zynqmp_print_silicon_idcode(void)
+{
+ uint32_t id, maskid, tmp;
+
+ id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+
+ tmp = id;
+ tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK |
+ ZYNQMP_CSU_IDCODE_FAMILY_MASK;
+ maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
+ ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT;
+ if (tmp != maskid) {
+ ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid);
+ return "UNKN";
+ }
+ VERBOSE("Xilinx IDCODE 0x%x\n", id);
+ return zynqmp_get_silicon_idcode_name();
+}
+
+static uint32_t zynqmp_get_ps_ver(void)
+{
+ uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
+
+ ver &= ZYNQMP_PS_VER_MASK;
+ ver >>= ZYNQMP_PS_VER_SHIFT;
+
+ return ver + 1U;
+}
+
+static void zynqmp_print_platform_name(void)
+{
+ uint32_t ver = zynqmp_get_silicon_ver();
+ uint32_t rtl = zynqmp_get_rtl_ver();
+ char *label = "Unknown";
+
+ switch (ver) {
+ case ZYNQMP_CSU_VERSION_QEMU:
+ label = "QEMU";
+ break;
+ case ZYNQMP_CSU_VERSION_SILICON:
+ label = "silicon";
+ break;
+ default:
+ /* Do nothing in default case */
+ break;
+ }
+
+ VERBOSE("TF-A running on %s/%s at 0x%x\n",
+ zynqmp_print_silicon_idcode(), label, BL31_BASE);
+ VERBOSE("TF-A running on v%d/RTL%d.%d\n",
+ zynqmp_get_ps_ver(), (rtl & 0xf0) >> 4, rtl & 0xf);
+}
+#else
+static inline void zynqmp_print_platform_name(void) { }
+#endif
+
+uint32_t zynqmp_get_bootmode(void)
+{
+ uint32_t r;
+ unsigned int ret;
+
+ ret = pm_mmio_read(CRL_APB_BOOT_MODE_USER, &r);
+
+ if (ret != PM_RET_SUCCESS) {
+ r = mmio_read_32(CRL_APB_BOOT_MODE_USER);
+ }
+
+ return r & CRL_APB_BOOT_MODE_MASK;
+}
+
+void zynqmp_config_setup(void)
+{
+ uint64_t counter_freq;
+
+ /* Configure IPI data for ZynqMP */
+ zynqmp_ipi_config_table_init();
+
+ zynqmp_print_platform_name();
+
+ /* Configure counter frequency */
+ counter_freq = read_cntfrq_el0();
+ if (counter_freq == ZYNQMP_DEFAULT_COUNTER_FREQ) {
+ write_cntfrq_el0(plat_get_syscnt_freq2());
+ }
+
+ generic_delay_timer_init();
+}
+
+uint32_t plat_get_syscnt_freq2(void)
+{
+ uint32_t ver = zynqmp_get_silicon_ver();
+
+ if (ver == ZYNQMP_CSU_VERSION_QEMU) {
+ return 65000000;
+ } else {
+ return mmio_read_32(IOU_SCNTRS_BASEFREQ);
+ }
+}
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
new file mode 100644
index 0000000..d8439f7
--- /dev/null
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <drivers/arm/gicv2.h>
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl zynqmp_calc_core_pos
+ .globl plat_my_core_pos
+ .globl platform_mem_init
+
+ /* -----------------------------------------------------
+ * void plat_secondary_cold_boot_setup (void);
+ *
+ * This function performs any platform specific actions
+ * needed for a secondary cpu after a cold reset e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ * TODO: Should we read the PSYS register to make sure
+ * that the request has gone through.
+ * -----------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+ mrs x0, mpidr_el1
+
+ /* Deactivate the gic cpu interface */
+ ldr x1, =BASE_GICC_BASE
+ mov w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1)
+ orr w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0)
+ str w0, [x1, #GICC_CTLR]
+
+ /*
+ * There is no sane reason to come out of this wfi. This
+ * cpu will be powered on and reset by the cpu_on pm api
+ */
+ dsb sy
+1:
+ no_ret plat_panic_handler
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+ mov x9, x30
+ bl plat_my_core_pos
+ cmp x0, #ZYNQMP_PRIMARY_CPU
+ cset x0, eq
+ ret x9
+endfunc plat_is_my_cpu_primary
+
+ /* -----------------------------------------------------
+ * unsigned int plat_my_core_pos(void)
+ * This function uses the zynqmp_calc_core_pos()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b zynqmp_calc_core_pos
+endfunc plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * unsigned int zynqmp_calc_core_pos(u_register_t mpidr)
+ * Helper function to calculate the core position.
+ * With this function: CorePos = (ClusterId * 4) +
+ * CoreId
+ * -----------------------------------------------------
+ */
+func zynqmp_calc_core_pos
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+endfunc zynqmp_calc_core_pos
+
+ /* ---------------------------------------------------------------------
+ * We don't need to carry out any memory initialization on ARM
+ * platforms. The Secure RAM is accessible straight away.
+ * ---------------------------------------------------------------------
+ */
+func platform_mem_init
+ ret
+endfunc platform_mem_init