diff options
Diffstat (limited to '')
-rw-r--r-- | plat/xilinx/zynqmp/aarch64/zynqmp_common.c | 391 | ||||
-rw-r--r-- | plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S | 86 |
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 |