diff options
Diffstat (limited to '')
-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 |
4 files changed, 391 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(); +} |