mirror of
https://github.com/CTCaer/switch-l4t-atf.git
synced 2025-01-31 15:22:32 +00:00
GIC: Add APIs to set interrupt type and query support
The back end GIC driver converts and assigns the interrupt type to suitable group. For GICv2, a build option GICV2_G0_FOR_EL3 is introduced, which determines to which type Group 0 interrupts maps to. - When the build option is set 0 (the default), Group 0 interrupts are meant for Secure EL1. This is presently the case. - Otherwise, Group 0 interrupts are meant for EL3. This means the SPD will have to synchronously hand over the interrupt to Secure EL1. The query API allows the platform to query whether the platform supports interrupts of a given type. API documentation updated. Change-Id: I60fdb4053ffe0bd006b3b20914914ebd311fc858 Co-authored-by: Yousuf A <yousuf.sait@arm.com> Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
This commit is contained in:
parent
f3a866004e
commit
74dce7fa6e
2
Makefile
2
Makefile
@ -449,6 +449,7 @@ $(eval $(call assert_boolean,ENABLE_RUNTIME_INSTRUMENTATION))
|
||||
$(eval $(call assert_boolean,ENABLE_SPE_FOR_LOWER_ELS))
|
||||
$(eval $(call assert_boolean,ERROR_DEPRECATED))
|
||||
$(eval $(call assert_boolean,GENERATE_COT))
|
||||
$(eval $(call assert_boolean,GICV2_G0_FOR_EL3))
|
||||
$(eval $(call assert_boolean,HW_ASSISTED_COHERENCY))
|
||||
$(eval $(call assert_boolean,LOAD_IMAGE_V2))
|
||||
$(eval $(call assert_boolean,NS_TIMER_SWITCH))
|
||||
@ -486,6 +487,7 @@ $(eval $(call add_define,ENABLE_PSCI_STAT))
|
||||
$(eval $(call add_define,ENABLE_RUNTIME_INSTRUMENTATION))
|
||||
$(eval $(call add_define,ENABLE_SPE_FOR_LOWER_ELS))
|
||||
$(eval $(call add_define,ERROR_DEPRECATED))
|
||||
$(eval $(call add_define,GICV2_G0_FOR_EL3))
|
||||
$(eval $(call add_define,HW_ASSISTED_COHERENCY))
|
||||
$(eval $(call add_define,LOAD_IMAGE_V2))
|
||||
$(eval $(call add_define,LOG_LEVEL))
|
||||
|
@ -126,6 +126,80 @@ This API should set the priority of the interrupt specified by first parameter
|
||||
In case of ARM standard platforms using GIC, the implementation of the API
|
||||
writes to GIC *Priority Register* set interrupt priority.
|
||||
|
||||
Function: int plat_ic_has_interrupt_type(unsigned int type); [optional]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : unsigned int
|
||||
Return : int
|
||||
|
||||
This API should return whether the platform supports a given interrupt type. The
|
||||
parameter ``type`` shall be one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``, or
|
||||
``INTR_TYPE_NS``.
|
||||
|
||||
In case of ARM standard platforms using GICv3, the implementation of the API
|
||||
returns ``1`` for all interrupt types.
|
||||
|
||||
In case of ARM standard platforms using GICv2, the API always return ``1`` for
|
||||
``INTR_TYPE_NS``. Return value for other types depends on the value of build
|
||||
option ``GICV2_G0_FOR_EL3``:
|
||||
|
||||
- For interrupt type ``INTR_TYPE_EL3``:
|
||||
|
||||
- When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``0``, indicating no support
|
||||
for EL3 interrupts.
|
||||
|
||||
- When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``1``, indicating support for
|
||||
EL3 interrupts.
|
||||
|
||||
- For interrupt type ``INTR_TYPE_S_EL1``:
|
||||
|
||||
- When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``1``, indicating support for
|
||||
Secure EL1 interrupts.
|
||||
|
||||
- When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``0``, indicating no support
|
||||
for Secure EL1 interrupts.
|
||||
|
||||
Function: void plat_ic_set_interrupt_type(unsigned int id, unsigned int type); [optional]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
Argument : unsigned int
|
||||
Argument : unsigned int
|
||||
Return : void
|
||||
|
||||
This API should set the interrupt specified by first parameter ``id`` to the
|
||||
type specified by second parameter ``type``. The ``type`` parameter can be
|
||||
one of:
|
||||
|
||||
- ``INTR_TYPE_NS``: interrupt is meant to be consumed by the Non-secure world.
|
||||
|
||||
- ``INTR_TYPE_S_EL1``: interrupt is meant to be consumed by Secure EL1.
|
||||
|
||||
- ``INTR_TYPE_EL3``: interrupt is meant to be consumed by EL3.
|
||||
|
||||
In case of ARM standard platforms using GIC, the implementation of the API
|
||||
writes to the GIC *Group Register* and *Group Modifier Register* (only GICv3) to
|
||||
assign the interrupt to the right group.
|
||||
|
||||
For GICv3:
|
||||
|
||||
- ``INTR_TYPE_NS`` maps to Group 1 interrupt.
|
||||
|
||||
- ``INTR_TYPE_S_EL1`` maps to Secure Group 1 interrupt.
|
||||
|
||||
- ``INTR_TYPE_EL3`` maps to Secure Group 0 interrupt.
|
||||
|
||||
For GICv2:
|
||||
|
||||
- ``INTR_TYPE_NS`` maps to Group 1 interrupt.
|
||||
|
||||
- When the build option ``GICV2_G0_FOR_EL3`` is set to ``0`` (the default),
|
||||
``INTR_TYPE_S_EL1`` maps to Group 0. Otherwise, ``INTR_TYPE_EL3`` maps to
|
||||
Group 0 interrupt.
|
||||
|
||||
----
|
||||
|
||||
*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
|
||||
|
@ -386,6 +386,19 @@ Common build options
|
||||
images will include support for Trusted Board Boot, but the FIP and FWU\_FIP
|
||||
will not include the corresponding certificates, causing a boot failure.
|
||||
|
||||
- ``GICV2_G0_FOR_EL3``: Unlike GICv3, the GICv2 architecture doesn't have
|
||||
inherent support for specific EL3 type interrupts. Setting this build option
|
||||
to ``1`` assumes GICv2 *Group 0* interrupts are expected to target EL3, both
|
||||
by `platform abstraction layer`__ and `Interrupt Management Framework`__.
|
||||
This allows GICv2 platforms to enable features requiring EL3 interrupt type.
|
||||
This also means that all GICv2 Group 0 interrupts are delivered to EL3, and
|
||||
the Secure Payload interrupts needs to be synchronously handed over to Secure
|
||||
EL1 for handling. The default value of this option is ``0``, which means the
|
||||
Group 0 interrupts are assumed to be handled by Secure EL1.
|
||||
|
||||
.. __: `platform-interrupt-controller-API.rst`
|
||||
.. __: `interrupt-framework-design.rst`
|
||||
|
||||
- ``HANDLE_EA_EL3_FIRST``: When defined External Aborts and SError Interrupts
|
||||
will be always trapped in EL3 i.e. in BL31 at runtime.
|
||||
|
||||
|
@ -10,11 +10,19 @@
|
||||
#include <debug.h>
|
||||
#include <gic_common.h>
|
||||
#include <gicv2.h>
|
||||
#include <spinlock.h>
|
||||
#include "../common/gic_common_private.h"
|
||||
#include "gicv2_private.h"
|
||||
|
||||
static const gicv2_driver_data_t *driver_data;
|
||||
|
||||
/*
|
||||
* Spinlock to guard registers needing read-modify-write. APIs protected by this
|
||||
* spinlock are used either at boot time (when only a single CPU is active), or
|
||||
* when the system is fully coherent.
|
||||
*/
|
||||
spinlock_t gic_lock;
|
||||
|
||||
/*******************************************************************************
|
||||
* Enable secure interrupts and use FIQs to route them. Disable legacy bypass
|
||||
* and set the priority mask register to allow all interrupts to trickle in.
|
||||
@ -335,3 +343,28 @@ void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority)
|
||||
|
||||
gicd_set_ipriorityr(driver_data->gicd_base, id, priority);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function assigns group for the interrupt identified by id. The group can
|
||||
* be any of GICV2_INTR_GROUP*
|
||||
******************************************************************************/
|
||||
void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
|
||||
{
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicd_base);
|
||||
assert(id <= MAX_SPI_ID);
|
||||
|
||||
/* Serialize read-modify-write to Distributor registers */
|
||||
spin_lock(&gic_lock);
|
||||
switch (type) {
|
||||
case GICV2_INTR_GROUP1:
|
||||
gicd_set_igroupr(driver_data->gicd_base, id);
|
||||
break;
|
||||
case GICV2_INTR_GROUP0:
|
||||
gicd_clr_igroupr(driver_data->gicd_base, id);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
spin_unlock(&gic_lock);
|
||||
}
|
||||
|
@ -9,11 +9,19 @@
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <gicv3.h>
|
||||
#include <spinlock.h>
|
||||
#include "gicv3_private.h"
|
||||
|
||||
const gicv3_driver_data_t *gicv3_driver_data;
|
||||
static unsigned int gicv2_compat;
|
||||
|
||||
/*
|
||||
* Spinlock to guard registers needing read-modify-write. APIs protected by this
|
||||
* spinlock are used either at boot time (when only a single CPU is active), or
|
||||
* when the system is fully coherent.
|
||||
*/
|
||||
spinlock_t gic_lock;
|
||||
|
||||
/*
|
||||
* Redistributor power operations are weakly bound so that they can be
|
||||
* overridden
|
||||
@ -892,3 +900,63 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
|
||||
gicd_set_ipriorityr(gicv3_driver_data->gicd_base, id, priority);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function assigns group for the interrupt identified by id. The proc_num
|
||||
* is used if the interrupt is SGI or PPI, and programs the corresponding
|
||||
* Redistributor interface. The group can be any of GICV3_INTR_GROUP*
|
||||
******************************************************************************/
|
||||
void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
|
||||
unsigned int type)
|
||||
{
|
||||
unsigned int igroup = 0, grpmod = 0;
|
||||
uintptr_t gicr_base;
|
||||
|
||||
assert(gicv3_driver_data);
|
||||
assert(gicv3_driver_data->gicd_base);
|
||||
assert(proc_num < gicv3_driver_data->rdistif_num);
|
||||
assert(gicv3_driver_data->rdistif_base_addrs);
|
||||
|
||||
switch (type) {
|
||||
case INTR_GROUP1S:
|
||||
igroup = 0;
|
||||
grpmod = 1;
|
||||
break;
|
||||
case INTR_GROUP0:
|
||||
igroup = 0;
|
||||
grpmod = 0;
|
||||
break;
|
||||
case INTR_GROUP1NS:
|
||||
igroup = 1;
|
||||
grpmod = 0;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (id < MIN_SPI_ID) {
|
||||
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
|
||||
if (igroup)
|
||||
gicr_set_igroupr0(gicr_base, id);
|
||||
else
|
||||
gicr_clr_igroupr0(gicr_base, id);
|
||||
|
||||
if (grpmod)
|
||||
gicr_set_igrpmodr0(gicr_base, id);
|
||||
else
|
||||
gicr_clr_igrpmodr0(gicr_base, id);
|
||||
} else {
|
||||
/* Serialize read-modify-write to Distributor registers */
|
||||
spin_lock(&gic_lock);
|
||||
if (igroup)
|
||||
gicd_set_igroupr(gicv3_driver_data->gicd_base, id);
|
||||
else
|
||||
gicd_clr_igroupr(gicv3_driver_data->gicd_base, id);
|
||||
|
||||
if (grpmod)
|
||||
gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id);
|
||||
else
|
||||
gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id);
|
||||
spin_unlock(&gic_lock);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,11 @@
|
||||
/*******************************************************************************
|
||||
* GICv2 miscellaneous definitions
|
||||
******************************************************************************/
|
||||
|
||||
/* Interrupt group definitions */
|
||||
#define GICV2_INTR_GROUP0 0
|
||||
#define GICV2_INTR_GROUP1 1
|
||||
|
||||
/* Interrupt IDs reported by the HPPIR and IAR registers */
|
||||
#define PENDING_G1_INTID 1022
|
||||
|
||||
@ -151,6 +156,7 @@ unsigned int gicv2_get_interrupt_active(unsigned int id);
|
||||
void gicv2_enable_interrupt(unsigned int id);
|
||||
void gicv2_disable_interrupt(unsigned int id);
|
||||
void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority);
|
||||
void gicv2_set_interrupt_type(unsigned int id, unsigned int type);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __GICV2_H__ */
|
||||
|
@ -355,6 +355,8 @@ void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num);
|
||||
void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num);
|
||||
void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
|
||||
unsigned int priority);
|
||||
void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
|
||||
unsigned int group);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __GICV3_H__ */
|
||||
|
@ -79,6 +79,8 @@ int plat_ic_is_sgi(unsigned int id);
|
||||
unsigned int plat_ic_get_interrupt_active(unsigned int id);
|
||||
void plat_ic_disable_interrupt(unsigned int id);
|
||||
void plat_ic_enable_interrupt(unsigned int id);
|
||||
int plat_ic_has_interrupt_type(unsigned int type);
|
||||
void plat_ic_set_interrupt_type(unsigned int id, unsigned int type);
|
||||
void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority);
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -77,6 +77,10 @@ FWU_FIP_NAME := fwu_fip.bin
|
||||
# For Chain of Trust
|
||||
GENERATE_COT := 0
|
||||
|
||||
# Hint platform interrupt control layer that Group 0 interrupts are for EL3. By
|
||||
# default, they are for Secure EL1.
|
||||
GICV2_G0_FOR_EL3 := 0
|
||||
|
||||
# Whether system coherency is managed in hardware, without explicit software
|
||||
# operations.
|
||||
HW_ASSISTED_COHERENCY := 0
|
||||
|
@ -28,6 +28,7 @@
|
||||
#pragma weak plat_ic_enable_interrupt
|
||||
#pragma weak plat_ic_disable_interrupt
|
||||
#pragma weak plat_ic_set_interrupt_priority
|
||||
#pragma weak plat_ic_set_interrupt_type
|
||||
|
||||
/*
|
||||
* This function returns the highest priority pending interrupt at
|
||||
@ -62,8 +63,13 @@ uint32_t plat_ic_get_pending_interrupt_type(void)
|
||||
id = gicv2_get_pending_interrupt_type();
|
||||
|
||||
/* Assume that all secure interrupts are S-EL1 interrupts */
|
||||
if (id < PENDING_G1_INTID)
|
||||
if (id < PENDING_G1_INTID) {
|
||||
#if GICV2_G0_FOR_EL3
|
||||
return INTR_TYPE_EL3;
|
||||
#else
|
||||
return INTR_TYPE_S_EL1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (id == GIC_SPURIOUS_INTERRUPT)
|
||||
return INTR_TYPE_INVAL;
|
||||
@ -92,7 +98,12 @@ uint32_t plat_ic_get_interrupt_type(uint32_t id)
|
||||
type = gicv2_get_interrupt_group(id);
|
||||
|
||||
/* Assume that all secure interrupts are S-EL1 interrupts */
|
||||
return (type) ? INTR_TYPE_NS : INTR_TYPE_S_EL1;
|
||||
return type == GICV2_INTR_GROUP1 ? INTR_TYPE_NS :
|
||||
#if GICV2_G0_FOR_EL3
|
||||
INTR_TYPE_EL3;
|
||||
#else
|
||||
INTR_TYPE_S_EL1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -171,3 +182,41 @@ void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
|
||||
{
|
||||
gicv2_set_interrupt_priority(id, priority);
|
||||
}
|
||||
|
||||
int plat_ic_has_interrupt_type(unsigned int type)
|
||||
{
|
||||
switch (type) {
|
||||
#if GICV2_G0_FOR_EL3
|
||||
case INTR_TYPE_EL3:
|
||||
#else
|
||||
case INTR_TYPE_S_EL1:
|
||||
#endif
|
||||
case INTR_TYPE_NS:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
|
||||
{
|
||||
int gicv2_type = 0;
|
||||
|
||||
/* Map canonical interrupt type to GICv2 type */
|
||||
switch (type) {
|
||||
#if GICV2_G0_FOR_EL3
|
||||
case INTR_TYPE_EL3:
|
||||
#else
|
||||
case INTR_TYPE_S_EL1:
|
||||
#endif
|
||||
gicv2_type = GICV2_INTR_GROUP0;
|
||||
break;
|
||||
case INTR_TYPE_NS:
|
||||
gicv2_type = GICV2_INTR_GROUP1;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
gicv2_set_interrupt_type(id, gicv2_type);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#pragma weak plat_ic_enable_interrupt
|
||||
#pragma weak plat_ic_disable_interrupt
|
||||
#pragma weak plat_ic_set_interrupt_priority
|
||||
#pragma weak plat_ic_set_interrupt_type
|
||||
|
||||
CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
|
||||
(INTR_TYPE_NS == INTR_GROUP1NS) &&
|
||||
@ -204,6 +205,18 @@ void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
|
||||
{
|
||||
gicv3_set_interrupt_priority(id, plat_my_core_pos(), priority);
|
||||
}
|
||||
|
||||
int plat_ic_has_interrupt_type(unsigned int type)
|
||||
{
|
||||
assert((type == INTR_TYPE_EL3) || (type == INTR_TYPE_S_EL1) ||
|
||||
(type == INTR_TYPE_NS));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
|
||||
{
|
||||
gicv3_set_interrupt_type(id, plat_my_core_pos(), type);
|
||||
}
|
||||
#endif
|
||||
#ifdef IMAGE_BL32
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user