1 /* 2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch_helpers.h> 8 #include <assert.h> 9 #include <bakery_lock.h> 10 #include <bl_common.h> 11 #include <context.h> 12 #include <context_mgmt.h> 13 #include <debug.h> 14 #include <denver.h> 15 #include <gic_v2.h> 16 #include <interrupt_mgmt.h> 17 #include <platform.h> 18 #include <tegra_def.h> 19 #include <tegra_private.h> 20 21 static DEFINE_BAKERY_LOCK(tegra_fiq_lock); 22 23 /******************************************************************************* 24 * Static variables 25 ******************************************************************************/ 26 static uint64_t ns_fiq_handler_addr; 27 static uint32_t fiq_handler_active; 28 static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT]; 29 30 /******************************************************************************* 31 * Handler for FIQ interrupts 32 ******************************************************************************/ 33 static uint64_t tegra_fiq_interrupt_handler(uint32_t id, 34 uint32_t flags, 35 void *handle, 36 void *cookie) 37 { 38 cpu_context_t *ctx = cm_get_context(NON_SECURE); 39 el3_state_t *el3state_ctx = get_el3state_ctx(ctx); 40 uint32_t cpu = plat_my_core_pos(); 41 uint32_t irq; 42 43 bakery_lock_get(&tegra_fiq_lock); 44 45 /* 46 * The FIQ was generated when the execution was in the non-secure 47 * world. Save the context registers to start with. 48 */ 49 cm_el1_sysregs_context_save(NON_SECURE); 50 51 /* 52 * Save elr_el3 and spsr_el3 from the saved context, and overwrite 53 * the context with the NS fiq_handler_addr and SPSR value. 54 */ 55 fiq_state[cpu].elr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_ELR_EL3)); 56 fiq_state[cpu].spsr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_SPSR_EL3)); 57 58 /* 59 * Set the new ELR to continue execution in the NS world using the 60 * FIQ handler registered earlier. 61 */ 62 assert(ns_fiq_handler_addr); 63 write_ctx_reg((el3state_ctx), (uint32_t)(CTX_ELR_EL3), (ns_fiq_handler_addr)); 64 65 /* 66 * Mark this interrupt as complete to avoid a FIQ storm. 67 */ 68 irq = plat_ic_acknowledge_interrupt(); 69 if (irq < 1022U) { 70 plat_ic_end_of_interrupt(irq); 71 } 72 73 bakery_lock_release(&tegra_fiq_lock); 74 75 return 0; 76 } 77 78 /******************************************************************************* 79 * Setup handler for FIQ interrupts 80 ******************************************************************************/ 81 void tegra_fiq_handler_setup(void) 82 { 83 uint32_t flags; 84 int32_t rc; 85 86 /* return if already registered */ 87 if (fiq_handler_active == 0U) { 88 /* 89 * Register an interrupt handler for FIQ interrupts generated for 90 * NS interrupt sources 91 */ 92 flags = 0U; 93 set_interrupt_rm_flag((flags), (NON_SECURE)); 94 rc = register_interrupt_type_handler(INTR_TYPE_EL3, 95 tegra_fiq_interrupt_handler, 96 flags); 97 if (rc != 0) { 98 panic(); 99 } 100 101 /* handler is now active */ 102 fiq_handler_active = 1; 103 } 104 } 105 106 /******************************************************************************* 107 * Validate and store NS world's entrypoint for FIQ interrupts 108 ******************************************************************************/ 109 void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint) 110 { 111 ns_fiq_handler_addr = entrypoint; 112 } 113 114 /******************************************************************************* 115 * Handler to return the NS EL1/EL0 CPU context 116 ******************************************************************************/ 117 int32_t tegra_fiq_get_intr_context(void) 118 { 119 cpu_context_t *ctx = cm_get_context(NON_SECURE); 120 gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx); 121 const el1_sys_regs_t *el1state_ctx = get_sysregs_ctx(ctx); 122 uint32_t cpu = plat_my_core_pos(); 123 uint64_t val; 124 125 /* 126 * We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so 127 * that el3_exit() sends these values back to the NS world. 128 */ 129 write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X0), (fiq_state[cpu].elr_el3)); 130 write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X1), (fiq_state[cpu].spsr_el3)); 131 132 val = read_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_SP_EL0)); 133 write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X2), (val)); 134 135 val = read_ctx_reg((el1state_ctx), (uint32_t)(CTX_SP_EL1)); 136 write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X3), (val)); 137 138 return 0; 139 } 140