178e2bd10SVarun Wadekar /* 2e0f924a5SMax Shvetsov * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved. 3f6178686SVarun Wadekar * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. 478e2bd10SVarun Wadekar * 582cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 678e2bd10SVarun Wadekar */ 778e2bd10SVarun Wadekar 878e2bd10SVarun Wadekar #include <assert.h> 909d40e0eSAntonio Nino Diaz 1009d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 1109d40e0eSAntonio Nino Diaz #include <bl31/interrupt_mgmt.h> 12*adb20a17SVarun Wadekar #include <bl31/ehf.h> 1309d40e0eSAntonio Nino Diaz #include <common/bl_common.h> 1409d40e0eSAntonio Nino Diaz #include <common/debug.h> 1578e2bd10SVarun Wadekar #include <context.h> 1678e2bd10SVarun Wadekar #include <denver.h> 1709d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/context_mgmt.h> 1809d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 1909d40e0eSAntonio Nino Diaz 20d16b045cSVarun Wadekar #if ENABLE_WDT_LEGACY_FIQ_HANDLING 21d16b045cSVarun Wadekar #include <flowctrl.h> 22d16b045cSVarun Wadekar #endif 2378e2bd10SVarun Wadekar #include <tegra_def.h> 2478e2bd10SVarun Wadekar #include <tegra_private.h> 2578e2bd10SVarun Wadekar 26d16b045cSVarun Wadekar /* Legacy FIQ used by earlier Tegra platforms */ 27d16b045cSVarun Wadekar #define LEGACY_FIQ_PPI_WDT 28U 28d16b045cSVarun Wadekar 29*adb20a17SVarun Wadekar /* Install priority level descriptors for each dispatcher */ 30*adb20a17SVarun Wadekar ehf_pri_desc_t plat_exceptions[] = { 31*adb20a17SVarun Wadekar EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_TEGRA_WDT_PRIO), 32*adb20a17SVarun Wadekar }; 33*adb20a17SVarun Wadekar 34*adb20a17SVarun Wadekar /* Expose priority descriptors to Exception Handling Framework */ 35*adb20a17SVarun Wadekar EHF_REGISTER_PRIORITIES(plat_exceptions, ARRAY_SIZE(plat_exceptions), 36*adb20a17SVarun Wadekar PLAT_PRI_BITS); 37*adb20a17SVarun Wadekar 3878e2bd10SVarun Wadekar /******************************************************************************* 3978e2bd10SVarun Wadekar * Static variables 4078e2bd10SVarun Wadekar ******************************************************************************/ 4178e2bd10SVarun Wadekar static uint64_t ns_fiq_handler_addr; 425bd1a177SAnthony Zhou static uint32_t fiq_handler_active; 4378e2bd10SVarun Wadekar static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT]; 4478e2bd10SVarun Wadekar 4578e2bd10SVarun Wadekar /******************************************************************************* 4678e2bd10SVarun Wadekar * Handler for FIQ interrupts 4778e2bd10SVarun Wadekar ******************************************************************************/ 48*adb20a17SVarun Wadekar static int tegra_fiq_interrupt_handler(unsigned int id, unsigned int flags, 49*adb20a17SVarun Wadekar void *handle, void *cookie) 5078e2bd10SVarun Wadekar { 5178e2bd10SVarun Wadekar cpu_context_t *ctx = cm_get_context(NON_SECURE); 5278e2bd10SVarun Wadekar el3_state_t *el3state_ctx = get_el3state_ctx(ctx); 535bd1a177SAnthony Zhou uint32_t cpu = plat_my_core_pos(); 5478e2bd10SVarun Wadekar 5582e73ae7SAnthony Zhou (void)flags; 5682e73ae7SAnthony Zhou (void)handle; 5782e73ae7SAnthony Zhou (void)cookie; 5882e73ae7SAnthony Zhou 5923ae8094SVarun Wadekar /* 6023ae8094SVarun Wadekar * Jump to NS world only if the NS world's FIQ handler has 6123ae8094SVarun Wadekar * been registered 6223ae8094SVarun Wadekar */ 6323ae8094SVarun Wadekar if (ns_fiq_handler_addr != 0U) { 6423ae8094SVarun Wadekar 6523ae8094SVarun Wadekar /* 6678e2bd10SVarun Wadekar * The FIQ was generated when the execution was in the non-secure 6778e2bd10SVarun Wadekar * world. Save the context registers to start with. 6878e2bd10SVarun Wadekar */ 6978e2bd10SVarun Wadekar cm_el1_sysregs_context_save(NON_SECURE); 7078e2bd10SVarun Wadekar 7178e2bd10SVarun Wadekar /* 7278e2bd10SVarun Wadekar * Save elr_el3 and spsr_el3 from the saved context, and overwrite 7378e2bd10SVarun Wadekar * the context with the NS fiq_handler_addr and SPSR value. 7478e2bd10SVarun Wadekar */ 755bd1a177SAnthony Zhou fiq_state[cpu].elr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_ELR_EL3)); 765bd1a177SAnthony Zhou fiq_state[cpu].spsr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_SPSR_EL3)); 7778e2bd10SVarun Wadekar 7878e2bd10SVarun Wadekar /* 7978e2bd10SVarun Wadekar * Set the new ELR to continue execution in the NS world using the 8078e2bd10SVarun Wadekar * FIQ handler registered earlier. 8178e2bd10SVarun Wadekar */ 8223ae8094SVarun Wadekar cm_set_elr_el3(NON_SECURE, ns_fiq_handler_addr); 8323ae8094SVarun Wadekar } 8478e2bd10SVarun Wadekar 85d16b045cSVarun Wadekar #if ENABLE_WDT_LEGACY_FIQ_HANDLING 86d16b045cSVarun Wadekar /* 87d16b045cSVarun Wadekar * Tegra platforms that use LEGACY_FIQ as the watchdog timer FIQ 88d16b045cSVarun Wadekar * need to issue an IPI to other CPUs, to allow them to handle 89d16b045cSVarun Wadekar * the "system hung" scenario. This interrupt is passed to the GICD 90d16b045cSVarun Wadekar * via the Flow Controller. So, once we receive this interrupt, 91d16b045cSVarun Wadekar * disable the routing so that we can mark it as "complete" in the 92d16b045cSVarun Wadekar * GIC later. 93d16b045cSVarun Wadekar */ 94*adb20a17SVarun Wadekar if (id == LEGACY_FIQ_PPI_WDT) { 95d16b045cSVarun Wadekar tegra_fc_disable_fiq_to_ccplex_routing(); 96d16b045cSVarun Wadekar } 97d16b045cSVarun Wadekar #endif 98d16b045cSVarun Wadekar 9978e2bd10SVarun Wadekar /* 10078e2bd10SVarun Wadekar * Mark this interrupt as complete to avoid a FIQ storm. 10178e2bd10SVarun Wadekar */ 102*adb20a17SVarun Wadekar plat_ic_end_of_interrupt(id); 10378e2bd10SVarun Wadekar 10478e2bd10SVarun Wadekar return 0; 10578e2bd10SVarun Wadekar } 10678e2bd10SVarun Wadekar 10778e2bd10SVarun Wadekar /******************************************************************************* 10878e2bd10SVarun Wadekar * Setup handler for FIQ interrupts 10978e2bd10SVarun Wadekar ******************************************************************************/ 11078e2bd10SVarun Wadekar void tegra_fiq_handler_setup(void) 11178e2bd10SVarun Wadekar { 11278e2bd10SVarun Wadekar /* return if already registered */ 1135bd1a177SAnthony Zhou if (fiq_handler_active == 0U) { 11478e2bd10SVarun Wadekar /* 11578e2bd10SVarun Wadekar * Register an interrupt handler for FIQ interrupts generated for 11678e2bd10SVarun Wadekar * NS interrupt sources 11778e2bd10SVarun Wadekar */ 118*adb20a17SVarun Wadekar ehf_register_priority_handler(PLAT_TEGRA_WDT_PRIO, tegra_fiq_interrupt_handler); 11978e2bd10SVarun Wadekar 12078e2bd10SVarun Wadekar /* handler is now active */ 12178e2bd10SVarun Wadekar fiq_handler_active = 1; 12278e2bd10SVarun Wadekar } 1235bd1a177SAnthony Zhou } 12478e2bd10SVarun Wadekar 12578e2bd10SVarun Wadekar /******************************************************************************* 12678e2bd10SVarun Wadekar * Validate and store NS world's entrypoint for FIQ interrupts 12778e2bd10SVarun Wadekar ******************************************************************************/ 12878e2bd10SVarun Wadekar void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint) 12978e2bd10SVarun Wadekar { 13078e2bd10SVarun Wadekar ns_fiq_handler_addr = entrypoint; 13178e2bd10SVarun Wadekar } 13278e2bd10SVarun Wadekar 13378e2bd10SVarun Wadekar /******************************************************************************* 13478e2bd10SVarun Wadekar * Handler to return the NS EL1/EL0 CPU context 13578e2bd10SVarun Wadekar ******************************************************************************/ 1365bd1a177SAnthony Zhou int32_t tegra_fiq_get_intr_context(void) 13778e2bd10SVarun Wadekar { 13878e2bd10SVarun Wadekar cpu_context_t *ctx = cm_get_context(NON_SECURE); 13978e2bd10SVarun Wadekar gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx); 140e0f924a5SMax Shvetsov const el1_sysregs_t *el1state_ctx = get_el1_sysregs_ctx(ctx); 1415bd1a177SAnthony Zhou uint32_t cpu = plat_my_core_pos(); 14278e2bd10SVarun Wadekar uint64_t val; 14378e2bd10SVarun Wadekar 14478e2bd10SVarun Wadekar /* 14578e2bd10SVarun Wadekar * We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so 14678e2bd10SVarun Wadekar * that el3_exit() sends these values back to the NS world. 14778e2bd10SVarun Wadekar */ 1485bd1a177SAnthony Zhou write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X0), (fiq_state[cpu].elr_el3)); 1495bd1a177SAnthony Zhou write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X1), (fiq_state[cpu].spsr_el3)); 15078e2bd10SVarun Wadekar 1515bd1a177SAnthony Zhou val = read_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_SP_EL0)); 1525bd1a177SAnthony Zhou write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X2), (val)); 15378e2bd10SVarun Wadekar 1545bd1a177SAnthony Zhou val = read_ctx_reg((el1state_ctx), (uint32_t)(CTX_SP_EL1)); 1555bd1a177SAnthony Zhou write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X3), (val)); 15678e2bd10SVarun Wadekar 15778e2bd10SVarun Wadekar return 0; 15878e2bd10SVarun Wadekar } 159