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 DEFINE_BAKERY_LOCK(tegra_fiq_lock); 22 23 /******************************************************************************* 24 * Static variables 25 ******************************************************************************/ 26 static uint64_t ns_fiq_handler_addr; 27 static unsigned int 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 int 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, CTX_ELR_EL3); 56 fiq_state[cpu].spsr_el3 = read_ctx_reg(el3state_ctx, 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, 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 < 1022) 70 plat_ic_end_of_interrupt(irq); 71 72 bakery_lock_release(&tegra_fiq_lock); 73 74 return 0; 75 } 76 77 /******************************************************************************* 78 * Setup handler for FIQ interrupts 79 ******************************************************************************/ 80 void tegra_fiq_handler_setup(void) 81 { 82 uint64_t flags; 83 int rc; 84 85 /* return if already registered */ 86 if (fiq_handler_active) 87 return; 88 89 /* 90 * Register an interrupt handler for FIQ interrupts generated for 91 * NS interrupt sources 92 */ 93 flags = 0; 94 set_interrupt_rm_flag(flags, NON_SECURE); 95 rc = register_interrupt_type_handler(INTR_TYPE_EL3, 96 tegra_fiq_interrupt_handler, 97 flags); 98 if (rc) 99 panic(); 100 101 /* handler is now active */ 102 fiq_handler_active = 1; 103 } 104 105 /******************************************************************************* 106 * Validate and store NS world's entrypoint for FIQ interrupts 107 ******************************************************************************/ 108 void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint) 109 { 110 ns_fiq_handler_addr = entrypoint; 111 } 112 113 /******************************************************************************* 114 * Handler to return the NS EL1/EL0 CPU context 115 ******************************************************************************/ 116 int tegra_fiq_get_intr_context(void) 117 { 118 cpu_context_t *ctx = cm_get_context(NON_SECURE); 119 gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx); 120 el1_sys_regs_t *el1state_ctx = get_sysregs_ctx(ctx); 121 int cpu = plat_my_core_pos(); 122 uint64_t val; 123 124 /* 125 * We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so 126 * that el3_exit() sends these values back to the NS world. 127 */ 128 write_ctx_reg(gpregs_ctx, CTX_GPREG_X0, fiq_state[cpu].elr_el3); 129 write_ctx_reg(gpregs_ctx, CTX_GPREG_X1, fiq_state[cpu].spsr_el3); 130 131 val = read_ctx_reg(gpregs_ctx, CTX_GPREG_SP_EL0); 132 write_ctx_reg(gpregs_ctx, CTX_GPREG_X2, val); 133 134 val = read_ctx_reg(el1state_ctx, CTX_SP_EL1); 135 write_ctx_reg(gpregs_ctx, CTX_GPREG_X3, val); 136 137 return 0; 138 } 139