Merge pull request #456 from soby-mathew/sm/gicv3-tsp-plat-changes-v2
Modify TSP and ARM standard platforms for new GIC drivers v2
This commit is contained in:
commit
4ca473db0d
|
@ -67,18 +67,15 @@ typedef struct intr_type_desc {
|
|||
static intr_type_desc_t intr_type_descs[MAX_INTR_TYPES];
|
||||
|
||||
/*******************************************************************************
|
||||
* This function validates the interrupt type. EL3 interrupts are currently not
|
||||
* supported.
|
||||
* This function validates the interrupt type.
|
||||
******************************************************************************/
|
||||
static int32_t validate_interrupt_type(uint32_t type)
|
||||
{
|
||||
if (type == INTR_TYPE_EL3)
|
||||
return -ENOTSUP;
|
||||
if (type == INTR_TYPE_S_EL1 || type == INTR_TYPE_NS ||
|
||||
type == INTR_TYPE_EL3)
|
||||
return 0;
|
||||
|
||||
if (type != INTR_TYPE_S_EL1 && type != INTR_TYPE_NS)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -95,6 +92,9 @@ static int32_t validate_routing_model(uint32_t type, uint32_t flags)
|
|||
if (type == INTR_TYPE_NS)
|
||||
return validate_ns_interrupt_rm(flags);
|
||||
|
||||
if (type == INTR_TYPE_EL3)
|
||||
return validate_el3_interrupt_rm(flags);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ func tsp_vector_table
|
|||
b tsp_cpu_off_entry
|
||||
b tsp_cpu_resume_entry
|
||||
b tsp_cpu_suspend_entry
|
||||
b tsp_fiq_entry
|
||||
b tsp_sel1_intr_entry
|
||||
b tsp_system_off_entry
|
||||
b tsp_system_reset_entry
|
||||
endfunc tsp_vector_table
|
||||
|
@ -325,13 +325,15 @@ func tsp_cpu_suspend_entry
|
|||
restore_args_call_smc
|
||||
endfunc tsp_cpu_suspend_entry
|
||||
|
||||
/*---------------------------------------------
|
||||
/*-------------------------------------------------
|
||||
* This entrypoint is used by the TSPD to pass
|
||||
* control for handling a pending S-EL1 FIQ.
|
||||
* 'x0' contains a magic number which indicates
|
||||
* this. TSPD expects control to be handed back
|
||||
* at the end of FIQ processing. This is done
|
||||
* through an SMC. The handover agreement is:
|
||||
* control for `synchronously` handling a S-EL1
|
||||
* Interrupt which was triggered while executing
|
||||
* in normal world. 'x0' contains a magic number
|
||||
* which indicates this. TSPD expects control to
|
||||
* be handed back at the end of interrupt
|
||||
* processing. This is done through an SMC.
|
||||
* The handover agreement is:
|
||||
*
|
||||
* 1. PSTATE.DAIF are set upon entry. 'x1' has
|
||||
* the ELR_EL3 from the non-secure state.
|
||||
|
@ -343,40 +345,54 @@ endfunc tsp_cpu_suspend_entry
|
|||
* 4. TSP can use 'x0-x18' to enable its C
|
||||
* runtime.
|
||||
* 5. TSP returns to TSPD using an SMC with
|
||||
* 'x0' = TSP_HANDLED_S_EL1_FIQ
|
||||
* ---------------------------------------------
|
||||
* 'x0' = TSP_HANDLED_S_EL1_INTR
|
||||
* ------------------------------------------------
|
||||
*/
|
||||
func tsp_fiq_entry
|
||||
func tsp_sel1_intr_entry
|
||||
#if DEBUG
|
||||
mov x2, #(TSP_HANDLE_FIQ_AND_RETURN & ~0xffff)
|
||||
movk x2, #(TSP_HANDLE_FIQ_AND_RETURN & 0xffff)
|
||||
mov_imm x2, TSP_HANDLE_SEL1_INTR_AND_RETURN
|
||||
cmp x0, x2
|
||||
b.ne tsp_fiq_entry_panic
|
||||
b.ne tsp_sel1_int_entry_panic
|
||||
#endif
|
||||
/*---------------------------------------------
|
||||
/*-------------------------------------------------
|
||||
* Save any previous context needed to perform
|
||||
* an exception return from S-EL1 e.g. context
|
||||
* from a previous IRQ. Update statistics and
|
||||
* handle the FIQ before returning to the TSPD.
|
||||
* from a previous Non secure Interrupt.
|
||||
* Update statistics and handle the S-EL1
|
||||
* interrupt before returning to the TSPD.
|
||||
* IRQ/FIQs are not enabled since that will
|
||||
* complicate the implementation. Execution
|
||||
* will be transferred back to the normal world
|
||||
* in any case. A non-zero return value from the
|
||||
* fiq handler is an error.
|
||||
* ---------------------------------------------
|
||||
* in any case. The handler can return 0
|
||||
* if the interrupt was handled or TSP_PREEMPTED
|
||||
* if the expected interrupt was preempted
|
||||
* by an interrupt that should be handled in EL3
|
||||
* e.g. Group 0 interrupt in GICv3. In both
|
||||
* the cases switch to EL3 using SMC with id
|
||||
* TSP_HANDLED_S_EL1_INTR. Any other return value
|
||||
* from the handler will result in panic.
|
||||
* ------------------------------------------------
|
||||
*/
|
||||
save_eret_context x2 x3
|
||||
bl tsp_update_sync_fiq_stats
|
||||
bl tsp_fiq_handler
|
||||
cbnz x0, tsp_fiq_entry_panic
|
||||
bl tsp_update_sync_sel1_intr_stats
|
||||
bl tsp_common_int_handler
|
||||
/* Check if the S-EL1 interrupt has been handled */
|
||||
cbnz x0, tsp_sel1_intr_check_preemption
|
||||
b tsp_sel1_intr_return
|
||||
tsp_sel1_intr_check_preemption:
|
||||
/* Check if the S-EL1 interrupt has been preempted */
|
||||
mov_imm x1, TSP_PREEMPTED
|
||||
cmp x0, x1
|
||||
b.ne tsp_sel1_int_entry_panic
|
||||
tsp_sel1_intr_return:
|
||||
mov_imm x0, TSP_HANDLED_S_EL1_INTR
|
||||
restore_eret_context x2 x3
|
||||
mov x0, #(TSP_HANDLED_S_EL1_FIQ & ~0xffff)
|
||||
movk x0, #(TSP_HANDLED_S_EL1_FIQ & 0xffff)
|
||||
smc #0
|
||||
|
||||
tsp_fiq_entry_panic:
|
||||
b tsp_fiq_entry_panic
|
||||
endfunc tsp_fiq_entry
|
||||
/* Should never reach here */
|
||||
tsp_sel1_int_entry_panic:
|
||||
b tsp_sel1_int_entry_panic
|
||||
endfunc tsp_sel1_intr_entry
|
||||
|
||||
/*---------------------------------------------
|
||||
* This entrypoint is used by the TSPD when this
|
||||
|
|
|
@ -70,6 +70,28 @@
|
|||
add sp, sp, SCRATCH_REG_SIZE
|
||||
.endm
|
||||
|
||||
/* ----------------------------------------------------
|
||||
* Common TSP interrupt handling routine
|
||||
* ----------------------------------------------------
|
||||
*/
|
||||
.macro handle_tsp_interrupt label
|
||||
/* Enable the SError interrupt */
|
||||
msr daifclr, #DAIF_ABT_BIT
|
||||
|
||||
save_caller_regs_and_lr
|
||||
bl tsp_common_int_handler
|
||||
cbz x0, interrupt_exit_\label
|
||||
|
||||
/*
|
||||
* This interrupt was not targetted to S-EL1 so send it to
|
||||
* the monitor and wait for execution to resume.
|
||||
*/
|
||||
smc #0
|
||||
interrupt_exit_\label:
|
||||
restore_caller_regs_and_lr
|
||||
eret
|
||||
.endm
|
||||
|
||||
.globl tsp_exceptions
|
||||
|
||||
/* -----------------------------------------------------
|
||||
|
@ -120,36 +142,12 @@ sync_exception_sp_elx:
|
|||
|
||||
.align 7
|
||||
irq_sp_elx:
|
||||
/* Enable the SError interrupt */
|
||||
msr daifclr, #DAIF_ABT_BIT
|
||||
|
||||
save_caller_regs_and_lr
|
||||
/* We just update some statistics in the handler */
|
||||
bl tsp_irq_received
|
||||
/* Hand over control to the normal world to handle the IRQ */
|
||||
smc #0
|
||||
/* The resume std smc starts from here */
|
||||
restore_caller_regs_and_lr
|
||||
eret
|
||||
handle_tsp_interrupt irq_sp_elx
|
||||
check_vector_size irq_sp_elx
|
||||
|
||||
.align 7
|
||||
fiq_sp_elx:
|
||||
/* Enable the SError interrupt */
|
||||
msr daifclr, #DAIF_ABT_BIT
|
||||
|
||||
save_caller_regs_and_lr
|
||||
bl tsp_fiq_handler
|
||||
cbz x0, fiq_sp_elx_done
|
||||
|
||||
/*
|
||||
* This FIQ was not targetted to S-EL1 so send it to
|
||||
* the monitor and wait for execution to resume.
|
||||
*/
|
||||
smc #0
|
||||
fiq_sp_elx_done:
|
||||
restore_caller_regs_and_lr
|
||||
eret
|
||||
handle_tsp_interrupt fiq_sp_elx
|
||||
check_vector_size fiq_sp_elx
|
||||
|
||||
.align 7
|
||||
|
|
|
@ -31,50 +31,70 @@
|
|||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <gic_v2.h>
|
||||
#include <platform.h>
|
||||
#include <platform_def.h>
|
||||
#include <tsp.h>
|
||||
#include "tsp_private.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* This function updates the TSP statistics for FIQs handled synchronously i.e
|
||||
* the ones that have been handed over by the TSPD. It also keeps count of the
|
||||
* number of times control was passed back to the TSPD after handling an FIQ.
|
||||
* In the future it will be possible that the TSPD hands over an FIQ to the TSP
|
||||
* but does not expect it to return execution. This statistic will be useful to
|
||||
* distinguish between these two models of synchronous FIQ handling.
|
||||
* The 'elr_el3' parameter contains the address of the instruction in normal
|
||||
* world where this FIQ was generated.
|
||||
* This function updates the TSP statistics for S-EL1 interrupts handled
|
||||
* synchronously i.e the ones that have been handed over by the TSPD. It also
|
||||
* keeps count of the number of times control was passed back to the TSPD
|
||||
* after handling the interrupt. In the future it will be possible that the
|
||||
* TSPD hands over an S-EL1 interrupt to the TSP but does not expect it to
|
||||
* return execution. This statistic will be useful to distinguish between these
|
||||
* two models of synchronous S-EL1 interrupt handling. The 'elr_el3' parameter
|
||||
* contains the address of the instruction in normal world where this S-EL1
|
||||
* interrupt was generated.
|
||||
******************************************************************************/
|
||||
void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3)
|
||||
void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3)
|
||||
{
|
||||
uint32_t linear_id = plat_my_core_pos();
|
||||
|
||||
tsp_stats[linear_id].sync_fiq_count++;
|
||||
if (type == TSP_HANDLE_FIQ_AND_RETURN)
|
||||
tsp_stats[linear_id].sync_fiq_ret_count++;
|
||||
tsp_stats[linear_id].sync_sel1_intr_count++;
|
||||
if (type == TSP_HANDLE_SEL1_INTR_AND_RETURN)
|
||||
tsp_stats[linear_id].sync_sel1_intr_ret_count++;
|
||||
|
||||
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
||||
spin_lock(&console_lock);
|
||||
VERBOSE("TSP: cpu 0x%lx sync fiq request from 0x%lx\n",
|
||||
VERBOSE("TSP: cpu 0x%lx sync s-el1 interrupt request from 0x%lx\n",
|
||||
read_mpidr(), elr_el3);
|
||||
VERBOSE("TSP: cpu 0x%lx: %d sync fiq requests, %d sync fiq returns\n",
|
||||
VERBOSE("TSP: cpu 0x%lx: %d sync s-el1 interrupt requests,"
|
||||
" %d sync s-el1 interrupt returns\n",
|
||||
read_mpidr(),
|
||||
tsp_stats[linear_id].sync_fiq_count,
|
||||
tsp_stats[linear_id].sync_fiq_ret_count);
|
||||
tsp_stats[linear_id].sync_sel1_intr_count,
|
||||
tsp_stats[linear_id].sync_sel1_intr_ret_count);
|
||||
spin_unlock(&console_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This function is invoked when a non S-EL1 interrupt is received and causes
|
||||
* the preemption of TSP. This function returns TSP_PREEMPTED and results
|
||||
* in the control being handed over to EL3 for handling the interrupt.
|
||||
*****************************************************************************/
|
||||
int32_t tsp_handle_preemption(void)
|
||||
{
|
||||
uint32_t linear_id = plat_my_core_pos();
|
||||
|
||||
tsp_stats[linear_id].preempt_intr_count++;
|
||||
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
||||
spin_lock(&console_lock);
|
||||
VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n",
|
||||
read_mpidr(), tsp_stats[linear_id].preempt_intr_count);
|
||||
spin_unlock(&console_lock);
|
||||
#endif
|
||||
return TSP_PREEMPTED;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* TSP FIQ handler called as a part of both synchronous and asynchronous
|
||||
* handling of FIQ interrupts. It returns 0 upon successfully handling a S-EL1
|
||||
* FIQ and treats all other FIQs as EL3 interrupts. It assumes that the GIC
|
||||
* architecture version in v2.0 and the secure physical timer interrupt is the
|
||||
* only S-EL1 interrupt that it needs to handle.
|
||||
* TSP interrupt handler is called as a part of both synchronous and
|
||||
* asynchronous handling of TSP interrupts. Currently the physical timer
|
||||
* interrupt is the only S-EL1 interrupt that this handler expects. It returns
|
||||
* 0 upon successfully handling the expected interrupt and all other
|
||||
* interrupts are treated as normal world or EL3 interrupts.
|
||||
******************************************************************************/
|
||||
int32_t tsp_fiq_handler(void)
|
||||
int32_t tsp_common_int_handler(void)
|
||||
{
|
||||
uint32_t linear_id = plat_my_core_pos(), id;
|
||||
|
||||
|
@ -82,16 +102,21 @@ int32_t tsp_fiq_handler(void)
|
|||
* Get the highest priority pending interrupt id and see if it is the
|
||||
* secure physical generic timer interrupt in which case, handle it.
|
||||
* Otherwise throw this interrupt at the EL3 firmware.
|
||||
*
|
||||
* There is a small time window between reading the highest priority
|
||||
* pending interrupt and acknowledging it during which another
|
||||
* interrupt of higher priority could become the highest pending
|
||||
* interrupt. This is not expected to happen currently for TSP.
|
||||
*/
|
||||
id = plat_ic_get_pending_interrupt_id();
|
||||
|
||||
/* TSP can only handle the secure physical timer interrupt */
|
||||
if (id != TSP_IRQ_SEC_PHY_TIMER)
|
||||
return TSP_EL3_FIQ;
|
||||
return tsp_handle_preemption();
|
||||
|
||||
/*
|
||||
* Handle the interrupt. Also sanity check if it has been preempted by
|
||||
* another secure interrupt through an assertion.
|
||||
* Acknowledge and handle the secure timer interrupt. Also sanity check
|
||||
* if it has been preempted by another interrupt through an assertion.
|
||||
*/
|
||||
id = plat_ic_acknowledge_interrupt();
|
||||
assert(id == TSP_IRQ_SEC_PHY_TIMER);
|
||||
|
@ -99,29 +124,14 @@ int32_t tsp_fiq_handler(void)
|
|||
plat_ic_end_of_interrupt(id);
|
||||
|
||||
/* Update the statistics and print some messages */
|
||||
tsp_stats[linear_id].fiq_count++;
|
||||
tsp_stats[linear_id].sel1_intr_count++;
|
||||
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
||||
spin_lock(&console_lock);
|
||||
VERBOSE("TSP: cpu 0x%lx handled fiq %d\n",
|
||||
VERBOSE("TSP: cpu 0x%lx handled S-EL1 interrupt %d\n",
|
||||
read_mpidr(), id);
|
||||
VERBOSE("TSP: cpu 0x%lx: %d fiq requests\n",
|
||||
read_mpidr(), tsp_stats[linear_id].fiq_count);
|
||||
VERBOSE("TSP: cpu 0x%lx: %d S-EL1 requests\n",
|
||||
read_mpidr(), tsp_stats[linear_id].sel1_intr_count);
|
||||
spin_unlock(&console_lock);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t tsp_irq_received(void)
|
||||
{
|
||||
uint32_t linear_id = plat_my_core_pos();
|
||||
|
||||
tsp_stats[linear_id].irq_count++;
|
||||
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
||||
spin_lock(&console_lock);
|
||||
VERBOSE("TSP: cpu 0x%lx received irq\n", read_mpidr());
|
||||
VERBOSE("TSP: cpu 0x%lx: %d irq requests\n",
|
||||
read_mpidr(), tsp_stats[linear_id].irq_count);
|
||||
spin_unlock(&console_lock);
|
||||
#endif
|
||||
return TSP_PREEMPTED;
|
||||
}
|
||||
|
|
|
@ -54,10 +54,14 @@
|
|||
|
||||
|
||||
typedef struct work_statistics {
|
||||
uint32_t fiq_count; /* Number of FIQs on this cpu */
|
||||
uint32_t irq_count; /* Number of IRQs on this cpu */
|
||||
uint32_t sync_fiq_count; /* Number of sync. fiqs on this cpu */
|
||||
uint32_t sync_fiq_ret_count; /* Number of fiq returns on this cpu */
|
||||
/* Number of s-el1 interrupts on this cpu */
|
||||
uint32_t sel1_intr_count;
|
||||
/* Number of non s-el1 interrupts on this cpu which preempted TSP */
|
||||
uint32_t preempt_intr_count;
|
||||
/* Number of sync s-el1 interrupts on this cpu */
|
||||
uint32_t sync_sel1_intr_count;
|
||||
/* Number of s-el1 interrupts returns on this cpu */
|
||||
uint32_t sync_sel1_intr_ret_count;
|
||||
uint32_t smc_count; /* Number of returns on this cpu */
|
||||
uint32_t eret_count; /* Number of entries on this cpu */
|
||||
uint32_t cpu_on_count; /* Number of cpu on requests */
|
||||
|
@ -115,8 +119,8 @@ void tsp_generic_timer_stop(void);
|
|||
void tsp_generic_timer_save(void);
|
||||
void tsp_generic_timer_restore(void);
|
||||
|
||||
/* FIQ management functions */
|
||||
void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3);
|
||||
/* S-EL1 interrupt management functions */
|
||||
void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3);
|
||||
|
||||
|
||||
/* Data structure to keep track of TSP statistics */
|
||||
|
|
|
@ -399,12 +399,12 @@ requirements mentioned earlier.
|
|||
1. It passes control to the Test Secure Payload to perform its
|
||||
initialisation. The TSP provides the address of the vector table
|
||||
`tsp_vectors` in the SP which also includes the handler for Secure-EL1
|
||||
interrupts in the `fiq_entry` field. The TSPD passes control to the TSP at
|
||||
interrupts in the `sel1_intr_entry` field. The TSPD passes control to the TSP at
|
||||
this address when it receives a Secure-EL1 interrupt.
|
||||
|
||||
The handover agreement between the TSP and the TSPD requires that the TSPD
|
||||
masks all interrupts (`PSTATE.DAIF` bits) when it calls
|
||||
`tsp_fiq_entry()`. The TSP has to preserve the callee saved general
|
||||
`tsp_sel1_intr_entry()`. The TSP has to preserve the callee saved general
|
||||
purpose, SP_EL1/Secure-EL0, LR, VFP and system registers. It can use
|
||||
`x0-x18` to enable its C runtime.
|
||||
|
||||
|
@ -514,7 +514,7 @@ runtime firmware is not aware of through its platform port.
|
|||
The routing model for Secure-EL1 and non-secure interrupts chosen by the TSP is
|
||||
described in Section 2.2.2. It is known to the TSPD service at build time.
|
||||
|
||||
The TSP implements an entrypoint (`tsp_fiq_entry()`) for handling Secure-EL1
|
||||
The TSP implements an entrypoint (`tsp_sel1_intr_entry()`) for handling Secure-EL1
|
||||
interrupts taken in non-secure state and routed through the TSPD service
|
||||
(synchronous handling model). It passes the reference to this entrypoint via
|
||||
`tsp_vectors` to the TSPD service.
|
||||
|
@ -700,9 +700,9 @@ takes the following actions upon being invoked.
|
|||
3. It saves the system register context for the non-secure state by calling
|
||||
`cm_el1_sysregs_context_save(NON_SECURE);`.
|
||||
|
||||
4. It sets the `ELR_EL3` system register to `tsp_fiq_entry` and sets the
|
||||
4. It sets the `ELR_EL3` system register to `tsp_sel1_intr_entry` and sets the
|
||||
`SPSR_EL3.DAIF` bits in the secure CPU context. It sets `x0` to
|
||||
`TSP_HANDLE_FIQ_AND_RETURN`. If the TSP was in the middle of handling a
|
||||
`TSP_HANDLE_SEL1_INTR_AND_RETURN`. If the TSP was in the middle of handling a
|
||||
standard SMC, then the `ELR_EL3` and `SPSR_EL3` registers in the secure CPU
|
||||
context are saved first.
|
||||
|
||||
|
@ -723,20 +723,20 @@ state.
|
|||
|
||||
![Image 1](diagrams/sec-int-handling.png?raw=true)
|
||||
|
||||
The TSP issues an SMC with `TSP_HANDLED_S_EL1_FIQ` as the function identifier to
|
||||
The TSP issues an SMC with `TSP_HANDLED_S_EL1_INTR` as the function identifier to
|
||||
signal completion of interrupt handling.
|
||||
|
||||
The TSP issues an SMC with `TSP_PREEMPTED` as the function identifier to signal
|
||||
generation of a non-secure interrupt in Secure-EL1.
|
||||
|
||||
The TSPD service takes the following actions in `tspd_smc_handler()` function
|
||||
upon receiving an SMC with `TSP_HANDLED_S_EL1_FIQ` and `TSP_PREEMPTED` as the
|
||||
upon receiving an SMC with `TSP_HANDLED_S_EL1_INTR` and `TSP_PREEMPTED` as the
|
||||
function identifiers:
|
||||
|
||||
1. It ensures that the call originated from the secure state otherwise
|
||||
execution returns to the non-secure state with `SMC_UNK` in `x0`.
|
||||
|
||||
2. If the function identifier is `TSP_HANDLED_S_EL1_FIQ`, it restores the
|
||||
2. If the function identifier is `TSP_HANDLED_S_EL1_INTR`, it restores the
|
||||
saved `ELR_EL3` and `SPSR_EL3` system registers back to the secure CPU
|
||||
context (see step 4 above) in case the TSP had been preempted by a non
|
||||
secure interrupt earlier. It does not save the secure context since the
|
||||
|
@ -811,7 +811,7 @@ state.
|
|||
|
||||
##### 2.3.3.1 Test secure payload behavior
|
||||
The TSPD hands control of a Secure-EL1 interrupt to the TSP at the
|
||||
`tsp_fiq_entry()`. The TSP handles the interrupt while ensuring that the
|
||||
`tsp_sel1_intr_entry()`. The TSP handles the interrupt while ensuring that the
|
||||
handover agreement described in Section 2.2.2.1 is maintained. It updates some
|
||||
statistics by calling `tsp_update_sync_fiq_stats()`. It then calls
|
||||
`tsp_fiq_handler()` which.
|
||||
|
@ -827,7 +827,7 @@ statistics by calling `tsp_update_sync_fiq_stats()`. It then calls
|
|||
end of interrupt processing.
|
||||
|
||||
The TSP passes control back to the TSPD by issuing an SMC64 with
|
||||
`TSP_HANDLED_S_EL1_FIQ` as the function identifier.
|
||||
`TSP_HANDLED_S_EL1_INTR` as the function identifier.
|
||||
|
||||
The TSP handles interrupts under the asynchronous model as follows.
|
||||
|
||||
|
|
|
@ -278,10 +278,13 @@ performed.
|
|||
(Coherent memory region is included) or 0 (Coherent memory region is
|
||||
excluded). Default is 1.
|
||||
|
||||
* `TSPD_ROUTE_IRQ_TO_EL3`: A non zero value enables the routing model
|
||||
for non-secure interrupts in which they are routed to EL3 (TSPD). The
|
||||
default model (when the value is 0) is to route non-secure interrupts
|
||||
to S-EL1 (TSP).
|
||||
* `TSP_NS_INTR_ASYNC_PREEMPT`: A non zero value enables the interrupt
|
||||
routing model which routes non-secure interrupts asynchronously from TSP
|
||||
to EL3 causing immediate preemption of TSP. The EL3 is responsible
|
||||
for saving and restoring the TSP context in this routing model. The
|
||||
default routing model (when the value is 0) is to route non-secure
|
||||
interrupts to TSP allowing it to save its context and hand over
|
||||
synchronously to EL3 via an SMC.
|
||||
|
||||
* `TRUSTED_BOARD_BOOT`: Boolean flag to include support for the Trusted Board
|
||||
Boot feature. When set to '1', BL1 and BL2 images include support to load
|
||||
|
|
|
@ -312,7 +312,7 @@ void gicv3_secure_spis_configure(uintptr_t gicd_base,
|
|||
unsigned int index, irq_num;
|
||||
uint64_t gic_affinity_val;
|
||||
|
||||
assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0));
|
||||
assert((int_grp == INTR_GROUP1S) || (int_grp == INTR_GROUP0));
|
||||
/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
|
||||
assert(num_ints ? (uintptr_t)sec_intr_list : 1);
|
||||
|
||||
|
@ -324,7 +324,7 @@ void gicv3_secure_spis_configure(uintptr_t gicd_base,
|
|||
gicd_clr_igroupr(gicd_base, irq_num);
|
||||
|
||||
/* Configure this interrupt as G0 or a G1S interrupt */
|
||||
if (int_grp == INT_TYPE_G1S)
|
||||
if (int_grp == INTR_GROUP1S)
|
||||
gicd_set_igrpmodr(gicd_base, irq_num);
|
||||
else
|
||||
gicd_clr_igrpmodr(gicd_base, irq_num);
|
||||
|
@ -386,7 +386,7 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
|
|||
{
|
||||
unsigned int index, irq_num;
|
||||
|
||||
assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0));
|
||||
assert((int_grp == INTR_GROUP1S) || (int_grp == INTR_GROUP0));
|
||||
/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
|
||||
assert(num_ints ? (uintptr_t)sec_intr_list : 1);
|
||||
|
||||
|
@ -398,7 +398,7 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
|
|||
gicr_clr_igroupr0(gicr_base, irq_num);
|
||||
|
||||
/* Configure this interrupt as G0 or a G1S interrupt */
|
||||
if (int_grp == INT_TYPE_G1S)
|
||||
if (int_grp == INTR_GROUP1S)
|
||||
gicr_set_igrpmodr0(gicr_base, irq_num);
|
||||
else
|
||||
gicr_clr_igrpmodr0(gicr_base, irq_num);
|
||||
|
|
|
@ -144,13 +144,13 @@ void gicv3_distif_init(void)
|
|||
gicv3_secure_spis_configure(driver_data->gicd_base,
|
||||
driver_data->g1s_interrupt_num,
|
||||
driver_data->g1s_interrupt_array,
|
||||
INT_TYPE_G1S);
|
||||
INTR_GROUP1S);
|
||||
|
||||
/* Configure the G0 SPIs */
|
||||
gicv3_secure_spis_configure(driver_data->gicd_base,
|
||||
driver_data->g0_interrupt_num,
|
||||
driver_data->g0_interrupt_array,
|
||||
INT_TYPE_G0);
|
||||
INTR_GROUP0);
|
||||
|
||||
/* Enable the secure SPIs now that they have been configured */
|
||||
gicd_set_ctlr(driver_data->gicd_base,
|
||||
|
@ -186,13 +186,13 @@ void gicv3_rdistif_init(unsigned int proc_num)
|
|||
gicv3_secure_ppi_sgi_configure(gicr_base,
|
||||
driver_data->g1s_interrupt_num,
|
||||
driver_data->g1s_interrupt_array,
|
||||
INT_TYPE_G1S);
|
||||
INTR_GROUP1S);
|
||||
|
||||
/* Configure the G0 SGIs/PPIs */
|
||||
gicv3_secure_ppi_sgi_configure(gicr_base,
|
||||
driver_data->g0_interrupt_num,
|
||||
driver_data->g0_interrupt_array,
|
||||
INT_TYPE_G0);
|
||||
INTR_GROUP0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -332,9 +332,9 @@ unsigned int gicv3_get_pending_interrupt_type(void)
|
|||
* this interrupt has been configured under by the interrupt controller i.e.
|
||||
* group0 or group1 Secure / Non Secure. The return value can be one of the
|
||||
* following :
|
||||
* INT_TYPE_G0 : The interrupt type is a Secure Group 0 interrupt
|
||||
* INT_TYPE_G1S : The interrupt type is a Secure Group 1 secure interrupt
|
||||
* INT_TYPE_G1NS: The interrupt type is a Secure Group 1 non secure
|
||||
* INTR_GROUP0 : The interrupt type is a Secure Group 0 interrupt
|
||||
* INTR_GROUP1S : The interrupt type is a Secure Group 1 secure interrupt
|
||||
* INTR_GROUP1NS: The interrupt type is a Secure Group 1 non secure
|
||||
* interrupt.
|
||||
******************************************************************************/
|
||||
unsigned int gicv3_get_interrupt_type(unsigned int id,
|
||||
|
@ -352,7 +352,7 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
|
|||
|
||||
/* All LPI interrupts are Group 1 non secure */
|
||||
if (id >= MIN_LPI_ID)
|
||||
return INT_TYPE_G1NS;
|
||||
return INTR_GROUP1NS;
|
||||
|
||||
if (id < MIN_SPI_ID) {
|
||||
assert(driver_data->rdistif_base_addrs);
|
||||
|
@ -370,12 +370,12 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
|
|||
* interrupt
|
||||
*/
|
||||
if (igroup)
|
||||
return INT_TYPE_G1NS;
|
||||
return INTR_GROUP1NS;
|
||||
|
||||
/* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */
|
||||
if (grpmodr)
|
||||
return INT_TYPE_G1S;
|
||||
return INTR_GROUP1S;
|
||||
|
||||
/* Else it is a Group 0 Secure interrupt */
|
||||
return INT_TYPE_G0;
|
||||
return INTR_GROUP0;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,10 @@
|
|||
#define INTR_NS_VALID_RM0 0x0
|
||||
/* Routed to EL1/EL2 from NS and to EL3 from Secure */
|
||||
#define INTR_NS_VALID_RM1 0x1
|
||||
/* Routed to EL3 from NS. Taken to S-EL1 from Secure and handed over to EL3 */
|
||||
#define INTR_EL3_VALID_RM0 0x2
|
||||
/* Routed to EL3 from NS and Secure */
|
||||
#define INTR_EL3_VALID_RM1 0x3
|
||||
/* This is the default routing model */
|
||||
#define INTR_DEFAULT_RM 0x0
|
||||
|
||||
|
@ -87,12 +91,16 @@
|
|||
* of interrupt. If the model does not match one of the valid masks
|
||||
* -EINVAL is returned.
|
||||
******************************************************************************/
|
||||
#define validate_sel1_interrupt_rm(x) (x == INTR_SEL1_VALID_RM0 ? 0 : \
|
||||
(x == INTR_SEL1_VALID_RM1 ? 0 :\
|
||||
#define validate_sel1_interrupt_rm(x) ((x) == INTR_SEL1_VALID_RM0 ? 0 : \
|
||||
((x) == INTR_SEL1_VALID_RM1 ? 0 :\
|
||||
-EINVAL))
|
||||
|
||||
#define validate_ns_interrupt_rm(x) (x == INTR_NS_VALID_RM0 ? 0 : \
|
||||
(x == INTR_NS_VALID_RM1 ? 0 :\
|
||||
#define validate_ns_interrupt_rm(x) ((x) == INTR_NS_VALID_RM0 ? 0 : \
|
||||
((x) == INTR_NS_VALID_RM1 ? 0 :\
|
||||
-EINVAL))
|
||||
|
||||
#define validate_el3_interrupt_rm(x) ((x) == INTR_EL3_VALID_RM0 ? 0 : \
|
||||
((x) == INTR_EL3_VALID_RM1 ? 0 :\
|
||||
-EINVAL))
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -45,12 +45,12 @@
|
|||
#define TSP_SYSTEM_RESET_DONE 0xf2000009
|
||||
|
||||
/*
|
||||
* Function identifiers to handle FIQs through the synchronous handling model.
|
||||
* If the TSP was previously interrupted then control has to be returned to
|
||||
* the TSPD after handling the interrupt else execution can remain in the TSP.
|
||||
* Function identifiers to handle S-El1 interrupt through the synchronous
|
||||
* handling model. If the TSP was previously interrupted then control has to
|
||||
* be returned to the TSPD after handling the interrupt else execution can
|
||||
* remain in the TSP.
|
||||
*/
|
||||
#define TSP_HANDLED_S_EL1_FIQ 0xf2000006
|
||||
#define TSP_EL3_FIQ 0xf2000007
|
||||
#define TSP_HANDLED_S_EL1_INTR 0xf2000006
|
||||
|
||||
/* SMC function ID that TSP uses to request service from secure monitor */
|
||||
#define TSP_GET_ARGS 0xf2001000
|
||||
|
@ -63,7 +63,7 @@
|
|||
#define TSP_SUB 0x2001
|
||||
#define TSP_MUL 0x2002
|
||||
#define TSP_DIV 0x2003
|
||||
#define TSP_HANDLE_FIQ_AND_RETURN 0x2004
|
||||
#define TSP_HANDLE_SEL1_INTR_AND_RETURN 0x2004
|
||||
|
||||
/*
|
||||
* Generate function IDs for TSP services to be used in SMC calls, by
|
||||
|
@ -115,7 +115,7 @@ typedef struct tsp_vectors {
|
|||
tsp_vector_isn_t cpu_off_entry;
|
||||
tsp_vector_isn_t cpu_resume_entry;
|
||||
tsp_vector_isn_t cpu_suspend_entry;
|
||||
tsp_vector_isn_t fiq_entry;
|
||||
tsp_vector_isn_t sel1_intr_entry;
|
||||
tsp_vector_isn_t system_off_entry;
|
||||
tsp_vector_isn_t system_reset_entry;
|
||||
} tsp_vectors_t;
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
* GICv3 miscellaneous definitions
|
||||
******************************************************************************/
|
||||
/* Interrupt group definitions */
|
||||
#define INT_TYPE_G1S 0
|
||||
#define INT_TYPE_G0 1
|
||||
#define INT_TYPE_G1NS 2
|
||||
#define INTR_GROUP1S 0
|
||||
#define INTR_GROUP0 1
|
||||
#define INTR_GROUP1NS 2
|
||||
|
||||
/* Interrupt IDs reported by the HPPIR and IAR registers */
|
||||
#define PENDING_G1S_INTID 1020
|
||||
|
|
|
@ -31,12 +31,21 @@
|
|||
#define __ARM_MACROS_S__
|
||||
|
||||
#include <cci.h>
|
||||
#include <gic_v2.h>
|
||||
#include <gic_common.h>
|
||||
#include <gicv2.h>
|
||||
#include <gicv3.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
.section .rodata.gic_reg_name, "aS"
|
||||
/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
|
||||
gicc_regs:
|
||||
.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
|
||||
|
||||
/* Applicable only to GICv3 with SRE enabled */
|
||||
icc_regs:
|
||||
.asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
|
||||
|
||||
/* Registers common to both GICv2 and GICv3 */
|
||||
gicd_pend_reg:
|
||||
.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \
|
||||
" Offset:\t\t\tvalue\n"
|
||||
|
@ -54,6 +63,28 @@ spacer:
|
|||
* ---------------------------------------------
|
||||
*/
|
||||
.macro arm_print_gic_regs
|
||||
/* Check for GICv3 system register access */
|
||||
mrs x7, id_aa64pfr0_el1
|
||||
ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
|
||||
cmp x7, #1
|
||||
b.ne print_gicv2
|
||||
|
||||
/* Check for SRE enable */
|
||||
mrs x8, ICC_SRE_EL3
|
||||
tst x8, #ICC_SRE_SRE_BIT
|
||||
b.eq print_gicv2
|
||||
|
||||
/* Load the icc reg list to x6 */
|
||||
adr x6, icc_regs
|
||||
/* Load the icc regs to gp regs used by str_in_crash_buf_print */
|
||||
mrs x8, ICC_HPPIR0_EL1
|
||||
mrs x9, ICC_HPPIR1_EL1
|
||||
mrs x10, ICC_CTLR_EL3
|
||||
/* Store to the crash buf and print to console */
|
||||
bl str_in_crash_buf_print
|
||||
b print_gic_common
|
||||
|
||||
print_gicv2:
|
||||
/* Load the gicc reg list to x6 */
|
||||
adr x6, gicc_regs
|
||||
/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
|
||||
|
@ -63,6 +94,7 @@ spacer:
|
|||
/* Store to the crash buf and print to console */
|
||||
bl str_in_crash_buf_print
|
||||
|
||||
print_gic_common:
|
||||
/* Print the GICD_ISPENDR regs */
|
||||
add x7, x16, #GICD_ISPENDR
|
||||
adr x4, gicd_pend_reg
|
||||
|
|
|
@ -42,12 +42,6 @@ enum arm_config_flags {
|
|||
};
|
||||
|
||||
typedef struct arm_config {
|
||||
uintptr_t gicd_base;
|
||||
uintptr_t gicc_base;
|
||||
uintptr_t gich_base;
|
||||
uintptr_t gicv_base;
|
||||
unsigned int max_aff0;
|
||||
unsigned int max_aff1;
|
||||
unsigned long flags;
|
||||
} arm_config_t;
|
||||
|
||||
|
|
|
@ -135,6 +135,22 @@
|
|||
#define ARM_IRQ_SEC_SGI_6 14
|
||||
#define ARM_IRQ_SEC_SGI_7 15
|
||||
|
||||
/*
|
||||
* Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
|
||||
* terminology. On a GICv2 system or mode, the lists will be merged and treated
|
||||
* as Group 0 interrupts.
|
||||
*/
|
||||
#define ARM_G1S_IRQS ARM_IRQ_SEC_PHY_TIMER, \
|
||||
ARM_IRQ_SEC_SGI_1, \
|
||||
ARM_IRQ_SEC_SGI_2, \
|
||||
ARM_IRQ_SEC_SGI_3, \
|
||||
ARM_IRQ_SEC_SGI_4, \
|
||||
ARM_IRQ_SEC_SGI_5, \
|
||||
ARM_IRQ_SEC_SGI_7
|
||||
|
||||
#define ARM_G0_IRQS ARM_IRQ_SEC_SGI_0, \
|
||||
ARM_IRQ_SEC_SGI_6
|
||||
|
||||
#define ARM_SHARED_RAM_ATTR ((PLAT_ARM_SHARED_RAM_CACHED ? \
|
||||
MT_MEMORY : MT_DEVICE) \
|
||||
| MT_RW | MT_SECURE)
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include <stdint.h>
|
||||
#include <xlat_tables.h>
|
||||
|
||||
|
||||
/*
|
||||
* Extern declarations common to ARM standard platforms
|
||||
*/
|
||||
|
@ -179,7 +178,11 @@ void arm_tsp_early_platform_setup(void);
|
|||
/*
|
||||
* Mandatory functions required in ARM standard platforms
|
||||
*/
|
||||
void plat_arm_gic_driver_init(void);
|
||||
void plat_arm_gic_init(void);
|
||||
void plat_arm_gic_cpuif_enable(void);
|
||||
void plat_arm_gic_cpuif_disable(void);
|
||||
void plat_arm_gic_pcpu_init(void);
|
||||
void plat_arm_security_setup(void);
|
||||
void plat_arm_pwrc_setup(void);
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@
|
|||
* ---------------------------------------------
|
||||
*/
|
||||
.macro plat_print_gic_regs
|
||||
mov_imm x16, PLAT_CSS_GICD_BASE
|
||||
mov_imm x17, PLAT_CSS_GICC_BASE
|
||||
mov_imm x16, PLAT_ARM_GICD_BASE
|
||||
mov_imm x17, PLAT_ARM_GICC_BASE
|
||||
arm_print_gic_regs
|
||||
.endm
|
||||
|
||||
|
|
|
@ -60,6 +60,16 @@
|
|||
#define CSS_IRQ_TZ_WDOG 86
|
||||
#define CSS_IRQ_SEC_SYS_TIMER 91
|
||||
|
||||
/*
|
||||
* Define a list of Group 1 Secure interrupts as per GICv3 terminology. On a
|
||||
* GICv2 system or mode, the interrupts will be treated as Group 0 interrupts.
|
||||
*/
|
||||
#define CSS_G1S_IRQS CSS_IRQ_MHU, \
|
||||
CSS_IRQ_GPU_SMMU_0, \
|
||||
CSS_IRQ_TZC, \
|
||||
CSS_IRQ_TZ_WDOG, \
|
||||
CSS_IRQ_SEC_SYS_TIMER
|
||||
|
||||
/*
|
||||
* SCP <=> AP boot configuration
|
||||
*
|
||||
|
|
|
@ -30,14 +30,23 @@
|
|||
|
||||
#include <arm_config.h>
|
||||
#include <arm_def.h>
|
||||
#include <arm_gic.h>
|
||||
#include <cci.h>
|
||||
#include <debug.h>
|
||||
#include <gicv2.h>
|
||||
#include <mmio.h>
|
||||
#include <plat_arm.h>
|
||||
#include <v2m_def.h>
|
||||
#include "../fvp_def.h"
|
||||
|
||||
#if (FVP_USE_GIC_DRIVER == FVP_GICV2)
|
||||
extern gicv2_driver_data_t arm_gic_data;
|
||||
#endif
|
||||
|
||||
/* Defines for GIC Driver build time selection */
|
||||
#define FVP_GICV2 1
|
||||
#define FVP_GICV3 2
|
||||
#define FVP_GICV3_LEGACY 3
|
||||
|
||||
/*******************************************************************************
|
||||
* arm_config holds the characteristics of the differences between the three FVP
|
||||
* platforms (Base, A53_A57 & Foundation). It will be populated during cold boot
|
||||
|
@ -110,33 +119,6 @@ const mmap_region_t plat_arm_mmap[] = {
|
|||
ARM_CASSERT_MMAP
|
||||
|
||||
|
||||
#if IMAGE_BL31 || IMAGE_BL32
|
||||
/* Array of secure interrupts to be configured by the gic driver */
|
||||
const unsigned int irq_sec_array[] = {
|
||||
ARM_IRQ_SEC_PHY_TIMER,
|
||||
ARM_IRQ_SEC_SGI_0,
|
||||
ARM_IRQ_SEC_SGI_1,
|
||||
ARM_IRQ_SEC_SGI_2,
|
||||
ARM_IRQ_SEC_SGI_3,
|
||||
ARM_IRQ_SEC_SGI_4,
|
||||
ARM_IRQ_SEC_SGI_5,
|
||||
ARM_IRQ_SEC_SGI_6,
|
||||
ARM_IRQ_SEC_SGI_7,
|
||||
FVP_IRQ_TZ_WDOG,
|
||||
FVP_IRQ_SEC_SYS_TIMER
|
||||
};
|
||||
|
||||
void plat_arm_gic_init(void)
|
||||
{
|
||||
arm_gic_init(arm_config.gicc_base,
|
||||
arm_config.gicd_base,
|
||||
BASE_GICR_BASE,
|
||||
irq_sec_array,
|
||||
ARRAY_SIZE(irq_sec_array));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* A single boot loader stack is expected to work on both the Foundation FVP
|
||||
* models and the two flavours of the Base FVP models (AEMv8 & Cortex). The
|
||||
|
@ -165,16 +147,28 @@ void fvp_config_setup(void)
|
|||
*/
|
||||
switch (bld) {
|
||||
case BLD_GIC_VE_MMAP:
|
||||
arm_config.gicd_base = VE_GICD_BASE;
|
||||
arm_config.gicc_base = VE_GICC_BASE;
|
||||
arm_config.gich_base = VE_GICH_BASE;
|
||||
arm_config.gicv_base = VE_GICV_BASE;
|
||||
#if IMAGE_BL31 || IMAGE_BL32
|
||||
#if FVP_USE_GIC_DRIVER == FVP_GICV2
|
||||
/*
|
||||
* If the FVP implements the VE compatible memory map, then the
|
||||
* GICv2 driver must be included in the build. Update the platform
|
||||
* data with the correct GICv2 base addresses before it is used
|
||||
* to initialise the driver.
|
||||
*
|
||||
* This update of platform data is temporary and will be removed
|
||||
* once VE memory map for FVP is no longer supported by Trusted
|
||||
* Firmware.
|
||||
*/
|
||||
arm_gic_data.gicd_base = VE_GICD_BASE;
|
||||
arm_gic_data.gicc_base = VE_GICC_BASE;
|
||||
|
||||
#else
|
||||
ERROR("Only GICv2 driver supported for VE memory map\n");
|
||||
panic();
|
||||
#endif /* __FVP_USE_GIC_DRIVER == FVP_GICV2__ */
|
||||
#endif /* __IMAGE_BL31 || IMAGE_BL32__ */
|
||||
break;
|
||||
case BLD_GIC_A53A57_MMAP:
|
||||
arm_config.gicd_base = BASE_GICD_BASE;
|
||||
arm_config.gicc_base = BASE_GICC_BASE;
|
||||
arm_config.gich_base = BASE_GICH_BASE;
|
||||
arm_config.gicv_base = BASE_GICV_BASE;
|
||||
break;
|
||||
default:
|
||||
ERROR("Unsupported board build %x\n", bld);
|
||||
|
@ -187,8 +181,6 @@ void fvp_config_setup(void)
|
|||
*/
|
||||
switch (hbi) {
|
||||
case HBI_FOUNDATION_FVP:
|
||||
arm_config.max_aff0 = 4;
|
||||
arm_config.max_aff1 = 1;
|
||||
arm_config.flags = 0;
|
||||
|
||||
/*
|
||||
|
@ -206,8 +198,6 @@ void fvp_config_setup(void)
|
|||
}
|
||||
break;
|
||||
case HBI_BASE_FVP:
|
||||
arm_config.max_aff0 = 4;
|
||||
arm_config.max_aff1 = 2;
|
||||
arm_config.flags |= ARM_CONFIG_BASE_MMAP |
|
||||
ARM_CONFIG_HAS_CCI | ARM_CONFIG_HAS_TZC;
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
|
||||
#include <arch.h>
|
||||
#include <asm_macros.S>
|
||||
#include <gic_v2.h>
|
||||
#include <gicv2.h>
|
||||
#include <gicv3.h>
|
||||
#include <platform_def.h>
|
||||
#include <v2m_def.h>
|
||||
#include "../drivers/pwrc/fvp_pwrc.h"
|
||||
|
@ -74,9 +75,26 @@ func plat_secondary_cold_boot_setup
|
|||
str w0, [x1, #PPOFFR_OFF]
|
||||
|
||||
/* ---------------------------------------------
|
||||
* Deactivate the gic cpu interface as well
|
||||
* Disable GIC bypass as well
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
/* Check for GICv3 system register access */
|
||||
mrs x0, id_aa64pfr0_el1
|
||||
ubfx x0, x0, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
|
||||
cmp x0, #1
|
||||
b.ne gicv2_bypass_disable
|
||||
|
||||
/* Check for SRE enable */
|
||||
mrs x1, ICC_SRE_EL3
|
||||
tst x1, #ICC_SRE_SRE_BIT
|
||||
b.eq gicv2_bypass_disable
|
||||
|
||||
mrs x2, ICC_SRE_EL3
|
||||
orr x2, x2, #(ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT)
|
||||
msr ICC_SRE_EL3, x2
|
||||
b secondary_cold_boot_wait
|
||||
|
||||
gicv2_bypass_disable:
|
||||
ldr x0, =VE_GICC_BASE
|
||||
ldr x1, =BASE_GICC_BASE
|
||||
fvp_choose_gicmmap x0, x1, x2, w2, x1
|
||||
|
@ -84,6 +102,7 @@ func plat_secondary_cold_boot_setup
|
|||
orr w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0)
|
||||
str w0, [x1, #GICC_CTLR]
|
||||
|
||||
secondary_cold_boot_wait:
|
||||
/* ---------------------------------------------
|
||||
* There is no sane reason to come out of this
|
||||
* wfi so panic if we do. This cpu will be pow-
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include <arch_helpers.h>
|
||||
#include <arm_config.h>
|
||||
#include <arm_gic.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
@ -72,7 +71,7 @@ const unsigned int arm_pm_idle_states[] = {
|
|||
static void fvp_cpu_pwrdwn_common(void)
|
||||
{
|
||||
/* Prevent interrupts from spuriously waking up this cpu */
|
||||
arm_gic_cpuif_deactivate();
|
||||
plat_arm_gic_cpuif_disable();
|
||||
|
||||
/* Program the power controller to power off this cpu. */
|
||||
fvp_pwrc_write_ppoffr(read_mpidr_el1());
|
||||
|
@ -93,6 +92,42 @@ static void fvp_cluster_pwrdwn_common(void)
|
|||
fvp_pwrc_write_pcoffr(mpidr);
|
||||
}
|
||||
|
||||
static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state)
|
||||
{
|
||||
unsigned long mpidr;
|
||||
|
||||
assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
|
||||
ARM_LOCAL_STATE_OFF);
|
||||
|
||||
/* Get the mpidr for this cpu */
|
||||
mpidr = read_mpidr_el1();
|
||||
|
||||
/* Perform the common cluster specific operations */
|
||||
if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
|
||||
ARM_LOCAL_STATE_OFF) {
|
||||
/*
|
||||
* This CPU might have woken up whilst the cluster was
|
||||
* attempting to power down. In this case the FVP power
|
||||
* controller will have a pending cluster power off request
|
||||
* which needs to be cleared by writing to the PPONR register.
|
||||
* This prevents the power controller from interpreting a
|
||||
* subsequent entry of this cpu into a simple wfi as a power
|
||||
* down request.
|
||||
*/
|
||||
fvp_pwrc_write_pponr(mpidr);
|
||||
|
||||
/* Enable coherency if this cluster was off */
|
||||
fvp_cci_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear PWKUPR.WEN bit to ensure interrupts do not interfere
|
||||
* with a cpu power down unless the bit is set again
|
||||
*/
|
||||
fvp_pwrc_clr_wen(mpidr);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* FVP handler called when a CPU is about to enter standby.
|
||||
******************************************************************************/
|
||||
|
@ -196,43 +231,13 @@ void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
|
|||
******************************************************************************/
|
||||
void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state)
|
||||
{
|
||||
unsigned long mpidr;
|
||||
|
||||
assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
|
||||
ARM_LOCAL_STATE_OFF);
|
||||
|
||||
/* Get the mpidr for this cpu */
|
||||
mpidr = read_mpidr_el1();
|
||||
|
||||
/* Perform the common cluster specific operations */
|
||||
if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
|
||||
ARM_LOCAL_STATE_OFF) {
|
||||
/*
|
||||
* This CPU might have woken up whilst the cluster was
|
||||
* attempting to power down. In this case the FVP power
|
||||
* controller will have a pending cluster power off request
|
||||
* which needs to be cleared by writing to the PPONR register.
|
||||
* This prevents the power controller from interpreting a
|
||||
* subsequent entry of this cpu into a simple wfi as a power
|
||||
* down request.
|
||||
*/
|
||||
fvp_pwrc_write_pponr(mpidr);
|
||||
|
||||
/* Enable coherency if this cluster was off */
|
||||
fvp_cci_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear PWKUPR.WEN bit to ensure interrupts do not interfere
|
||||
* with a cpu power down unless the bit is set again
|
||||
*/
|
||||
fvp_pwrc_clr_wen(mpidr);
|
||||
fvp_power_domain_on_finish_common(target_state);
|
||||
|
||||
/* Enable the gic cpu interface */
|
||||
arm_gic_cpuif_setup();
|
||||
plat_arm_gic_pcpu_init();
|
||||
|
||||
/* TODO: This setup is needed only after a cold boot */
|
||||
arm_gic_pcpu_distif_setup();
|
||||
/* Program the gic per-cpu distributor or re-distributor interface */
|
||||
plat_arm_gic_cpuif_enable();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -251,7 +256,10 @@ void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
|
|||
ARM_LOCAL_STATE_RET)
|
||||
return;
|
||||
|
||||
fvp_pwr_domain_on_finish(target_state);
|
||||
fvp_power_domain_on_finish_common(target_state);
|
||||
|
||||
/* Enable the gic cpu interface */
|
||||
plat_arm_gic_cpuif_enable();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -53,16 +53,14 @@
|
|||
/* Check if VE mmap */
|
||||
cmp w16, #BLD_GIC_VE_MMAP
|
||||
b.eq use_ve_mmap
|
||||
/* Check if Cortex-A53/A57 mmap */
|
||||
cmp w16, #BLD_GIC_A53A57_MMAP
|
||||
b.ne exit_print_gic_regs
|
||||
/* Assume Base Cortex mmap */
|
||||
mov_imm x17, BASE_GICC_BASE
|
||||
mov_imm x16, BASE_GICD_BASE
|
||||
b print_gicc_regs
|
||||
b print_gic_regs
|
||||
use_ve_mmap:
|
||||
mov_imm x17, VE_GICC_BASE
|
||||
mov_imm x16, VE_GICD_BASE
|
||||
print_gicc_regs:
|
||||
print_gic_regs:
|
||||
arm_print_gic_regs
|
||||
.endm
|
||||
|
||||
|
|
|
@ -121,5 +121,24 @@
|
|||
TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO) | \
|
||||
TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO_OLD))
|
||||
|
||||
/*
|
||||
* GIC related constants to cater for both GICv2 and GICv3 instances of an
|
||||
* FVP. They could be overriden at runtime in case the FVP implements the legacy
|
||||
* VE memory map.
|
||||
*/
|
||||
#define PLAT_ARM_GICD_BASE BASE_GICD_BASE
|
||||
#define PLAT_ARM_GICR_BASE BASE_GICR_BASE
|
||||
#define PLAT_ARM_GICC_BASE BASE_GICC_BASE
|
||||
|
||||
/*
|
||||
* Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
|
||||
* terminology. On a GICv2 system or mode, the lists will be merged and treated
|
||||
* as Group 0 interrupts.
|
||||
*/
|
||||
#define PLAT_ARM_G1S_IRQS ARM_G1S_IRQS, \
|
||||
FVP_IRQ_TZ_WDOG, \
|
||||
FVP_IRQ_SEC_SYS_TIMER
|
||||
|
||||
#define PLAT_ARM_G0_IRQS ARM_G0_IRQS
|
||||
|
||||
#endif /* __PLATFORM_DEF_H__ */
|
||||
|
|
|
@ -28,6 +28,35 @@
|
|||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
# Use the Legacy GICv3 driver on the FVP by default to maintain compatibility.
|
||||
FVP_USE_GIC_DRIVER := FVP_GICV3_LEGACY
|
||||
|
||||
# The FVP platform depends on this macro to build with correct GIC driver.
|
||||
$(eval $(call add_define,FVP_USE_GIC_DRIVER))
|
||||
|
||||
# Choose the GIC sources depending upon the how the FVP will be invoked
|
||||
ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
|
||||
FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
|
||||
drivers/arm/gic/v3/gicv3_main.c \
|
||||
drivers/arm/gic/v3/gicv3_helpers.c \
|
||||
plat/common/plat_gicv3.c \
|
||||
plat/arm/common/arm_gicv3.c
|
||||
else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2)
|
||||
FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
|
||||
drivers/arm/gic/v2/gicv2_main.c \
|
||||
drivers/arm/gic/v2/gicv2_helpers.c \
|
||||
plat/common/plat_gicv2.c \
|
||||
plat/arm/common/arm_gicv2.c
|
||||
else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3_LEGACY)
|
||||
FVP_GIC_SOURCES := drivers/arm/gic/arm_gic.c \
|
||||
drivers/arm/gic/gic_v2.c \
|
||||
drivers/arm/gic/gic_v3.c \
|
||||
plat/common/plat_gic.c \
|
||||
plat/arm/common/arm_gicv3_legacy.c
|
||||
else
|
||||
$(error "Incorrect GIC driver chosen on FVP port")
|
||||
endif
|
||||
|
||||
PLAT_INCLUDES := -Iplat/arm/board/fvp/include
|
||||
|
||||
|
||||
|
@ -62,7 +91,8 @@ BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \
|
|||
plat/arm/board/fvp/fvp_security.c \
|
||||
plat/arm/board/fvp/fvp_topology.c \
|
||||
plat/arm/board/fvp/aarch64/fvp_helpers.S \
|
||||
plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c
|
||||
plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c \
|
||||
${FVP_GIC_SOURCES}
|
||||
|
||||
# Disable the PSCI platform compatibility layer
|
||||
ENABLE_PLAT_COMPAT := 0
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
# TSP source files specific to FVP platform
|
||||
BL32_SOURCES += plat/arm/board/fvp/fvp_topology.c \
|
||||
plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c \
|
||||
plat/arm/board/fvp/tsp/fvp_tsp_setup.c
|
||||
plat/arm/board/fvp/tsp/fvp_tsp_setup.c \
|
||||
${FVP_GIC_SOURCES}
|
||||
|
||||
include plat/arm/common/tsp/arm_tsp.mk
|
||||
|
|
|
@ -94,17 +94,18 @@
|
|||
*/
|
||||
|
||||
/* GIC related constants (no GICR in GIC-400) */
|
||||
#define PLAT_CSS_GICD_BASE 0x2c010000
|
||||
#define PLAT_CSS_GICR_BASE 0x0
|
||||
#define PLAT_CSS_GICC_BASE 0x2c02f000
|
||||
#define PLAT_CSS_GICH_BASE 0x2c04f000
|
||||
#define PLAT_CSS_GICV_BASE 0x2c06f000
|
||||
#define PLAT_ARM_GICD_BASE 0x2c010000
|
||||
#define PLAT_ARM_GICC_BASE 0x2c02f000
|
||||
#define PLAT_ARM_GICH_BASE 0x2c04f000
|
||||
#define PLAT_ARM_GICV_BASE 0x2c06f000
|
||||
|
||||
#define PLAT_CSS_IRQ_SEC_LIST CSS_IRQ_MHU, \
|
||||
CSS_IRQ_GPU_SMMU_0, \
|
||||
CSS_IRQ_TZC, \
|
||||
CSS_IRQ_TZ_WDOG, \
|
||||
CSS_IRQ_SEC_SYS_TIMER, \
|
||||
/*
|
||||
* Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
|
||||
* terminology. On a GICv2 system or mode, the lists will be merged and treated
|
||||
* as Group 0 interrupts.
|
||||
*/
|
||||
#define PLAT_ARM_G1S_IRQS CSS_G1S_IRQS, \
|
||||
ARM_G1S_IRQS, \
|
||||
JUNO_IRQ_DMA_SMMU, \
|
||||
JUNO_IRQ_HDLCD0_SMMU, \
|
||||
JUNO_IRQ_HDLCD1_SMMU, \
|
||||
|
@ -114,6 +115,8 @@
|
|||
JUNO_IRQ_GPU_SMMU_1, \
|
||||
JUNO_IRQ_ETR_SMMU
|
||||
|
||||
#define PLAT_ARM_G0_IRQS ARM_G0_IRQS
|
||||
|
||||
/*
|
||||
* Required ARM CSS SoC based platform porting definitions
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,12 @@
|
|||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
JUNO_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
|
||||
drivers/arm/gic/v2/gicv2_main.c \
|
||||
drivers/arm/gic/v2/gicv2_helpers.c \
|
||||
plat/common/plat_gicv2.c \
|
||||
plat/arm/common/arm_gicv2.c
|
||||
|
||||
PLAT_INCLUDES := -Iplat/arm/board/juno/include
|
||||
|
||||
PLAT_BL_COMMON_SOURCES := plat/arm/board/juno/aarch64/juno_helpers.S
|
||||
|
@ -44,7 +50,8 @@ BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \
|
|||
lib/cpus/aarch64/cortex_a57.S \
|
||||
lib/cpus/aarch64/cortex_a72.S \
|
||||
plat/arm/board/juno/juno_pm.c \
|
||||
plat/arm/board/juno/juno_security.c
|
||||
plat/arm/board/juno/juno_security.c \
|
||||
${JUNO_GIC_SOURCES}
|
||||
|
||||
# Enable workarounds for selected Cortex-A57 erratas.
|
||||
ERRATA_A57_806969 := 0
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
BL32_SOURCES += plat/arm/css/common/css_topology.c
|
||||
BL32_SOURCES += plat/arm/css/common/css_topology.c \
|
||||
${JUNO_GIC_SOURCES}
|
||||
|
||||
include plat/arm/common/tsp/arm_tsp.mk
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include <arch.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <arm_def.h>
|
||||
#include <arm_gic.h>
|
||||
#include <assert.h>
|
||||
#include <bl_common.h>
|
||||
#include <cci.h>
|
||||
|
@ -200,9 +199,9 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2,
|
|||
******************************************************************************/
|
||||
void arm_bl31_platform_setup(void)
|
||||
{
|
||||
/* Initialize the gic cpu and distributor interfaces */
|
||||
/* Initialize the GIC driver, cpu and distributor interfaces */
|
||||
plat_arm_gic_driver_init();
|
||||
plat_arm_gic_init();
|
||||
arm_gic_setup();
|
||||
|
||||
#if RESET_TO_BL31
|
||||
/*
|
||||
|
|
|
@ -108,15 +108,11 @@ BL2_SOURCES += drivers/arm/tzc400/tzc400.c \
|
|||
|
||||
BL31_SOURCES += drivers/arm/cci/cci.c \
|
||||
drivers/arm/ccn/ccn.c \
|
||||
drivers/arm/gic/arm_gic.c \
|
||||
drivers/arm/gic/gic_v2.c \
|
||||
drivers/arm/gic/gic_v3.c \
|
||||
drivers/arm/tzc400/tzc400.c \
|
||||
plat/arm/common/arm_bl31_setup.c \
|
||||
plat/arm/common/arm_pm.c \
|
||||
plat/arm/common/arm_security.c \
|
||||
plat/arm/common/arm_topology.c \
|
||||
plat/common/plat_gic.c \
|
||||
plat/common/aarch64/platform_mp_stack.S \
|
||||
plat/common/aarch64/plat_psci_common.c
|
||||
|
||||
|
@ -127,9 +123,9 @@ ifneq (${TRUSTED_BOARD_BOOT},0)
|
|||
|
||||
# Include common TBB sources
|
||||
AUTH_SOURCES := drivers/auth/auth_mod.c \
|
||||
drivers/auth/crypto_mod.c \
|
||||
drivers/auth/img_parser_mod.c \
|
||||
drivers/auth/tbbr/tbbr_cot.c \
|
||||
drivers/auth/crypto_mod.c \
|
||||
drivers/auth/img_parser_mod.c \
|
||||
drivers/auth/tbbr/tbbr_cot.c \
|
||||
|
||||
BL1_SOURCES += ${AUTH_SOURCES}
|
||||
BL2_SOURCES += ${AUTH_SOURCES}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of ARM nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <gicv2.h>
|
||||
#include <plat_arm.h>
|
||||
#include <platform.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
/******************************************************************************
|
||||
* The following functions are defined as weak to allow a platform to override
|
||||
* the way the GICv2 driver is initialised and used.
|
||||
*****************************************************************************/
|
||||
#pragma weak plat_arm_gic_driver_init
|
||||
#pragma weak plat_arm_gic_init
|
||||
#pragma weak plat_arm_gic_cpuif_enable
|
||||
#pragma weak plat_arm_gic_cpuif_disable
|
||||
#pragma weak plat_arm_gic_pcpu_init
|
||||
|
||||
/******************************************************************************
|
||||
* On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
|
||||
* interrupts.
|
||||
*****************************************************************************/
|
||||
const unsigned int g0_interrupt_array[] = {
|
||||
PLAT_ARM_G1S_IRQS,
|
||||
PLAT_ARM_G0_IRQS
|
||||
};
|
||||
|
||||
/*
|
||||
* Ideally `arm_gic_data` structure definition should be a `const` but it is
|
||||
* kept as modifiable for overwriting with different GICD and GICC base when
|
||||
* running on FVP with VE memory map.
|
||||
*/
|
||||
gicv2_driver_data_t arm_gic_data = {
|
||||
.gicd_base = PLAT_ARM_GICD_BASE,
|
||||
.gicc_base = PLAT_ARM_GICC_BASE,
|
||||
.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
|
||||
.g0_interrupt_array = g0_interrupt_array,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to initialize the GICv2 only driver.
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_driver_init(void)
|
||||
{
|
||||
gicv2_driver_init(&arm_gic_data);
|
||||
}
|
||||
|
||||
void plat_arm_gic_init(void)
|
||||
{
|
||||
gicv2_distif_init();
|
||||
gicv2_pcpu_distif_init();
|
||||
gicv2_cpuif_enable();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to enable the GICv2 CPU interface
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_cpuif_enable(void)
|
||||
{
|
||||
gicv2_cpuif_enable();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to disable the GICv2 CPU interface
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_cpuif_disable(void)
|
||||
{
|
||||
gicv2_cpuif_disable();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to initialize the per cpu distributor interface in GICv2
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_pcpu_init(void)
|
||||
{
|
||||
gicv2_pcpu_distif_init();
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of ARM nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <arm_def.h>
|
||||
#include <gicv3.h>
|
||||
#include <plat_arm.h>
|
||||
#include <platform.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
/******************************************************************************
|
||||
* The following functions are defined as weak to allow a platform to override
|
||||
* the way the GICv3 driver is initialised and used.
|
||||
*****************************************************************************/
|
||||
#pragma weak plat_arm_gic_driver_init
|
||||
#pragma weak plat_arm_gic_init
|
||||
#pragma weak plat_arm_gic_cpuif_enable
|
||||
#pragma weak plat_arm_gic_cpuif_disable
|
||||
#pragma weak plat_arm_gic_pcpu_init
|
||||
|
||||
/* The GICv3 driver only needs to be initialized in EL3 */
|
||||
uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
|
||||
|
||||
/* Array of Group1 secure interrupts to be configured by the gic driver */
|
||||
const unsigned int g1s_interrupt_array[] = {
|
||||
PLAT_ARM_G1S_IRQS
|
||||
};
|
||||
|
||||
/* Array of Group0 interrupts to be configured by the gic driver */
|
||||
const unsigned int g0_interrupt_array[] = {
|
||||
PLAT_ARM_G0_IRQS
|
||||
};
|
||||
|
||||
const gicv3_driver_data_t arm_gic_data = {
|
||||
.gicd_base = PLAT_ARM_GICD_BASE,
|
||||
.gicr_base = PLAT_ARM_GICR_BASE,
|
||||
.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
|
||||
.g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
|
||||
.g0_interrupt_array = g0_interrupt_array,
|
||||
.g1s_interrupt_array = g1s_interrupt_array,
|
||||
.rdistif_num = PLATFORM_CORE_COUNT,
|
||||
.rdistif_base_addrs = rdistif_base_addrs,
|
||||
.mpidr_to_core_pos = plat_arm_calc_core_pos
|
||||
};
|
||||
|
||||
void plat_arm_gic_driver_init(void)
|
||||
{
|
||||
/*
|
||||
* The GICv3 driver is initialized in EL3 and does not need
|
||||
* to be initialized again in SEL1. This is because the S-EL1
|
||||
* can use GIC system registers to manage interrupts and does
|
||||
* not need GIC interface base addresses to be configured.
|
||||
*/
|
||||
#if IMAGE_BL31
|
||||
gicv3_driver_init(&arm_gic_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to initialize the GIC. Only invoked by BL31
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_init(void)
|
||||
{
|
||||
gicv3_distif_init();
|
||||
gicv3_rdistif_init(plat_my_core_pos());
|
||||
gicv3_cpuif_enable(plat_my_core_pos());
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to enable the GIC CPU interface
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_cpuif_enable(void)
|
||||
{
|
||||
gicv3_cpuif_enable(plat_my_core_pos());
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to disable the GIC CPU interface
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_cpuif_disable(void)
|
||||
{
|
||||
gicv3_cpuif_disable(plat_my_core_pos());
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to initialize the per-cpu redistributor interface in GICv3
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_pcpu_init(void)
|
||||
{
|
||||
gicv3_rdistif_init(plat_my_core_pos());
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of ARM nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <arm_def.h>
|
||||
#include <arm_gic.h>
|
||||
#include <plat_arm.h>
|
||||
#include <platform.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
/******************************************************************************
|
||||
* The following function is defined as weak to allow a platform to override
|
||||
* the way the Legacy GICv3 driver is initialised and used.
|
||||
*****************************************************************************/
|
||||
#pragma weak plat_arm_gic_driver_init
|
||||
#pragma weak plat_arm_gic_init
|
||||
#pragma weak plat_arm_gic_cpuif_enable
|
||||
#pragma weak plat_arm_gic_cpuif_disable
|
||||
#pragma weak plat_arm_gic_pcpu_init
|
||||
|
||||
/*
|
||||
* In the GICv3 Legacy mode, the Group 1 secure interrupts are treated as Group
|
||||
* 0 interrupts.
|
||||
*/
|
||||
const unsigned int irq_sec_array[] = {
|
||||
PLAT_ARM_G0_IRQS,
|
||||
PLAT_ARM_G1S_IRQS
|
||||
};
|
||||
|
||||
void plat_arm_gic_driver_init(void)
|
||||
{
|
||||
arm_gic_init(PLAT_ARM_GICC_BASE,
|
||||
PLAT_ARM_GICD_BASE,
|
||||
PLAT_ARM_GICR_BASE,
|
||||
irq_sec_array,
|
||||
ARRAY_SIZE(irq_sec_array));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to initialize the GIC.
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_init(void)
|
||||
{
|
||||
arm_gic_setup();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to enable the GIC CPU interface
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_cpuif_enable(void)
|
||||
{
|
||||
arm_gic_cpuif_setup();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to disable the GIC CPU interface
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_cpuif_disable(void)
|
||||
{
|
||||
arm_gic_cpuif_deactivate();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ARM common helper to initialize the per-cpu distributor in GICv2 or
|
||||
* redistributor interface in GICv3.
|
||||
*****************************************************************************/
|
||||
void plat_arm_gic_pcpu_init(void)
|
||||
{
|
||||
arm_gic_pcpu_distif_setup();
|
||||
}
|
|
@ -164,9 +164,13 @@ void arm_system_pwr_domain_resume(void)
|
|||
/* Assert system power domain is available on the platform */
|
||||
assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
|
||||
|
||||
arm_gic_setup();
|
||||
/*
|
||||
* TODO: On GICv3 systems, figure out whether the core that wakes up
|
||||
* first from system suspend need to initialize the re-distributor
|
||||
* interface of all the other suspended cores.
|
||||
*/
|
||||
plat_arm_gic_init();
|
||||
plat_arm_security_setup();
|
||||
|
||||
arm_configure_sys_timer();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,6 @@
|
|||
#
|
||||
|
||||
# TSP source files common to ARM standard platforms
|
||||
BL32_SOURCES += drivers/arm/gic/arm_gic.c \
|
||||
drivers/arm/gic/gic_v2.c \
|
||||
plat/arm/common/arm_topology.c \
|
||||
BL32_SOURCES += plat/arm/common/arm_topology.c \
|
||||
plat/arm/common/tsp/arm_tsp_setup.c \
|
||||
plat/common/aarch64/platform_mp_stack.S \
|
||||
plat/common/plat_gic.c
|
||||
plat/common/aarch64/platform_mp_stack.S
|
||||
|
|
|
@ -89,7 +89,7 @@ void tsp_early_platform_setup(void)
|
|||
******************************************************************************/
|
||||
void tsp_platform_setup(void)
|
||||
{
|
||||
plat_arm_gic_init();
|
||||
plat_arm_gic_driver_init();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of ARM nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <arm_gic.h>
|
||||
#include <bl_common.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
|
||||
#if IMAGE_BL31 || IMAGE_BL32
|
||||
|
||||
const unsigned int irq_sec_array[] = {
|
||||
PLAT_CSS_IRQ_SEC_LIST,
|
||||
ARM_IRQ_SEC_PHY_TIMER,
|
||||
ARM_IRQ_SEC_SGI_0,
|
||||
ARM_IRQ_SEC_SGI_1,
|
||||
ARM_IRQ_SEC_SGI_2,
|
||||
ARM_IRQ_SEC_SGI_3,
|
||||
ARM_IRQ_SEC_SGI_4,
|
||||
ARM_IRQ_SEC_SGI_5,
|
||||
ARM_IRQ_SEC_SGI_6,
|
||||
ARM_IRQ_SEC_SGI_7
|
||||
};
|
||||
|
||||
|
||||
/* Weak definitions may be overridden in specific CSS based platform */
|
||||
#pragma weak plat_arm_gic_init
|
||||
|
||||
void plat_arm_gic_init(void)
|
||||
{
|
||||
arm_gic_init(PLAT_CSS_GICC_BASE,
|
||||
PLAT_CSS_GICD_BASE,
|
||||
PLAT_CSS_GICR_BASE,
|
||||
irq_sec_array,
|
||||
ARRAY_SIZE(irq_sec_array));
|
||||
}
|
||||
|
||||
#endif /* IMAGE_BL31 || IMAGE_BL32 */
|
|
@ -32,8 +32,7 @@ PLAT_INCLUDES += -Iinclude/plat/arm/css/common \
|
|||
-Iinclude/plat/arm/css/common/aarch64
|
||||
|
||||
|
||||
PLAT_BL_COMMON_SOURCES += plat/arm/css/common/aarch64/css_helpers.S \
|
||||
plat/arm/css/common/css_common.c
|
||||
PLAT_BL_COMMON_SOURCES += plat/arm/css/common/aarch64/css_helpers.S
|
||||
|
||||
#BL1_SOURCES +=
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <arm_gic.h>
|
||||
#include <cassert.h>
|
||||
#include <cci.h>
|
||||
#include <css_pm.h>
|
||||
|
@ -41,6 +40,12 @@
|
|||
#include <platform_def.h>
|
||||
#include "css_scpi.h"
|
||||
|
||||
/* Macros to read the CSS power domain state */
|
||||
#define CSS_CORE_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL0]
|
||||
#define CSS_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL1]
|
||||
#define CSS_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) ?\
|
||||
(state)->pwr_domain_state[ARM_PWR_LVL2] : 0)
|
||||
|
||||
/* Allow CSS platforms to override `plat_arm_psci_pm_ops` */
|
||||
#pragma weak plat_arm_psci_pm_ops
|
||||
|
||||
|
@ -93,51 +98,39 @@ int css_pwr_domain_on(u_register_t mpidr)
|
|||
return PSCI_E_SUCCESS;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Handler called when a power level 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.
|
||||
******************************************************************************/
|
||||
void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
|
||||
static void css_pwr_domain_on_finisher_common(
|
||||
const psci_power_state_t *target_state)
|
||||
{
|
||||
assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
|
||||
ARM_LOCAL_STATE_OFF);
|
||||
|
||||
if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
|
||||
/*
|
||||
* Perform system initialization if woken up from system
|
||||
* suspend.
|
||||
*/
|
||||
if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
|
||||
ARM_LOCAL_STATE_OFF)
|
||||
arm_system_pwr_domain_resume();
|
||||
}
|
||||
assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
|
||||
|
||||
/*
|
||||
* Perform the common cluster specific operations i.e enable coherency
|
||||
* if this cluster was off.
|
||||
*/
|
||||
if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
|
||||
ARM_LOCAL_STATE_OFF)
|
||||
if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
|
||||
cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Handler called when a power level 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. This handler would never be invoked with
|
||||
* the system power domain uninitialized as either the primary would have taken
|
||||
* care of it as part of cold boot or the first core awakened from system
|
||||
* suspend would have already initialized it.
|
||||
******************************************************************************/
|
||||
void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
|
||||
{
|
||||
/* Assert that the system power domain need not be initialized */
|
||||
assert(CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_RUN);
|
||||
|
||||
if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
|
||||
/*
|
||||
* Skip GIC CPU interface and per-CPU Distributor interface
|
||||
* setups if woken up from system suspend as it is done as
|
||||
* part of css_system_pwr_domain_resume().
|
||||
*/
|
||||
if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
|
||||
ARM_LOCAL_STATE_OFF)
|
||||
return;
|
||||
}
|
||||
css_pwr_domain_on_finisher_common(target_state);
|
||||
|
||||
/* Program the gic per-cpu distributor or re-distributor interface */
|
||||
plat_arm_gic_pcpu_init();
|
||||
|
||||
/* Enable the gic cpu interface */
|
||||
arm_gic_cpuif_setup();
|
||||
|
||||
/* todo: Is this setup only needed after a cold boot? */
|
||||
arm_gic_pcpu_distif_setup();
|
||||
plat_arm_gic_cpuif_enable();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -152,21 +145,14 @@ static void css_power_down_common(const psci_power_state_t *target_state)
|
|||
uint32_t system_state = scpi_power_on;
|
||||
|
||||
/* Prevent interrupts from spuriously waking up this cpu */
|
||||
arm_gic_cpuif_deactivate();
|
||||
plat_arm_gic_cpuif_disable();
|
||||
|
||||
if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
|
||||
/*
|
||||
* Check if power down at system power domain level is
|
||||
* requested.
|
||||
*/
|
||||
if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
|
||||
ARM_LOCAL_STATE_OFF)
|
||||
/* Check if power down at system power domain level is requested */
|
||||
if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
|
||||
system_state = scpi_power_retention;
|
||||
}
|
||||
|
||||
/* Cluster is to be turned off, so disable coherency */
|
||||
if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
|
||||
ARM_LOCAL_STATE_OFF) {
|
||||
if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
|
||||
cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
|
||||
cluster_state = scpi_power_off;
|
||||
}
|
||||
|
@ -187,9 +173,7 @@ static void css_power_down_common(const psci_power_state_t *target_state)
|
|||
******************************************************************************/
|
||||
void css_pwr_domain_off(const psci_power_state_t *target_state)
|
||||
{
|
||||
assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
|
||||
ARM_LOCAL_STATE_OFF);
|
||||
|
||||
assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
|
||||
css_power_down_common(target_state);
|
||||
}
|
||||
|
||||
|
@ -200,16 +184,13 @@ void css_pwr_domain_off(const psci_power_state_t *target_state)
|
|||
void css_pwr_domain_suspend(const psci_power_state_t *target_state)
|
||||
{
|
||||
/*
|
||||
* Juno has retention only at cpu level. Just return
|
||||
* CSS currently supports retention only at cpu level. Just return
|
||||
* as nothing is to be done for retention.
|
||||
*/
|
||||
if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
|
||||
ARM_LOCAL_STATE_RET)
|
||||
if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
|
||||
return;
|
||||
|
||||
assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
|
||||
ARM_LOCAL_STATE_OFF);
|
||||
|
||||
assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
|
||||
css_power_down_common(target_state);
|
||||
}
|
||||
|
||||
|
@ -223,14 +204,18 @@ void css_pwr_domain_suspend(const psci_power_state_t *target_state)
|
|||
void css_pwr_domain_suspend_finish(
|
||||
const psci_power_state_t *target_state)
|
||||
{
|
||||
/*
|
||||
* Return as nothing is to be done on waking up from retention.
|
||||
*/
|
||||
if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
|
||||
ARM_LOCAL_STATE_RET)
|
||||
/* Return as nothing is to be done on waking up from retention. */
|
||||
if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
|
||||
return;
|
||||
|
||||
css_pwr_domain_on_finish(target_state);
|
||||
/* Perform system domain restore if woken up from system suspend */
|
||||
if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
|
||||
arm_system_pwr_domain_resume();
|
||||
else
|
||||
/* Enable the gic cpu interface */
|
||||
plat_arm_gic_cpuif_enable();
|
||||
|
||||
css_pwr_domain_on_finisher_common(target_state);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of ARM nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <gic_common.h>
|
||||
#include <gicv2.h>
|
||||
#include <interrupt_mgmt.h>
|
||||
|
||||
/*
|
||||
* The following platform GIC functions are weakly defined. They
|
||||
* provide typical implementations that may be re-used by multiple
|
||||
* platforms but may also be overridden by a platform if required.
|
||||
*/
|
||||
#pragma weak plat_ic_get_pending_interrupt_id
|
||||
#pragma weak plat_ic_get_pending_interrupt_type
|
||||
#pragma weak plat_ic_acknowledge_interrupt
|
||||
#pragma weak plat_ic_get_interrupt_type
|
||||
#pragma weak plat_ic_end_of_interrupt
|
||||
#pragma weak plat_interrupt_type_to_line
|
||||
|
||||
/*
|
||||
* This function returns the highest priority pending interrupt at
|
||||
* the Interrupt controller
|
||||
*/
|
||||
uint32_t plat_ic_get_pending_interrupt_id(void)
|
||||
{
|
||||
unsigned int id;
|
||||
|
||||
id = gicv2_get_pending_interrupt_id();
|
||||
if (id == GIC_SPURIOUS_INTERRUPT)
|
||||
return INTR_ID_UNAVAILABLE;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the type of the highest priority pending interrupt
|
||||
* at the Interrupt controller. In the case of GICv2, the Highest Priority
|
||||
* Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
|
||||
* the pending interrupt. The type of interrupt depends upon the id value
|
||||
* as follows.
|
||||
* 1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
|
||||
* 2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
|
||||
* 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
|
||||
* type.
|
||||
*/
|
||||
uint32_t plat_ic_get_pending_interrupt_type(void)
|
||||
{
|
||||
unsigned int id;
|
||||
|
||||
id = gicv2_get_pending_interrupt_type();
|
||||
|
||||
/* Assume that all secure interrupts are S-EL1 interrupts */
|
||||
if (id < PENDING_G1_INTID)
|
||||
return INTR_TYPE_S_EL1;
|
||||
|
||||
if (id == GIC_SPURIOUS_INTERRUPT)
|
||||
return INTR_TYPE_INVAL;
|
||||
|
||||
return INTR_TYPE_NS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the highest priority pending interrupt at
|
||||
* the Interrupt controller and indicates to the Interrupt controller
|
||||
* that the interrupt processing has started.
|
||||
*/
|
||||
uint32_t plat_ic_acknowledge_interrupt(void)
|
||||
{
|
||||
return gicv2_acknowledge_interrupt();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the type of the interrupt `id`, depending on how
|
||||
* the interrupt has been configured in the interrupt controller
|
||||
*/
|
||||
uint32_t plat_ic_get_interrupt_type(uint32_t id)
|
||||
{
|
||||
unsigned int type;
|
||||
|
||||
type = gicv2_get_interrupt_group(id);
|
||||
|
||||
/* Assume that all secure interrupts are S-EL1 interrupts */
|
||||
return (type) ? INTR_TYPE_NS : INTR_TYPE_S_EL1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This functions is used to indicate to the interrupt controller that
|
||||
* the processing of the interrupt corresponding to the `id` has
|
||||
* finished.
|
||||
*/
|
||||
void plat_ic_end_of_interrupt(uint32_t id)
|
||||
{
|
||||
gicv2_end_of_interrupt(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
|
||||
* The interrupt controller knows which pin/line it uses to signal a type of
|
||||
* interrupt. It lets the interrupt management framework determine
|
||||
* for a type of interrupt and security state, which line should be used in the
|
||||
* SCR_EL3 to control its routing to EL3. The interrupt line is represented
|
||||
* as the bit position of the IRQ or FIQ bit in the SCR_EL3.
|
||||
*/
|
||||
uint32_t plat_interrupt_type_to_line(uint32_t type,
|
||||
uint32_t security_state)
|
||||
{
|
||||
assert(type == INTR_TYPE_S_EL1 ||
|
||||
type == INTR_TYPE_EL3 ||
|
||||
type == INTR_TYPE_NS);
|
||||
|
||||
/* Non-secure interrupts are signaled on the IRQ line always */
|
||||
if (type == INTR_TYPE_NS)
|
||||
return __builtin_ctz(SCR_IRQ_BIT);
|
||||
|
||||
/*
|
||||
* Secure interrupts are signaled using the IRQ line if the FIQ is
|
||||
* not enabled else they are signaled using the FIQ line.
|
||||
*/
|
||||
return ((gicv2_is_fiq_enabled()) ? __builtin_ctz(SCR_FIQ_BIT) :
|
||||
__builtin_ctz(SCR_IRQ_BIT));
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of ARM nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <bl_common.h>
|
||||
#include <cassert.h>
|
||||
#include <gic_common.h>
|
||||
#include <gicv3.h>
|
||||
#include <interrupt_mgmt.h>
|
||||
#include <platform.h>
|
||||
|
||||
#if IMAGE_BL31
|
||||
|
||||
/*
|
||||
* The following platform GIC functions are weakly defined. They
|
||||
* provide typical implementations that may be re-used by multiple
|
||||
* platforms but may also be overridden by a platform if required.
|
||||
*/
|
||||
#pragma weak plat_ic_get_pending_interrupt_id
|
||||
#pragma weak plat_ic_get_pending_interrupt_type
|
||||
#pragma weak plat_ic_acknowledge_interrupt
|
||||
#pragma weak plat_ic_get_interrupt_type
|
||||
#pragma weak plat_ic_end_of_interrupt
|
||||
#pragma weak plat_interrupt_type_to_line
|
||||
|
||||
CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
|
||||
(INTR_TYPE_NS == INTR_GROUP1NS) &&
|
||||
(INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch);
|
||||
|
||||
/*
|
||||
* This function returns the highest priority pending interrupt at
|
||||
* the Interrupt controller
|
||||
*/
|
||||
uint32_t plat_ic_get_pending_interrupt_id(void)
|
||||
{
|
||||
unsigned int irqnr;
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
irqnr = gicv3_get_pending_interrupt_id();
|
||||
return (gicv3_is_intr_id_special_identifier(irqnr)) ?
|
||||
INTR_ID_UNAVAILABLE : irqnr;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the type of the highest priority pending interrupt
|
||||
* at the Interrupt controller. In the case of GICv3, the Highest Priority
|
||||
* Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine
|
||||
* the id of the pending interrupt. The type of interrupt depends upon the
|
||||
* id value as follows.
|
||||
* 1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt
|
||||
* 2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt.
|
||||
* 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
|
||||
* type.
|
||||
* 4. All other interrupt id's are reported as EL3 interrupt.
|
||||
*/
|
||||
uint32_t plat_ic_get_pending_interrupt_type(void)
|
||||
{
|
||||
unsigned int irqnr;
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
irqnr = gicv3_get_pending_interrupt_type();
|
||||
|
||||
switch (irqnr) {
|
||||
case PENDING_G1S_INTID:
|
||||
return INTR_TYPE_S_EL1;
|
||||
case PENDING_G1NS_INTID:
|
||||
return INTR_TYPE_NS;
|
||||
case GIC_SPURIOUS_INTERRUPT:
|
||||
return INTR_TYPE_INVAL;
|
||||
default:
|
||||
return INTR_TYPE_EL3;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the highest priority pending interrupt at
|
||||
* the Interrupt controller and indicates to the Interrupt controller
|
||||
* that the interrupt processing has started.
|
||||
*/
|
||||
uint32_t plat_ic_acknowledge_interrupt(void)
|
||||
{
|
||||
assert(IS_IN_EL3());
|
||||
return gicv3_acknowledge_interrupt();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the type of the interrupt `id`, depending on how
|
||||
* the interrupt has been configured in the interrupt controller
|
||||
*/
|
||||
uint32_t plat_ic_get_interrupt_type(uint32_t id)
|
||||
{
|
||||
assert(IS_IN_EL3());
|
||||
return gicv3_get_interrupt_type(id, plat_my_core_pos());
|
||||
}
|
||||
|
||||
/*
|
||||
* This functions is used to indicate to the interrupt controller that
|
||||
* the processing of the interrupt corresponding to the `id` has
|
||||
* finished.
|
||||
*/
|
||||
void plat_ic_end_of_interrupt(uint32_t id)
|
||||
{
|
||||
assert(IS_IN_EL3());
|
||||
gicv3_end_of_interrupt(id);
|
||||
}
|
||||
|
||||
/*
|
||||
* An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
|
||||
* The interrupt controller knows which pin/line it uses to signal a type of
|
||||
* interrupt. It lets the interrupt management framework determine for a type of
|
||||
* interrupt and security state, which line should be used in the SCR_EL3 to
|
||||
* control its routing to EL3. The interrupt line is represented as the bit
|
||||
* position of the IRQ or FIQ bit in the SCR_EL3.
|
||||
*/
|
||||
uint32_t plat_interrupt_type_to_line(uint32_t type,
|
||||
uint32_t security_state)
|
||||
{
|
||||
assert(type == INTR_TYPE_S_EL1 ||
|
||||
type == INTR_TYPE_EL3 ||
|
||||
type == INTR_TYPE_NS);
|
||||
|
||||
assert(sec_state_is_valid(security_state));
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
switch (type) {
|
||||
case INTR_TYPE_S_EL1:
|
||||
/*
|
||||
* The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts
|
||||
* and as FIQ in the NS-EL0/1/2 contexts
|
||||
*/
|
||||
if (security_state == SECURE)
|
||||
return __builtin_ctz(SCR_IRQ_BIT);
|
||||
else
|
||||
return __builtin_ctz(SCR_FIQ_BIT);
|
||||
case INTR_TYPE_NS:
|
||||
/*
|
||||
* The Non secure interrupts will be signaled as FIQ in S-EL0/1
|
||||
* contexts and as IRQ in the NS-EL0/1/2 contexts.
|
||||
*/
|
||||
if (security_state == SECURE)
|
||||
return __builtin_ctz(SCR_FIQ_BIT);
|
||||
else
|
||||
return __builtin_ctz(SCR_IRQ_BIT);
|
||||
default:
|
||||
assert(0);
|
||||
/* Fall through in the release build */
|
||||
case INTR_TYPE_EL3:
|
||||
/*
|
||||
* The EL3 interrupts are signaled as FIQ in both S-EL0/1 and
|
||||
* NS-EL0/1/2 contexts
|
||||
*/
|
||||
return __builtin_ctz(SCR_FIQ_BIT);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if IMAGE_BL32
|
||||
|
||||
#pragma weak plat_ic_get_pending_interrupt_id
|
||||
#pragma weak plat_ic_acknowledge_interrupt
|
||||
#pragma weak plat_ic_end_of_interrupt
|
||||
|
||||
/*
|
||||
* This function returns the highest priority pending interrupt at
|
||||
* the Interrupt controller
|
||||
*/
|
||||
uint32_t plat_ic_get_pending_interrupt_id(void)
|
||||
{
|
||||
unsigned int irqnr;
|
||||
|
||||
assert(IS_IN_EL1());
|
||||
irqnr = gicv3_get_pending_interrupt_id_sel1();
|
||||
return (irqnr == GIC_SPURIOUS_INTERRUPT) ?
|
||||
INTR_ID_UNAVAILABLE : irqnr;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the highest priority pending interrupt at
|
||||
* the Interrupt controller and indicates to the Interrupt controller
|
||||
* that the interrupt processing has started.
|
||||
*/
|
||||
uint32_t plat_ic_acknowledge_interrupt(void)
|
||||
{
|
||||
assert(IS_IN_EL1());
|
||||
return gicv3_acknowledge_interrupt_sel1();
|
||||
}
|
||||
|
||||
/*
|
||||
* This functions is used to indicate to the interrupt controller that
|
||||
* the processing of the interrupt corresponding to the `id` has
|
||||
* finished.
|
||||
*/
|
||||
void plat_ic_end_of_interrupt(uint32_t id)
|
||||
{
|
||||
assert(IS_IN_EL1());
|
||||
gicv3_end_of_interrupt_sel1(id);
|
||||
}
|
||||
#endif
|
|
@ -55,7 +55,17 @@ NEED_BL32 := yes
|
|||
|
||||
# Flag used to enable routing of non-secure interrupts to EL3 when they are
|
||||
# generated while the code is executing in S-EL1/0.
|
||||
TSPD_ROUTE_IRQ_TO_EL3 := 0
|
||||
TSP_NS_INTR_ASYNC_PREEMPT := 0
|
||||
|
||||
$(eval $(call assert_boolean,TSPD_ROUTE_IRQ_TO_EL3))
|
||||
$(eval $(call add_define,TSPD_ROUTE_IRQ_TO_EL3))
|
||||
# If TSPD_ROUTE_IRQ_TO_EL3 build flag is defined, use it to define value for
|
||||
# TSP_NS_INTR_ASYNC_PREEMPT for backward compatibility.
|
||||
ifdef TSPD_ROUTE_IRQ_TO_EL3
|
||||
ifeq (${ERROR_DEPRECATED},1)
|
||||
$(error "TSPD_ROUTE_IRQ_TO_EL3 is deprecated. Please use the new build flag TSP_NS_INTR_ASYNC_PREEMPT")
|
||||
endif
|
||||
$(warning "TSPD_ROUTE_IRQ_TO_EL3 is deprecated. Please use the new build flag TSP_NS_INTR_ASYNC_PREEMPT")
|
||||
TSP_NS_INTR_ASYNC_PREEMPT := ${TSPD_ROUTE_IRQ_TO_EL3}
|
||||
endif
|
||||
|
||||
$(eval $(call assert_boolean,TSP_NS_INTR_ASYNC_PREEMPT))
|
||||
$(eval $(call add_define,TSP_NS_INTR_ASYNC_PREEMPT))
|
||||
|
|
|
@ -72,9 +72,16 @@ DEFINE_SVC_UUID(tsp_uuid,
|
|||
|
||||
int32_t tspd_init(void);
|
||||
|
||||
/*
|
||||
* This helper function handles Secure EL1 preemption. The preemption could be
|
||||
* due Non Secure interrupts or EL3 interrupts. In both the cases we context
|
||||
* switch to the normal world and in case of EL3 interrupts, it will again be
|
||||
* routed to EL3 which will get handled at the exception vectors.
|
||||
*/
|
||||
uint64_t tspd_handle_sp_preemption(void *handle)
|
||||
{
|
||||
cpu_context_t *ns_cpu_context;
|
||||
|
||||
assert(handle == cm_get_context(SECURE));
|
||||
cm_el1_sysregs_context_save(SECURE);
|
||||
/* Get a reference to the non-secure context */
|
||||
|
@ -82,18 +89,30 @@ uint64_t tspd_handle_sp_preemption(void *handle)
|
|||
assert(ns_cpu_context);
|
||||
|
||||
/*
|
||||
* Restore non-secure state. The secure system
|
||||
* register context will be saved when required.
|
||||
* To allow Secure EL1 interrupt handler to re-enter TSP while TSP
|
||||
* is preempted, the secure system register context which will get
|
||||
* overwritten must be additionally saved. This is currently done
|
||||
* by the TSPD S-EL1 interrupt handler.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Restore non-secure state.
|
||||
*/
|
||||
cm_el1_sysregs_context_restore(NON_SECURE);
|
||||
cm_set_next_eret_context(NON_SECURE);
|
||||
|
||||
/*
|
||||
* The TSP was preempted during STD SMC execution.
|
||||
* Return back to the normal world with SMC_PREEMPTED as error
|
||||
* code in x0.
|
||||
*/
|
||||
SMC_RET1(ns_cpu_context, SMC_PREEMPTED);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function is the handler registered for S-EL1 interrupts by the TSPD. It
|
||||
* validates the interrupt and upon success arranges entry into the TSP at
|
||||
* 'tsp_fiq_entry()' for handling the interrupt.
|
||||
* 'tsp_sel1_intr_entry()' for handling the interrupt.
|
||||
******************************************************************************/
|
||||
static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
|
||||
uint32_t flags,
|
||||
|
@ -121,44 +140,44 @@ static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
|
|||
* Determine if the TSP was previously preempted. Its last known
|
||||
* context has to be preserved in this case.
|
||||
* The TSP should return control to the TSPD after handling this
|
||||
* FIQ. Preserve essential EL3 context to allow entry into the
|
||||
* TSP at the FIQ entry point using the 'cpu_context' structure.
|
||||
* There is no need to save the secure system register context
|
||||
* since the TSP is supposed to preserve it during S-EL1 interrupt
|
||||
* handling.
|
||||
* S-EL1 interrupt. Preserve essential EL3 context to allow entry into
|
||||
* the TSP at the S-EL1 interrupt entry point using the 'cpu_context'
|
||||
* structure. There is no need to save the secure system register
|
||||
* context since the TSP is supposed to preserve it during S-EL1
|
||||
* interrupt handling.
|
||||
*/
|
||||
if (get_std_smc_active_flag(tsp_ctx->state)) {
|
||||
tsp_ctx->saved_spsr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
|
||||
CTX_SPSR_EL3);
|
||||
tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
|
||||
CTX_ELR_EL3);
|
||||
#if TSPD_ROUTE_IRQ_TO_EL3
|
||||
#if TSP_NS_INTR_ASYNC_PREEMPT
|
||||
/*Need to save the previously interrupted secure context */
|
||||
memcpy(&tsp_ctx->sp_ctx, &tsp_ctx->cpu_ctx, TSPD_SP_CTX_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
cm_el1_sysregs_context_restore(SECURE);
|
||||
cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->fiq_entry,
|
||||
cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->sel1_intr_entry,
|
||||
SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
|
||||
|
||||
cm_set_next_eret_context(SECURE);
|
||||
|
||||
/*
|
||||
* Tell the TSP that it has to handle an FIQ synchronously. Also the
|
||||
* instruction in normal world where the interrupt was generated is
|
||||
* passed for debugging purposes. It is safe to retrieve this address
|
||||
* from ELR_EL3 as the secure context will not take effect until
|
||||
* el3_exit().
|
||||
* Tell the TSP that it has to handle a S-EL1 interrupt synchronously.
|
||||
* Also the instruction in normal world where the interrupt was
|
||||
* generated is passed for debugging purposes. It is safe to retrieve
|
||||
* this address from ELR_EL3 as the secure context will not take effect
|
||||
* until el3_exit().
|
||||
*/
|
||||
SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_FIQ_AND_RETURN, read_elr_el3());
|
||||
SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_SEL1_INTR_AND_RETURN, read_elr_el3());
|
||||
}
|
||||
|
||||
#if TSPD_ROUTE_IRQ_TO_EL3
|
||||
#if TSP_NS_INTR_ASYNC_PREEMPT
|
||||
/*******************************************************************************
|
||||
* This function is the handler registered for S-EL1 interrupts by the TSPD. It
|
||||
* validates the interrupt and upon success arranges entry into the TSP at
|
||||
* 'tsp_fiq_entry()' for handling the interrupt.
|
||||
* This function is the handler registered for Non secure interrupts by the
|
||||
* TSPD. It validates the interrupt and upon success arranges entry into the
|
||||
* normal world for handling the interrupt.
|
||||
******************************************************************************/
|
||||
static uint64_t tspd_ns_interrupt_handler(uint32_t id,
|
||||
uint32_t flags,
|
||||
|
@ -312,10 +331,11 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
|
|||
|
||||
/*
|
||||
* This function ID is used only by the TSP to indicate that it has
|
||||
* finished handling a S-EL1 FIQ interrupt. Execution should resume
|
||||
* finished handling a S-EL1 interrupt or was preempted by a higher
|
||||
* priority pending EL3 interrupt. Execution should resume
|
||||
* in the normal world.
|
||||
*/
|
||||
case TSP_HANDLED_S_EL1_FIQ:
|
||||
case TSP_HANDLED_S_EL1_INTR:
|
||||
if (ns)
|
||||
SMC_RET1(handle, SMC_UNK);
|
||||
|
||||
|
@ -332,7 +352,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
|
|||
SMC_SET_EL3(&tsp_ctx->cpu_ctx,
|
||||
CTX_ELR_EL3,
|
||||
tsp_ctx->saved_elr_el3);
|
||||
#if TSPD_ROUTE_IRQ_TO_EL3
|
||||
#if TSP_NS_INTR_ASYNC_PREEMPT
|
||||
/*
|
||||
* Need to restore the previously interrupted
|
||||
* secure context.
|
||||
|
@ -356,35 +376,6 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
|
|||
|
||||
SMC_RET0((uint64_t) ns_cpu_context);
|
||||
|
||||
|
||||
/*
|
||||
* This function ID is used only by the TSP to indicate that it was
|
||||
* interrupted due to a EL3 FIQ interrupt. Execution should resume
|
||||
* in the normal world.
|
||||
*/
|
||||
case TSP_EL3_FIQ:
|
||||
if (ns)
|
||||
SMC_RET1(handle, SMC_UNK);
|
||||
|
||||
assert(handle == cm_get_context(SECURE));
|
||||
|
||||
/* Assert that standard SMC execution has been preempted */
|
||||
assert(get_std_smc_active_flag(tsp_ctx->state));
|
||||
|
||||
/* Save the secure system register state */
|
||||
cm_el1_sysregs_context_save(SECURE);
|
||||
|
||||
/* Get a reference to the non-secure context */
|
||||
ns_cpu_context = cm_get_context(NON_SECURE);
|
||||
assert(ns_cpu_context);
|
||||
|
||||
/* Restore non-secure state */
|
||||
cm_el1_sysregs_context_restore(NON_SECURE);
|
||||
cm_set_next_eret_context(NON_SECURE);
|
||||
|
||||
SMC_RET1(ns_cpu_context, TSP_EL3_FIQ);
|
||||
|
||||
|
||||
/*
|
||||
* This function ID is used only by the SP to indicate it has
|
||||
* finished initialising itself after a cold boot
|
||||
|
@ -422,7 +413,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
|
|||
if (rc)
|
||||
panic();
|
||||
|
||||
#if TSPD_ROUTE_IRQ_TO_EL3
|
||||
#if TSP_NS_INTR_ASYNC_PREEMPT
|
||||
/*
|
||||
* Register an interrupt handler for NS interrupts when
|
||||
* generated during code executing in secure state are
|
||||
|
@ -438,8 +429,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
|
|||
panic();
|
||||
|
||||
/*
|
||||
* Disable the interrupt NS locally since it will be enabled globally
|
||||
* within cm_init_my_context.
|
||||
* Disable the NS interrupt locally.
|
||||
*/
|
||||
disable_intr_rm_local(INTR_TYPE_NS, SECURE);
|
||||
#endif
|
||||
|
@ -561,7 +551,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
|
|||
set_std_smc_active_flag(tsp_ctx->state);
|
||||
cm_set_elr_el3(SECURE, (uint64_t)
|
||||
&tsp_vectors->std_smc_entry);
|
||||
#if TSPD_ROUTE_IRQ_TO_EL3
|
||||
#if TSP_NS_INTR_ASYNC_PREEMPT
|
||||
/*
|
||||
* Enable the routing of NS interrupts to EL3
|
||||
* during STD SMC processing on this core.
|
||||
|
@ -592,7 +582,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
|
|||
cm_set_next_eret_context(NON_SECURE);
|
||||
if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_STD) {
|
||||
clr_std_smc_active_flag(tsp_ctx->state);
|
||||
#if TSPD_ROUTE_IRQ_TO_EL3
|
||||
#if TSP_NS_INTR_ASYNC_PREEMPT
|
||||
/*
|
||||
* Disable the routing of NS interrupts to EL3
|
||||
* after STD SMC processing is finished on this
|
||||
|
@ -635,7 +625,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
|
|||
* We are done stashing the non-secure context. Ask the
|
||||
* secure payload to do the work now.
|
||||
*/
|
||||
#if TSPD_ROUTE_IRQ_TO_EL3
|
||||
#if TSP_NS_INTR_ASYNC_PREEMPT
|
||||
/*
|
||||
* Enable the routing of NS interrupts to EL3 during resumption
|
||||
* of STD SMC call on this core.
|
||||
|
|
|
@ -130,7 +130,7 @@ static void tspd_cpu_on_finish_handler(uint64_t unused)
|
|||
/* Initialise this cpu's secure context */
|
||||
cm_init_my_context(&tsp_on_entrypoint);
|
||||
|
||||
#if TSPD_ROUTE_IRQ_TO_EL3
|
||||
#if TSP_NS_INTR_ASYNC_PREEMPT
|
||||
/*
|
||||
* Disable the NS interrupt locally since it will be enabled globally
|
||||
* within cm_init_my_context.
|
||||
|
|
|
@ -183,10 +183,10 @@ CASSERT(TSPD_SP_CTX_SIZE == sizeof(sp_ctx_regs_t), \
|
|||
|
||||
/*******************************************************************************
|
||||
* Structure which helps the SPD to maintain the per-cpu state of the SP.
|
||||
* 'saved_spsr_el3' - temporary copy to allow FIQ handling when the TSP has been
|
||||
* preempted.
|
||||
* 'saved_elr_el3' - temporary copy to allow FIQ handling when the TSP has been
|
||||
* preempted.
|
||||
* 'saved_spsr_el3' - temporary copy to allow S-EL1 interrupt handling when
|
||||
* the TSP has been preempted.
|
||||
* 'saved_elr_el3' - temporary copy to allow S-EL1 interrupt handling when
|
||||
* the TSP has been preempted.
|
||||
* 'state' - collection of flags to track SP state e.g. on/off
|
||||
* 'mpidr' - mpidr to associate a context with a cpu
|
||||
* 'c_rt_ctx' - stack address to restore C runtime context from after
|
||||
|
@ -207,7 +207,7 @@ typedef struct tsp_context {
|
|||
uint64_t c_rt_ctx;
|
||||
cpu_context_t cpu_ctx;
|
||||
uint64_t saved_tsp_args[TSP_NUM_ARGS];
|
||||
#if TSPD_ROUTE_IRQ_TO_EL3
|
||||
#if TSP_NS_INTR_ASYNC_PREEMPT
|
||||
sp_ctx_regs_t sp_ctx;
|
||||
#endif
|
||||
} tsp_context_t;
|
||||
|
|
Loading…
Reference in New Issue