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/nvidia/tegra/common | |
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/nvidia/tegra/common')
-rw-r--r-- | plat/nvidia/tegra/common/aarch64/tegra_helpers.S | 446 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_bl31_setup.c | 361 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_common.mk | 59 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_delay_timer.c | 57 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_fiq_glue.c | 149 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_gicv2.c | 72 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_gicv3.c | 79 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_io_storage.c | 20 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_platform.c | 311 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_pm.c | 340 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_sdei.c | 56 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_sip_calls.c | 158 | ||||
-rw-r--r-- | plat/nvidia/tegra/common/tegra_stack_protector.c | 28 |
13 files changed, 2136 insertions, 0 deletions
diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S new file mode 100644 index 0000000..72ecd54 --- /dev/null +++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <assert_macros.S> +#include <cortex_a57.h> +#include <cpu_macros.S> + +#include <platform_def.h> +#include <tegra_def.h> +#include <tegra_platform.h> + +#define MIDR_PN_CORTEX_A57 0xD07 + +/******************************************************************************* + * Implementation defined ACTLR_EL3 bit definitions + ******************************************************************************/ +#define ACTLR_ELx_L2ACTLR_BIT (U(1) << 6) +#define ACTLR_ELx_L2ECTLR_BIT (U(1) << 5) +#define ACTLR_ELx_L2CTLR_BIT (U(1) << 4) +#define ACTLR_ELx_CPUECTLR_BIT (U(1) << 1) +#define ACTLR_ELx_CPUACTLR_BIT (U(1) << 0) +#define ACTLR_ELx_ENABLE_ALL_ACCESS (ACTLR_ELx_L2ACTLR_BIT | \ + ACTLR_ELx_L2ECTLR_BIT | \ + ACTLR_ELx_L2CTLR_BIT | \ + ACTLR_ELx_CPUECTLR_BIT | \ + ACTLR_ELx_CPUACTLR_BIT) + + /* Global functions */ + .globl plat_is_my_cpu_primary + .globl plat_my_core_pos + .globl plat_get_my_entrypoint + .globl plat_secondary_cold_boot_setup + .globl platform_mem_init + .globl plat_crash_console_init + .globl plat_crash_console_putc + .globl plat_crash_console_flush + .weak plat_core_pos_by_mpidr + .globl tegra_secure_entrypoint + .globl plat_reset_handler + + /* Global variables */ + .globl tegra_sec_entry_point + .globl ns_image_entrypoint + .globl tegra_bl31_phys_base + .globl tegra_console_base + + /* --------------------- + * Common CPU init code + * --------------------- + */ +.macro cpu_init_common + + /* ------------------------------------------------ + * We enable procesor retention, L2/CPUECTLR NS + * access and ECC/Parity protection for A57 CPUs + * ------------------------------------------------ + */ + mrs x0, midr_el1 + mov x1, #(MIDR_PN_MASK << MIDR_PN_SHIFT) + and x0, x0, x1 + lsr x0, x0, #MIDR_PN_SHIFT + cmp x0, #MIDR_PN_CORTEX_A57 + b.ne 1f + + /* --------------------------- + * Enable processor retention + * --------------------------- + */ + mrs x0, CORTEX_A57_L2ECTLR_EL1 + mov x1, #RETENTION_ENTRY_TICKS_512 + bic x0, x0, #CORTEX_A57_L2ECTLR_RET_CTRL_MASK + orr x0, x0, x1 + msr CORTEX_A57_L2ECTLR_EL1, x0 + isb + + mrs x0, CORTEX_A57_ECTLR_EL1 + mov x1, #RETENTION_ENTRY_TICKS_512 + bic x0, x0, #CORTEX_A57_ECTLR_CPU_RET_CTRL_MASK + orr x0, x0, x1 + msr CORTEX_A57_ECTLR_EL1, x0 + isb + + /* ------------------------------------------------------- + * Enable L2 and CPU ECTLR RW access from non-secure world + * ------------------------------------------------------- + */ + mrs x0, actlr_el3 + mov x1, #ACTLR_ELx_ENABLE_ALL_ACCESS + orr x0, x0, x1 + msr actlr_el3, x0 + mrs x0, actlr_el2 + mov x1, #ACTLR_ELx_ENABLE_ALL_ACCESS + orr x0, x0, x1 + msr actlr_el2, x0 + isb + + /* -------------------------------- + * Enable the cycle count register + * -------------------------------- + */ +1: mrs x0, pmcr_el0 + ubfx x0, x0, #11, #5 // read PMCR.N field + mov x1, #1 + lsl x0, x1, x0 + sub x0, x0, #1 // mask of event counters + orr x0, x0, #0x80000000 // disable overflow intrs + msr pmintenclr_el1, x0 + msr pmuserenr_el0, x1 // enable user mode access + + /* ---------------------------------------------------------------- + * Allow non-privileged access to CNTVCT: Set CNTKCTL (Kernel Count + * register), bit 1 (EL0VCTEN) to enable access to CNTVCT/CNTFRQ + * registers from EL0. + * ---------------------------------------------------------------- + */ + mrs x0, cntkctl_el1 + orr x0, x0, #EL0VCTEN_BIT + msr cntkctl_el1, x0 +.endm + + /* ----------------------------------------------------- + * bool plat_is_my_cpu_primary(void); + * + * This function checks if this is the Primary CPU + * + * Registers clobbered: x0, x1 + * ----------------------------------------------------- + */ +func plat_is_my_cpu_primary + mrs x0, mpidr_el1 + adr x1, tegra_primary_cpu_mpid + ldr x1, [x1] + cmp x0, x1 + cset x0, eq + ret +endfunc plat_is_my_cpu_primary + + /* ---------------------------------------------------------- + * unsigned int plat_my_core_pos(void); + * + * result: CorePos = CoreId + (ClusterId * cpus per cluster) + * Registers clobbered: x0, x8 + * ---------------------------------------------------------- + */ +func plat_my_core_pos + mov x8, x30 + mrs x0, mpidr_el1 + bl plat_core_pos_by_mpidr + ret x8 +endfunc plat_my_core_pos + + /* ----------------------------------------------------- + * unsigned long plat_get_my_entrypoint (void); + * + * Main job of this routine is to distinguish between + * a cold and warm boot. If the tegra_sec_entry_point for + * this CPU is present, then it's a warm boot. + * + * ----------------------------------------------------- + */ +func plat_get_my_entrypoint + adr x1, tegra_sec_entry_point + ldr x0, [x1] + ret +endfunc plat_get_my_entrypoint + + /* ----------------------------------------------------- + * void plat_secondary_cold_boot_setup (void); + * + * This function performs any platform specific actions + * needed for a secondary cpu after a cold reset. Right + * now this is a stub function. + * ----------------------------------------------------- + */ +func plat_secondary_cold_boot_setup + mov x0, #0 + ret +endfunc plat_secondary_cold_boot_setup + + /* -------------------------------------------------------- + * void platform_mem_init (void); + * + * Any memory init, relocation to be done before the + * platform boots. Called very early in the boot process. + * -------------------------------------------------------- + */ +func platform_mem_init + mov x0, #0 + ret +endfunc platform_mem_init + + /* --------------------------------------------------- + * Function to handle a platform reset and store + * input parameters passed by BL2. + * --------------------------------------------------- + */ +func plat_reset_handler + + /* ---------------------------------------------------- + * Verify if we are running from BL31_BASE address + * ---------------------------------------------------- + */ + adr x18, bl31_entrypoint + mov x17, #BL31_BASE + cmp x18, x17 + b.eq 1f + + /* ---------------------------------------------------- + * Copy the entire BL31 code to BL31_BASE if we are not + * running from it already + * ---------------------------------------------------- + */ + mov x0, x17 + mov x1, x18 + adr x2, __RELA_END__ + sub x2, x2, x18 +_loop16: + cmp x2, #16 + b.lo _loop1 + ldp x3, x4, [x1], #16 + stp x3, x4, [x0], #16 + sub x2, x2, #16 + b _loop16 + /* copy byte per byte */ +_loop1: + cbz x2, _end + ldrb w3, [x1], #1 + strb w3, [x0], #1 + subs x2, x2, #1 + b.ne _loop1 + + /* ---------------------------------------------------- + * Jump to BL31_BASE and start execution again + * ---------------------------------------------------- + */ +_end: mov x0, x20 + mov x1, x21 + br x17 +1: + + /* ----------------------------------- + * derive and save the phys_base addr + * ----------------------------------- + */ + adr x17, tegra_bl31_phys_base + ldr x18, [x17] + cbnz x18, 1f + adr x18, bl31_entrypoint + str x18, [x17] + + /* ----------------------------------- + * save the boot CPU MPID value + * ----------------------------------- + */ + mrs x0, mpidr_el1 + adr x1, tegra_primary_cpu_mpid + str x0, [x1] + +1: cpu_init_common + + ret +endfunc plat_reset_handler + + /* ------------------------------------------------------ + * int32_t plat_core_pos_by_mpidr(u_register_t mpidr) + * + * This function implements a part of the critical + * interface between the psci generic layer and the + * platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error + * code (-1) is returned in case the MPIDR is invalid. + * + * Clobbers: x0-x3 + * ------------------------------------------------------ + */ +func plat_core_pos_by_mpidr + lsr x1, x0, #MPIDR_AFF0_SHIFT + and x1, x1, #MPIDR_AFFLVL_MASK /* core id */ + lsr x2, x0, #MPIDR_AFF1_SHIFT + and x2, x2, #MPIDR_AFFLVL_MASK /* cluster id */ + + /* core_id >= PLATFORM_MAX_CPUS_PER_CLUSTER */ + mov x0, #-1 + cmp x1, #(PLATFORM_MAX_CPUS_PER_CLUSTER - 1) + b.gt 1f + + /* cluster_id >= PLATFORM_CLUSTER_COUNT */ + cmp x2, #(PLATFORM_CLUSTER_COUNT - 1) + b.gt 1f + + /* CorePos = CoreId + (ClusterId * cpus per cluster) */ + mov x3, #PLATFORM_MAX_CPUS_PER_CLUSTER + mul x3, x3, x2 + add x0, x1, x3 + +1: + ret +endfunc plat_core_pos_by_mpidr + + /* ---------------------------------------- + * Secure entrypoint function for CPU boot + * ---------------------------------------- + */ +func tegra_secure_entrypoint _align=6 + +#if ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT + + /* -------------------------------------------------------- + * Skip the invalidate BTB workaround for Tegra210B01 SKUs. + * -------------------------------------------------------- + */ + mov x0, #TEGRA_MISC_BASE + add x0, x0, #HARDWARE_REVISION_OFFSET + ldr w1, [x0] + lsr w1, w1, #CHIP_ID_SHIFT + and w1, w1, #CHIP_ID_MASK + cmp w1, #TEGRA_CHIPID_TEGRA21 /* T210? */ + b.ne 2f + ldr w1, [x0] + lsr w1, w1, #MAJOR_VERSION_SHIFT + and w1, w1, #MAJOR_VERSION_MASK + cmp w1, #0x02 /* T210 B01? */ + b.eq 2f + + /* ------------------------------------------------------- + * Invalidate BTB along with I$ to remove any stale + * entries from the branch predictor array. + * ------------------------------------------------------- + */ + mrs x0, CORTEX_A57_CPUACTLR_EL1 + orr x0, x0, #1 + msr CORTEX_A57_CPUACTLR_EL1, x0 /* invalidate BTB and I$ together */ + dsb sy + isb + ic iallu /* actual invalidate */ + dsb sy + isb + + mrs x0, CORTEX_A57_CPUACTLR_EL1 + bic x0, x0, #1 + msr CORTEX_A57_CPUACTLR_EL1, X0 /* restore original CPUACTLR_EL1 */ + dsb sy + isb + + .rept 7 + nop /* wait */ + .endr + + /* ----------------------------------------------- + * Extract OSLK bit and check if it is '1'. This + * bit remains '0' for A53 on warm-resets. If '1', + * turn off regional clock gating and request warm + * reset. + * ----------------------------------------------- + */ + mrs x0, oslsr_el1 + and x0, x0, #2 + mrs x1, mpidr_el1 + bics xzr, x0, x1, lsr #7 /* 0 = slow cluster or warm reset */ + b.eq restore_oslock + mov x0, xzr + msr oslar_el1, x0 /* os lock stays 0 across warm reset */ + mov x3, #3 + movz x4, #0x8000, lsl #48 + msr CORTEX_A57_CPUACTLR_EL1, x4 /* turn off RCG */ + isb + msr rmr_el3, x3 /* request warm reset */ + isb + dsb sy +1: wfi + b 1b + + /* -------------------------------------------------- + * These nops are here so that speculative execution + * won't harm us before we are done with warm reset. + * -------------------------------------------------- + */ + .rept 65 + nop + .endr +2: + /* -------------------------------------------------- + * Do not insert instructions here + * -------------------------------------------------- + */ +#endif + + /* -------------------------------------------------- + * Restore OS Lock bit + * -------------------------------------------------- + */ +restore_oslock: + mov x0, #1 + msr oslar_el1, x0 + + /* -------------------------------------------------- + * Get secure world's entry point and jump to it + * -------------------------------------------------- + */ + bl plat_get_my_entrypoint + br x0 +endfunc tegra_secure_entrypoint + + .data + .align 3 + + /* -------------------------------------------------- + * CPU Secure entry point - resume from suspend + * -------------------------------------------------- + */ +tegra_sec_entry_point: + .quad 0 + + /* -------------------------------------------------- + * NS world's cold boot entry point + * -------------------------------------------------- + */ +ns_image_entrypoint: + .quad 0 + + /* -------------------------------------------------- + * BL31's physical base address + * -------------------------------------------------- + */ +tegra_bl31_phys_base: + .quad 0 + + /* -------------------------------------------------- + * UART controller base for console init + * -------------------------------------------------- + */ +tegra_console_base: + .quad 0 + + /* -------------------------------------------------- + * MPID value for the boot CPU + * -------------------------------------------------- + */ +tegra_primary_cpu_mpid: + .quad 0 diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c new file mode 100644 index 0000000..e3068b6 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020-2023, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <inttypes.h> +#include <stddef.h> +#include <string.h> + +#include <platform_def.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <bl31/bl31.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <cortex_a57.h> +#include <denver.h> +#include <drivers/console.h> +#include <lib/mmio.h> +#include <lib/utils.h> +#include <lib/utils_def.h> +#include <plat/common/platform.h> + +#include <memctrl.h> +#include <profiler.h> +#include <smmu.h> +#include <tegra_def.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +/* length of Trusty's input parameters (in bytes) */ +#define TRUSTY_PARAMS_LEN_BYTES (4096*2) + +/******************************************************************************* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + ******************************************************************************/ +IMPORT_SYM(uint64_t, __RW_START__, BL31_RW_START); + +extern uint64_t tegra_bl31_phys_base; + +static entry_point_info_t bl33_image_ep_info, bl32_image_ep_info; +static plat_params_from_bl2_t plat_bl31_params_from_bl2 = { + .tzdram_size = TZDRAM_SIZE +}; +#ifdef SPD_trusty +static aapcs64_params_t bl32_args; +#endif + +/******************************************************************************* + * This variable holds the non-secure image entry address + ******************************************************************************/ +extern uint64_t ns_image_entrypoint; + +/******************************************************************************* + * Return a pointer to the 'entry_point_info' structure of the next image for + * security state specified. BL33 corresponds to the non-secure image type + * while BL32 corresponds to the secure image type. + ******************************************************************************/ +entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) +{ + entry_point_info_t *ep = NULL; + + /* return BL32 entry point info if it is valid */ + if (type == NON_SECURE) { + ep = &bl33_image_ep_info; + } else if ((type == SECURE) && (bl32_image_ep_info.pc != 0U)) { + ep = &bl32_image_ep_info; + } + + return ep; +} + +/******************************************************************************* + * Return a pointer to the 'plat_params_from_bl2_t' structure. The BL2 image + * passes this platform specific information. + ******************************************************************************/ +plat_params_from_bl2_t *bl31_get_plat_params(void) +{ + return &plat_bl31_params_from_bl2; +} + +/******************************************************************************* + * Perform any BL31 specific platform actions. Populate the BL33 and BL32 image + * info. + ******************************************************************************/ +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + struct tegra_bl31_params *arg_from_bl2 = plat_get_bl31_params(); + plat_params_from_bl2_t *plat_params = plat_get_bl31_plat_params(); + int32_t ret; + + /* + * Tegra platforms will receive boot parameters through custom + * mechanisms. So, we ignore the input parameters. + */ + (void)arg0; + (void)arg1; + + /* + * Copy BL3-3, BL3-2 entry point information. + * They are stored in Secure RAM, in BL2's address space. + */ + assert(arg_from_bl2 != NULL); + assert(arg_from_bl2->bl33_ep_info != NULL); + bl33_image_ep_info = *arg_from_bl2->bl33_ep_info; + + if (arg_from_bl2->bl32_ep_info != NULL) { + bl32_image_ep_info = *arg_from_bl2->bl32_ep_info; +#ifdef SPD_trusty + /* save BL32 boot parameters */ + memcpy(&bl32_args, &arg_from_bl2->bl32_ep_info->args, sizeof(bl32_args)); +#endif + } + + /* + * Parse platform specific parameters + */ + assert(plat_params != NULL); + plat_bl31_params_from_bl2.tzdram_base = plat_params->tzdram_base; + plat_bl31_params_from_bl2.tzdram_size = plat_params->tzdram_size; + plat_bl31_params_from_bl2.uart_id = plat_params->uart_id; + plat_bl31_params_from_bl2.l2_ecc_parity_prot_dis = plat_params->l2_ecc_parity_prot_dis; + plat_bl31_params_from_bl2.sc7entry_fw_size = plat_params->sc7entry_fw_size; + plat_bl31_params_from_bl2.sc7entry_fw_base = plat_params->sc7entry_fw_base; + + /* + * It is very important that we run either from TZDRAM or TZSRAM base. + * Add an explicit check here. + */ + if ((plat_bl31_params_from_bl2.tzdram_base != (uint64_t)BL31_BASE) && + (TEGRA_TZRAM_BASE != BL31_BASE)) { + panic(); + } + + /* + * Enable console for the platform + */ + plat_enable_console(plat_params->uart_id); + + /* + * The previous bootloader passes the base address of the shared memory + * location to store the boot profiler logs. Sanity check the + * address and initialise the profiler library, if it looks ok. + */ + ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base, + PROFILER_SIZE_BYTES); + if (ret == (int32_t)0) { + + /* store the membase for the profiler lib */ + plat_bl31_params_from_bl2.boot_profiler_shmem_base = + plat_params->boot_profiler_shmem_base; + + /* initialise the profiler library */ + boot_profiler_init(plat_params->boot_profiler_shmem_base, + TEGRA_TMRUS_BASE); + } + + /* + * Add timestamp for platform early setup entry. + */ + boot_profiler_add_record("[TF] early setup entry"); + + /* + * Initialize delay timer + */ + tegra_delay_timer_init(); + + /* Early platform setup for Tegra SoCs */ + plat_early_platform_setup(); + + /* + * Add timestamp for platform early setup exit. + */ + boot_profiler_add_record("[TF] early setup exit"); + + INFO("BL3-1: Boot CPU: %s Processor [%lx]\n", + (((read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK) + == DENVER_IMPL) ? "Denver" : "ARM", read_mpidr()); +} + +#ifdef SPD_trusty +void plat_trusty_set_boot_args(aapcs64_params_t *args) +{ + /* + * arg0 = TZDRAM aperture available for BL32 + * arg1 = BL32 boot params + * arg2 = EKS Blob Length + * arg3 = Boot Profiler Carveout Base + */ + args->arg0 = bl32_args.arg0; + args->arg1 = bl32_args.arg2; + + /* update EKS size */ + args->arg2 = bl32_args.arg4; + + /* Profiler Carveout Base */ + args->arg3 = bl32_args.arg5; +} +#endif + +/******************************************************************************* + * Initialize the gic, configure the SCR. + ******************************************************************************/ +void bl31_platform_setup(void) +{ + /* + * Add timestamp for platform setup entry. + */ + boot_profiler_add_record("[TF] plat setup entry"); + + /* Initialize the gic cpu and distributor interfaces */ + plat_gic_setup(); + + /* + * Setup secondary CPU POR infrastructure. + */ + plat_secondary_setup(); + + /* + * Initial Memory Controller configuration. + */ + tegra_memctrl_setup(); + + /* + * Late setup handler to allow platforms to performs additional + * functionality. + * This handler gets called with MMU enabled. + */ + plat_late_platform_setup(); + + /* + * Add timestamp for platform setup exit. + */ + boot_profiler_add_record("[TF] plat setup exit"); + + INFO("BL3-1: Tegra platform setup complete\n"); +} + +/******************************************************************************* + * Perform any BL3-1 platform runtime setup prior to BL3-1 cold boot exit + ******************************************************************************/ +void bl31_plat_runtime_setup(void) +{ + /* + * Platform specific runtime setup + */ + plat_runtime_setup(); + + /* + * Add final timestamp before exiting BL31. + */ + boot_profiler_add_record("[TF] bl31 exit"); + boot_profiler_deinit(); +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this only initializes the mmu in a quick and dirty way. + ******************************************************************************/ +void bl31_plat_arch_setup(void) +{ + uint64_t rw_start = BL31_RW_START; + uint64_t rw_size = BL_END - BL31_RW_START; + uint64_t rodata_start = BL_RO_DATA_BASE; + uint64_t rodata_size = BL_RO_DATA_END - BL_RO_DATA_BASE; + uint64_t code_base = BL_CODE_BASE; + uint64_t code_size = BL_CODE_END - BL_CODE_BASE; + const mmap_region_t *plat_mmio_map = NULL; + const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); + + /* + * Add timestamp for arch setup entry. + */ + boot_profiler_add_record("[TF] arch setup entry"); + + /* add MMIO space */ + plat_mmio_map = plat_get_mmio_map(); + if (plat_mmio_map != NULL) { + mmap_add(plat_mmio_map); + } else { + WARN("MMIO map not available\n"); + } + + /* add memory regions */ + mmap_add_region(rw_start, rw_start, + rw_size, + MT_MEMORY | MT_RW | MT_SECURE); + mmap_add_region(rodata_start, rodata_start, + rodata_size, + MT_RO_DATA | MT_SECURE); + mmap_add_region(code_base, code_base, + code_size, + MT_CODE | MT_SECURE); + + /* map TZDRAM used by BL31 as coherent memory */ + if (TEGRA_TZRAM_BASE == tegra_bl31_phys_base) { + mmap_add_region(params_from_bl2->tzdram_base, + params_from_bl2->tzdram_base, + BL31_SIZE, + MT_DEVICE | MT_RW | MT_SECURE); + } + + /* set up translation tables */ + init_xlat_tables(); + + /* enable the MMU */ + enable_mmu_el3(0); + + /* + * Add timestamp for arch setup exit. + */ + boot_profiler_add_record("[TF] arch setup exit"); + + INFO("BL3-1: Tegra: MMU enabled\n"); +} + +/******************************************************************************* + * Check if the given NS DRAM range is valid + ******************************************************************************/ +int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes) +{ + uint64_t end = base + size_in_bytes - U(1); + + /* + * Sanity check the input values + */ + if ((base == 0U) || (size_in_bytes == 0U)) { + ERROR("NS address 0x%" PRIx64 " (%" PRId64 " bytes) is invalid\n", + base, size_in_bytes); + return -EINVAL; + } + + /* + * Check if the NS DRAM address is valid + */ + if ((base < TEGRA_DRAM_BASE) || (base >= TEGRA_DRAM_END) || + (end > TEGRA_DRAM_END)) { + + ERROR("NS address 0x%" PRIx64 " is out-of-bounds!\n", base); + return -EFAULT; + } + + /* + * TZDRAM aperture contains the BL31 and BL32 images, so we need + * to check if the NS DRAM range overlaps the TZDRAM aperture. + */ + if ((base < (uint64_t)TZDRAM_END) && (end > tegra_bl31_phys_base)) { + ERROR("NS address 0x%" PRIx64 " overlaps TZDRAM!\n", base); + return -ENOTSUP; + } + + /* valid NS address */ + return 0; +} diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk new file mode 100644 index 0000000..3791018 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_common.mk @@ -0,0 +1,59 @@ +# +# Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2020, NVIDIA Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_INCLUDES := -Iplat/nvidia/tegra/include/drivers \ + -Iplat/nvidia/tegra/include/lib \ + -Iplat/nvidia/tegra/include + +include lib/xlat_tables_v2/xlat_tables.mk +PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} + +TEGRA_COMMON := plat/nvidia/tegra/common +TEGRA_DRIVERS := plat/nvidia/tegra/drivers +TEGRA_LIBS := plat/nvidia/tegra/lib + +# Include GICv3 driver files +include drivers/arm/gic/v3/gicv3.mk +TEGRA_GICv3_SOURCES := $(GICV3_SOURCES) \ + plat/common/plat_gicv3.c \ + ${TEGRA_COMMON}/tegra_gicv3.c + +# Include GICv2 driver files +include drivers/arm/gic/v2/gicv2.mk + +TEGRA_GICv2_SOURCES := ${GICV2_SOURCES} \ + plat/common/plat_gicv2.c \ + ${TEGRA_COMMON}/tegra_gicv2.c + +TEGRA_GICv3_SOURCES := drivers/arm/gic/common/gic_common.c \ + drivers/arm/gic/v3/arm_gicv3_common.c \ + drivers/arm/gic/v3/gicv3_main.c \ + drivers/arm/gic/v3/gicv3_helpers.c \ + plat/common/plat_gicv3.c \ + ${TEGRA_COMMON}/tegra_gicv3.c + +BL31_SOURCES += drivers/delay_timer/delay_timer.c \ + drivers/io/io_storage.c \ + plat/common/aarch64/crash_console_helpers.S \ + ${TEGRA_LIBS}/debug/profiler.c \ + ${TEGRA_COMMON}/aarch64/tegra_helpers.S \ + ${TEGRA_LIBS}/debug/profiler.c \ + ${TEGRA_COMMON}/tegra_bl31_setup.c \ + ${TEGRA_COMMON}/tegra_delay_timer.c \ + ${TEGRA_COMMON}/tegra_fiq_glue.c \ + ${TEGRA_COMMON}/tegra_io_storage.c \ + ${TEGRA_COMMON}/tegra_platform.c \ + ${TEGRA_COMMON}/tegra_pm.c \ + ${TEGRA_COMMON}/tegra_sip_calls.c \ + ${TEGRA_COMMON}/tegra_sdei.c + +ifneq ($(ENABLE_STACK_PROTECTOR), 0) +BL31_SOURCES += ${TEGRA_COMMON}/tegra_stack_protector.c +endif +ifeq (${EL3_EXCEPTION_HANDLING},1) +BL31_SOURCES += plat/common/aarch64/plat_ehf.c +endif diff --git a/plat/nvidia/tegra/common/tegra_delay_timer.c b/plat/nvidia/tegra/common/tegra_delay_timer.c new file mode 100644 index 0000000..d9547c4 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_delay_timer.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> + +#include <drivers/delay_timer.h> +#include <lib/mmio.h> +#include <lib/utils_def.h> +#include <plat/common/platform.h> + +#include <tegra_def.h> +#include <tegra_private.h> + +static uint32_t tegra_timer_get_value(void) +{ + /* enable cntps_tval_el1 timer, mask interrupt */ + write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT); + + /* + * Generic delay timer implementation expects the timer to be a down + * counter. The value is clipped from 64 to 32 bits. + */ + return (uint32_t)(read_cntps_tval_el1()); +} + +/* + * Initialise the architecture provided counter as the delay timer. + */ +void tegra_delay_timer_init(void) +{ + static timer_ops_t tegra_timer_ops; + + /* Value in ticks */ + uint32_t multiplier = MHZ_TICKS_PER_SEC; + + /* Value in ticks per second (Hz) */ + uint32_t divider = plat_get_syscnt_freq2(); + + /* Reduce multiplier and divider by dividing them repeatedly by 10 */ + while (((multiplier % 10U) == 0U) && ((divider % 10U) == 0U)) { + multiplier /= 10U; + divider /= 10U; + } + + /* enable cntps_tval_el1 timer, mask interrupt */ + write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT); + + /* register the timer */ + tegra_timer_ops.get_timer_value = tegra_timer_get_value; + tegra_timer_ops.clk_mult = multiplier; + tegra_timer_ops.clk_div = divider; + timer_init(&tegra_timer_ops); +} diff --git a/plat/nvidia/tegra/common/tegra_fiq_glue.c b/plat/nvidia/tegra/common/tegra_fiq_glue.c new file mode 100644 index 0000000..5309d98 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_fiq_glue.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <bl31/interrupt_mgmt.h> +#include <bl31/ehf.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <context.h> +#include <denver.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <plat/common/platform.h> + +#if ENABLE_WDT_LEGACY_FIQ_HANDLING +#include <flowctrl.h> +#endif +#include <tegra_def.h> +#include <tegra_private.h> + +/* Legacy FIQ used by earlier Tegra platforms */ +#define LEGACY_FIQ_PPI_WDT 28U + +/******************************************************************************* + * Static variables + ******************************************************************************/ +static uint64_t ns_fiq_handler_addr; +static uint32_t fiq_handler_active; +static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT]; + +/******************************************************************************* + * Handler for FIQ interrupts + ******************************************************************************/ +static int tegra_fiq_interrupt_handler(unsigned int id, unsigned int flags, + void *handle, void *cookie) +{ + cpu_context_t *ctx = cm_get_context(NON_SECURE); + el3_state_t *el3state_ctx = get_el3state_ctx(ctx); + uint32_t cpu = plat_my_core_pos(); + + (void)flags; + (void)handle; + (void)cookie; + + /* + * Jump to NS world only if the NS world's FIQ handler has + * been registered + */ + if (ns_fiq_handler_addr != 0U) { + + /* + * The FIQ was generated when the execution was in the non-secure + * world. Save the context registers to start with. + */ + cm_el1_sysregs_context_save(NON_SECURE); + + /* + * Save elr_el3 and spsr_el3 from the saved context, and overwrite + * the context with the NS fiq_handler_addr and SPSR value. + */ + fiq_state[cpu].elr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_ELR_EL3)); + fiq_state[cpu].spsr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_SPSR_EL3)); + + /* + * Set the new ELR to continue execution in the NS world using the + * FIQ handler registered earlier. + */ + cm_set_elr_el3(NON_SECURE, ns_fiq_handler_addr); + } + +#if ENABLE_WDT_LEGACY_FIQ_HANDLING + /* + * Tegra platforms that use LEGACY_FIQ as the watchdog timer FIQ + * need to issue an IPI to other CPUs, to allow them to handle + * the "system hung" scenario. This interrupt is passed to the GICD + * via the Flow Controller. So, once we receive this interrupt, + * disable the routing so that we can mark it as "complete" in the + * GIC later. + */ + if (id == LEGACY_FIQ_PPI_WDT) { + tegra_fc_disable_fiq_to_ccplex_routing(); + } +#endif + + /* + * Mark this interrupt as complete to avoid a FIQ storm. + */ + plat_ic_end_of_interrupt(id); + + return 0; +} + +/******************************************************************************* + * Setup handler for FIQ interrupts + ******************************************************************************/ +void tegra_fiq_handler_setup(void) +{ + /* return if already registered */ + if (fiq_handler_active == 0U) { + /* + * Register an interrupt handler for FIQ interrupts generated for + * NS interrupt sources + */ + ehf_register_priority_handler(PLAT_TEGRA_WDT_PRIO, tegra_fiq_interrupt_handler); + + /* handler is now active */ + fiq_handler_active = 1; + } +} + +/******************************************************************************* + * Validate and store NS world's entrypoint for FIQ interrupts + ******************************************************************************/ +void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint) +{ + ns_fiq_handler_addr = entrypoint; +} + +/******************************************************************************* + * Handler to return the NS EL1/EL0 CPU context + ******************************************************************************/ +int32_t tegra_fiq_get_intr_context(void) +{ + cpu_context_t *ctx = cm_get_context(NON_SECURE); + gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx); + const el1_sysregs_t *el1state_ctx = get_el1_sysregs_ctx(ctx); + uint32_t cpu = plat_my_core_pos(); + uint64_t val; + + /* + * We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so + * that el3_exit() sends these values back to the NS world. + */ + write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X0), (fiq_state[cpu].elr_el3)); + write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X1), (fiq_state[cpu].spsr_el3)); + + val = read_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_SP_EL0)); + write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X2), (val)); + + val = read_ctx_reg((el1state_ctx), (uint32_t)(CTX_SP_EL1)); + write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X3), (val)); + + return 0; +} diff --git a/plat/nvidia/tegra/common/tegra_gicv2.c b/plat/nvidia/tegra/common/tegra_gicv2.c new file mode 100644 index 0000000..012107e --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_gicv2.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <platform_def.h> + +#include <common/bl_common.h> +#include <drivers/arm/gicv2.h> +#include <lib/utils.h> +#include <plat/common/platform.h> + +#include <tegra_private.h> +#include <tegra_def.h> + +static unsigned int tegra_target_masks[PLATFORM_CORE_COUNT]; + +/****************************************************************************** + * Tegra common helper to setup the GICv2 driver data. + *****************************************************************************/ +void tegra_gic_setup(const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + /* + * Tegra GIC configuration settings + */ + static gicv2_driver_data_t tegra_gic_data; + + /* + * Register Tegra GICv2 driver + */ + tegra_gic_data.gicd_base = TEGRA_GICD_BASE; + tegra_gic_data.gicc_base = TEGRA_GICC_BASE; + tegra_gic_data.interrupt_props = interrupt_props; + tegra_gic_data.interrupt_props_num = interrupt_props_num; + tegra_gic_data.target_masks = tegra_target_masks; + tegra_gic_data.target_masks_num = ARRAY_SIZE(tegra_target_masks); + gicv2_driver_init(&tegra_gic_data); +} + +/****************************************************************************** + * Tegra common helper to initialize the GICv2 only driver. + *****************************************************************************/ +void tegra_gic_init(void) +{ + gicv2_distif_init(); + gicv2_pcpu_distif_init(); + gicv2_set_pe_target_mask(plat_my_core_pos()); + gicv2_cpuif_enable(); +} + +/****************************************************************************** + * Tegra common helper to disable the GICv2 CPU interface + *****************************************************************************/ +void tegra_gic_cpuif_deactivate(void) +{ + gicv2_cpuif_disable(); +} + +/****************************************************************************** + * Tegra common helper to initialize the per cpu distributor interface + * in GICv2 + *****************************************************************************/ +void tegra_gic_pcpu_init(void) +{ + gicv2_pcpu_distif_init(); + gicv2_set_pe_target_mask(plat_my_core_pos()); + gicv2_cpuif_enable(); +} diff --git a/plat/nvidia/tegra/common/tegra_gicv3.c b/plat/nvidia/tegra/common/tegra_gicv3.c new file mode 100644 index 0000000..cba2f9b --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_gicv3.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <common/bl_common.h> +#include <drivers/arm/gicv3.h> +#include <lib/utils.h> + +#include <plat/common/platform.h> +#include <platform_def.h> +#include <tegra_private.h> +#include <tegra_def.h> + +/* The GICv3 driver only needs to be initialized in EL3 */ +static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; + +static unsigned int plat_tegra_mpidr_to_core_pos(unsigned long mpidr) +{ + return (unsigned int)plat_core_pos_by_mpidr(mpidr); +} + +/****************************************************************************** + * Tegra common helper to setup the GICv3 driver data. + *****************************************************************************/ +void tegra_gic_setup(const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + /* + * Tegra GIC configuration settings + */ + static gicv3_driver_data_t tegra_gic_data; + + /* + * Register Tegra GICv3 driver + */ + tegra_gic_data.gicd_base = TEGRA_GICD_BASE; + tegra_gic_data.gicr_base = TEGRA_GICR_BASE; + tegra_gic_data.rdistif_num = PLATFORM_CORE_COUNT; + tegra_gic_data.rdistif_base_addrs = rdistif_base_addrs; + tegra_gic_data.mpidr_to_core_pos = plat_tegra_mpidr_to_core_pos; + tegra_gic_data.interrupt_props = interrupt_props; + tegra_gic_data.interrupt_props_num = interrupt_props_num; + gicv3_driver_init(&tegra_gic_data); + + /* initialize the GICD and GICR */ + tegra_gic_init(); +} + +/****************************************************************************** + * Tegra common helper to initialize the GICv3 only driver. + *****************************************************************************/ +void tegra_gic_init(void) +{ + gicv3_distif_init(); + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} + +/****************************************************************************** + * Tegra common helper to disable the GICv3 CPU interface + *****************************************************************************/ +void tegra_gic_cpuif_deactivate(void) +{ + gicv3_cpuif_disable(plat_my_core_pos()); +} + +/****************************************************************************** + * Tegra common helper to initialize the per cpu distributor interface + * in GICv3 + *****************************************************************************/ +void tegra_gic_pcpu_init(void) +{ + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} diff --git a/plat/nvidia/tegra/common/tegra_io_storage.c b/plat/nvidia/tegra/common/tegra_io_storage.c new file mode 100644 index 0000000..21641aa --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_io_storage.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <errno.h> +#include <plat/common/platform.h> + +/* + * Return an IO device handle and specification which can be used to access + * an image. Use this to enforce platform load policy. + * + * This function is not supported at this time + */ +int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, + uintptr_t *image_spec) +{ + return -ENOTSUP; +} diff --git a/plat/nvidia/tegra/common/tegra_platform.c b/plat/nvidia/tegra/common/tegra_platform.c new file mode 100644 index 0000000..6d736b5 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_platform.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020-2023, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <lib/mmio.h> +#include <lib/smccc.h> +#include <services/arm_arch_svc.h> +#include <tegra_def.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +/******************************************************************************* + * Tegra platforms + ******************************************************************************/ +typedef enum tegra_platform { + TEGRA_PLATFORM_SILICON = 0U, + TEGRA_PLATFORM_QT, + TEGRA_PLATFORM_FPGA, + TEGRA_PLATFORM_EMULATION, + TEGRA_PLATFORM_LINSIM, + TEGRA_PLATFORM_UNIT_FPGA, + TEGRA_PLATFORM_VIRT_DEV_KIT, + TEGRA_PLATFORM_MAX, +} tegra_platform_t; + +/******************************************************************************* + * Tegra macros defining all the SoC minor versions + ******************************************************************************/ +#define TEGRA_MINOR_QT U(0) +#define TEGRA_MINOR_FPGA U(1) +#define TEGRA_MINOR_ASIM_QT U(2) +#define TEGRA_MINOR_ASIM_LINSIM U(3) +#define TEGRA_MINOR_DSIM_ASIM_LINSIM U(4) +#define TEGRA_MINOR_UNIT_FPGA U(5) +#define TEGRA_MINOR_VIRT_DEV_KIT U(6) + +/******************************************************************************* + * Tegra macros defining all the SoC pre_si_platform + ******************************************************************************/ +#define TEGRA_PRE_SI_QT U(1) +#define TEGRA_PRE_SI_FPGA U(2) +#define TEGRA_PRE_SI_UNIT_FPGA U(3) +#define TEGRA_PRE_SI_ASIM_QT U(4) +#define TEGRA_PRE_SI_ASIM_LINSIM U(5) +#define TEGRA_PRE_SI_DSIM_ASIM_LINSIM U(6) +#define TEGRA_PRE_SI_VDK U(8) + +/* + * Read the chip ID value + */ +static uint32_t tegra_get_chipid(void) +{ + return mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET); +} + +/* + * Read the chip's major version from chip ID value + */ +uint32_t tegra_get_chipid_major(void) +{ + return (tegra_get_chipid() >> MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK; +} + +/* + * Read the chip's minor version from the chip ID value + */ +uint32_t tegra_get_chipid_minor(void) +{ + return (tegra_get_chipid() >> MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK; +} + +/* + * Read the chip's pre_si_platform valus from the chip ID value + */ +static uint32_t tegra_get_chipid_pre_si_platform(void) +{ + return (tegra_get_chipid() >> PRE_SI_PLATFORM_SHIFT) & PRE_SI_PLATFORM_MASK; +} + +bool tegra_chipid_is_t186(void) +{ + uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK; + + return (chip_id == TEGRA_CHIPID_TEGRA18); +} + +bool tegra_chipid_is_t210(void) +{ + uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK; + + return (chip_id == TEGRA_CHIPID_TEGRA21); +} + +bool tegra_chipid_is_t210_b01(void) +{ + return (tegra_chipid_is_t210() && (tegra_get_chipid_major() == 0x2U)); +} + +bool tegra_chipid_is_t194(void) +{ + uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK; + + return (chip_id == TEGRA_CHIPID_TEGRA19); +} + +/* + * Read the chip ID value and derive the platform + */ +static tegra_platform_t tegra_get_platform(void) +{ + uint32_t major, minor, pre_si_platform; + tegra_platform_t ret; + + /* get the major/minor chip ID values */ + major = tegra_get_chipid_major(); + minor = tegra_get_chipid_minor(); + pre_si_platform = tegra_get_chipid_pre_si_platform(); + + if (major == 0U) { + /* + * The minor version number is used by simulation platforms + */ + switch (minor) { + /* + * Cadence's QuickTurn emulation system is a Solaris-based + * chip emulation system + */ + case TEGRA_MINOR_QT: + case TEGRA_MINOR_ASIM_QT: + ret = TEGRA_PLATFORM_QT; + break; + + /* + * FPGAs are used during early software/hardware development + */ + case TEGRA_MINOR_FPGA: + ret = TEGRA_PLATFORM_FPGA; + break; + /* + * Linsim is a reconfigurable, clock-driven, mixed RTL/cmodel + * simulation framework. + */ + case TEGRA_MINOR_ASIM_LINSIM: + case TEGRA_MINOR_DSIM_ASIM_LINSIM: + ret = TEGRA_PLATFORM_LINSIM; + break; + + /* + * Unit FPGAs run the actual hardware block IP on the FPGA with + * the other parts of the system using Linsim. + */ + case TEGRA_MINOR_UNIT_FPGA: + ret = TEGRA_PLATFORM_UNIT_FPGA; + break; + /* + * The Virtualizer Development Kit (VDK) is the standard chip + * development from Synopsis. + */ + case TEGRA_MINOR_VIRT_DEV_KIT: + ret = TEGRA_PLATFORM_VIRT_DEV_KIT; + break; + + default: + ret = TEGRA_PLATFORM_MAX; + break; + } + + } else if (pre_si_platform > 0U) { + + switch (pre_si_platform) { + /* + * Cadence's QuickTurn emulation system is a Solaris-based + * chip emulation system + */ + case TEGRA_PRE_SI_QT: + case TEGRA_PRE_SI_ASIM_QT: + ret = TEGRA_PLATFORM_QT; + break; + + /* + * FPGAs are used during early software/hardware development + */ + case TEGRA_PRE_SI_FPGA: + ret = TEGRA_PLATFORM_FPGA; + break; + /* + * Linsim is a reconfigurable, clock-driven, mixed RTL/cmodel + * simulation framework. + */ + case TEGRA_PRE_SI_ASIM_LINSIM: + case TEGRA_PRE_SI_DSIM_ASIM_LINSIM: + ret = TEGRA_PLATFORM_LINSIM; + break; + + /* + * Unit FPGAs run the actual hardware block IP on the FPGA with + * the other parts of the system using Linsim. + */ + case TEGRA_PRE_SI_UNIT_FPGA: + ret = TEGRA_PLATFORM_UNIT_FPGA; + break; + /* + * The Virtualizer Development Kit (VDK) is the standard chip + * development from Synopsis. + */ + case TEGRA_PRE_SI_VDK: + ret = TEGRA_PLATFORM_VIRT_DEV_KIT; + break; + + default: + ret = TEGRA_PLATFORM_MAX; + break; + } + + } else { + /* Actual silicon platforms have a non-zero major version */ + ret = TEGRA_PLATFORM_SILICON; + } + + return ret; +} + +bool tegra_platform_is_silicon(void) +{ + return ((tegra_get_platform() == TEGRA_PLATFORM_SILICON) ? true : false); +} + +bool tegra_platform_is_qt(void) +{ + return ((tegra_get_platform() == TEGRA_PLATFORM_QT) ? true : false); +} + +bool tegra_platform_is_linsim(void) +{ + tegra_platform_t plat = tegra_get_platform(); + + return (((plat == TEGRA_PLATFORM_LINSIM) || + (plat == TEGRA_PLATFORM_UNIT_FPGA)) ? true : false); +} + +bool tegra_platform_is_fpga(void) +{ + return ((tegra_get_platform() == TEGRA_PLATFORM_FPGA) ? true : false); +} + +bool tegra_platform_is_emulation(void) +{ + return (tegra_get_platform() == TEGRA_PLATFORM_EMULATION); +} + +bool tegra_platform_is_unit_fpga(void) +{ + return ((tegra_get_platform() == TEGRA_PLATFORM_UNIT_FPGA) ? true : false); +} + +bool tegra_platform_is_virt_dev_kit(void) +{ + return ((tegra_get_platform() == TEGRA_PLATFORM_VIRT_DEV_KIT) ? true : false); +} + +/* + * This function returns soc version which mainly consist of below fields + * + * soc_version[30:24] = JEP-106 continuation code for the SiP + * soc_version[23:16] = JEP-106 identification code with parity bit for the SiP + * soc_version[0:15] = chip identification + */ +int32_t plat_get_soc_version(void) +{ + uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK; + uint32_t major_rev = tegra_get_chipid_major(); + uint32_t manfid = SOC_ID_SET_JEP_106(JEDEC_NVIDIA_BKID, JEDEC_NVIDIA_MFID); + + return (int32_t)(manfid | (((chip_id << MAJOR_VERSION_SHIFT) | major_rev) & + SOC_ID_IMPL_DEF_MASK)); +} + +/* + * This function returns soc revision in below format + * + * soc_revision[8:15] = major version number + * soc_revision[0:7] = minor version number + */ +int32_t plat_get_soc_revision(void) +{ + return (int32_t)(((tegra_get_chipid_major() << 8) | tegra_get_chipid_minor()) & + SOC_ID_REV_MASK); +} + +/***************************************************************************** + * plat_is_smccc_feature_available() - This function checks whether SMCCC feature + * is availabile for the platform or not. + * @fid: SMCCC function id + * + * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and + * SMC_ARCH_CALL_NOT_SUPPORTED otherwise. + *****************************************************************************/ +int32_t plat_is_smccc_feature_available(u_register_t fid) +{ + switch (fid) { + case SMCCC_ARCH_SOC_ID: + return SMC_ARCH_CALL_SUCCESS; + default: + return SMC_ARCH_CALL_NOT_SUPPORTED; + } +} diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c new file mode 100644 index 0000000..8edb024 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020-2023, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <platform_def.h> + +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <context.h> +#include <drivers/console.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <lib/mmio.h> +#include <lib/psci/psci.h> +#include <plat/common/platform.h> + +#include <memctrl.h> +#include <pmc.h> +#include <tegra_def.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +extern uint64_t tegra_bl31_phys_base; +extern uint64_t tegra_sec_entry_point; + +/******************************************************************************* + * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` + * call to get the `power_state` parameter. This allows the platform to encode + * the appropriate State-ID field within the `power_state` parameter which can + * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. +******************************************************************************/ +static void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) +{ + /* all affinities use system suspend state id */ + for (uint32_t i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) { + req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN; + } +} + +/******************************************************************************* + * Handler called when an affinity instance is about to enter standby. + ******************************************************************************/ +static void tegra_cpu_standby(plat_local_state_t cpu_state) +{ + u_register_t saved_scr_el3; + + (void)cpu_state; + + /* Tegra SoC specific handler */ + if (tegra_soc_cpu_standby(cpu_state) != PSCI_E_SUCCESS) + ERROR("%s failed\n", __func__); + + saved_scr_el3 = read_scr_el3(); + + /* + * As per ARM ARM D1.17.2, any physical IRQ interrupt received by the + * PE will be treated as a wake-up event, if SCR_EL3.IRQ is set to '1', + * irrespective of the value of the PSTATE.I bit value. + */ + write_scr_el3(saved_scr_el3 | SCR_IRQ_BIT); + + /* + * Enter standby state + * + * dsb & isb is good practice before using wfi to enter low power states + */ + dsb(); + isb(); + wfi(); + + /* + * Restore saved scr_el3 that has IRQ bit cleared as we don't want EL3 + * handling any further interrupts + */ + write_scr_el3(saved_scr_el3); +} + +/******************************************************************************* + * Handler called when an affinity instance is about to be turned on. The + * level and mpidr determine the affinity instance. + ******************************************************************************/ +static int32_t tegra_pwr_domain_on(u_register_t mpidr) +{ + return tegra_soc_pwr_domain_on(mpidr); +} + +/******************************************************************************* + * 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. + * Return error if CPU off sequence is not allowed for the current core. + ******************************************************************************/ +static int tegra_pwr_domain_off_early(const psci_power_state_t *target_state) +{ + return tegra_soc_pwr_domain_off_early(target_state); +} + +/******************************************************************************* + * 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. + ******************************************************************************/ +static void tegra_pwr_domain_off(const psci_power_state_t *target_state) +{ + (void)tegra_soc_pwr_domain_off(target_state); + + /* disable GICC */ + tegra_gic_cpuif_deactivate(); +} + +/******************************************************************************* + * Handler called when a power domain is about to be suspended. The + * target_state encodes the power state that each level should transition to. + * This handler is called with SMP and data cache enabled, when + * HW_ASSISTED_COHERENCY = 0 + ******************************************************************************/ +void tegra_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state) +{ + tegra_soc_pwr_domain_suspend_pwrdown_early(target_state); +} + +/******************************************************************************* + * Handler called when a power domain is about to be suspended. The + * target_state encodes the power state that each level should transition to. + ******************************************************************************/ +static void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) +{ + (void)tegra_soc_pwr_domain_suspend(target_state); + + /* disable GICC */ + tegra_gic_cpuif_deactivate(); +} + +/******************************************************************************* + * Handler called at the end of the power domain suspend sequence. The + * target_state encodes the power state that each level should transition to. + ******************************************************************************/ +static __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t + *target_state) +{ + /* call the chip's power down handler */ + (void)tegra_soc_pwr_domain_power_down_wfi(target_state); + + /* Disable console if we are entering deep sleep. */ + if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == + PSTATE_ID_SOC_POWERDN) { + INFO("%s: complete. Entering System Suspend...\n", __func__); + console_flush(); + console_switch_state(0); + } + + wfi(); + panic(); +} + +/******************************************************************************* + * 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. + ******************************************************************************/ +static void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + const plat_params_from_bl2_t *plat_params; + + /* + * Check if we are exiting from deep sleep. + */ + if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == + PSTATE_ID_SOC_POWERDN) { + + /* + * On entering System Suspend state, the GIC loses power + * completely. Initialize the GIC global distributor and + * GIC cpu interfaces. + */ + tegra_gic_init(); + + /* Restart console output. */ + console_switch_state(CONSOLE_FLAG_RUNTIME); + + /* + * Restore Memory Controller settings as it loses state + * during system suspend. + */ + tegra_memctrl_restore_settings(); + + /* + * Security configuration to allow DRAM/device access. + */ + plat_params = bl31_get_plat_params(); + tegra_memctrl_tzdram_setup(plat_params->tzdram_base, + (uint32_t)plat_params->tzdram_size); + + } else { + /* + * Initialize the GIC cpu and distributor interfaces + */ + tegra_gic_pcpu_init(); + } + + /* + * Reset hardware settings. + */ + (void)tegra_soc_pwr_domain_on_finish(target_state); +} + +/******************************************************************************* + * 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. + ******************************************************************************/ +static void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) +{ + tegra_pwr_domain_on_finish(target_state); +} + +/******************************************************************************* + * Handler called when the system wants to be powered off + ******************************************************************************/ +static __dead2 void tegra_system_off(void) +{ + INFO("Powering down system...\n"); + + tegra_soc_prepare_system_off(); +} + +/******************************************************************************* + * Handler called when the system wants to be restarted. + ******************************************************************************/ +static __dead2 void tegra_system_reset(void) +{ + INFO("Restarting system...\n"); + + /* per-SoC system reset handler */ + (void)tegra_soc_prepare_system_reset(); + + /* wait for the system to reset */ + for (;;) { + ; + } +} + +/******************************************************************************* + * Handler called to check the validity of the power state parameter. + ******************************************************************************/ +static int32_t tegra_validate_power_state(uint32_t power_state, + psci_power_state_t *req_state) +{ + assert(req_state != NULL); + + return tegra_soc_validate_power_state(power_state, req_state); +} + +/******************************************************************************* + * Platform handler called to check the validity of the non secure entrypoint. + ******************************************************************************/ +static int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint) +{ + int32_t ret = PSCI_E_INVALID_ADDRESS; + + /* + * Check if the non secure entrypoint lies within the non + * secure DRAM. + */ + if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) { + ret = PSCI_E_SUCCESS; + } + + return ret; +} + +/******************************************************************************* + * Export the platform handlers to enable psci to invoke them + ******************************************************************************/ +static plat_psci_ops_t tegra_plat_psci_ops = { + .cpu_standby = tegra_cpu_standby, + .pwr_domain_on = tegra_pwr_domain_on, + .pwr_domain_off_early = tegra_pwr_domain_off_early, + .pwr_domain_off = tegra_pwr_domain_off, + .pwr_domain_suspend_pwrdown_early = tegra_pwr_domain_suspend_pwrdown_early, + .pwr_domain_suspend = tegra_pwr_domain_suspend, + .pwr_domain_on_finish = tegra_pwr_domain_on_finish, + .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, + .pwr_domain_pwr_down_wfi = tegra_pwr_domain_power_down_wfi, + .system_off = tegra_system_off, + .system_reset = tegra_system_reset, + .validate_power_state = tegra_validate_power_state, + .validate_ns_entrypoint = tegra_validate_ns_entrypoint, + .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, +}; + +/******************************************************************************* + * Export the platform specific power ops and initialize Power Controller + ******************************************************************************/ +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; + + /* + * Flush entrypoint variable to PoC since it will be + * accessed after a reset with the caches turned off. + */ + tegra_sec_entry_point = sec_entrypoint; + flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); + + /* + * Reset hardware settings. + */ + (void)tegra_soc_pwr_domain_on_finish(&target_state); + + /* + * Disable System Suspend if the platform does not + * support it + */ + if (!plat_supports_system_suspend()) { + tegra_plat_psci_ops.get_sys_suspend_power_state = NULL; + } + + /* + * Initialize PSCI ops struct + */ + *psci_ops = &tegra_plat_psci_ops; + + return 0; +} + +/******************************************************************************* + * Platform handler to calculate the proper target power level at the + * specified affinity level + ******************************************************************************/ +plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, + const plat_local_state_t *states, + unsigned int ncpu) +{ + return tegra_soc_get_target_pwr_state(lvl, states, ncpu); +} diff --git a/plat/nvidia/tegra/common/tegra_sdei.c b/plat/nvidia/tegra/common/tegra_sdei.c new file mode 100644 index 0000000..9241b81 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_sdei.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* SDEI configuration for Tegra platforms */ + +#include <platform_def.h> + +#include <bl31/ehf.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <lib/utils_def.h> +#include <services/sdei.h> + +/* Private event mappings */ +static sdei_ev_map_t tegra_sdei_private[] = { + /* Event 0 definition */ + SDEI_DEFINE_EVENT_0(TEGRA_SDEI_SGI_PRIVATE), + + /* Dynamic private events */ + SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + + /* General purpose explicit events */ + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_0, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_1, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_2, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_3, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_4, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_5, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_6, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_7, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_8, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_9, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_10, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_11, SDEI_MAPF_CRITICAL) +}; + +/* Shared event mappings */ +static sdei_ev_map_t tegra_sdei_shared[] = { + /* Dynamic shared events */ + SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) +}; + +void plat_sdei_setup(void) +{ + INFO("SDEI platform setup\n"); +} + +/* Export Tegra SDEI events */ +REGISTER_SDEI_MAP(tegra_sdei_private, tegra_sdei_shared); diff --git a/plat/nvidia/tegra/common/tegra_sip_calls.c b/plat/nvidia/tegra/common/tegra_sip_calls.c new file mode 100644 index 0000000..80a2c4d --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_sip_calls.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <common/runtime_svc.h> +#include <lib/mmio.h> + +#include <memctrl.h> +#include <tegra_platform.h> +#include <tegra_private.h> + +/******************************************************************************* + * Common Tegra SiP SMCs + ******************************************************************************/ +#define TEGRA_SIP_NEW_VIDEOMEM_REGION 0x82000003 +#define TEGRA_SIP_FIQ_NS_ENTRYPOINT 0x82000005 +#define TEGRA_SIP_FIQ_NS_GET_CONTEXT 0x82000006 + +/******************************************************************************* + * This function is responsible for handling all SiP calls + ******************************************************************************/ +uintptr_t tegra_sip_handler(uint32_t smc_fid, + u_register_t x1, + u_register_t x2, + u_register_t x3, + u_register_t x4, + void *cookie, + void *handle, + u_register_t flags) +{ + uint32_t regval, local_x2_32 = (uint32_t)x2; + int32_t err; + + /* Check if this is a SoC specific SiP */ + err = plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); + if (err == 0) { + + SMC_RET1(handle, (uint64_t)err); + + } else { + + switch (smc_fid) { + + case TEGRA_SIP_NEW_VIDEOMEM_REGION: + /* Check whether Video memory resize is enabled */ + if (mmio_read_32(TEGRA_MC_BASE + MC_VIDEO_PROTECT_REG_CTRL) + != MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED) { + ERROR("Video Memory Resize isn't enabled! \n"); + SMC_RET1(handle, (uint64_t)-ENOTSUP); + } + + /* + * Check if Video Memory overlaps TZDRAM (contains bl31/bl32) + * or falls outside of the valid DRAM range + */ + err = bl31_check_ns_address(x1, local_x2_32); + if (err != 0) { + SMC_RET1(handle, (uint64_t)err); + } + + /* + * Check if Video Memory is aligned to 1MB. + */ + if (((x1 & 0xFFFFFU) != 0U) || ((local_x2_32 & 0xFFFFFU) != 0U)) { + ERROR("Unaligned Video Memory base address!\n"); + SMC_RET1(handle, (uint64_t)-ENOTSUP); + } + + /* + * The GPU is the user of the Video Memory region. In order to + * transition to the new memory region smoothly, we program the + * new base/size ONLY if the GPU is in reset mode. + */ + regval = mmio_read_32(TEGRA_CAR_RESET_BASE + + TEGRA_GPU_RESET_REG_OFFSET); + if ((regval & GPU_RESET_BIT) == 0U) { + ERROR("GPU not in reset! Video Memory setup failed\n"); + SMC_RET1(handle, (uint64_t)-ENOTSUP); + } + + /* new video memory carveout settings */ + tegra_memctrl_videomem_setup(x1, local_x2_32); + + /* + * Ensure again that GPU is still in reset after VPR resize + */ + regval = mmio_read_32(TEGRA_CAR_RESET_BASE + + TEGRA_GPU_RESET_REG_OFFSET); + if ((regval & GPU_RESET_BIT) == 0U) { + mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_GPU_SET_OFFSET, + GPU_SET_BIT); + } + + SMC_RET1(handle, 0); + + /* + * The NS world registers the address of its handler to be + * used for processing the FIQ. This is normally used by the + * NS FIQ debugger driver to detect system hangs by programming + * a watchdog timer to fire a FIQ interrupt. + */ + case TEGRA_SIP_FIQ_NS_ENTRYPOINT: + + if (x1 == 0U) { + SMC_RET1(handle, SMC_UNK); + } + + /* + * TODO: Check if x1 contains a valid DRAM address + */ + + /* store the NS world's entrypoint */ + tegra_fiq_set_ns_entrypoint(x1); + + SMC_RET1(handle, 0); + + /* + * The NS world's FIQ handler issues this SMC to get the NS EL1/EL0 + * CPU context when the FIQ interrupt was triggered. This allows the + * NS world to understand the CPU state when the watchdog interrupt + * triggered. + */ + case TEGRA_SIP_FIQ_NS_GET_CONTEXT: + + /* retrieve context registers when FIQ triggered */ + (void)tegra_fiq_get_intr_context(); + + SMC_RET0(handle); + + default: + ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); + break; + } + } + + SMC_RET1(handle, SMC_UNK); +} + +/* Define a runtime service descriptor for fast SMC calls */ +DECLARE_RT_SVC( + tegra_sip_fast, + + (OEN_SIP_START), + (OEN_SIP_END), + (SMC_TYPE_FAST), + (NULL), + (tegra_sip_handler) +); diff --git a/plat/nvidia/tegra/common/tegra_stack_protector.c b/plat/nvidia/tegra/common/tegra_stack_protector.c new file mode 100644 index 0000000..f6c459a --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_stack_protector.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <arch_helpers.h> +#include <lib/mmio.h> +#include <plat/common/platform.h> +#include <platform_def.h> + +u_register_t plat_get_stack_protector_canary(void) +{ + u_register_t seed; + + /* + * Ideally, a random number should be returned instead. As the + * platform does not have any random number generator, this is + * better than nothing, but not really secure. + */ + seed = mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET); + seed <<= 32; + seed |= mmio_read_32(TEGRA_TMRUS_BASE); + + return seed ^ read_cntpct_el0(); +} |