Home | History | Annotate | Download | only in common
      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