Commit b39908af authored by Achin Gupta's avatar Achin Gupta
Browse files

Merge pull request #439 from soby-mathew/sm/new-gic-driver

Introduce new GICv3 and GICv2 drivers
parents 5b33041c 23a45010
/*
* 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));
}
/*
* 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);
}
/*
* 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);
}
/*
* 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__ */
/*
* 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);
}
}
}
/*
* 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;
}
/*
* 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__ */
/*
* 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>
......
/*
* 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__ */
/*
* 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) \
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment