diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
commit | be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b (patch) | |
tree | 779c248fb61c83f65d1f0dc867f2053d76b4e03a /plat/nuvoton | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-upstream.tar.xz arm-trusted-firmware-upstream.zip |
Adding upstream version 2.10.0+dfsg.upstream/2.10.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plat/nuvoton')
-rw-r--r-- | plat/nuvoton/common/nuvoton_helpers.S | 214 | ||||
-rw-r--r-- | plat/nuvoton/common/nuvoton_pm.c | 75 | ||||
-rw-r--r-- | plat/nuvoton/common/nuvoton_topology.c | 51 | ||||
-rw-r--r-- | plat/nuvoton/common/plat_nuvoton_gic.c | 51 | ||||
-rw-r--r-- | plat/nuvoton/npcm845x/npcm845x_bl31_setup.c | 334 | ||||
-rw-r--r-- | plat/nuvoton/npcm845x/npcm845x_common.c | 27 | ||||
-rw-r--r-- | plat/nuvoton/npcm845x/npcm845x_psci.c | 436 | ||||
-rw-r--r-- | plat/nuvoton/npcm845x/npcm845x_serial_port.c | 136 | ||||
-rw-r--r-- | plat/nuvoton/npcm845x/platform.mk | 354 |
9 files changed, 1678 insertions, 0 deletions
diff --git a/plat/nuvoton/common/nuvoton_helpers.S b/plat/nuvoton/common/nuvoton_helpers.S new file mode 100644 index 0000000..09035a1 --- /dev/null +++ b/plat/nuvoton/common/nuvoton_helpers.S @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved. + * + * Copyright (C) 2022-2023 Nuvoton Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef NUVOTON_HELPERS_S +#define NUVOTON_HELPERS_S + +#include <asm_macros.S> +#include <cortex_a35.h> +#include <platform_def.h> + + .globl plat_is_my_cpu_primary + .globl plat_my_core_pos + .globl plat_calc_core_pos + .globl plat_reset_handler + .globl plat_get_my_entrypoint + .globl plat_secondary_cold_boot_setup + .globl plat_crash_console_init + .globl plat_crash_console_putc + .globl plat_crash_console_flush + .globl platform_mem_init + .globl npcm845x_mailbox_init + + /* -------------------------------------------------------------------- + * Helper macro that reads the part number of the current CPU and jumps + * to the given label if it matches the CPU MIDR provided. + * + * Clobbers x0. + * -------------------------------------------------------------------- + */ + .macro jump_if_cpu_midr _cpu_midr, _label + + mrs x0, midr_el1 + ubfx x0, x0, MIDR_PN_SHIFT, #12 + cmp w0, #((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK) + b.eq \_label + + .endm + + /* ---------------------------------------------- + * The mailbox_base is used to distinguish warm/cold + * reset. The mailbox_base is in the data section, not + * in .bss, this allows function to start using this + * variable before the runtime memory is initialized. + * ---------------------------------------------- + */ + .section .data.mailbox_base + .align 3 + mailbox_base: .quad 0x0 + + /* --------------------------------------------- + * void plat_reset_handler(void); + * + * To add: Determine the SoC type and call the appropriate + * reset handler. + *----------------------------------------------- */ + +func plat_reset_handler + ret +endfunc plat_reset_handler + + /* ---------------------------------------------- + * unsigned int plat_is_my_cpu_primary(void); + * This function checks if this is the primary CPU + * ---------------------------------------------- + */ +func plat_is_my_cpu_primary + mrs x0, mpidr_el1 + and x0, x0, #(MPIDR_CPU_MASK) + cmp x0, #PLAT_PRIMARY_CPU + cset x0, eq + ret +endfunc plat_is_my_cpu_primary + + /* ---------------------------------------------- + * unsigned int plat_my_core_pos(void) + * This Function uses the plat_calc_core_pos() + * to get the index of the calling CPU. + * ---------------------------------------------- + */ +func plat_my_core_pos + mrs x0, mpidr_el1 + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret +endfunc plat_my_core_pos + + /* + * unsigned int plat_calc_core_pos(uint64_t mpidr) + * helper function to calculate the core position. + * With this function. + */ +func plat_calc_core_pos + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret +endfunc plat_calc_core_pos + + /* --------------------------------------------- + * function to get the entrypoint. + * --------------------------------------------- + */ + /* --------------------------------------------------------------------- + * uintptr_t plat_get_my_entrypoint (void); + * + * Main job of this routine is to distinguish between a cold and a warm + * boot. + * + * This functions returns: + * - 0 for a cold boot. + * - Any other value for a warm boot. + * --------------------------------------------------------------------- + */ +func plat_get_my_entrypoint + mov x1, x30 + bl plat_is_my_cpu_primary + /* + * Secondaries always cold boot. + */ + cbz w0, 1f + /* + * Primaries warm boot if they are requested + * to power off. + */ + mov_imm x0, PLAT_NPCM_TM_HOLD_BASE + ldr x0, [x0] + cmp x0, PLAT_NPCM_TM_HOLD_STATE_BSP_OFF + adr x0, plat_wait_for_warm_boot + csel x0, x0, xzr, eq + ret x1 +1: mov x0, #0 + ret x1 +endfunc plat_get_my_entrypoint + +func npcm845x_mailbox_init + adrp x1, mailbox_base + str x0, [x1, :lo12:mailbox_base] + ret +endfunc npcm845x_mailbox_init + +func plat_wait_for_warm_boot + /* + * Calculate address of our hold entry. + * As the function will never return, there is no need to save LR. + */ + bl plat_my_core_pos + lsl x0, x0, #3 + mov x8, x0 + mov_imm x2, PLAT_NPCM_TM_HOLD_BASE + add x0, x0, x2 + mov_imm x2, PLAT_NPCM_TRUSTED_NOTIFICATION_BASE + add x8, x8, x2 + /* + * This code runs way before requesting the warmboot of this core, + * so it is possible to clear the mailbox before getting a request + * to boot. + */ + mov x1, PLAT_NPCM_TM_HOLD_STATE_WAIT + str x1,[x0] + + /* Notify that core is in pending state - do not use x0!, uses x7 and x8! */ + mov x7, PLAT_NPCM_TM_NOTIFICATION_START + str x7,[x8] + /* + * This code runs way before requesting the warmboot of this core, + * so it is possible to clear the mailbox before getting a request + * to boot. + */ + mov x1, PLAT_NPCM_TM_HOLD_STATE_WAIT + str x1,[x0] + /* Wait until we have a go */ +poll_mailbox: + wfe + ldr x1, [x0] + cmp x1, PLAT_NPCM_TM_HOLD_STATE_GO + bne poll_mailbox + + mov x7, PLAT_NPCM_TM_NOTIFICATION_BR + str x7,[x8] + /* Jump to the provided entrypoint */ + mov_imm x0, PLAT_NPCM_TM_ENTRYPOINT + ldr x1, [x0] + br x1 +endfunc plat_wait_for_warm_boot + +func plat_secondary_cold_boot_setup + b plat_wait_for_warm_boot +endfunc plat_secondary_cold_boot_setup + +func plat_crash_console_init + mov x0, #1 + ret +endfunc plat_crash_console_init + +func plat_crash_console_putc + ret +endfunc plat_crash_console_putc + +func plat_crash_console_flush + mov x0, #0 + ret +endfunc plat_crash_console_flush + +func platform_mem_init + ret +endfunc platform_mem_init + +#endif /* NUVOTON_HELPERS_S */ diff --git a/plat/nuvoton/common/nuvoton_pm.c b/plat/nuvoton/common/nuvoton_pm.c new file mode 100644 index 0000000..833ebfb --- /dev/null +++ b/plat/nuvoton/common/nuvoton_pm.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved. + * + * Copyright (C) 2023 Nuvoton Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <lib/psci/psci.h> +#include <plat/arm/common/plat_arm.h> +#include <plat/common/platform.h> +#include <platform_def.h> + + +/* Allow npcm845x to override these functions */ +#pragma weak plat_arm_program_trusted_mailbox +#pragma weak plat_setup_psci_ops /* changed to weak */ + + +/******************************************************************************* + * ARM standard platform handler called to check the validity of the non secure + * entrypoint. Returns 0 if the entrypoint is valid, or -1 otherwise. + ******************************************************************************/ +int arm_validate_ns_entrypoint(uintptr_t entrypoint) +{ + /* + * Check if the non secure entrypoint lies within the non + * secure DRAM. + */ + if ((entrypoint >= ARM_NS_DRAM1_BASE) && + (entrypoint < (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) { + return 0; + } +#ifdef __aarch64__ + if ((entrypoint >= ARM_DRAM2_BASE) && + (entrypoint < (ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) { + return 0; + } +#endif + + return -1; +} + +int arm_validate_psci_entrypoint(uintptr_t entrypoint) +{ + return (arm_validate_ns_entrypoint(entrypoint) == 0) ? PSCI_E_SUCCESS : + PSCI_E_INVALID_ADDRESS; +} + +/****************************************************************************** + * Helper function to save the platform state before a system suspend. Save the + * state of the system components which are not in the Always ON power domain. + *****************************************************************************/ +void arm_system_pwr_domain_save(void) +{ + /* Assert system power domain is available on the platform */ + assert(PLAT_MAX_PWR_LVL > ARM_PWR_LVL1); + + plat_arm_gic_save(); + + /* + * Unregister console now so that it is not registered for a second + * time during resume. + */ + arm_console_runtime_end(); + + /* + * All the other peripheral which are configured by TF-A are + * re-initialized on resume from system suspend. Hence we + * don't save their state here. + */ +} diff --git a/plat/nuvoton/common/nuvoton_topology.c b/plat/nuvoton/common/nuvoton_topology.c new file mode 100644 index 0000000..892d9e2 --- /dev/null +++ b/plat/nuvoton/common/nuvoton_topology.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved. + * + * Copyright (C) 2022-2023 Nuvoton Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <common/debug.h> +#include <lib/psci/psci.h> +#include <lib/semihosting.h> +#include <plat/common/platform.h> + +/* + * Since NPCM845 have only powered/non-powered state, + * the tree is structure of level 0 + * (Single cluster == 0) and 4 representing a "leaf" for every CPU + */ +const unsigned char npcm845x_power_domain_tree_desc[] = { + PLATFORM_CLUSTER_COUNT, + PLATFORM_MAX_CPU_PER_CLUSTER +}; + +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + /* A single cluster with 4 CPUs */ + return npcm845x_power_domain_tree_desc; +} + +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + unsigned int cluster_id, cpu_id; + + mpidr &= MPIDR_AFFINITY_MASK; + + if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) { + return -1; + } + + cluster_id = (unsigned int)MPIDR_AFFLVL1_VAL(mpidr); + cpu_id = (unsigned int)MPIDR_AFFLVL0_VAL(mpidr); + + if (cluster_id > PLATFORM_CLUSTER_COUNT || + cpu_id > PLATFORM_MAX_CPU_PER_CLUSTER) { + return -1; + } + + return (int)(cpu_id + (cluster_id * 4)); +} diff --git a/plat/nuvoton/common/plat_nuvoton_gic.c b/plat/nuvoton/common/plat_nuvoton_gic.c new file mode 100644 index 0000000..300670d --- /dev/null +++ b/plat/nuvoton/common/plat_nuvoton_gic.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved. + * + * Copyright (C) 2022-2023 Nuvoton Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/interrupt_props.h> +#include <drivers/arm/gicv2.h> +#include <plat/common/platform.h> +#include <platform_def.h> + +static const interrupt_prop_t g0_interrupt_props[] = { + INTR_PROP_DESC(FIQ_SMP_CALL_SGI, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), +}; + +gicv2_driver_data_t arm_gic_data = { + .gicd_base = BASE_GICD_BASE, + .gicc_base = BASE_GICC_BASE, + .interrupt_props = g0_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(g0_interrupt_props), +}; + +void plat_gic_driver_init(void) +{ + gicv2_driver_init(&arm_gic_data); +} + +void plat_gic_init(void) +{ + gicv2_distif_init(); + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} + +void plat_gic_cpuif_enable(void) +{ + gicv2_cpuif_enable(); +} + +void plat_gic_cpuif_disable(void) +{ + gicv2_cpuif_disable(); +} + +void plat_gic_pcpu_init(void) +{ + gicv2_pcpu_distif_init(); +} diff --git a/plat/nuvoton/npcm845x/npcm845x_bl31_setup.c b/plat/nuvoton/npcm845x/npcm845x_bl31_setup.c new file mode 100644 index 0000000..08448db --- /dev/null +++ b/plat/nuvoton/npcm845x/npcm845x_bl31_setup.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved. + * + * Copyright (C) 2017-2023 Nuvoton Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <drivers/console.h> +#include <drivers/generic_delay_timer.h> +#include <drivers/ti/uart/uart_16550.h> +#include <lib/debugfs.h> +#include <lib/extensions/ras.h> +#include <lib/mmio.h> +#include <lib/xlat_tables/xlat_tables_compat.h> +#include <npcm845x_clock.h> +#include <npcm845x_gcr.h> +#include <npcm845x_lpuart.h> +#include <plat/arm/common/plat_arm.h> +#include <plat/common/platform.h> +#include <plat_npcm845x.h> +#include <platform_def.h> + +/* + * Placeholder variables for copying the arguments that have been passed to + * BL31 from BL2. + */ +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; + +#if !RESET_TO_BL31 +/* + * Check that BL31_BASE is above ARM_FW_CONFIG_LIMIT. The reserved page + * is required for SOC_FW_CONFIG/TOS_FW_CONFIG passed from BL2. + */ +/* CASSERT(BL31_BASE >= ARM_FW_CONFIG_LIMIT, assert_bl31_base_overflows); */ +#endif /* !RESET_TO_BL31 */ + +#define MAP_BL31_TOTAL MAP_REGION_FLAT( \ + BL31_START, \ + BL31_END - BL31_START, \ + MT_MEMORY | MT_RW | EL3_PAS) + +#if SEPARATE_NOBITS_REGION +#define MAP_BL31_NOBITS MAP_REGION_FLAT( \ + BL31_NOBITS_BASE, \ + BL31_NOBITS_LIMIT - \ + BL31_NOBITS_BASE, \ + MT_MEMORY | MT_RW | EL3_PAS) +#endif /* SEPARATE_NOBITS_REGION */ + +/****************************************************************************** + * Return a pointer to the 'entry_point_info' structure of the next image + * for the security state specified. BL33 corresponds to the non-secure + * image type while BL32 corresponds to the secure image type. + * A NULL pointer is returned if the image does not exist. + *****************************************************************************/ +struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type) +{ + entry_point_info_t *next_image_info; + + assert(sec_state_is_valid(type)); + next_image_info = (type == NON_SECURE) + ? &bl33_image_ep_info : &bl32_image_ep_info; +/* + * None of the images on the ARM development platforms can have 0x0 + * as the entrypoint + */ + if (next_image_info->pc) { + return next_image_info; + } else { + return NULL; + } +} + +int board_uart_init(void) +{ + unsigned long UART_BASE_ADDR; + static console_t console; + +#ifdef CONFIG_TARGET_ARBEL_PALLADIUM + UART_Init(UART0_DEV, UART_MUX_MODE1, + UART_BAUDRATE_115200); + UART_BASE_ADDR = npcm845x_get_base_uart(UART0_DEV); +#else + UART_BASE_ADDR = npcm845x_get_base_uart(UART0_DEV); +#endif /* CONFIG_TARGET_ARBEL_PALLADIUM */ + +/* + * Register UART w/o initialization - + * A clock rate of zero means to skip the initialisation. + */ + console_16550_register((uintptr_t)UART_BASE_ADDR, 0, 0, &console); + + return 0; +} + +unsigned int plat_get_syscnt_freq2(void) +{ + return (unsigned int)COUNTER_FREQUENCY; +} + +/****************************************************************************** + * Perform any BL31 early platform setup common to ARM standard platforms. + * Here is an opportunity to copy parameters passed by the calling EL (S-EL1 + * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be + * done before the MMU is initialized so that the memory layout can be used + * while creating page tables. BL2 has flushed this information to memory, + * so we are guaranteed to pick up good data. + *****************************************************************************/ +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ +#if RESET_TO_BL31 + void *from_bl2 = (void *)arg0; + void *plat_params_from_bl2 = (void *)arg3; + + if (from_bl2 != NULL) { + assert(from_bl2 == NULL); + } + + if (plat_params_from_bl2 != NULL) { + assert(plat_params_from_bl2 == NULL); + } +#endif /* RESET_TO_BL31 */ + +/* Initialize Delay timer */ + generic_delay_timer_init(); + +/* Do Specific Board/Chip initializations */ + board_uart_init(); + +#if RESET_TO_BL31 + /* There are no parameters from BL2 if BL31 is a reset vector */ + assert(from_bl2 == NULL); + assert(plat_params_from_bl2 == NULL); + +#ifdef BL32_BASE + /* Populate entry point information for BL32 */ + SET_PARAM_HEAD(&bl32_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); + bl32_image_ep_info.pc = BL32_BASE; + bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry(); + +#if defined(SPD_spmd) +/* + * SPM (hafnium in secure world) expects SPM Core manifest base address + * in x0, which in !RESET_TO_BL31 case loaded after base of non shared + * SRAM(after 4KB offset of SRAM). But in RESET_TO_BL31 case all non + * shared SRAM is allocated to BL31, so to avoid overwriting of manifest + * keep it in the last page. + */ + bl32_image_ep_info.args.arg0 = ARM_TRUSTED_SRAM_BASE + + PLAT_ARM_TRUSTED_SRAM_SIZE - PAGE_SIZE; +#endif /* SPD_spmd */ +#endif /* BL32_BASE */ + +/* Populate entry point information for BL33 */ + SET_PARAM_HEAD(&bl33_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + +/* + * Tell BL31 where the non-trusted software image + * is located and the entry state information + */ + bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); + /* Generic ARM code will switch to EL2, revert to EL1 */ + bl33_image_ep_info.spsr = arm_get_spsr_for_bl33_entry(); + bl33_image_ep_info.spsr &= ~0x8; + bl33_image_ep_info.spsr |= 0x4; + + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, (uint32_t)NON_SECURE); + +#if defined(SPD_spmd) && !(ARM_LINUX_KERNEL_AS_BL33) +/* + * Hafnium in normal world expects its manifest address in x0, + * which is loaded at base of DRAM. + */ + bl33_image_ep_info.args.arg0 = (u_register_t)ARM_DRAM1_BASE; +#endif /* SPD_spmd && !ARM_LINUX_KERNEL_AS_BL33 */ + +#if ARM_LINUX_KERNEL_AS_BL33 +/* + * According to the file ``Documentation/arm64/booting.txt`` of the + * Linux kernel tree, Linux expects the physical address of the device + * tree blob (DTB) in x0, while x1-x3 are reserved for future use and + * must be 0. + */ + bl33_image_ep_info.args.arg0 = (u_register_t)ARM_PRELOADED_DTB_BASE; + bl33_image_ep_info.args.arg1 = 0U; + bl33_image_ep_info.args.arg2 = 0U; + bl33_image_ep_info.args.arg3 = 0U; +#endif /* ARM_LINUX_KERNEL_AS_BL33 */ + +#else /* RESET_TO_BL31 */ +/* + * In debug builds, we pass a special value in 'plat_params_from_bl2' + * to verify platform parameters from BL2 to BL31. + * In release builds, it's not used. + */ + assert(((unsigned long long)plat_params_from_bl2) == + ARM_BL31_PLAT_PARAM_VAL); + +/* + * Check params passed from BL2 should not be NULL, + */ + bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; + + assert(params_from_bl2 != NULL); + assert(params_from_bl2->h.type == PARAM_BL_PARAMS); + assert(params_from_bl2->h.version >= VERSION_2); + + bl_params_node_t *bl_params = params_from_bl2->head; + +/* + * Copy BL33 and BL32 (if present), entry point information. + * They are stored in Secure RAM, in BL2's address space. + */ + while (bl_params != NULL) { + if (bl_params->image_id == BL32_IMAGE_ID) { + bl32_image_ep_info = *bl_params->ep_info; + } + + if (bl_params->image_id == BL33_IMAGE_ID) { + bl33_image_ep_info = *bl_params->ep_info; + } + + bl_params = bl_params->next_params_info; + } + + if (bl33_image_ep_info.pc == 0U) { + panic(); + } +#endif /* RESET_TO_BL31 */ +} + +/******************************************************************************* + * Perform any BL31 platform setup common to ARM standard platforms + ******************************************************************************/ +void bl31_platform_setup(void) +{ +/* Initialize the GIC driver, cpu and distributor interfaces */ + plat_gic_driver_init(); + plat_gic_init(); + +#if RESET_TO_BL31 +#if defined(PLAT_ARM_MEM_PROT_ADDR) + arm_nor_psci_do_dyn_mem_protect(); +#endif /* PLAT_ARM_MEM_PROT_ADDR */ +#else +/* + * In this soluction, we also do the security initialzation + * even when BL31 is not in the reset vector + */ + npcm845x_security_setup(); +#endif /* RESET_TO_BL31 */ + +/* Enable and initialize the System level generic timer */ + mmio_write_32(ARM_SYS_CNTCTL_BASE + CNTCR_OFF, + CNTCR_FCREQ(0U) | CNTCR_EN); + +/* Initialize power controller before setting up topology */ + plat_arm_pwrc_setup(); + +#if RAS_EXTENSION + ras_init(); +#endif + +#if USE_DEBUGFS + debugfs_init(); +#endif /* USE_DEBUGFS */ +} + +void arm_console_runtime_init(void) +{ +/* Added in order to ignore the original weak function */ +} + +void plat_arm_program_trusted_mailbox(uintptr_t address) +{ +/* + * now we don't use ARM mailbox, + * so that function added to ignore the weak one + */ +} + +void __init bl31_plat_arch_setup(void) +{ + npcm845x_bl31_plat_arch_setup(); +} + +void __init plat_arm_pwrc_setup(void) +{ +/* NPCM850 is always powered so no need for power control */ +} + +void __init npcm845x_bl31_plat_arch_setup(void) +{ + const mmap_region_t bl_regions[] = { + MAP_BL31_TOTAL, +#if SEPARATE_NOBITS_REGION + MAP_BL31_NOBITS, +#endif /* SEPARATE_NOBITS_REGION */ + ARM_MAP_BL_RO, +#if USE_ROMLIB + ARM_MAP_ROMLIB_CODE, + ARM_MAP_ROMLIB_DATA, +#endif /* USE_ROMLIB */ +#if USE_COHERENT_MEM + ARM_MAP_BL_COHERENT_RAM, +#endif /* USE_COHERENT_MEM */ + ARM_MAP_SHARED_RAM, +#ifdef SECONDARY_BRINGUP + ARM_MAP_NS_DRAM1, + #ifdef BL32_BASE + ARM_MAP_BL32_CORE_MEM + #endif /* BL32_BASE */ +#endif /* SECONDARY_BRINGUP */ + {0} + }; + setup_page_tables(bl_regions, plat_arm_get_mmap()); + enable_mmu_el3(0U); +} diff --git a/plat/nuvoton/npcm845x/npcm845x_common.c b/plat/nuvoton/npcm845x/npcm845x_common.c new file mode 100644 index 0000000..fc393fd --- /dev/null +++ b/plat/nuvoton/npcm845x/npcm845x_common.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved. + * + * Copyright (C) 2022-2023 Nuvoton Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <lib/mmio.h> + +#include <lib/xlat_tables/xlat_tables_compat.h> +#include <plat/arm/common/plat_arm.h> +#include <plat/common/platform.h> + +#include <platform_def.h> + +const mmap_region_t plat_arm_mmap[] = { + MAP_DEVICE0, + MAP_DEVICE1, + {0} +}; diff --git a/plat/nuvoton/npcm845x/npcm845x_psci.c b/plat/nuvoton/npcm845x/npcm845x_psci.c new file mode 100644 index 0000000..a954265 --- /dev/null +++ b/plat/nuvoton/npcm845x/npcm845x_psci.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved. + * + * Copyright (C) 2017-2023 Nuvoton Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <stdbool.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/gicv2.h> +#include <lib/mmio.h> +#include <lib/psci/psci.h> +#include <lib/semihosting.h> +#include <npcm845x_clock.h> +#include <plat/arm/common/plat_arm.h> +#include <plat/common/platform.h> +#include <plat_npcm845x.h> + +#define ADP_STOPPED_APPLICATION_EXIT 0x20026 + +/* Make composite power state parameter till power level 0 */ +#if PSCI_EXTENDED_STATE_ID +/* Not Extended */ +#define npcm845x_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ + (((lvl0_state) << PSTATE_ID_SHIFT) | \ + ((type) << PSTATE_TYPE_SHIFT)) +#else +#define npcm845x_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ + (((lvl0_state) << PSTATE_ID_SHIFT) | \ + ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ + ((type) << PSTATE_TYPE_SHIFT)) +#endif /* PSCI_EXTENDED_STATE_ID */ + +#define npcm845x_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ + (((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \ + npcm845x_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) + +/* + * The table storing the valid idle power states. Ensure that the + * array entries are populated in ascending order of state-id to + * enable us to use binary search during power state validation. + * The table must be terminated by a NULL entry. + */ +static const unsigned int npcm845x_pm_idle_states[] = { +/* + * Cluster = 0 (RUN) CPU=1 (RET, higest in idle) - + * Retention. The Power state is Stand-by + */ + +/* State-id - 0x01 */ + npcm845x_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET, + MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY), + +/* + * For testing purposes. + * Only CPU suspend to standby is supported by NPCM845x + */ + /* State-id - 0x02 */ + npcm845x_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF, + MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN), + 0, +}; + +/******************************************************************************* + * Platform handler called to check the validity of the non secure + * entrypoint. + ******************************************************************************/ +int npcm845x_validate_ns_entrypoint(uintptr_t entrypoint) +{ + /* + * Check if the non secure entrypoint lies within the non + * secure DRAM. + */ + NOTICE("%s() nuvoton_psci\n", __func__); +#ifdef PLAT_ARM_TRUSTED_DRAM_BASE + if ((entrypoint >= PLAT_ARM_TRUSTED_DRAM_BASE) && + (entrypoint < (PLAT_ARM_TRUSTED_DRAM_BASE + + PLAT_ARM_TRUSTED_DRAM_SIZE))) { + return PSCI_E_INVALID_ADDRESS; + } +#endif /* PLAT_ARM_TRUSTED_DRAM_BASE */ + /* For TFTS purposes, '0' is also illegal */ + #ifdef SPD_tspd + if (entrypoint == 0) { + return PSCI_E_INVALID_ADDRESS; + } + #endif /* SPD_tspd */ + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Platform handler called when a CPU is about to enter standby. + ******************************************************************************/ +void npcm845x_cpu_standby(plat_local_state_t cpu_state) +{ + NOTICE("%s() nuvoton_psci\n", __func__); + + uint64_t scr; + + scr = read_scr_el3(); + write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); + + /* + * Enter standby state + * dsb is good practice before using wfi to enter low power states + */ + isb(); + dsb(); + wfi(); + + /* Once awake */ + write_scr_el3(scr); +} + +/******************************************************************************* + * Platform handler called when a power domain is about to be turned on. The + * mpidr determines the CPU to be turned on. + ******************************************************************************/ +int npcm845x_pwr_domain_on(u_register_t mpidr) +{ + int rc = PSCI_E_SUCCESS; + int cpu_id = plat_core_pos_by_mpidr(mpidr); + + if ((unsigned int)cpu_id >= PLATFORM_CORE_COUNT) { + ERROR("%s() CPU 0x%X\n", __func__, cpu_id); + return PSCI_E_INVALID_PARAMS; + } + + if (cpu_id == -1) { + /* domain on was not called by a CPU */ + ERROR("%s() was not per CPU 0x%X\n", __func__, cpu_id); + return PSCI_E_INVALID_PARAMS; + } + + unsigned int pos = (unsigned int)plat_core_pos_by_mpidr(mpidr); + uintptr_t hold_base = PLAT_NPCM_TM_HOLD_BASE; + + assert(pos < PLATFORM_CORE_COUNT); + + hold_base += pos * PLAT_NPCM_TM_HOLD_ENTRY_SIZE; + + mmio_write_64(hold_base, PLAT_NPCM_TM_HOLD_STATE_GO); + /* No cache maintenance here, hold_base is mapped as device memory. */ + + /* Make sure that the write has completed */ + dsb(); + isb(); + + sev(); + + return rc; +} + + +/******************************************************************************* + * Platform handler called when a power domain is about to be suspended. The + * target_state encodes the power state that each level should transition to. + ******************************************************************************/ +void npcm845x_pwr_domain_suspend(const psci_power_state_t *target_state) +{ + NOTICE("%s() nuvoton_psci\n", __func__); + + for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { + INFO("%s: target_state->pwr_domain_state[%lu]=%x\n", + __func__, i, target_state->pwr_domain_state[i]); + } + + gicv2_cpuif_disable(); + + NOTICE("%s() Out of suspend\n", __func__); +} + + +/******************************************************************************* + * Platform handler called when a power domain has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. + ******************************************************************************/ +void npcm845x_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + NOTICE("%s() nuvoton_psci\n", __func__); + + for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { + INFO("%s: target_state->pwr_domain_state[%lu]=%x\n", + __func__, i, target_state->pwr_domain_state[i]); + } + + assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == + PLAT_LOCAL_STATE_OFF); + + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} + + +/******************************************************************************* + * Platform handler called when a power domain has just been powered on after + * having been suspended earlier. The target_state encodes the low power state + * that each level has woken up from. + ******************************************************************************/ +void npcm845x_pwr_domain_suspend_finish(const psci_power_state_t *target_state) +{ + NOTICE("%s() nuvoton_psci\n", __func__); + + for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { + INFO("%s: target_state->pwr_domain_state[%lu]=%x\n", + __func__, i, target_state->pwr_domain_state[i]); + } + + assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == + PLAT_LOCAL_STATE_OFF); + + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} + + +void __dead2 npcm845x_system_reset(void) +{ + uintptr_t RESET_BASE_ADDR; + uint32_t val; + + NOTICE("%s() nuvoton_psci\n", __func__); + console_flush(); + + dsbsy(); + isb(); + + /* + * In future - support all reset types. For now, SW1 reset + * Enable software reset 1 to reboot the BMC + */ + RESET_BASE_ADDR = (uintptr_t)0xF0801000; + + /* Read SW1 control register */ + val = mmio_read_32(RESET_BASE_ADDR + 0x44); + /* Keep SPI BMC & MC persist*/ + val &= 0xFBFFFFDF; + /* Setting SW1 control register */ + mmio_write_32(RESET_BASE_ADDR + 0x44, val); + /* Set SW1 reset */ + mmio_write_32(RESET_BASE_ADDR + 0x14, 0x8); + dsb(); + + while (1) { + ; + } +} + +int npcm845x_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + unsigned int state_id; + int i; + + NOTICE("%s() nuvoton_psci\n", __func__); + assert(req_state); + + /* + * Currently we are using a linear search for finding the matching + * entry in the idle power state array. This can be made a binary + * search if the number of entries justify the additional complexity. + */ + for (i = 0; !!npcm845x_pm_idle_states[i]; i++) { + if (power_state == npcm845x_pm_idle_states[i]) { + break; + } + } + + /* Return error if entry not found in the idle state array */ + if (!npcm845x_pm_idle_states[i]) { + return PSCI_E_INVALID_PARAMS; + } + + i = 0; + state_id = psci_get_pstate_id(power_state); + + /* Parse the State ID and populate the state info parameter */ + while (state_id) { + req_state->pwr_domain_state[i++] = (uint8_t)state_id & + PLAT_LOCAL_PSTATE_MASK; + state_id >>= PLAT_LOCAL_PSTATE_WIDTH; + } + + return PSCI_E_SUCCESS; +} + +/* + * The NPCM845 doesn't truly support power management at SYSTEM power domain. + * The SYSTEM_SUSPEND will be down-graded to the cluster level within + * the platform layer. The `fake` SYSTEM_SUSPEND allows us to validate + * some of the driver save and restore sequences on FVP. + */ +#if !ARM_BL31_IN_DRAM +void npcm845x_get_sys_suspend_power_state(psci_power_state_t *req_state) +{ + unsigned int i; + + NOTICE("%s() nuvoton_psci\n", __func__); + + for (i = ARM_PWR_LVL0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { + req_state->pwr_domain_state[i] = (uint8_t)PLAT_LOCAL_STATE_OFF; + } +} +#endif /* !ARM_BL31_IN_DRAM */ + +/* + * The rest of the PSCI implementation are for testing purposes only. + * Not supported in Arbel + */ +void __dead2 npcm845x_system_off(void) +{ + console_flush(); + + dsbsy(); + isb(); + + /* NPCM845 doesn't allow real system off, Do reaset instead */ + /* Do reset here TBD which, in the meanwhile SW1 reset */ + for (;;) { + wfi(); + } +} + +void __dead2 plat_secondary_cold_boot_setup(void); + +void __dead2 npcm845x_pwr_down_wfi( + const psci_power_state_t *target_state) +{ + uintptr_t hold_base = PLAT_NPCM_TM_HOLD_BASE; + unsigned int pos = plat_my_core_pos(); + + if (pos == 0) { + /* + * The secondaries will always be in a wait + * for warm boot on reset, but the BSP needs + * to be able to distinguish between waiting + * for warm boot (e.g. after psci_off, waiting + * for psci_on) and a cold boot. + */ + mmio_write_64(hold_base, PLAT_NPCM_TM_HOLD_STATE_BSP_OFF); + /* No cache maintenance here, we run with caches off already. */ + dsb(); + isb(); + } + + wfe(); + + while (1) { + ; + } +} + +/******************************************************************************* + * Platform handler called when a power domain is about to be turned off. The + * target_state encodes the power state that each level should transition to. + ******************************************************************************/ +void npcm845x_pwr_domain_off(const psci_power_state_t *target_state) +{ + NOTICE("%s() nuvoton_psci\n", __func__); + + for (size_t i = 0; (uint64_t)i <= PLAT_MAX_PWR_LVL; i++) { + INFO("%s: target_state->pwr_domain_state[%lu]=%x\n", + __func__, i, target_state->pwr_domain_state[i]); + } + + plat_secondary_cold_boot_setup(); +} + +static const plat_psci_ops_t npcm845x_plat_psci_ops = { + .cpu_standby = npcm845x_cpu_standby, + .pwr_domain_on = npcm845x_pwr_domain_on, + .pwr_domain_suspend = npcm845x_pwr_domain_suspend, + .pwr_domain_on_finish = npcm845x_pwr_domain_on_finish, + .pwr_domain_suspend_finish = npcm845x_pwr_domain_suspend_finish, + .system_reset = npcm845x_system_reset, + .validate_power_state = npcm845x_validate_power_state, + .validate_ns_entrypoint = npcm845x_validate_ns_entrypoint, + + /* For testing purposes only This PSCI states are not supported */ + .pwr_domain_off = npcm845x_pwr_domain_off, + .pwr_domain_pwr_down_wfi = npcm845x_pwr_down_wfi, +}; + +/* For reference only + * typedef struct plat_psci_ops { + * void (*cpu_standby)(plat_local_state_t cpu_state); + * int (*pwr_domain_on)(u_register_t mpidr); + * void (*pwr_domain_off)(const psci_power_state_t *target_state); + * void (*pwr_domain_suspend_pwrdown_early)( + * const psci_power_state_t *target_state); + * void (*pwr_domain_suspend)(const psci_power_state_t *target_state); + * void (*pwr_domain_on_finish)(const psci_power_state_t *target_state); + * void (*pwr_domain_on_finish_late)( + * const psci_power_state_t *target_state); + * void (*pwr_domain_suspend_finish)( + * const psci_power_state_t *target_state); + * void __dead2 (*pwr_domain_pwr_down_wfi)( + * const psci_power_state_t *target_state); + * void __dead2 (*system_off)(void); + * void __dead2 (*system_reset)(void); + * int (*validate_power_state)(unsigned int power_state, + * psci_power_state_t *req_state); + * int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint); + * void (*get_sys_suspend_power_state)( + * psci_power_state_t *req_state); + * int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state, + * int pwrlvl); + * int (*translate_power_state_by_mpidr)(u_register_t mpidr, + * unsigned int power_state, + * psci_power_state_t *output_state); + * int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level); + * int (*mem_protect_chk)(uintptr_t base, u_register_t length); + * int (*read_mem_protect)(int *val); + * int (*write_mem_protect)(int val); + * int (*system_reset2)(int is_vendor, + * int reset_type, u_register_t cookie); + * } plat_psci_ops_t; + */ + +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + uintptr_t *entrypoint = (void *)PLAT_NPCM_TM_ENTRYPOINT; + + *entrypoint = sec_entrypoint; + + *psci_ops = &npcm845x_plat_psci_ops; + + return 0; +} diff --git a/plat/nuvoton/npcm845x/npcm845x_serial_port.c b/plat/nuvoton/npcm845x/npcm845x_serial_port.c new file mode 100644 index 0000000..946e9d0 --- /dev/null +++ b/plat/nuvoton/npcm845x/npcm845x_serial_port.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved. + * + * Copyright (C) 2017-2023 Nuvoton Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdbool.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/gicv2.h> +#include <drivers/delay_timer.h> +#include <drivers/generic_delay_timer.h> +#include <lib/mmio.h> +#include <lib/psci/psci.h> +#include <npcm845x_clock.h> +#include <npcm845x_gcr.h> +#include <npcm845x_lpuart.h> +#include <plat_npcm845x.h> + + +uintptr_t npcm845x_get_base_uart(UART_DEV_T devNum) +{ + return 0xF0000000 + devNum * 0x1000; +} + +uintptr_t npcm845x_get_base_clk(void) +{ + return 0xF0801000; +} + +uintptr_t npcm845x_get_base_gcr(void) +{ + return 0xF0800000; +} + +void npcm845x_wait_for_empty(int uart_n) +{ + volatile struct npcmX50_uart *uart = (struct npcmX50_uart *)npcm845x_get_base_uart(uart_n); + + while ((*(uint8_t *)(uintptr_t)(&uart->lsr) & 0x40) == 0x00) { +/* + * wait for THRE (Transmitter Holding Register Empty) + * and TSR (Transmitter Shift Register) to be empty. + * Some delay. notice needed some delay so UartUpdateTool + * will pass w/o error log + */ + } + + volatile int delay; + + for (delay = 0; delay < 10000; delay++) { + ; + } +} + +int UART_Init(UART_DEV_T devNum, UART_BAUDRATE_T baudRate) +{ + uint32_t val = 0; + uintptr_t clk_base = npcm845x_get_base_clk(); + uintptr_t gcr_base = npcm845x_get_base_gcr(); + uintptr_t uart_base = npcm845x_get_base_uart(devNum); + volatile struct npcmX50_uart *uart = (struct npcmX50_uart *)uart_base; + +/* Use CLKREF to be independent of CPU frequency */ + volatile struct clk_ctl *clk_ctl_obj = (struct clk_ctl *)clk_base; + volatile struct npcm845x_gcr *gcr_ctl_obj = + (struct npcm845x_gcr *)gcr_base; + + clk_ctl_obj->clksel = clk_ctl_obj->clksel & ~(0x3 << 8); + clk_ctl_obj->clksel = clk_ctl_obj->clksel | (0x2 << 8); + + /* Set devider according to baudrate */ + clk_ctl_obj->clkdiv1 = + (unsigned int)(clk_ctl_obj->clkdiv1 & ~(0x1F << 16)); + + /* clear bits 11-15 - set value 0 */ + if (devNum == UART3_DEV) { + clk_ctl_obj->clkdiv2 = + (unsigned int)(clk_ctl_obj->clkdiv2 & ~(0x1F << 11)); + } + + npcm845x_wait_for_empty(devNum); + + val = (uint32_t)LCR_WLS_8bit; + mmio_write_8((uintptr_t)&uart->lcr, (uint8_t)val); + + /* disable all interrupts */ + mmio_write_8((uintptr_t)&uart->ier, 0); + + /* + * Set the RX FIFO trigger level, reset RX, TX FIFO + */ + val = (uint32_t)(FCR_FME | FCR_RFR | FCR_TFR | FCR_RFITL_4B); + + /* reset TX and RX FIFO */ + mmio_write_8((uintptr_t)(&uart->fcr), (uint8_t)val); + + /* Set port for 8 bit, 1 stop, no parity */ + val = (uint32_t)LCR_WLS_8bit; + + /* Set DLAB bit; Accesses the Divisor Latch Registers (DLL, DLM). */ + val |= 0x80; + mmio_write_8((uintptr_t)(&uart->lcr), (uint8_t)val); + + /* Baud Rate = UART Clock 24MHz / (16 * (11+2)) = 115384 */ + mmio_write_8((uintptr_t)(&uart->dll), 11); + mmio_write_8((uintptr_t)(&uart->dlm), 0x00); + + val = mmio_read_8((uintptr_t)&uart->lcr); + + /* Clear DLAB bit; Accesses RBR, THR or IER registers. */ + val &= 0x7F; + mmio_write_8((uintptr_t)(&uart->lcr), (uint8_t)val); + + if (devNum == UART0_DEV) { + gcr_ctl_obj->mfsel4 &= ~(1 << 1); + gcr_ctl_obj->mfsel1 |= 1 << 9; + } else if (devNum == UART3_DEV) { + /* Pin Mux */ + gcr_ctl_obj->mfsel4 &= ~(1 << 1); + gcr_ctl_obj->mfsel1 |= 1 << 11; + gcr_ctl_obj->spswc &= (7 << 0); + gcr_ctl_obj->spswc |= (2 << 0); + } else { + /* halt */ + while (1) { + ; + } + } + + return 0; +} diff --git a/plat/nuvoton/npcm845x/platform.mk b/plat/nuvoton/npcm845x/platform.mk new file mode 100644 index 0000000..92c7e2f --- /dev/null +++ b/plat/nuvoton/npcm845x/platform.mk @@ -0,0 +1,354 @@ +# +# Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved. +# +# Copyright (c) 2017-2023 Nuvoton Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# This is a debug flag for bring-up. It allows reducing CPU numbers +# SECONDARY_BRINGUP := 1 +RESET_TO_BL31 := 1 +SPMD_SPM_AT_SEL2 := 0 +#temporary until the RAM size is reduced +USE_COHERENT_MEM := 1 + + +$(eval $(call add_define,RESET_TO_BL31)) + +ifeq (${ARCH}, aarch64) +# On ARM standard platorms, the TSP can execute from Trusted SRAM, +# Trusted DRAM (if available) or the TZC secured area of DRAM. +# TZC secured DRAM is the default. + +# Process ARM_BL31_IN_DRAM flag +ARM_BL31_IN_DRAM := 0 +$(eval $(call assert_boolean,ARM_BL31_IN_DRAM)) +$(eval $(call add_define,ARM_BL31_IN_DRAM)) +endif + +# For the original power-state parameter format, the State-ID can be encoded +# according to the recommended encoding or zero. This flag determines which +# State-ID encoding to be parsed. +ARM_RECOM_STATE_ID_ENC := 0 + +# If the PSCI_EXTENDED_STATE_ID is set, then ARM_RECOM_STATE_ID_ENC +# need to be set. Else throw a build error. +ifeq (${PSCI_EXTENDED_STATE_ID}, 1) +ifeq (${ARM_RECOM_STATE_ID_ENC}, 0) +$(error Build option ARM_RECOM_STATE_ID_ENC needs to be set if \ + PSCI_EXTENDED_STATE_ID is set for ARM platforms) +endif +endif + +# Process ARM_RECOM_STATE_ID_ENC flag +$(eval $(call assert_boolean,ARM_RECOM_STATE_ID_ENC)) +$(eval $(call add_define,ARM_RECOM_STATE_ID_ENC)) + +# Process ARM_DISABLE_TRUSTED_WDOG flag +# By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set +ARM_DISABLE_TRUSTED_WDOG := 0 +ifeq (${SPIN_ON_BL1_EXIT}, 1) +ARM_DISABLE_TRUSTED_WDOG := 1 +endif +$(eval $(call assert_boolean,ARM_DISABLE_TRUSTED_WDOG)) +$(eval $(call add_define,ARM_DISABLE_TRUSTED_WDOG)) + +# Process ARM_CONFIG_CNTACR +ARM_CONFIG_CNTACR := 1 +$(eval $(call assert_boolean,ARM_CONFIG_CNTACR)) +$(eval $(call add_define,ARM_CONFIG_CNTACR)) + +# Process ARM_BL31_IN_DRAM flag +ARM_BL31_IN_DRAM := 0 +$(eval $(call assert_boolean,ARM_BL31_IN_DRAM)) +$(eval $(call add_define,ARM_BL31_IN_DRAM)) + +# Process ARM_PLAT_MT flag +ARM_PLAT_MT := 0 +$(eval $(call assert_boolean,ARM_PLAT_MT)) +$(eval $(call add_define,ARM_PLAT_MT)) + +# Use translation tables library v2 by default +ARM_XLAT_TABLES_LIB_V1 := 0 +$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1)) +$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1)) + +# Don't have the Linux kernel as a BL33 image by default +ARM_LINUX_KERNEL_AS_BL33 := 0 +$(eval $(call assert_boolean,ARM_LINUX_KERNEL_AS_BL33)) +$(eval $(call add_define,ARM_LINUX_KERNEL_AS_BL33)) + +ifeq (${ARM_LINUX_KERNEL_AS_BL33},1) +ifeq (${ARCH},aarch64) +ifneq (${RESET_TO_BL31},1) +$(error "ARM_LINUX_KERNEL_AS_BL33 is only available if RESET_TO_BL31=1.") +endif +else +ifneq (${RESET_TO_SP_MIN},1) +$(error "ARM_LINUX_KERNEL_AS_BL33 is only available if RESET_TO_SP_MIN=1.") +endif +endif + +ifndef PRELOADED_BL33_BASE +$(error "PRELOADED_BL33_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.") +endif + +ifndef ARM_PRELOADED_DTB_BASE +$(error "ARM_PRELOADED_DTB_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.") +endif + +$(eval $(call add_define,ARM_PRELOADED_DTB_BASE)) +endif + +# Use an implementation of SHA-256 with a smaller memory footprint +# but reduced speed. +$(eval $(call add_define,MBEDTLS_SHA256_SMALLER)) + +# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images +# in the FIP if the platform requires. +ifneq ($(BL32_EXTRA1),) +$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1)) +endif +ifneq ($(BL32_EXTRA2),) +$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2)) +endif + +# Enable PSCI_STAT_COUNT/RESIDENCY APIs on ARM platforms +ENABLE_PSCI_STAT := 1 +ENABLE_PMF := 1 + +# On ARM platforms, separate the code and read-only data sections to allow +# mapping the former as executable and the latter as execute-never. +SEPARATE_CODE_AND_RODATA := 1 + +# On ARM platforms, disable SEPARATE_NOBITS_REGION by default. Both PROGBITS +# and NOBITS sections of BL31 image are adjacent to each other and loaded +# into Trusted SRAM. +SEPARATE_NOBITS_REGION := 0 + +# In order to support SEPARATE_NOBITS_REGION for Arm platforms, we need to load +# BL31 PROGBITS into secure DRAM space and BL31 NOBITS into SRAM. Hence mandate +# the build to require that ARM_BL31_IN_DRAM is enabled as well. +ifeq ($(SEPARATE_NOBITS_REGION),1) +ifneq ($(ARM_BL31_IN_DRAM),1) +$(error For SEPARATE_NOBITS_REGION, ARM_BL31_IN_DRAM must be enabled) +endif + +ifneq ($(RECLAIM_INIT_CODE),0) +$(error For SEPARATE_NOBITS_REGION, RECLAIM_INIT_CODE cannot be supported) +endif +endif + +# Enable PIE support for RESET_TO_BL31 case +ifeq (${RESET_TO_BL31},1) +ENABLE_PIE := 1 +endif + +PLAT_INCLUDES := -Iinclude/plat/nuvoton/npcm845x \ + -Iinclude/plat/nuvoton/common \ + -Iinclude/drivers/nuvoton/npcm845x \ + +ifeq (${ARCH}, aarch64) +PLAT_INCLUDES += -Iinclude/plat/arm/common/aarch64 +endif + +# Include GICv3 driver files +include drivers/arm/gic/v2/gicv2.mk + +NPCM850_GIC_SOURCES := ${GICV2_SOURCES} + +BL31_SOURCES +=lib/cpus/aarch64/cortex_a35.S \ + plat/common/plat_psci_common.c \ + drivers/ti/uart/aarch64/16550_console.S \ + plat/nuvoton/npcm845x/npcm845x_psci.c \ + plat/nuvoton/npcm845x/npcm845x_serial_port.c \ + plat/nuvoton/common/nuvoton_topology.c \ + plat/nuvoton/npcm845x/npcm845x_bl31_setup.c + +PLAT_BL_COMMON_SOURCES := drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ + plat/common/plat_gicv2.c \ + plat/arm/common/arm_gicv2.c \ + plat/nuvoton/common/plat_nuvoton_gic.c \ + ${NPCM850_GIC_SOURCES} \ + plat/nuvoton/npcm845x/npcm845x_common.c \ + plat/nuvoton/common/nuvoton_helpers.S \ + lib/semihosting/semihosting.c \ + lib/semihosting/${ARCH}/semihosting_call.S \ + plat/arm/common/arm_common.c \ + plat/arm/common/arm_console.c + +ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1) +PLAT_BL_COMMON_SOURCES += lib/xlat_tables/xlat_tables_common.c \ + lib/xlat_tables/${ARCH}/xlat_tables.c +else +include lib/xlat_tables_v2/xlat_tables.mk + +PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} +endif + +ARM_IO_SOURCES += plat/arm/common/arm_io_storage.c \ + plat/arm/common/fconf/arm_fconf_io.c + +ifeq (${SPD},spmd) +ifeq (${SPMD_SPM_AT_SEL2},1) +ARM_IO_SOURCES += plat/arm/common/fconf/arm_fconf_sp.c +endif +endif + +BL1_SOURCES += drivers/io/io_fip.c \ + drivers/io/io_memmap.c \ + drivers/io/io_storage.c \ + plat/arm/common/arm_bl1_setup.c \ + plat/arm/common/arm_err.c \ + ${ARM_IO_SOURCES} + +ifdef EL3_PAYLOAD_BASE +# Need the plat_arm_program_trusted_mailbox() function to release secondary CPUs +# from their holding pen +BL1_SOURCES += plat/arm/common/arm_pm.c +endif + +BL2_SOURCES += drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ + drivers/io/io_fip.c \ + drivers/io/io_memmap.c \ + drivers/io/io_storage.c \ + plat/arm/common/arm_bl2_setup.c \ + plat/arm/common/arm_err.c \ + ${ARM_IO_SOURCES} + +# Firmware Configuration Framework sources +include lib/fconf/fconf.mk + +# Add `libfdt` and Arm common helpers required for Dynamic Config +include lib/libfdt/libfdt.mk + +DYN_CFG_SOURCES += plat/arm/common/arm_dyn_cfg.c \ + plat/arm/common/arm_dyn_cfg_helpers.c \ + common/fdt_wrappers.c + +BL1_SOURCES += ${DYN_CFG_SOURCES} +BL2_SOURCES += ${DYN_CFG_SOURCES} + +ifeq (${BL2_AT_EL3},1) +BL2_SOURCES += plat/arm/common/arm_bl2_el3_setup.c +endif + +# Because BL1/BL2 execute in AArch64 mode but BL32 in AArch32 we need to use +# the AArch32 descriptors. +BL2_SOURCES += plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c +BL2_SOURCES += plat/arm/common/arm_image_load.c \ + common/desc_image_load.c + +ifeq (${SPD},opteed) +BL2_SOURCES += lib/optee/optee_utils.c +endif + +BL2U_SOURCES += drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ + plat/arm/common/arm_bl2u_setup.c + +BL31_SOURCES += plat/arm/common/arm_bl31_setup.c \ + plat/nuvoton/common/nuvoton_pm.c \ + plat/nuvoton/common/nuvoton_topology.c \ + plat/common/plat_psci_common.c + +ifeq (${ENABLE_PMF}, 1) +ifeq (${ARCH}, aarch64) +BL31_SOURCES += plat/arm/common/aarch64/execution_state_switch.c \ + plat/arm/common/arm_sip_svc.c \ + plat/arm/common/plat_arm_sip_svc.c \ + lib/pmf/pmf_smc.c +else +BL32_SOURCES += plat/arm/common/arm_sip_svc.c \ + plat/arm/common/plat_arm_sip_svc.c \ + lib/pmf/pmf_smc.c +endif +endif + +ifeq (${EL3_EXCEPTION_HANDLING},1) +BL31_SOURCES += plat/arm/common/aarch64/arm_ehf.c +endif + +ifeq (${SDEI_SUPPORT},1) +BL31_SOURCES += plat/arm/common/aarch64/arm_sdei.c +ifeq (${SDEI_IN_FCONF},1) +BL31_SOURCES += plat/arm/common/fconf/fconf_sdei_getter.c +endif +endif + +# RAS sources +ifeq (${RAS_EXTENSION},1) +BL31_SOURCES += lib/extensions/ras/std_err_record.c \ + lib/extensions/ras/ras_common.c +endif + +# Pointer Authentication sources +ifeq (${ENABLE_PAUTH}, 1) +PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c +endif + +ifeq (${SPD},spmd) +BL31_SOURCES += plat/common/plat_spmd_manifest.c \ + common/fdt_wrappers.c \ + ${LIBFDT_SRCS} +endif + +ifneq (${TRUSTED_BOARD_BOOT},0) +# Include common TBB sources +AUTH_SOURCES := drivers/auth/auth_mod.c \ + drivers/auth/crypto_mod.c \ + drivers/auth/img_parser_mod.c \ + lib/fconf/fconf_tbbr_getter.c + +# Include the selected chain of trust sources. +ifeq (${COT},tbbr) +AUTH_SOURCES += drivers/auth/tbbr/tbbr_cot_common.c +BL1_SOURCES += drivers/auth/tbbr/tbbr_cot_bl1.c +BL2_SOURCES += drivers/auth/tbbr/tbbr_cot_bl2.c +else ifeq (${COT},dualroot) +AUTH_SOURCES += drivers/auth/dualroot/cot.c +else +$(error Unknown chain of trust ${COT}) +endif + +BL1_SOURCES += ${AUTH_SOURCES} \ + bl1/tbbr/tbbr_img_desc.c \ + plat/arm/common/arm_bl1_fwu.c \ + plat/common/tbbr/plat_tbbr.c + +BL2_SOURCES += ${AUTH_SOURCES} \ + plat/common/tbbr/plat_tbbr.c + +$(eval $(call TOOL_ADD_IMG,ns_bl2u,--fwu,FWU_)) + +# We expect to locate the *.mk files under the directories specified below +CRYPTO_LIB_MK := drivers/auth/mbedtls/mbedtls_crypto.mk + +IMG_PARSER_LIB_MK := drivers/auth/mbedtls/mbedtls_x509.mk + +$(info Including ${CRYPTO_LIB_MK}) +include ${CRYPTO_LIB_MK} + +$(info Including ${IMG_PARSER_LIB_MK}) +include ${IMG_PARSER_LIB_MK} +endif + +ifeq (${MEASURED_BOOT},1) +MEASURED_BOOT_MK := drivers/measured_boot/measured_boot.mk +$(info Including ${MEASURED_BOOT_MK}) +include ${MEASURED_BOOT_MK} +endif + +ifeq (${EL3_EXCEPTION_HANDLING},1) +BL31_SOURCES += plat/arm/common/aarch64/arm_ehf.c +endif + +BL1_SOURCES := +BL2_SOURCES := +BL2U_SOURCES := + +DEBUG_CONSOLE ?= 0 +$(eval $(call add_define,DEBUG_CONSOLE)) |