mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 01:24:27 +00:00
Merge pull request #439 from soby-mathew/sm/new-gic-driver
Introduce new GICv3 and GICv2 drivers
This commit is contained in:
commit
b39908af74
15 changed files with 2626 additions and 13 deletions
308
drivers/arm/gic/common/gic_common.c
Normal file
308
drivers/arm/gic/common/gic_common.c
Normal file
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* 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 <mmio.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface accessors for reading entire registers
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Accessor to read the GIC Distributor IGROUPR corresponding to the interrupt
|
||||
* `id`, 32 interrupt ids at a time.
|
||||
*/
|
||||
unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> IGROUPR_SHIFT;
|
||||
return mmio_read_32(base + GICD_IGROUPR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor ISENABLER corresponding to the
|
||||
* interrupt `id`, 32 interrupt ids at a time.
|
||||
*/
|
||||
unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> ISENABLER_SHIFT;
|
||||
return mmio_read_32(base + GICD_ISENABLER + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor ICENABLER corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> ICENABLER_SHIFT;
|
||||
return mmio_read_32(base + GICD_ICENABLER + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor ISPENDR corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> ISPENDR_SHIFT;
|
||||
return mmio_read_32(base + GICD_ISPENDR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor ICPENDR corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> ICPENDR_SHIFT;
|
||||
return mmio_read_32(base + GICD_ICPENDR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor ISACTIVER corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> ISACTIVER_SHIFT;
|
||||
return mmio_read_32(base + GICD_ISACTIVER + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor ICACTIVER corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> ICACTIVER_SHIFT;
|
||||
return mmio_read_32(base + GICD_ICACTIVER + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor IPRIORITYR corresponding to the
|
||||
* interrupt `id`, 4 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> IPRIORITYR_SHIFT;
|
||||
return mmio_read_32(base + GICD_IPRIORITYR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor ICGFR corresponding to the
|
||||
* interrupt `id`, 16 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> ICFGR_SHIFT;
|
||||
return mmio_read_32(base + GICD_ICFGR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor NSACR corresponding to the
|
||||
* interrupt `id`, 16 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> NSACR_SHIFT;
|
||||
return mmio_read_32(base + GICD_NSACR + (n << 2));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface accessors for writing entire registers
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Accessor to write the GIC Distributor IGROUPR corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> IGROUPR_SHIFT;
|
||||
mmio_write_32(base + GICD_IGROUPR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor ISENABLER corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> ISENABLER_SHIFT;
|
||||
mmio_write_32(base + GICD_ISENABLER + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor ICENABLER corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> ICENABLER_SHIFT;
|
||||
mmio_write_32(base + GICD_ICENABLER + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor ISPENDR corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> ISPENDR_SHIFT;
|
||||
mmio_write_32(base + GICD_ISPENDR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor ICPENDR corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> ICPENDR_SHIFT;
|
||||
mmio_write_32(base + GICD_ICPENDR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor ISACTIVER corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> ISACTIVER_SHIFT;
|
||||
mmio_write_32(base + GICD_ISACTIVER + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor ICACTIVER corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> ICACTIVER_SHIFT;
|
||||
mmio_write_32(base + GICD_ICACTIVER + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor IPRIORITYR corresponding to the
|
||||
* interrupt `id`, 4 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> IPRIORITYR_SHIFT;
|
||||
mmio_write_32(base + GICD_IPRIORITYR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor ICFGR corresponding to the
|
||||
* interrupt `id`, 16 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> ICFGR_SHIFT;
|
||||
mmio_write_32(base + GICD_ICFGR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor NSACR corresponding to the
|
||||
* interrupt `id`, 16 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> NSACR_SHIFT;
|
||||
mmio_write_32(base + GICD_NSACR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface accessors for individual interrupt manipulation
|
||||
******************************************************************************/
|
||||
unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicd_read_igroupr(base, id);
|
||||
|
||||
return (reg_val >> bit_num) & 0x1;
|
||||
}
|
||||
|
||||
void gicd_set_igroupr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicd_read_igroupr(base, id);
|
||||
|
||||
gicd_write_igroupr(base, id, reg_val | (1 << bit_num));
|
||||
}
|
||||
|
||||
void gicd_clr_igroupr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicd_read_igroupr(base, id);
|
||||
|
||||
gicd_write_igroupr(base, id, reg_val & ~(1 << bit_num));
|
||||
}
|
||||
|
||||
void gicd_set_isenabler(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1);
|
||||
|
||||
gicd_write_isenabler(base, id, (1 << bit_num));
|
||||
}
|
||||
|
||||
void gicd_set_icenabler(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << ICENABLER_SHIFT) - 1);
|
||||
|
||||
gicd_write_icenabler(base, id, (1 << bit_num));
|
||||
}
|
||||
|
||||
void gicd_set_ispendr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << ISPENDR_SHIFT) - 1);
|
||||
|
||||
gicd_write_ispendr(base, id, (1 << bit_num));
|
||||
}
|
||||
|
||||
void gicd_set_icpendr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << ICPENDR_SHIFT) - 1);
|
||||
|
||||
gicd_write_icpendr(base, id, (1 << bit_num));
|
||||
}
|
||||
|
||||
void gicd_set_isactiver(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1);
|
||||
|
||||
gicd_write_isactiver(base, id, (1 << bit_num));
|
||||
}
|
||||
|
||||
void gicd_set_icactiver(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << ICACTIVER_SHIFT) - 1);
|
||||
|
||||
gicd_write_icactiver(base, id, (1 << bit_num));
|
||||
}
|
230
drivers/arm/gic/v2/gicv2_helpers.c
Normal file
230
drivers/arm/gic/v2/gicv2_helpers.c
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* 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.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <gic_common.h>
|
||||
#include "gicv2_private.h"
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor ITARGETSR corresponding to the
|
||||
* interrupt `id`, 4 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> ITARGETSR_SHIFT;
|
||||
return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor CPENDSGIR corresponding to the
|
||||
* interrupt `id`, 4 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> CPENDSGIR_SHIFT;
|
||||
return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor SPENDSGIR corresponding to the
|
||||
* interrupt `id`, 4 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> SPENDSGIR_SHIFT;
|
||||
return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor ITARGETSR corresponding to the
|
||||
* interrupt `id`, 4 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> ITARGETSR_SHIFT;
|
||||
mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor CPENDSGIR corresponding to the
|
||||
* interrupt `id`, 4 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> CPENDSGIR_SHIFT;
|
||||
mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor SPENDSGIR corresponding to the
|
||||
* interrupt `id`, 4 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> SPENDSGIR_SHIFT;
|
||||
mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor ITARGETSR corresponding to the
|
||||
* interrupt `id`.
|
||||
*/
|
||||
void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
|
||||
{
|
||||
unsigned byte_off = id & ((1 << ITARGETSR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicd_read_itargetsr(base, id);
|
||||
|
||||
gicd_write_itargetsr(base, id, reg_val | (target << (byte_off << 3)));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Get the current CPU bit mask from GICD_ITARGETSR0
|
||||
******************************************************************************/
|
||||
unsigned int gicv2_get_cpuif_id(uintptr_t base)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
val = gicd_read_itargetsr(base, 0);
|
||||
return val & GIC_TARGET_CPU_MASK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper function to configure the default attributes of SPIs.
|
||||
******************************************************************************/
|
||||
void gicv2_spis_configure_defaults(uintptr_t gicd_base)
|
||||
{
|
||||
unsigned int index, num_ints;
|
||||
|
||||
num_ints = gicd_read_typer(gicd_base);
|
||||
num_ints &= TYPER_IT_LINES_NO_MASK;
|
||||
num_ints = (num_ints + 1) << 5;
|
||||
|
||||
/*
|
||||
* Treat all SPIs as G1NS by default. The number of interrupts is
|
||||
* calculated as 32 * (IT_LINES + 1). We do 32 at a time.
|
||||
*/
|
||||
for (index = MIN_SPI_ID; index < num_ints; index += 32)
|
||||
gicd_write_igroupr(gicd_base, index, ~0U);
|
||||
|
||||
/* Setup the default SPI priorities doing four at a time */
|
||||
for (index = MIN_SPI_ID; index < num_ints; index += 4)
|
||||
gicd_write_ipriorityr(gicd_base,
|
||||
index,
|
||||
GICD_IPRIORITYR_DEF_VAL);
|
||||
|
||||
/* Treat all SPIs as level triggered by default, 16 at a time */
|
||||
for (index = MIN_SPI_ID; index < num_ints; index += 16)
|
||||
gicd_write_icfgr(gicd_base, index, 0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper function to configure secure G0 SPIs.
|
||||
******************************************************************************/
|
||||
void gicv2_secure_spis_configure(uintptr_t gicd_base,
|
||||
unsigned int num_ints,
|
||||
const unsigned int *sec_intr_list)
|
||||
{
|
||||
unsigned int index, irq_num;
|
||||
|
||||
/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
|
||||
assert(num_ints ? (uintptr_t)sec_intr_list : 1);
|
||||
|
||||
for (index = 0; index < num_ints; index++) {
|
||||
irq_num = sec_intr_list[index];
|
||||
if (irq_num >= MIN_SPI_ID) {
|
||||
/* Configure this interrupt as a secure interrupt */
|
||||
gicd_clr_igroupr(gicd_base, irq_num);
|
||||
|
||||
/* Set the priority of this interrupt */
|
||||
gicd_write_ipriorityr(gicd_base,
|
||||
irq_num,
|
||||
GIC_HIGHEST_SEC_PRIORITY);
|
||||
|
||||
/* Target the secure interrupts to primary CPU */
|
||||
gicd_set_itargetsr(gicd_base, irq_num,
|
||||
gicv2_get_cpuif_id(gicd_base));
|
||||
|
||||
/* Enable this interrupt */
|
||||
gicd_set_isenabler(gicd_base, irq_num);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper function to configure secure G0 SGIs and PPIs.
|
||||
******************************************************************************/
|
||||
void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
|
||||
unsigned int num_ints,
|
||||
const unsigned int *sec_intr_list)
|
||||
{
|
||||
unsigned int index, irq_num, sec_ppi_sgi_mask = 0;
|
||||
|
||||
/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
|
||||
assert(num_ints ? (uintptr_t)sec_intr_list : 1);
|
||||
|
||||
/*
|
||||
* Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
|
||||
* more scalable approach as it avoids clearing the enable bits in the
|
||||
* GICD_CTLR.
|
||||
*/
|
||||
gicd_write_icenabler(gicd_base, 0, ~0);
|
||||
|
||||
/* Setup the default PPI/SGI priorities doing four at a time */
|
||||
for (index = 0; index < MIN_SPI_ID; index += 4)
|
||||
gicd_write_ipriorityr(gicd_base,
|
||||
index,
|
||||
GICD_IPRIORITYR_DEF_VAL);
|
||||
|
||||
for (index = 0; index < num_ints; index++) {
|
||||
irq_num = sec_intr_list[index];
|
||||
if (irq_num < MIN_SPI_ID) {
|
||||
/* We have an SGI or a PPI. They are Group0 at reset */
|
||||
sec_ppi_sgi_mask |= 1U << irq_num;
|
||||
|
||||
/* Set the priority of this interrupt */
|
||||
gicd_write_ipriorityr(gicd_base,
|
||||
irq_num,
|
||||
GIC_HIGHEST_SEC_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Invert the bitmask to create a mask for non-secure PPIs and
|
||||
* SGIs. Program the GICD_IGROUPR0 with this bit mask.
|
||||
*/
|
||||
gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
|
||||
|
||||
/* Enable the Group 0 SGIs and PPIs */
|
||||
gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
|
||||
}
|
254
drivers/arm/gic/v2/gicv2_main.c
Normal file
254
drivers/arm/gic/v2/gicv2_main.c
Normal file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* 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.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <gic_common.h>
|
||||
#include <gicv2.h>
|
||||
#include "gicv2_private.h"
|
||||
|
||||
static const gicv2_driver_data_t *driver_data;
|
||||
|
||||
/*******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
void gicv2_cpuif_enable(void)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicc_base);
|
||||
|
||||
/*
|
||||
* Enable the Group 0 interrupts, FIQEn and disable Group 0/1
|
||||
* bypass.
|
||||
*/
|
||||
val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0;
|
||||
val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
|
||||
|
||||
/* Program the idle priority in the PMR */
|
||||
gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK);
|
||||
gicc_write_ctlr(driver_data->gicc_base, val);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Place the cpu interface in a state where it can never make a cpu exit wfi as
|
||||
* as result of an asserted interrupt. This is critical for powering down a cpu
|
||||
******************************************************************************/
|
||||
void gicv2_cpuif_disable(void)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicc_base);
|
||||
|
||||
/* Disable secure, non-secure interrupts and disable their bypass */
|
||||
val = gicc_read_ctlr(driver_data->gicc_base);
|
||||
val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT);
|
||||
val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
|
||||
val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
|
||||
gicc_write_ctlr(driver_data->gicc_base, val);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Per cpu gic distributor setup which will be done by all cpus after a cold
|
||||
* boot/hotplug. This marks out the secure SPIs and PPIs & enables them.
|
||||
******************************************************************************/
|
||||
void gicv2_pcpu_distif_init(void)
|
||||
{
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicd_base);
|
||||
assert(driver_data->g0_interrupt_array);
|
||||
|
||||
gicv2_secure_ppi_sgi_setup(driver_data->gicd_base,
|
||||
driver_data->g0_interrupt_num,
|
||||
driver_data->g0_interrupt_array);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Global gic distributor init which will be done by the primary cpu after a
|
||||
* cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It
|
||||
* then enables the secure GIC distributor interface.
|
||||
******************************************************************************/
|
||||
void gicv2_distif_init(void)
|
||||
{
|
||||
unsigned int ctlr;
|
||||
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicd_base);
|
||||
assert(driver_data->g0_interrupt_array);
|
||||
|
||||
/* Disable the distributor before going further */
|
||||
ctlr = gicd_read_ctlr(driver_data->gicd_base);
|
||||
gicd_write_ctlr(driver_data->gicd_base,
|
||||
ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT));
|
||||
|
||||
/* Set the default attribute of all SPIs */
|
||||
gicv2_spis_configure_defaults(driver_data->gicd_base);
|
||||
|
||||
/* Configure the G0 SPIs */
|
||||
gicv2_secure_spis_configure(driver_data->gicd_base,
|
||||
driver_data->g0_interrupt_num,
|
||||
driver_data->g0_interrupt_array);
|
||||
|
||||
/* Re-enable the secure SPIs now that they have been configured */
|
||||
gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Initialize the ARM GICv2 driver with the provided platform inputs
|
||||
******************************************************************************/
|
||||
void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data)
|
||||
{
|
||||
unsigned int gic_version;
|
||||
assert(plat_driver_data);
|
||||
assert(plat_driver_data->gicd_base);
|
||||
assert(plat_driver_data->gicc_base);
|
||||
|
||||
/*
|
||||
* The platform should provide a list of atleast one type of
|
||||
* interrupts
|
||||
*/
|
||||
assert(plat_driver_data->g0_interrupt_array);
|
||||
|
||||
/*
|
||||
* If there are no interrupts of a particular type, then the number of
|
||||
* interrupts of that type should be 0 and vice-versa.
|
||||
*/
|
||||
assert(plat_driver_data->g0_interrupt_array ?
|
||||
plat_driver_data->g0_interrupt_num :
|
||||
plat_driver_data->g0_interrupt_num == 0);
|
||||
|
||||
/* Ensure that this is a GICv2 system */
|
||||
gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
|
||||
gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT)
|
||||
& PIDR2_ARCH_REV_MASK;
|
||||
assert(gic_version == ARCH_REV_GICV2);
|
||||
|
||||
driver_data = plat_driver_data;
|
||||
|
||||
INFO("ARM GICv2 driver initialized\n");
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This function returns whether FIQ is enabled in the GIC CPU interface.
|
||||
*****************************************************************************/
|
||||
unsigned int gicv2_is_fiq_enabled(void)
|
||||
{
|
||||
unsigned int gicc_ctlr;
|
||||
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicc_base);
|
||||
|
||||
gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base);
|
||||
return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function returns the type of the highest priority pending interrupt at
|
||||
* the GIC cpu interface. The return values can be one of the following :
|
||||
* PENDING_G1_INTID : The interrupt type is non secure Group 1.
|
||||
* 0 - 1019 : The interrupt type is secure Group 0.
|
||||
* GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with
|
||||
* sufficient priority to be signaled
|
||||
******************************************************************************/
|
||||
unsigned int gicv2_get_pending_interrupt_type(void)
|
||||
{
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicc_base);
|
||||
|
||||
return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function returns the id of the highest priority pending interrupt at
|
||||
* the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no
|
||||
* interrupt pending.
|
||||
******************************************************************************/
|
||||
unsigned int gicv2_get_pending_interrupt_id(void)
|
||||
{
|
||||
unsigned int id;
|
||||
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicc_base);
|
||||
|
||||
id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
|
||||
|
||||
/*
|
||||
* Find out which non-secure interrupt it is under the assumption that
|
||||
* the GICC_CTLR.AckCtl bit is 0.
|
||||
*/
|
||||
if (id == PENDING_G1_INTID)
|
||||
id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This functions reads the GIC cpu interface Interrupt Acknowledge register
|
||||
* to start handling the pending secure 0 interrupt. It returns the
|
||||
* contents of the IAR.
|
||||
******************************************************************************/
|
||||
unsigned int gicv2_acknowledge_interrupt(void)
|
||||
{
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicc_base);
|
||||
|
||||
return gicc_read_IAR(driver_data->gicc_base);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This functions writes the GIC cpu interface End Of Interrupt register with
|
||||
* the passed value to finish handling the active secure group 0 interrupt.
|
||||
******************************************************************************/
|
||||
void gicv2_end_of_interrupt(unsigned int id)
|
||||
{
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicc_base);
|
||||
|
||||
gicc_write_EOIR(driver_data->gicc_base, id);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function returns the type of the interrupt id depending upon the group
|
||||
* this interrupt has been configured under by the interrupt controller i.e.
|
||||
* group0 secure or group1 non secure. It returns zero for Group 0 secure and
|
||||
* one for Group 1 non secure interrupt.
|
||||
******************************************************************************/
|
||||
unsigned int gicv2_get_interrupt_group(unsigned int id)
|
||||
{
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicd_base);
|
||||
|
||||
return gicd_get_igroupr(driver_data->gicd_base, id);
|
||||
}
|
147
drivers/arm/gic/v2/gicv2_private.h
Normal file
147
drivers/arm/gic/v2/gicv2_private.h
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GICV2_PRIVATE_H__
|
||||
#define __GICV2_PRIVATE_H__
|
||||
|
||||
#include <gicv2.h>
|
||||
#include <mmio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* Private function prototypes
|
||||
******************************************************************************/
|
||||
void gicv2_spis_configure_defaults(uintptr_t gicd_base);
|
||||
void gicv2_secure_spis_configure(uintptr_t gicd_base,
|
||||
unsigned int num_ints,
|
||||
const unsigned int *sec_intr_list);
|
||||
void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
|
||||
unsigned int num_ints,
|
||||
const unsigned int *sec_intr_list);
|
||||
unsigned int gicv2_get_cpuif_id(uintptr_t base);
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface accessors for reading entire registers
|
||||
******************************************************************************/
|
||||
static inline unsigned int gicd_read_pidr2(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICD_PIDR2_GICV2);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC CPU interface accessors for reading entire registers
|
||||
******************************************************************************/
|
||||
|
||||
static inline unsigned int gicc_read_ctlr(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICC_CTLR);
|
||||
}
|
||||
|
||||
static inline unsigned int gicc_read_pmr(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICC_PMR);
|
||||
}
|
||||
|
||||
static inline unsigned int gicc_read_BPR(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICC_BPR);
|
||||
}
|
||||
|
||||
static inline unsigned int gicc_read_IAR(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICC_IAR);
|
||||
}
|
||||
|
||||
static inline unsigned int gicc_read_EOIR(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICC_EOIR);
|
||||
}
|
||||
|
||||
static inline unsigned int gicc_read_hppir(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICC_HPPIR);
|
||||
}
|
||||
|
||||
static inline unsigned int gicc_read_ahppir(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICC_AHPPIR);
|
||||
}
|
||||
|
||||
static inline unsigned int gicc_read_dir(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICC_DIR);
|
||||
}
|
||||
|
||||
static inline unsigned int gicc_read_iidr(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICC_IIDR);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC CPU interface accessors for writing entire registers
|
||||
******************************************************************************/
|
||||
|
||||
static inline void gicc_write_ctlr(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICC_CTLR, val);
|
||||
}
|
||||
|
||||
static inline void gicc_write_pmr(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICC_PMR, val);
|
||||
}
|
||||
|
||||
static inline void gicc_write_BPR(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICC_BPR, val);
|
||||
}
|
||||
|
||||
|
||||
static inline void gicc_write_IAR(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICC_IAR, val);
|
||||
}
|
||||
|
||||
static inline void gicc_write_EOIR(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICC_EOIR, val);
|
||||
}
|
||||
|
||||
static inline void gicc_write_hppir(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICC_HPPIR, val);
|
||||
}
|
||||
|
||||
static inline void gicc_write_dir(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICC_DIR, val);
|
||||
}
|
||||
|
||||
#endif /* __GICV2_PRIVATE_H__ */
|
415
drivers/arm/gic/v3/gicv3_helpers.c
Normal file
415
drivers/arm/gic/v3/gicv3_helpers.c
Normal file
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
* 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.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <gic_common.h>
|
||||
#include "gicv3_private.h"
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Distributor IGRPMODR corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> IGRPMODR_SHIFT;
|
||||
return mmio_read_32(base + GICD_IGRPMODR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Distributor IGRPMODR corresponding to the
|
||||
* interrupt `id`, 32 interrupt IDs at a time.
|
||||
*/
|
||||
void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> IGRPMODR_SHIFT;
|
||||
mmio_write_32(base + GICD_IGRPMODR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to get the bit corresponding to interrupt ID
|
||||
* in GIC Distributor IGRPMODR.
|
||||
*/
|
||||
unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicd_read_igrpmodr(base, id);
|
||||
|
||||
return (reg_val >> bit_num) & 0x1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to set the bit corresponding to interrupt ID
|
||||
* in GIC Distributor IGRPMODR.
|
||||
*/
|
||||
void gicd_set_igrpmodr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicd_read_igrpmodr(base, id);
|
||||
|
||||
gicd_write_igrpmodr(base, id, reg_val | (1 << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to clear the bit corresponding to interrupt ID
|
||||
* in GIC Distributor IGRPMODR.
|
||||
*/
|
||||
void gicd_clr_igrpmodr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicd_read_igrpmodr(base, id);
|
||||
|
||||
gicd_write_igrpmodr(base, id, reg_val & ~(1 << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to read the GIC Re-distributor IPRIORITYR corresponding to the
|
||||
* interrupt `id`, 4 interrupts IDs at a time.
|
||||
*/
|
||||
unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned n = id >> IPRIORITYR_SHIFT;
|
||||
return mmio_read_32(base + GICR_IPRIORITYR + (n << 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to write the GIC Re-distributor IPRIORITYR corresponding to the
|
||||
* interrupt `id`, 4 interrupts IDs at a time.
|
||||
*/
|
||||
void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
|
||||
{
|
||||
unsigned n = id >> IPRIORITYR_SHIFT;
|
||||
mmio_write_32(base + GICR_IPRIORITYR + (n << 2), val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to get the bit corresponding to interrupt ID
|
||||
* from GIC Re-distributor IGROUPR0.
|
||||
*/
|
||||
unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicr_read_igroupr0(base);
|
||||
|
||||
return (reg_val >> bit_num) & 0x1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to set the bit corresponding to interrupt ID
|
||||
* in GIC Re-distributor IGROUPR0.
|
||||
*/
|
||||
void gicr_set_igroupr0(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicr_read_igroupr0(base);
|
||||
|
||||
gicr_write_igroupr0(base, reg_val | (1 << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to clear the bit corresponding to interrupt ID
|
||||
* in GIC Re-distributor IGROUPR0.
|
||||
*/
|
||||
void gicr_clr_igroupr0(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicr_read_igroupr0(base);
|
||||
|
||||
gicr_write_igroupr0(base, reg_val & ~(1 << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to get the bit corresponding to interrupt ID
|
||||
* from GIC Re-distributor IGRPMODR0.
|
||||
*/
|
||||
unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicr_read_igrpmodr0(base);
|
||||
|
||||
return (reg_val >> bit_num) & 0x1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to set the bit corresponding to interrupt ID
|
||||
* in GIC Re-distributor IGRPMODR0.
|
||||
*/
|
||||
void gicr_set_igrpmodr0(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicr_read_igrpmodr0(base);
|
||||
|
||||
gicr_write_igrpmodr0(base, reg_val | (1 << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to clear the bit corresponding to interrupt ID
|
||||
* in GIC Re-distributor IGRPMODR0.
|
||||
*/
|
||||
void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1);
|
||||
unsigned int reg_val = gicr_read_igrpmodr0(base);
|
||||
|
||||
gicr_write_igrpmodr0(base, reg_val & ~(1 << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor to set the bit corresponding to interrupt ID
|
||||
* in GIC Re-distributor ISENABLER0.
|
||||
*/
|
||||
void gicr_set_isenabler0(uintptr_t base, unsigned int id)
|
||||
{
|
||||
unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1);
|
||||
|
||||
gicr_write_isenabler0(base, (1 << bit_num));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* This function marks the core as awake in the re-distributor and
|
||||
* ensures that the interface is active.
|
||||
*****************************************************************************/
|
||||
void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base)
|
||||
{
|
||||
/*
|
||||
* The WAKER_PS_BIT should be changed to 0
|
||||
* only when WAKER_CA_BIT is 1.
|
||||
*/
|
||||
assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT);
|
||||
|
||||
/* Mark the connected core as awake */
|
||||
gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_PS_BIT);
|
||||
|
||||
/* Wait till the WAKER_CA_BIT changes to 0 */
|
||||
while (gicr_read_waker(gicr_base) & WAKER_CA_BIT)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* This function marks the core as asleep in the re-distributor and ensures
|
||||
* that the interface is quiescent.
|
||||
*****************************************************************************/
|
||||
void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base)
|
||||
{
|
||||
/* Mark the connected core as asleep */
|
||||
gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_PS_BIT);
|
||||
|
||||
/* Wait till the WAKER_CA_BIT changes to 1 */
|
||||
while (!(gicr_read_waker(gicr_base) & WAKER_CA_BIT))
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* This function probes the Redistributor frames when the driver is initialised
|
||||
* and saves their base addresses. These base addresses are used later to
|
||||
* initialise each Redistributor interface.
|
||||
******************************************************************************/
|
||||
void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
|
||||
unsigned int rdistif_num,
|
||||
uintptr_t gicr_base,
|
||||
mpidr_hash_fn mpidr_to_core_pos)
|
||||
{
|
||||
unsigned long mpidr;
|
||||
unsigned int proc_num;
|
||||
unsigned long long typer_val;
|
||||
uintptr_t rdistif_base = gicr_base;
|
||||
|
||||
assert(rdistif_base_addrs);
|
||||
|
||||
/*
|
||||
* Iterate over the Redistributor frames. Store the base address of each
|
||||
* frame in the platform provided array. Use the "Processor Number"
|
||||
* field to index into the array if the platform has not provided a hash
|
||||
* function to convert an MPIDR (obtained from the "Affinity Value"
|
||||
* field into a linear index.
|
||||
*/
|
||||
do {
|
||||
typer_val = gicr_read_typer(rdistif_base);
|
||||
if (mpidr_to_core_pos) {
|
||||
mpidr = mpidr_from_gicr_typer(typer_val);
|
||||
proc_num = mpidr_to_core_pos(mpidr);
|
||||
} else {
|
||||
proc_num = (typer_val >> TYPER_PROC_NUM_SHIFT) &
|
||||
TYPER_PROC_NUM_MASK;
|
||||
}
|
||||
assert(proc_num < rdistif_num);
|
||||
rdistif_base_addrs[proc_num] = rdistif_base;
|
||||
rdistif_base += (1 << GICR_PCPUBASE_SHIFT);
|
||||
} while (!(typer_val & TYPER_LAST_BIT));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper function to configure the default attributes of SPIs.
|
||||
******************************************************************************/
|
||||
void gicv3_spis_configure_defaults(uintptr_t gicd_base)
|
||||
{
|
||||
unsigned int index, num_ints;
|
||||
|
||||
num_ints = gicd_read_typer(gicd_base);
|
||||
num_ints &= TYPER_IT_LINES_NO_MASK;
|
||||
num_ints = (num_ints + 1) << 5;
|
||||
|
||||
/*
|
||||
* Treat all SPIs as G1NS by default. The number of interrupts is
|
||||
* calculated as 32 * (IT_LINES + 1). We do 32 at a time.
|
||||
*/
|
||||
for (index = MIN_SPI_ID; index < num_ints; index += 32)
|
||||
gicd_write_igroupr(gicd_base, index, ~0U);
|
||||
|
||||
/* Setup the default SPI priorities doing four at a time */
|
||||
for (index = MIN_SPI_ID; index < num_ints; index += 4)
|
||||
gicd_write_ipriorityr(gicd_base,
|
||||
index,
|
||||
GICD_IPRIORITYR_DEF_VAL);
|
||||
|
||||
/*
|
||||
* Treat all SPIs as level triggered by default, write 16 at
|
||||
* a time
|
||||
*/
|
||||
for (index = MIN_SPI_ID; index < num_ints; index += 16)
|
||||
gicd_write_icfgr(gicd_base, index, 0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper function to configure secure G0 and G1S SPIs.
|
||||
******************************************************************************/
|
||||
void gicv3_secure_spis_configure(uintptr_t gicd_base,
|
||||
unsigned int num_ints,
|
||||
const unsigned int *sec_intr_list,
|
||||
unsigned int int_grp)
|
||||
{
|
||||
unsigned int index, irq_num;
|
||||
uint64_t gic_affinity_val;
|
||||
|
||||
assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0));
|
||||
/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
|
||||
assert(num_ints ? (uintptr_t)sec_intr_list : 1);
|
||||
|
||||
for (index = 0; index < num_ints; index++) {
|
||||
irq_num = sec_intr_list[index];
|
||||
if (irq_num >= MIN_SPI_ID) {
|
||||
|
||||
/* Configure this interrupt as a secure interrupt */
|
||||
gicd_clr_igroupr(gicd_base, irq_num);
|
||||
|
||||
/* Configure this interrupt as G0 or a G1S interrupt */
|
||||
if (int_grp == INT_TYPE_G1S)
|
||||
gicd_set_igrpmodr(gicd_base, irq_num);
|
||||
else
|
||||
gicd_clr_igrpmodr(gicd_base, irq_num);
|
||||
|
||||
/* Set the priority of this interrupt */
|
||||
gicd_write_ipriorityr(gicd_base,
|
||||
irq_num,
|
||||
GIC_HIGHEST_SEC_PRIORITY);
|
||||
|
||||
/* Target SPIs to the primary CPU */
|
||||
gic_affinity_val =
|
||||
gicd_irouter_val_from_mpidr(read_mpidr(), 0);
|
||||
gicd_write_irouter(gicd_base,
|
||||
irq_num,
|
||||
gic_affinity_val);
|
||||
|
||||
/* Enable this interrupt */
|
||||
gicd_set_isenabler(gicd_base, irq_num);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper function to configure the default attributes of SPIs.
|
||||
******************************************************************************/
|
||||
void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
/*
|
||||
* Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
|
||||
* more scalable approach as it avoids clearing the enable bits in the
|
||||
* GICD_CTLR
|
||||
*/
|
||||
gicr_write_icenabler0(gicr_base, ~0);
|
||||
gicr_wait_for_pending_write(gicr_base);
|
||||
|
||||
/* Treat all SGIs/PPIs as G1NS by default. */
|
||||
gicr_write_igroupr0(gicr_base, ~0U);
|
||||
|
||||
/* Setup the default PPI/SGI priorities doing four at a time */
|
||||
for (index = 0; index < MIN_SPI_ID; index += 4)
|
||||
gicr_write_ipriorityr(gicr_base,
|
||||
index,
|
||||
GICD_IPRIORITYR_DEF_VAL);
|
||||
|
||||
/* Configure all PPIs as level triggered by default */
|
||||
gicr_write_icfgr1(gicr_base, 0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper function to configure secure G0 and G1S SPIs.
|
||||
******************************************************************************/
|
||||
void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
|
||||
unsigned int num_ints,
|
||||
const unsigned int *sec_intr_list,
|
||||
unsigned int int_grp)
|
||||
{
|
||||
unsigned int index, irq_num;
|
||||
|
||||
assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0));
|
||||
/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
|
||||
assert(num_ints ? (uintptr_t)sec_intr_list : 1);
|
||||
|
||||
for (index = 0; index < num_ints; index++) {
|
||||
irq_num = sec_intr_list[index];
|
||||
if (irq_num < MIN_SPI_ID) {
|
||||
|
||||
/* Configure this interrupt as a secure interrupt */
|
||||
gicr_clr_igroupr0(gicr_base, irq_num);
|
||||
|
||||
/* Configure this interrupt as G0 or a G1S interrupt */
|
||||
if (int_grp == INT_TYPE_G1S)
|
||||
gicr_set_igrpmodr0(gicr_base, irq_num);
|
||||
else
|
||||
gicr_clr_igrpmodr0(gicr_base, irq_num);
|
||||
|
||||
/* Set the priority of this interrupt */
|
||||
gicr_write_ipriorityr(gicr_base,
|
||||
irq_num,
|
||||
GIC_HIGHEST_SEC_PRIORITY);
|
||||
|
||||
/* Enable this interrupt */
|
||||
gicr_set_isenabler0(gicr_base, irq_num);
|
||||
}
|
||||
}
|
||||
}
|
381
drivers/arm/gic/v3/gicv3_main.c
Normal file
381
drivers/arm/gic/v3/gicv3_main.c
Normal file
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* 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.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <gic_common.h>
|
||||
#include <gicv3.h>
|
||||
#include "gicv3_private.h"
|
||||
|
||||
static const gicv3_driver_data_t *driver_data;
|
||||
static unsigned int gicv2_compat;
|
||||
|
||||
/*******************************************************************************
|
||||
* This function initialises the ARM GICv3 driver in EL3 with provided platform
|
||||
* inputs.
|
||||
******************************************************************************/
|
||||
void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
|
||||
{
|
||||
unsigned int gic_version;
|
||||
|
||||
assert(plat_driver_data);
|
||||
assert(plat_driver_data->gicd_base);
|
||||
assert(plat_driver_data->gicr_base);
|
||||
assert(plat_driver_data->rdistif_num);
|
||||
assert(plat_driver_data->rdistif_base_addrs);
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
/*
|
||||
* The platform should provide a list of at least one type of
|
||||
* interrupts
|
||||
*/
|
||||
assert(plat_driver_data->g0_interrupt_array ||
|
||||
plat_driver_data->g1s_interrupt_array);
|
||||
|
||||
/*
|
||||
* If there are no interrupts of a particular type, then the number of
|
||||
* interrupts of that type should be 0 and vice-versa.
|
||||
*/
|
||||
assert(plat_driver_data->g0_interrupt_array ?
|
||||
plat_driver_data->g0_interrupt_num :
|
||||
plat_driver_data->g0_interrupt_num == 0);
|
||||
assert(plat_driver_data->g1s_interrupt_array ?
|
||||
plat_driver_data->g1s_interrupt_num :
|
||||
plat_driver_data->g1s_interrupt_num == 0);
|
||||
|
||||
/* Check for system register support */
|
||||
assert(read_id_aa64pfr0_el1() &
|
||||
(ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT));
|
||||
|
||||
/* The GIC version should be 3.0 */
|
||||
gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
|
||||
gic_version >>= PIDR2_ARCH_REV_SHIFT;
|
||||
gic_version &= PIDR2_ARCH_REV_MASK;
|
||||
assert(gic_version == ARCH_REV_GICV3);
|
||||
|
||||
/*
|
||||
* Find out whether the GIC supports the GICv2 compatibility mode. The
|
||||
* ARE_S bit resets to 0 if supported
|
||||
*/
|
||||
gicv2_compat = gicd_read_ctlr(plat_driver_data->gicd_base);
|
||||
gicv2_compat >>= CTLR_ARE_S_SHIFT;
|
||||
gicv2_compat = !(gicv2_compat & CTLR_ARE_S_MASK);
|
||||
|
||||
/*
|
||||
* Find the base address of each implemented Redistributor interface.
|
||||
* The number of interfaces should be equal to the number of CPUs in the
|
||||
* system. The memory for saving these addresses has to be allocated by
|
||||
* the platform port
|
||||
*/
|
||||
gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs,
|
||||
plat_driver_data->rdistif_num,
|
||||
plat_driver_data->gicr_base,
|
||||
plat_driver_data->mpidr_to_core_pos);
|
||||
|
||||
driver_data = plat_driver_data;
|
||||
|
||||
INFO("GICv3 %s legacy support detected."
|
||||
" ARM GICV3 driver initialized in EL3\n",
|
||||
gicv2_compat ? "with" : "without");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function initialises the GIC distributor interface based upon the data
|
||||
* provided by the platform while initialising the driver.
|
||||
******************************************************************************/
|
||||
void gicv3_distif_init(void)
|
||||
{
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicd_base);
|
||||
assert(driver_data->g1s_interrupt_array);
|
||||
assert(driver_data->g0_interrupt_array);
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
/*
|
||||
* Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring
|
||||
* the ARE_S bit. The Distributor might generate a system error
|
||||
* otherwise.
|
||||
*/
|
||||
gicd_clr_ctlr(driver_data->gicd_base,
|
||||
CTLR_ENABLE_G0_BIT |
|
||||
CTLR_ENABLE_G1S_BIT |
|
||||
CTLR_ENABLE_G1NS_BIT,
|
||||
RWP_TRUE);
|
||||
|
||||
/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
|
||||
gicd_set_ctlr(driver_data->gicd_base,
|
||||
CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
|
||||
|
||||
/* Set the default attribute of all SPIs */
|
||||
gicv3_spis_configure_defaults(driver_data->gicd_base);
|
||||
|
||||
/* Configure the G1S SPIs */
|
||||
gicv3_secure_spis_configure(driver_data->gicd_base,
|
||||
driver_data->g1s_interrupt_num,
|
||||
driver_data->g1s_interrupt_array,
|
||||
INT_TYPE_G1S);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Enable the secure SPIs now that they have been configured */
|
||||
gicd_set_ctlr(driver_data->gicd_base,
|
||||
CTLR_ENABLE_G1S_BIT | CTLR_ENABLE_G0_BIT,
|
||||
RWP_TRUE);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function initialises the GIC Redistributor interface of the calling CPU
|
||||
* (identified by the 'proc_num' parameter) based upon the data provided by the
|
||||
* platform while initialising the driver.
|
||||
******************************************************************************/
|
||||
void gicv3_rdistif_init(unsigned int proc_num)
|
||||
{
|
||||
uintptr_t gicr_base;
|
||||
|
||||
assert(driver_data);
|
||||
assert(proc_num < driver_data->rdistif_num);
|
||||
assert(driver_data->rdistif_base_addrs);
|
||||
assert(driver_data->gicd_base);
|
||||
assert(gicd_read_ctlr(driver_data->gicd_base) & CTLR_ARE_S_BIT);
|
||||
assert(driver_data->g1s_interrupt_array);
|
||||
assert(driver_data->g0_interrupt_array);
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
gicr_base = driver_data->rdistif_base_addrs[proc_num];
|
||||
|
||||
/* Set the default attribute of all SGIs and PPIs */
|
||||
gicv3_ppi_sgi_configure_defaults(gicr_base);
|
||||
|
||||
/* Configure the G1S SGIs/PPIs */
|
||||
gicv3_secure_ppi_sgi_configure(gicr_base,
|
||||
driver_data->g1s_interrupt_num,
|
||||
driver_data->g1s_interrupt_array,
|
||||
INT_TYPE_G1S);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function enables the GIC CPU interface of the calling CPU using only
|
||||
* system register accesses.
|
||||
******************************************************************************/
|
||||
void gicv3_cpuif_enable(unsigned int proc_num)
|
||||
{
|
||||
uintptr_t gicr_base;
|
||||
unsigned int scr_el3;
|
||||
unsigned int icc_sre_el3;
|
||||
|
||||
assert(driver_data);
|
||||
assert(proc_num < driver_data->rdistif_num);
|
||||
assert(driver_data->rdistif_base_addrs);
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
/* Mark the connected core as awake */
|
||||
gicr_base = driver_data->rdistif_base_addrs[proc_num];
|
||||
gicv3_rdistif_mark_core_awake(gicr_base);
|
||||
|
||||
/* Disable the legacy interrupt bypass */
|
||||
icc_sre_el3 = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT;
|
||||
|
||||
/*
|
||||
* Enable system register access for EL3 and allow lower exception
|
||||
* levels to configure the same for themselves. If the legacy mode is
|
||||
* not supported, the SRE bit is RAO/WI
|
||||
*/
|
||||
icc_sre_el3 |= (ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT);
|
||||
write_icc_sre_el3(read_icc_sre_el3() | icc_sre_el3);
|
||||
|
||||
scr_el3 = read_scr_el3();
|
||||
|
||||
/*
|
||||
* Switch to NS state to write Non secure ICC_SRE_EL1 and
|
||||
* ICC_SRE_EL2 registers.
|
||||
*/
|
||||
write_scr_el3(scr_el3 | SCR_NS_BIT);
|
||||
isb();
|
||||
|
||||
write_icc_sre_el2(read_icc_sre_el2() | icc_sre_el3);
|
||||
write_icc_sre_el1(ICC_SRE_SRE_BIT);
|
||||
isb();
|
||||
|
||||
/* Switch to secure state. */
|
||||
write_scr_el3(scr_el3 & (~SCR_NS_BIT));
|
||||
isb();
|
||||
|
||||
/* Program the idle priority in the PMR */
|
||||
write_icc_pmr_el1(GIC_PRI_MASK);
|
||||
|
||||
/* Enable Group0 interrupts */
|
||||
write_icc_igrpen0_el1(IGRPEN1_EL1_ENABLE_G0_BIT);
|
||||
|
||||
/* Enable Group1 Secure interrupts */
|
||||
write_icc_igrpen1_el3(read_icc_igrpen1_el3() |
|
||||
IGRPEN1_EL3_ENABLE_G1S_BIT);
|
||||
|
||||
/* Write the secure ICC_SRE_EL1 register */
|
||||
write_icc_sre_el1(ICC_SRE_SRE_BIT);
|
||||
isb();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function disables the GIC CPU interface of the calling CPU using
|
||||
* only system register accesses.
|
||||
******************************************************************************/
|
||||
void gicv3_cpuif_disable(unsigned int proc_num)
|
||||
{
|
||||
uintptr_t gicr_base;
|
||||
|
||||
assert(driver_data);
|
||||
assert(proc_num < driver_data->rdistif_num);
|
||||
assert(driver_data->rdistif_base_addrs);
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
/* Disable legacy interrupt bypass */
|
||||
write_icc_sre_el3(read_icc_sre_el3() |
|
||||
(ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT));
|
||||
|
||||
/* Disable Group0 interrupts */
|
||||
write_icc_igrpen0_el1(read_icc_igrpen0_el1() &
|
||||
~IGRPEN1_EL1_ENABLE_G0_BIT);
|
||||
|
||||
/* Disable Group1 Secure interrupts */
|
||||
write_icc_igrpen1_el3(read_icc_igrpen1_el3() &
|
||||
~IGRPEN1_EL3_ENABLE_G1S_BIT);
|
||||
|
||||
/* Synchronise accesses to group enable registers */
|
||||
isb();
|
||||
|
||||
/* Mark the connected core as asleep */
|
||||
gicr_base = driver_data->rdistif_base_addrs[proc_num];
|
||||
gicv3_rdistif_mark_core_asleep(gicr_base);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function returns the id of the highest priority pending interrupt at
|
||||
* the GIC cpu interface.
|
||||
******************************************************************************/
|
||||
unsigned int gicv3_get_pending_interrupt_id(void)
|
||||
{
|
||||
unsigned int id;
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
id = read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK;
|
||||
|
||||
/*
|
||||
* If the ID is special identifier corresponding to G1S or G1NS
|
||||
* interrupt, then read the highest pending group 1 interrupt.
|
||||
*/
|
||||
if ((id == PENDING_G1S_INTID) || (id == PENDING_G1NS_INTID))
|
||||
return read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function returns the type of the highest priority pending interrupt at
|
||||
* the GIC cpu interface. The return values can be one of the following :
|
||||
* PENDING_G1S_INTID : The interrupt type is secure Group 1.
|
||||
* PENDING_G1NS_INTID : The interrupt type is non secure Group 1.
|
||||
* 0 - 1019 : The interrupt type is secure Group 0.
|
||||
* GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with
|
||||
* sufficient priority to be signaled
|
||||
******************************************************************************/
|
||||
unsigned int gicv3_get_pending_interrupt_type(void)
|
||||
{
|
||||
assert(IS_IN_EL3());
|
||||
return read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function returns the type of the interrupt id depending upon the group
|
||||
* 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
|
||||
* interrupt.
|
||||
******************************************************************************/
|
||||
unsigned int gicv3_get_interrupt_type(unsigned int id,
|
||||
unsigned int proc_num)
|
||||
{
|
||||
unsigned int igroup, grpmodr;
|
||||
uintptr_t gicr_base;
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
assert(driver_data);
|
||||
|
||||
/* Ensure the parameters are valid */
|
||||
assert(id < PENDING_G1S_INTID || id >= MIN_LPI_ID);
|
||||
assert(proc_num < driver_data->rdistif_num);
|
||||
|
||||
/* All LPI interrupts are Group 1 non secure */
|
||||
if (id >= MIN_LPI_ID)
|
||||
return INT_TYPE_G1NS;
|
||||
|
||||
if (id < MIN_SPI_ID) {
|
||||
assert(driver_data->rdistif_base_addrs);
|
||||
gicr_base = driver_data->rdistif_base_addrs[proc_num];
|
||||
igroup = gicr_get_igroupr0(gicr_base, id);
|
||||
grpmodr = gicr_get_igrpmodr0(gicr_base, id);
|
||||
} else {
|
||||
assert(driver_data->gicd_base);
|
||||
igroup = gicd_get_igroupr(driver_data->gicd_base, id);
|
||||
grpmodr = gicd_get_igrpmodr(driver_data->gicd_base, id);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the IGROUP bit is set, then it is a Group 1 Non secure
|
||||
* interrupt
|
||||
*/
|
||||
if (igroup)
|
||||
return INT_TYPE_G1NS;
|
||||
|
||||
/* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */
|
||||
if (grpmodr)
|
||||
return INT_TYPE_G1S;
|
||||
|
||||
/* Else it is a Group 0 Secure interrupt */
|
||||
return INT_TYPE_G0;
|
||||
}
|
232
drivers/arm/gic/v3/gicv3_private.h
Normal file
232
drivers/arm/gic/v3/gicv3_private.h
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GICV3_PRIVATE_H__
|
||||
#define __GICV3_PRIVATE_H__
|
||||
|
||||
#include <gicv3.h>
|
||||
#include <mmio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv3 private macro definitions
|
||||
******************************************************************************/
|
||||
|
||||
/* Constants to indicate the status of the RWP bit */
|
||||
#define RWP_TRUE 1
|
||||
#define RWP_FALSE 0
|
||||
|
||||
/*
|
||||
* Macro to wait for updates to :
|
||||
* GICD_CTLR[2:0] - the Group Enables
|
||||
* GICD_CTLR[5:4] - the ARE bits
|
||||
* GICD_ICENABLERn - the clearing of enable state for SPIs
|
||||
*/
|
||||
#define gicd_wait_for_pending_write(gicd_base) \
|
||||
do { \
|
||||
; \
|
||||
} while (gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT)
|
||||
|
||||
/*
|
||||
* Macro to convert an mpidr to a value suitable for programming into a
|
||||
* GICD_IROUTER. Bits[31:24] in the MPIDR are cleared as they are not relevant
|
||||
* to GICv3.
|
||||
*/
|
||||
#define gicd_irouter_val_from_mpidr(mpidr, irm) \
|
||||
((mpidr & ~(0xff << 24)) | \
|
||||
(irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT)
|
||||
|
||||
/*
|
||||
* Macro to wait for updates to :
|
||||
* GICR_ICENABLER0
|
||||
* GICR_CTLR.DPG1S
|
||||
* GICR_CTLR.DPG1NS
|
||||
* GICR_CTLR.DPG0
|
||||
*/
|
||||
#define gicr_wait_for_pending_write(gicr_base) \
|
||||
do { \
|
||||
; \
|
||||
} while (gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT)
|
||||
|
||||
/*
|
||||
* Macro to convert a GICR_TYPER affinity value into a MPIDR value. Bits[31:24]
|
||||
* are zeroes.
|
||||
*/
|
||||
#define mpidr_from_gicr_typer(typer_val) \
|
||||
((((typer_val >> 56) & MPIDR_AFFLVL_MASK) << MPIDR_AFF3_SHIFT) | \
|
||||
((typer_val >> 32) & 0xffffff))
|
||||
|
||||
/*******************************************************************************
|
||||
* Private function prototypes
|
||||
******************************************************************************/
|
||||
unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id);
|
||||
unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id);
|
||||
unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id);
|
||||
unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id);
|
||||
unsigned int gicv3_get_pending_grp1_interrupt_id(unsigned int pending_grp);
|
||||
void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_set_igrpmodr(uintptr_t base, unsigned int id);
|
||||
void gicr_set_igrpmodr0(uintptr_t base, unsigned int id);
|
||||
void gicr_set_isenabler0(uintptr_t base, unsigned int id);
|
||||
void gicr_set_igroupr0(uintptr_t base, unsigned int id);
|
||||
void gicd_clr_igrpmodr(uintptr_t base, unsigned int id);
|
||||
void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id);
|
||||
void gicr_clr_igroupr0(uintptr_t base, unsigned int id);
|
||||
void gicv3_spis_configure_defaults(uintptr_t gicd_base);
|
||||
void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base);
|
||||
void gicv3_secure_spis_configure(uintptr_t gicd_base,
|
||||
unsigned int num_ints,
|
||||
const unsigned int *sec_intr_list,
|
||||
unsigned int int_grp);
|
||||
void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base,
|
||||
unsigned int num_ints,
|
||||
const unsigned int *sec_intr_list,
|
||||
unsigned int int_grp);
|
||||
void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
|
||||
unsigned int rdistif_num,
|
||||
uintptr_t gicr_base,
|
||||
mpidr_hash_fn mpidr_to_core_pos);
|
||||
void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base);
|
||||
void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base);
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface accessors
|
||||
******************************************************************************/
|
||||
static inline unsigned int gicd_read_pidr2(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICD_PIDR2_GICV3);
|
||||
}
|
||||
|
||||
static inline unsigned long long gicd_read_irouter(uintptr_t base, unsigned int id)
|
||||
{
|
||||
return mmio_read_64(base + GICD_IROUTER + (id << 3));
|
||||
}
|
||||
|
||||
static inline void gicd_write_irouter(uintptr_t base,
|
||||
unsigned int id,
|
||||
unsigned long long affinity)
|
||||
{
|
||||
mmio_write_64(base + GICD_IROUTER + (id << 3), affinity);
|
||||
}
|
||||
|
||||
static inline void gicd_clr_ctlr(uintptr_t base,
|
||||
unsigned int bitmap,
|
||||
unsigned int rwp)
|
||||
{
|
||||
gicd_write_ctlr(base, gicd_read_ctlr(base) & ~bitmap);
|
||||
if (rwp)
|
||||
gicd_wait_for_pending_write(base);
|
||||
}
|
||||
|
||||
static inline void gicd_set_ctlr(uintptr_t base,
|
||||
unsigned int bitmap,
|
||||
unsigned int rwp)
|
||||
{
|
||||
gicd_write_ctlr(base, gicd_read_ctlr(base) | bitmap);
|
||||
if (rwp)
|
||||
gicd_wait_for_pending_write(base);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Redistributor interface accessors
|
||||
******************************************************************************/
|
||||
static inline unsigned long long gicr_read_ctlr(uintptr_t base)
|
||||
{
|
||||
return mmio_read_64(base + GICR_CTLR);
|
||||
}
|
||||
|
||||
static inline unsigned long long gicr_read_typer(uintptr_t base)
|
||||
{
|
||||
return mmio_read_64(base + GICR_TYPER);
|
||||
}
|
||||
|
||||
static inline unsigned int gicr_read_waker(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICR_WAKER);
|
||||
}
|
||||
|
||||
static inline void gicr_write_waker(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICR_WAKER, val);
|
||||
}
|
||||
|
||||
static inline unsigned int gicr_read_icenabler0(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICR_ICENABLER0);
|
||||
}
|
||||
|
||||
static inline void gicr_write_icenabler0(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICR_ICENABLER0, val);
|
||||
}
|
||||
|
||||
static inline unsigned int gicr_read_isenabler0(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICR_ISENABLER0);
|
||||
}
|
||||
|
||||
static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICR_ISENABLER0, val);
|
||||
}
|
||||
|
||||
static inline unsigned int gicr_read_igroupr0(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICR_IGROUPR0);
|
||||
}
|
||||
|
||||
static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICR_IGROUPR0, val);
|
||||
}
|
||||
|
||||
static inline unsigned int gicr_read_igrpmodr0(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICR_IGRPMODR0);
|
||||
}
|
||||
|
||||
static inline void gicr_write_igrpmodr0(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICR_IGRPMODR0, val);
|
||||
}
|
||||
|
||||
static inline unsigned int gicr_read_icfgr1(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICR_ICFGR1);
|
||||
}
|
||||
|
||||
static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICR_ICFGR1, val);
|
||||
}
|
||||
|
||||
#endif /* __GICV3_PRIVATE_H__ */
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef __ARM_GIC_H__
|
||||
#define __ARM_GIC_H__
|
||||
|
||||
#include <common_def.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -40,18 +41,18 @@ void arm_gic_init(uintptr_t gicc_base,
|
|||
uintptr_t gicd_base,
|
||||
uintptr_t gicr_base,
|
||||
const unsigned int *irq_sec_ptr,
|
||||
unsigned int num_irqs);
|
||||
void arm_gic_setup(void);
|
||||
void arm_gic_cpuif_deactivate(void);
|
||||
void arm_gic_cpuif_setup(void);
|
||||
void arm_gic_pcpu_distif_setup(void);
|
||||
unsigned int num_irqs) __warn_deprecated;
|
||||
void arm_gic_setup(void) __warn_deprecated;
|
||||
void arm_gic_cpuif_deactivate(void) __warn_deprecated;
|
||||
void arm_gic_cpuif_setup(void) __warn_deprecated;
|
||||
void arm_gic_pcpu_distif_setup(void) __warn_deprecated;
|
||||
|
||||
uint32_t arm_gic_interrupt_type_to_line(uint32_t type,
|
||||
uint32_t security_state);
|
||||
uint32_t arm_gic_get_pending_interrupt_type(void);
|
||||
uint32_t arm_gic_get_pending_interrupt_id(void);
|
||||
uint32_t arm_gic_acknowledge_interrupt(void);
|
||||
void arm_gic_end_of_interrupt(uint32_t id);
|
||||
uint32_t arm_gic_get_interrupt_type(uint32_t id);
|
||||
uint32_t security_state) __warn_deprecated;
|
||||
uint32_t arm_gic_get_pending_interrupt_type(void) __warn_deprecated;
|
||||
uint32_t arm_gic_get_pending_interrupt_id(void) __warn_deprecated;
|
||||
uint32_t arm_gic_acknowledge_interrupt(void) __warn_deprecated;
|
||||
void arm_gic_end_of_interrupt(uint32_t id) __warn_deprecated;
|
||||
uint32_t arm_gic_get_interrupt_type(uint32_t id) __warn_deprecated;
|
||||
|
||||
#endif /* __GIC_H__ */
|
||||
|
|
173
include/drivers/arm/gic_common.h
Normal file
173
include/drivers/arm/gic_common.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GIC_COMMON_H__
|
||||
#define __GIC_COMMON_H__
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface general definitions
|
||||
******************************************************************************/
|
||||
/* Constants to categorise interrupts */
|
||||
#define MIN_SGI_ID 0
|
||||
#define MIN_PPI_ID 16
|
||||
#define MIN_SPI_ID 32
|
||||
|
||||
/* Mask for the priority field common to all GIC interfaces */
|
||||
#define GIC_PRI_MASK 0xff
|
||||
|
||||
/* Constant to indicate a spurious interrupt in all GIC versions */
|
||||
#define GIC_SPURIOUS_INTERRUPT 1023
|
||||
|
||||
/* Constants to categorise priorities */
|
||||
#define GIC_HIGHEST_SEC_PRIORITY 0
|
||||
#define GIC_LOWEST_SEC_PRIORITY 127
|
||||
#define GIC_HIGHEST_NS_PRIORITY 128
|
||||
#define GIC_LOWEST_NS_PRIORITY 254 /* 255 would disable an interrupt */
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface register offsets that are common to GICv3 & GICv2
|
||||
******************************************************************************/
|
||||
#define GICD_CTLR 0x0
|
||||
#define GICD_TYPER 0x4
|
||||
#define GICD_IIDR 0x8
|
||||
#define GICD_IGROUPR 0x80
|
||||
#define GICD_ISENABLER 0x100
|
||||
#define GICD_ICENABLER 0x180
|
||||
#define GICD_ISPENDR 0x200
|
||||
#define GICD_ICPENDR 0x280
|
||||
#define GICD_ISACTIVER 0x300
|
||||
#define GICD_ICACTIVER 0x380
|
||||
#define GICD_IPRIORITYR 0x400
|
||||
#define GICD_ICFGR 0xc00
|
||||
#define GICD_NSACR 0xe00
|
||||
|
||||
/* GICD_CTLR bit definitions */
|
||||
#define CTLR_ENABLE_G0_SHIFT 0
|
||||
#define CTLR_ENABLE_G0_MASK 0x1
|
||||
#define CTLR_ENABLE_G0_BIT (1 << CTLR_ENABLE_G0_SHIFT)
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface register constants that are common to GICv3 & GICv2
|
||||
******************************************************************************/
|
||||
#define PIDR2_ARCH_REV_SHIFT 4
|
||||
#define PIDR2_ARCH_REV_MASK 0xf
|
||||
|
||||
/* GICv3 revision as reported by the PIDR2 register */
|
||||
#define ARCH_REV_GICV3 0x3
|
||||
/* GICv2 revision as reported by the PIDR2 register */
|
||||
#define ARCH_REV_GICV2 0x2
|
||||
|
||||
#define IGROUPR_SHIFT 5
|
||||
#define ISENABLER_SHIFT 5
|
||||
#define ICENABLER_SHIFT ISENABLER_SHIFT
|
||||
#define ISPENDR_SHIFT 5
|
||||
#define ICPENDR_SHIFT ISPENDR_SHIFT
|
||||
#define ISACTIVER_SHIFT 5
|
||||
#define ICACTIVER_SHIFT ISACTIVER_SHIFT
|
||||
#define IPRIORITYR_SHIFT 2
|
||||
#define ICFGR_SHIFT 4
|
||||
#define NSACR_SHIFT 4
|
||||
|
||||
/* GICD_TYPER shifts and masks */
|
||||
#define TYPER_IT_LINES_NO_SHIFT 0
|
||||
#define TYPER_IT_LINES_NO_MASK 0x1f
|
||||
|
||||
/* Value used to initialize Normal world interrupt priorities four at a time */
|
||||
#define GICD_IPRIORITYR_DEF_VAL \
|
||||
(GIC_HIGHEST_NS_PRIORITY | \
|
||||
(GIC_HIGHEST_NS_PRIORITY << 8) | \
|
||||
(GIC_HIGHEST_NS_PRIORITY << 16) | \
|
||||
(GIC_HIGHEST_NS_PRIORITY << 24))
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <mmio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor interface register accessors that are common to GICv3 & GICv2
|
||||
******************************************************************************/
|
||||
static inline unsigned int gicd_read_ctlr(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICD_CTLR);
|
||||
}
|
||||
|
||||
static inline unsigned int gicd_read_typer(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICD_TYPER);
|
||||
}
|
||||
|
||||
static inline unsigned int gicd_read_iidr(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICD_IIDR);
|
||||
}
|
||||
|
||||
static inline void gicd_write_ctlr(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICD_CTLR, val);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* GIC Distributor function prototypes
|
||||
******************************************************************************/
|
||||
unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id);
|
||||
unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id);
|
||||
void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val);
|
||||
void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val);
|
||||
unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id);
|
||||
void gicd_set_igroupr(uintptr_t base, unsigned int id);
|
||||
void gicd_clr_igroupr(uintptr_t base, unsigned int id);
|
||||
void gicd_set_isenabler(uintptr_t base, unsigned int id);
|
||||
void gicd_set_icenabler(uintptr_t base, unsigned int id);
|
||||
void gicd_set_ispendr(uintptr_t base, unsigned int id);
|
||||
void gicd_set_icpendr(uintptr_t base, unsigned int id);
|
||||
void gicd_set_isactiver(uintptr_t base, unsigned int id);
|
||||
void gicd_set_icactiver(uintptr_t base, unsigned int id);
|
||||
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __GIC_COMMON_H__ */
|
|
@ -31,6 +31,13 @@
|
|||
#ifndef __GIC_V2_H__
|
||||
#define __GIC_V2_H__
|
||||
|
||||
/******************************************************************************
|
||||
* THIS DRIVER IS DEPRECATED. For GICv2 systems, use the driver in gicv2.h
|
||||
* and for GICv3 systems, use the driver in gicv3.h.
|
||||
*****************************************************************************/
|
||||
#if ERROR_DEPRECATED
|
||||
#error " The legacy ARM GIC driver is deprecated."
|
||||
#endif
|
||||
|
||||
#define GIC400_NUM_SPIS 480
|
||||
#define MAX_PPIS 14
|
||||
|
|
|
@ -31,6 +31,14 @@
|
|||
#ifndef __GIC_V3_H__
|
||||
#define __GIC_V3_H__
|
||||
|
||||
/******************************************************************************
|
||||
* THIS DRIVER IS DEPRECATED. For GICv2 systems, use the driver in gicv2.h
|
||||
* and for GICv3 systems, use the driver in gicv3.h.
|
||||
*****************************************************************************/
|
||||
#if ERROR_DEPRECATED
|
||||
#error " The legacy ARM GIC driver is deprecated."
|
||||
#endif
|
||||
|
||||
#include <mmio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
165
include/drivers/arm/gicv2.h
Normal file
165
include/drivers/arm/gicv2.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GICV2_H__
|
||||
#define __GICV2_H__
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv2 miscellaneous definitions
|
||||
******************************************************************************/
|
||||
/* Interrupt IDs reported by the HPPIR and IAR registers */
|
||||
#define PENDING_G1_INTID 1022
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv2 specific Distributor interface register offsets and constants.
|
||||
******************************************************************************/
|
||||
#define GICD_ITARGETSR 0x800
|
||||
#define GICD_SGIR 0xF00
|
||||
#define GICD_CPENDSGIR 0xF10
|
||||
#define GICD_SPENDSGIR 0xF20
|
||||
#define GICD_PIDR2_GICV2 0xFE8
|
||||
|
||||
#define ITARGETSR_SHIFT 2
|
||||
#define GIC_TARGET_CPU_MASK 0xff
|
||||
|
||||
#define CPENDSGIR_SHIFT 2
|
||||
#define SPENDSGIR_SHIFT CPENDSGIR_SHIFT
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv2 specific CPU interface register offsets and constants.
|
||||
******************************************************************************/
|
||||
/* Physical CPU Interface registers */
|
||||
#define GICC_CTLR 0x0
|
||||
#define GICC_PMR 0x4
|
||||
#define GICC_BPR 0x8
|
||||
#define GICC_IAR 0xC
|
||||
#define GICC_EOIR 0x10
|
||||
#define GICC_RPR 0x14
|
||||
#define GICC_HPPIR 0x18
|
||||
#define GICC_AHPPIR 0x28
|
||||
#define GICC_IIDR 0xFC
|
||||
#define GICC_DIR 0x1000
|
||||
#define GICC_PRIODROP GICC_EOIR
|
||||
|
||||
/* GICC_CTLR bit definitions */
|
||||
#define EOI_MODE_NS (1 << 10)
|
||||
#define EOI_MODE_S (1 << 9)
|
||||
#define IRQ_BYP_DIS_GRP1 (1 << 8)
|
||||
#define FIQ_BYP_DIS_GRP1 (1 << 7)
|
||||
#define IRQ_BYP_DIS_GRP0 (1 << 6)
|
||||
#define FIQ_BYP_DIS_GRP0 (1 << 5)
|
||||
#define CBPR (1 << 4)
|
||||
#define FIQ_EN_SHIFT 3
|
||||
#define FIQ_EN_BIT (1 << FIQ_EN_SHIFT)
|
||||
#define ACK_CTL (1 << 2)
|
||||
|
||||
/* GICC_IIDR bit masks and shifts */
|
||||
#define GICC_IIDR_PID_SHIFT 20
|
||||
#define GICC_IIDR_ARCH_SHIFT 16
|
||||
#define GICC_IIDR_REV_SHIFT 12
|
||||
#define GICC_IIDR_IMP_SHIFT 0
|
||||
|
||||
#define GICC_IIDR_PID_MASK 0xfff
|
||||
#define GICC_IIDR_ARCH_MASK 0xf
|
||||
#define GICC_IIDR_REV_MASK 0xf
|
||||
#define GICC_IIDR_IMP_MASK 0xfff
|
||||
|
||||
/* HYP view virtual CPU Interface registers */
|
||||
#define GICH_CTL 0x0
|
||||
#define GICH_VTR 0x4
|
||||
#define GICH_ELRSR0 0x30
|
||||
#define GICH_ELRSR1 0x34
|
||||
#define GICH_APR0 0xF0
|
||||
#define GICH_LR_BASE 0x100
|
||||
|
||||
/* Virtual CPU Interface registers */
|
||||
#define GICV_CTL 0x0
|
||||
#define GICV_PRIMASK 0x4
|
||||
#define GICV_BP 0x8
|
||||
#define GICV_INTACK 0xC
|
||||
#define GICV_EOI 0x10
|
||||
#define GICV_RUNNINGPRI 0x14
|
||||
#define GICV_HIGHESTPEND 0x18
|
||||
#define GICV_DEACTIVATE 0x1000
|
||||
|
||||
/* GICD_CTLR bit definitions */
|
||||
#define CTLR_ENABLE_G1_SHIFT 1
|
||||
#define CTLR_ENABLE_G1_MASK 0x1
|
||||
#define CTLR_ENABLE_G1_BIT (1 << CTLR_ENABLE_G1_SHIFT)
|
||||
|
||||
/* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */
|
||||
#define INT_ID_MASK 0x3ff
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* This structure describes some of the implementation defined attributes of
|
||||
* the GICv2 IP. It is used by the platform port to specify these attributes
|
||||
* in order to initialize the GICv2 driver. The attributes are described
|
||||
* below.
|
||||
*
|
||||
* 1. The 'gicd_base' field contains the base address of the Distributor
|
||||
* interface programmer's view.
|
||||
*
|
||||
* 2. The 'gicc_base' field contains the base address of the CPU Interface
|
||||
* programmer's view.
|
||||
*
|
||||
* 3. The 'g0_interrupt_array' field is a pointer to an array in which each
|
||||
* entry corresponds to an ID of a Group 0 interrupt.
|
||||
*
|
||||
* 4. The 'g0_interrupt_num' field contains the number of entries in the
|
||||
* 'g0_interrupt_array'.
|
||||
******************************************************************************/
|
||||
typedef struct gicv2_driver_data {
|
||||
uintptr_t gicd_base;
|
||||
uintptr_t gicc_base;
|
||||
unsigned int g0_interrupt_num;
|
||||
const unsigned int *g0_interrupt_array;
|
||||
} gicv2_driver_data_t;
|
||||
|
||||
/*******************************************************************************
|
||||
* Function prototypes
|
||||
******************************************************************************/
|
||||
void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data);
|
||||
void gicv2_distif_init(void);
|
||||
void gicv2_pcpu_distif_init(void);
|
||||
void gicv2_cpuif_enable(void);
|
||||
void gicv2_cpuif_disable(void);
|
||||
unsigned int gicv2_is_fiq_enabled(void);
|
||||
unsigned int gicv2_get_pending_interrupt_type(void);
|
||||
unsigned int gicv2_get_pending_interrupt_id(void);
|
||||
unsigned int gicv2_acknowledge_interrupt(void);
|
||||
void gicv2_end_of_interrupt(unsigned int id);
|
||||
unsigned int gicv2_get_interrupt_group(unsigned int id);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __GICV2_H__ */
|
266
include/drivers/arm/gicv3.h
Normal file
266
include/drivers/arm/gicv3.h
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GICV3_H__
|
||||
#define __GICV3_H__
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv3 miscellaneous definitions
|
||||
******************************************************************************/
|
||||
/* Interrupt group definitions */
|
||||
#define INT_TYPE_G1S 0
|
||||
#define INT_TYPE_G0 1
|
||||
#define INT_TYPE_G1NS 2
|
||||
|
||||
/* Interrupt IDs reported by the HPPIR and IAR registers */
|
||||
#define PENDING_G1S_INTID 1020
|
||||
#define PENDING_G1NS_INTID 1021
|
||||
|
||||
/* Constant to categorize LPI interrupt */
|
||||
#define MIN_LPI_ID 8192
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv3 specific Distributor interface register offsets and constants.
|
||||
******************************************************************************/
|
||||
#define GICD_STATUSR 0x10
|
||||
#define GICD_SETSPI_NSR 0x40
|
||||
#define GICD_CLRSPI_NSR 0x48
|
||||
#define GICD_SETSPI_SR 0x50
|
||||
#define GICD_CLRSPI_SR 0x50
|
||||
#define GICD_IGRPMODR 0xd00
|
||||
#define GICD_IROUTER 0x6100
|
||||
#define GICD_PIDR2_GICV3 0xffe8
|
||||
|
||||
#define IGRPMODR_SHIFT 5
|
||||
|
||||
/* GICD_CTLR bit definitions */
|
||||
#define CTLR_ENABLE_G1NS_SHIFT 1
|
||||
#define CTLR_ENABLE_G1S_SHIFT 2
|
||||
#define CTLR_ARE_S_SHIFT 4
|
||||
#define CTLR_ARE_NS_SHIFT 5
|
||||
#define CTLR_DS_SHIFT 6
|
||||
#define CTLR_E1NWF_SHIFT 7
|
||||
#define GICD_CTLR_RWP_SHIFT 31
|
||||
|
||||
#define CTLR_ENABLE_G1NS_MASK 0x1
|
||||
#define CTLR_ENABLE_G1S_MASK 0x1
|
||||
#define CTLR_ARE_S_MASK 0x1
|
||||
#define CTLR_ARE_NS_MASK 0x1
|
||||
#define CTLR_DS_MASK 0x1
|
||||
#define CTLR_E1NWF_MASK 0x1
|
||||
#define GICD_CTLR_RWP_MASK 0x1
|
||||
|
||||
#define CTLR_ENABLE_G1NS_BIT (1 << CTLR_ENABLE_G1NS_SHIFT)
|
||||
#define CTLR_ENABLE_G1S_BIT (1 << CTLR_ENABLE_G1S_SHIFT)
|
||||
#define CTLR_ARE_S_BIT (1 << CTLR_ARE_S_SHIFT)
|
||||
#define CTLR_ARE_NS_BIT (1 << CTLR_ARE_NS_SHIFT)
|
||||
#define CTLR_DS_BIT (1 << CTLR_DS_SHIFT)
|
||||
#define CTLR_E1NWF_BIT (1 << CTLR_E1NWF_SHIFT)
|
||||
#define GICD_CTLR_RWP_BIT (1 << GICD_CTLR_RWP_SHIFT)
|
||||
|
||||
/* GICD_IROUTER shifts and masks */
|
||||
#define IROUTER_IRM_SHIFT 31
|
||||
#define IROUTER_IRM_MASK 0x1
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv3 Re-distributor interface registers & constants
|
||||
******************************************************************************/
|
||||
#define GICR_PCPUBASE_SHIFT 0x11
|
||||
#define GICR_SGIBASE_OFFSET (1 << 0x10) /* 64 KB */
|
||||
#define GICR_CTLR 0x0
|
||||
#define GICR_TYPER 0x08
|
||||
#define GICR_WAKER 0x14
|
||||
#define GICR_IGROUPR0 (GICR_SGIBASE_OFFSET + 0x80)
|
||||
#define GICR_ISENABLER0 (GICR_SGIBASE_OFFSET + 0x100)
|
||||
#define GICR_ICENABLER0 (GICR_SGIBASE_OFFSET + 0x180)
|
||||
#define GICR_IPRIORITYR (GICR_SGIBASE_OFFSET + 0x400)
|
||||
#define GICR_ICFGR0 (GICR_SGIBASE_OFFSET + 0xc00)
|
||||
#define GICR_ICFGR1 (GICR_SGIBASE_OFFSET + 0xc04)
|
||||
#define GICR_IGRPMODR0 (GICR_SGIBASE_OFFSET + 0xd00)
|
||||
|
||||
/* GICR_CTLR bit definitions */
|
||||
#define GICR_CTLR_RWP_SHIFT 3
|
||||
#define GICR_CTLR_RWP_MASK 0x1
|
||||
#define GICR_CTLR_RWP_BIT (1 << GICR_CTLR_RWP_SHIFT)
|
||||
|
||||
/* GICR_WAKER bit definitions */
|
||||
#define WAKER_CA_SHIFT 2
|
||||
#define WAKER_PS_SHIFT 1
|
||||
|
||||
#define WAKER_CA_MASK 0x1
|
||||
#define WAKER_PS_MASK 0x1
|
||||
|
||||
#define WAKER_CA_BIT (1 << WAKER_CA_SHIFT)
|
||||
#define WAKER_PS_BIT (1 << WAKER_PS_SHIFT)
|
||||
|
||||
/* GICR_TYPER bit definitions */
|
||||
#define TYPER_AFF_VAL_SHIFT 32
|
||||
#define TYPER_PROC_NUM_SHIFT 8
|
||||
#define TYPER_LAST_SHIFT 4
|
||||
|
||||
#define TYPER_AFF_VAL_MASK 0xffffffff
|
||||
#define TYPER_PROC_NUM_MASK 0xffff
|
||||
#define TYPER_LAST_MASK 0x1
|
||||
|
||||
#define TYPER_LAST_BIT (1 << TYPER_LAST_SHIFT)
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv3 CPU interface registers & constants
|
||||
******************************************************************************/
|
||||
/* ICC_SRE bit definitions*/
|
||||
#define ICC_SRE_EN_BIT (1 << 3)
|
||||
#define ICC_SRE_DIB_BIT (1 << 2)
|
||||
#define ICC_SRE_DFB_BIT (1 << 1)
|
||||
#define ICC_SRE_SRE_BIT (1 << 0)
|
||||
|
||||
/* ICC_IGRPEN1_EL3 bit definitions */
|
||||
#define IGRPEN1_EL3_ENABLE_G1NS_SHIFT 0
|
||||
#define IGRPEN1_EL3_ENABLE_G1S_SHIFT 1
|
||||
|
||||
#define IGRPEN1_EL3_ENABLE_G1NS_BIT (1 << IGRPEN1_EL3_ENABLE_G1NS_SHIFT)
|
||||
#define IGRPEN1_EL3_ENABLE_G1S_BIT (1 << IGRPEN1_EL3_ENABLE_G1S_SHIFT)
|
||||
|
||||
/* ICC_IGRPEN0_EL1 bit definitions */
|
||||
#define IGRPEN1_EL1_ENABLE_G0_SHIFT 0
|
||||
#define IGRPEN1_EL1_ENABLE_G0_BIT (1 << IGRPEN1_EL1_ENABLE_G0_SHIFT)
|
||||
|
||||
/* ICC_HPPIR0_EL1 bit definitions */
|
||||
#define HPPIR0_EL1_INTID_SHIFT 0
|
||||
#define HPPIR0_EL1_INTID_MASK 0xffffff
|
||||
|
||||
/* ICC_HPPIR1_EL1 bit definitions */
|
||||
#define HPPIR1_EL1_INTID_SHIFT 0
|
||||
#define HPPIR1_EL1_INTID_MASK 0xffffff
|
||||
|
||||
/* ICC_IAR0_EL1 bit definitions */
|
||||
#define IAR0_EL1_INTID_SHIFT 0
|
||||
#define IAR0_EL1_INTID_MASK 0xffffff
|
||||
|
||||
/* ICC_IAR1_EL1 bit definitions */
|
||||
#define IAR1_EL1_INTID_SHIFT 0
|
||||
#define IAR1_EL1_INTID_MASK 0xffffff
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define gicv3_is_intr_id_special_identifier(id) \
|
||||
(((id) >= PENDING_G1S_INTID) && ((id) <= GIC_SPURIOUS_INTERRUPT))
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper GICv3 macros for SEL1
|
||||
******************************************************************************/
|
||||
#define gicv3_acknowledge_interrupt_sel1() read_icc_iar1_el1() &\
|
||||
IAR1_EL1_INTID_MASK
|
||||
#define gicv3_get_pending_interrupt_id_sel1() read_icc_hppir1_el1() &\
|
||||
HPPIR1_EL1_INTID_MASK
|
||||
#define gicv3_end_of_interrupt_sel1(id) write_icc_eoir1_el1(id)
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Helper GICv3 macros for EL3
|
||||
******************************************************************************/
|
||||
#define gicv3_acknowledge_interrupt() read_icc_iar0_el1() &\
|
||||
IAR0_EL1_INTID_MASK
|
||||
#define gicv3_end_of_interrupt(id) write_icc_eoir0_el1(id)
|
||||
|
||||
/*******************************************************************************
|
||||
* This structure describes some of the implementation defined attributes of the
|
||||
* GICv3 IP. It is used by the platform port to specify these attributes in order
|
||||
* to initialise the GICV3 driver. The attributes are described below.
|
||||
*
|
||||
* 1. The 'gicd_base' field contains the base address of the Distributor
|
||||
* interface programmer's view.
|
||||
*
|
||||
* 2. The 'gicr_base' field contains the base address of the Re-distributor
|
||||
* interface programmer's view.
|
||||
*
|
||||
* 3. The 'g0_interrupt_array' field is a ponter to an array in which each
|
||||
* entry corresponds to an ID of a Group 0 interrupt.
|
||||
*
|
||||
* 4. The 'g0_interrupt_num' field contains the number of entries in the
|
||||
* 'g0_interrupt_array'.
|
||||
*
|
||||
* 5. The 'g1s_interrupt_array' field is a ponter to an array in which each
|
||||
* entry corresponds to an ID of a Group 1 interrupt.
|
||||
*
|
||||
* 6. The 'g1s_interrupt_num' field contains the number of entries in the
|
||||
* 'g1s_interrupt_array'.
|
||||
*
|
||||
* 7. The 'rdistif_num' field contains the number of Redistributor interfaces
|
||||
* the GIC implements. This is equal to the number of CPUs or CPU interfaces
|
||||
* instantiated in the GIC.
|
||||
*
|
||||
* 8. The 'rdistif_base_addrs' field is a pointer to an array that has an entry
|
||||
* for storing the base address of the Redistributor interface frame of each
|
||||
* CPU in the system. The size of the array = 'rdistif_num'. The base
|
||||
* addresses are detected during driver initialisation.
|
||||
*
|
||||
* 9. The 'mpidr_to_core_pos' field is a pointer to a hash function which the
|
||||
* driver will use to convert an MPIDR value to a linear core index. This
|
||||
* index will be used for accessing the 'rdistif_base_addrs' array. This is
|
||||
* an optional field. A GICv3 implementation maps each MPIDR to a linear core
|
||||
* index as well. This mapping can be found by reading the "Affinity Value"
|
||||
* and "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the
|
||||
* "Processor Numbers" are suitable to index into an array to access core
|
||||
* specific information. If this not the case, the platform port must provide
|
||||
* a hash function. Otherwise, the "Processor Number" field will be used to
|
||||
* access the array elements.
|
||||
******************************************************************************/
|
||||
typedef unsigned int (*mpidr_hash_fn)(unsigned long mpidr);
|
||||
|
||||
typedef struct gicv3_driver_data {
|
||||
uintptr_t gicd_base;
|
||||
uintptr_t gicr_base;
|
||||
unsigned int g0_interrupt_num;
|
||||
unsigned int g1s_interrupt_num;
|
||||
const unsigned int *g0_interrupt_array;
|
||||
const unsigned int *g1s_interrupt_array;
|
||||
unsigned int rdistif_num;
|
||||
uintptr_t *rdistif_base_addrs;
|
||||
mpidr_hash_fn mpidr_to_core_pos;
|
||||
} gicv3_driver_data_t;
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv3 EL3 driver API
|
||||
******************************************************************************/
|
||||
void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data);
|
||||
void gicv3_distif_init(void);
|
||||
void gicv3_rdistif_init(unsigned int proc_num);
|
||||
void gicv3_cpuif_enable(unsigned int proc_num);
|
||||
void gicv3_cpuif_disable(unsigned int proc_num);
|
||||
unsigned int gicv3_get_pending_interrupt_type(void);
|
||||
unsigned int gicv3_get_pending_interrupt_id(void);
|
||||
unsigned int gicv3_get_interrupt_type(unsigned int id,
|
||||
unsigned int proc_num);
|
||||
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __GICV3_H__ */
|
|
@ -88,6 +88,14 @@
|
|||
#define ICC_CTLR_EL1 S3_0_C12_C12_4
|
||||
#define ICC_CTLR_EL3 S3_6_C12_C12_4
|
||||
#define ICC_PMR_EL1 S3_0_C4_C6_0
|
||||
#define ICC_IGRPEN1_EL3 S3_6_c12_c12_7
|
||||
#define ICC_IGRPEN0_EL1 S3_0_c12_c12_6
|
||||
#define ICC_HPPIR0_EL1 S3_0_c12_c8_2
|
||||
#define ICC_HPPIR1_EL1 S3_0_c12_c12_2
|
||||
#define ICC_IAR0_EL1 S3_0_c12_c8_0
|
||||
#define ICC_IAR1_EL1 S3_0_c12_c12_0
|
||||
#define ICC_EOIR0_EL1 S3_0_c12_c8_1
|
||||
#define ICC_EOIR1_EL1 S3_0_c12_c12_1
|
||||
|
||||
/*******************************************************************************
|
||||
* Generic timer memory mapped registers & offsets
|
||||
|
@ -122,6 +130,10 @@
|
|||
#define ID_AA64PFR0_EL3_SHIFT 12
|
||||
#define ID_AA64PFR0_ELX_MASK 0xf
|
||||
|
||||
#define ID_AA64PFR0_GIC_SHIFT 24
|
||||
#define ID_AA64PFR0_GIC_WIDTH 4
|
||||
#define ID_AA64PFR0_GIC_MASK ((1 << ID_AA64PFR0_GIC_WIDTH) - 1)
|
||||
|
||||
/* ID_PFR1_EL1 definitions */
|
||||
#define ID_PFR1_VIRTEXT_SHIFT 12
|
||||
#define ID_PFR1_VIRTEXT_MASK 0xf
|
||||
|
|
|
@ -74,6 +74,14 @@ static inline void write_ ## _name(const uint64_t v) \
|
|||
_DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \
|
||||
_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
|
||||
|
||||
/* Define read function for renamed system register */
|
||||
#define DEFINE_RENAME_SYSREG_READ_FUNC(_name, _reg_name) \
|
||||
_DEFINE_SYSREG_READ_FUNC(_name, _reg_name)
|
||||
|
||||
/* Define write function for renamed system register */
|
||||
#define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name) \
|
||||
_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
|
||||
|
||||
/* Define write function for special system registers */
|
||||
#define DEFINE_SYSREG_WRITE_CONST_FUNC(_name) \
|
||||
_DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _name)
|
||||
|
@ -284,12 +292,18 @@ DEFINE_SYSREG_READ_FUNC(isr_el1)
|
|||
|
||||
DEFINE_SYSREG_READ_FUNC(ctr_el0)
|
||||
|
||||
/* GICv3 System Registers */
|
||||
|
||||
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1)
|
||||
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2)
|
||||
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el3, ICC_SRE_EL3)
|
||||
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_pmr_el1, ICC_PMR_EL1)
|
||||
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el3, ICC_IGRPEN1_EL3)
|
||||
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0_EL1)
|
||||
DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir0_el1, ICC_HPPIR0_EL1)
|
||||
DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir1_el1, ICC_HPPIR1_EL1)
|
||||
DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1)
|
||||
DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1)
|
||||
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1)
|
||||
DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1)
|
||||
|
||||
|
||||
#define IS_IN_EL(x) \
|
||||
|
|
Loading…
Add table
Reference in a new issue