Merge pull request #961 from jeenu-arm/gic-600
Introduce ARM GIC-600 driver
This commit is contained in:
commit
c66f4adee3
|
@ -638,6 +638,7 @@ map is explained in the [Firmware Design].
|
|||
if `FVP_CLUSTER_COUNT` > 2.
|
||||
|
||||
* `FVP_USE_GIC_DRIVER` : Selects the GIC driver to be built. Options:
|
||||
- `FVP_GIC600` : The GIC600 implementation of GICv3 is selected
|
||||
- `FVP_GICV2` : The GICv2 only driver is selected
|
||||
- `FVP_GICV3` : The GICv3 only driver is selected (default option)
|
||||
- `FVP_GICV3_LEGACY`: The Legacy GICv3 driver is selected (deprecated)
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
* Driver for GIC600-specific features. This driver only overrides APIs that are
|
||||
* different to those generic ones in GICv3 driver.
|
||||
*
|
||||
* GIC600 supports independently power-gating redistributor interface.
|
||||
*/
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <gicv3.h>
|
||||
|
||||
#include "gicv3_private.h"
|
||||
|
||||
/* GIC600-specific register offsets */
|
||||
#define GICR_PWRR 0x24
|
||||
|
||||
/* GICR_PWRR fields */
|
||||
#define PWRR_RDPD_SHIFT 0
|
||||
#define PWRR_RDGPD_SHIFT 2
|
||||
#define PWRR_RDGPO_SHIFT 3
|
||||
|
||||
#define PWRR_RDGPD (1 << PWRR_RDGPD_SHIFT)
|
||||
#define PWRR_RDGPO (1 << PWRR_RDGPO_SHIFT)
|
||||
|
||||
/* Values to write to GICR_PWRR register to power redistributor */
|
||||
#define PWRR_ON (0 << PWRR_RDPD_SHIFT)
|
||||
#define PWRR_OFF (1 << PWRR_RDPD_SHIFT)
|
||||
|
||||
/* Generic GICv3 resources */
|
||||
extern const gicv3_driver_data_t *gicv3_driver_data;
|
||||
|
||||
/* GIC600-specific accessor functions */
|
||||
static void gicr_write_pwrr(uintptr_t base, unsigned int val)
|
||||
{
|
||||
mmio_write_32(base + GICR_PWRR, val);
|
||||
}
|
||||
|
||||
static uint32_t gicr_read_pwrr(uintptr_t base)
|
||||
{
|
||||
return mmio_read_32(base + GICR_PWRR);
|
||||
}
|
||||
|
||||
static int gicr_group_powering_down(uint32_t pwrr)
|
||||
{
|
||||
/*
|
||||
* Whether the redistributor group power down operation is in transit:
|
||||
* i.e. it's intending to, but not finished yet.
|
||||
*/
|
||||
return ((pwrr & PWRR_RDGPD) && !(pwrr & PWRR_RDGPO));
|
||||
}
|
||||
|
||||
static void gic600_pwr_on(uintptr_t base)
|
||||
{
|
||||
/* Power on redistributor */
|
||||
gicr_write_pwrr(base, PWRR_ON);
|
||||
|
||||
/* Wait until the power on state is reflected */
|
||||
while (gicr_read_pwrr(base) & PWRR_RDGPO)
|
||||
;
|
||||
}
|
||||
|
||||
static void gic600_pwr_off(uintptr_t base)
|
||||
{
|
||||
/* Power off redistributor */
|
||||
gicr_write_pwrr(base, PWRR_OFF);
|
||||
|
||||
/*
|
||||
* If this is the last man, turning this redistributor frame off will
|
||||
* result in the group itself being powered off. In that case, wait as
|
||||
* long as it's in transition, or has aborted the transition altogether
|
||||
* for any reason.
|
||||
*/
|
||||
if (gicr_read_pwrr(base) & PWRR_RDGPD) {
|
||||
while (gicr_group_powering_down(gicr_read_pwrr(base)))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Power off GIC600 redistributor
|
||||
*/
|
||||
void gicv3_rdistif_off(unsigned int proc_num)
|
||||
{
|
||||
uintptr_t gicr_base;
|
||||
|
||||
assert(gicv3_driver_data);
|
||||
assert(proc_num < gicv3_driver_data->rdistif_num);
|
||||
assert(gicv3_driver_data->rdistif_base_addrs);
|
||||
|
||||
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
|
||||
assert(gicr_base);
|
||||
|
||||
/* Attempt to power redistributor off */
|
||||
gic600_pwr_off(gicr_base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Power on GIC600 redistributor
|
||||
*/
|
||||
void gicv3_rdistif_on(unsigned int proc_num)
|
||||
{
|
||||
uintptr_t gicr_base;
|
||||
|
||||
assert(gicv3_driver_data);
|
||||
assert(proc_num < gicv3_driver_data->rdistif_num);
|
||||
assert(gicv3_driver_data->rdistif_base_addrs);
|
||||
|
||||
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
|
||||
assert(gicr_base);
|
||||
|
||||
/* Power redistributor on */
|
||||
gic600_pwr_on(gicr_base);
|
||||
}
|
|
@ -8,12 +8,10 @@
|
|||
#include <arch_helpers.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <gic_common.h>
|
||||
#include <gicv3.h>
|
||||
#include "../common/gic_common_private.h"
|
||||
#include "gicv3_private.h"
|
||||
|
||||
static const gicv3_driver_data_t *driver_data;
|
||||
const gicv3_driver_data_t *gicv3_driver_data;
|
||||
static unsigned int gicv2_compat;
|
||||
|
||||
/*
|
||||
|
@ -90,18 +88,20 @@ void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
|
|||
plat_driver_data->gicr_base,
|
||||
plat_driver_data->mpidr_to_core_pos);
|
||||
|
||||
driver_data = plat_driver_data;
|
||||
gicv3_driver_data = plat_driver_data;
|
||||
|
||||
/*
|
||||
* The GIC driver data is initialized by the primary CPU with caches
|
||||
* enabled. When the secondary CPU boots up, it initializes the
|
||||
* GICC/GICR interface with the caches disabled. Hence flush the
|
||||
* driver_data to ensure coherency. This is not required if the
|
||||
* driver data to ensure coherency. This is not required if the
|
||||
* platform has HW_ASSISTED_COHERENCY enabled.
|
||||
*/
|
||||
#if !HW_ASSISTED_COHERENCY
|
||||
flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data));
|
||||
flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data));
|
||||
flush_dcache_range((uintptr_t) &gicv3_driver_data,
|
||||
sizeof(gicv3_driver_data));
|
||||
flush_dcache_range((uintptr_t) gicv3_driver_data,
|
||||
sizeof(*gicv3_driver_data));
|
||||
#endif
|
||||
|
||||
INFO("GICv3 %s legacy support detected."
|
||||
|
@ -117,10 +117,10 @@ void gicv3_distif_init(void)
|
|||
{
|
||||
unsigned int bitmap = 0;
|
||||
|
||||
assert(driver_data);
|
||||
assert(driver_data->gicd_base);
|
||||
assert(driver_data->g1s_interrupt_array ||
|
||||
driver_data->g0_interrupt_array);
|
||||
assert(gicv3_driver_data);
|
||||
assert(gicv3_driver_data->gicd_base);
|
||||
assert(gicv3_driver_data->g1s_interrupt_array ||
|
||||
gicv3_driver_data->g0_interrupt_array);
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
|
@ -129,39 +129,39 @@ void gicv3_distif_init(void)
|
|||
* the ARE_S bit. The Distributor might generate a system error
|
||||
* otherwise.
|
||||
*/
|
||||
gicd_clr_ctlr(driver_data->gicd_base,
|
||||
gicd_clr_ctlr(gicv3_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,
|
||||
gicd_set_ctlr(gicv3_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);
|
||||
gicv3_spis_configure_defaults(gicv3_driver_data->gicd_base);
|
||||
|
||||
/* Configure the G1S SPIs */
|
||||
if (driver_data->g1s_interrupt_array) {
|
||||
gicv3_secure_spis_configure(driver_data->gicd_base,
|
||||
driver_data->g1s_interrupt_num,
|
||||
driver_data->g1s_interrupt_array,
|
||||
if (gicv3_driver_data->g1s_interrupt_array) {
|
||||
gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
|
||||
gicv3_driver_data->g1s_interrupt_num,
|
||||
gicv3_driver_data->g1s_interrupt_array,
|
||||
INTR_GROUP1S);
|
||||
bitmap |= CTLR_ENABLE_G1S_BIT;
|
||||
}
|
||||
|
||||
/* Configure the G0 SPIs */
|
||||
if (driver_data->g0_interrupt_array) {
|
||||
gicv3_secure_spis_configure(driver_data->gicd_base,
|
||||
driver_data->g0_interrupt_num,
|
||||
driver_data->g0_interrupt_array,
|
||||
if (gicv3_driver_data->g0_interrupt_array) {
|
||||
gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
|
||||
gicv3_driver_data->g0_interrupt_num,
|
||||
gicv3_driver_data->g0_interrupt_array,
|
||||
INTR_GROUP0);
|
||||
bitmap |= CTLR_ENABLE_G0_BIT;
|
||||
}
|
||||
|
||||
/* Enable the secure SPIs now that they have been configured */
|
||||
gicd_set_ctlr(driver_data->gicd_base, bitmap, RWP_TRUE);
|
||||
gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -173,37 +173,37 @@ 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 ||
|
||||
driver_data->g0_interrupt_array);
|
||||
assert(gicv3_driver_data);
|
||||
assert(proc_num < gicv3_driver_data->rdistif_num);
|
||||
assert(gicv3_driver_data->rdistif_base_addrs);
|
||||
assert(gicv3_driver_data->gicd_base);
|
||||
assert(gicd_read_ctlr(gicv3_driver_data->gicd_base) & CTLR_ARE_S_BIT);
|
||||
assert(gicv3_driver_data->g1s_interrupt_array ||
|
||||
gicv3_driver_data->g0_interrupt_array);
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
/* Power on redistributor */
|
||||
gicv3_rdistif_on(proc_num);
|
||||
|
||||
gicr_base = driver_data->rdistif_base_addrs[proc_num];
|
||||
gicr_base = gicv3_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 */
|
||||
if (driver_data->g1s_interrupt_array) {
|
||||
if (gicv3_driver_data->g1s_interrupt_array) {
|
||||
gicv3_secure_ppi_sgi_configure(gicr_base,
|
||||
driver_data->g1s_interrupt_num,
|
||||
driver_data->g1s_interrupt_array,
|
||||
gicv3_driver_data->g1s_interrupt_num,
|
||||
gicv3_driver_data->g1s_interrupt_array,
|
||||
INTR_GROUP1S);
|
||||
}
|
||||
|
||||
/* Configure the G0 SGIs/PPIs */
|
||||
if (driver_data->g0_interrupt_array) {
|
||||
if (gicv3_driver_data->g0_interrupt_array) {
|
||||
gicv3_secure_ppi_sgi_configure(gicr_base,
|
||||
driver_data->g0_interrupt_num,
|
||||
driver_data->g0_interrupt_array,
|
||||
gicv3_driver_data->g0_interrupt_num,
|
||||
gicv3_driver_data->g0_interrupt_array,
|
||||
INTR_GROUP0);
|
||||
}
|
||||
}
|
||||
|
@ -231,13 +231,13 @@ void gicv3_cpuif_enable(unsigned int proc_num)
|
|||
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(gicv3_driver_data);
|
||||
assert(proc_num < gicv3_driver_data->rdistif_num);
|
||||
assert(gicv3_driver_data->rdistif_base_addrs);
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
/* Mark the connected core as awake */
|
||||
gicr_base = driver_data->rdistif_base_addrs[proc_num];
|
||||
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
|
||||
gicv3_rdistif_mark_core_awake(gicr_base);
|
||||
|
||||
/* Disable the legacy interrupt bypass */
|
||||
|
@ -291,9 +291,9 @@ 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(gicv3_driver_data);
|
||||
assert(proc_num < gicv3_driver_data->rdistif_num);
|
||||
assert(gicv3_driver_data->rdistif_base_addrs);
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
|
||||
|
@ -314,7 +314,7 @@ void gicv3_cpuif_disable(unsigned int proc_num)
|
|||
isb();
|
||||
|
||||
/* Mark the connected core as asleep */
|
||||
gicr_base = driver_data->rdistif_base_addrs[proc_num];
|
||||
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
|
||||
gicv3_rdistif_mark_core_asleep(gicr_base);
|
||||
}
|
||||
|
||||
|
@ -371,25 +371,25 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
|
|||
uintptr_t gicr_base;
|
||||
|
||||
assert(IS_IN_EL3());
|
||||
assert(driver_data);
|
||||
assert(gicv3_driver_data);
|
||||
|
||||
/* Ensure the parameters are valid */
|
||||
assert(id < PENDING_G1S_INTID || id >= MIN_LPI_ID);
|
||||
assert(proc_num < driver_data->rdistif_num);
|
||||
assert(proc_num < gicv3_driver_data->rdistif_num);
|
||||
|
||||
/* All LPI interrupts are Group 1 non secure */
|
||||
if (id >= MIN_LPI_ID)
|
||||
return INTR_GROUP1NS;
|
||||
|
||||
if (id < MIN_SPI_ID) {
|
||||
assert(driver_data->rdistif_base_addrs);
|
||||
gicr_base = driver_data->rdistif_base_addrs[proc_num];
|
||||
assert(gicv3_driver_data->rdistif_base_addrs);
|
||||
gicr_base = gicv3_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);
|
||||
assert(gicv3_driver_data->gicd_base);
|
||||
igroup = gicd_get_igroupr(gicv3_driver_data->gicd_base, id);
|
||||
grpmodr = gicd_get_igrpmodr(gicv3_driver_data->gicd_base, id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -7,9 +7,11 @@
|
|||
#ifndef __GICV3_PRIVATE_H__
|
||||
#define __GICV3_PRIVATE_H__
|
||||
|
||||
#include <gic_common.h>
|
||||
#include <gicv3.h>
|
||||
#include <mmio.h>
|
||||
#include <stdint.h>
|
||||
#include "../common/gic_common_private.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* GICv3 private macro definitions
|
||||
|
|
|
@ -31,13 +31,18 @@ endif
|
|||
|
||||
$(eval $(call add_define,FVP_INTERCONNECT_DRIVER))
|
||||
|
||||
# Choose the GIC sources depending upon the how the FVP will be invoked
|
||||
ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
|
||||
FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
|
||||
FVP_GICV3_SOURCES := drivers/arm/gic/common/gic_common.c \
|
||||
drivers/arm/gic/v3/gicv3_main.c \
|
||||
drivers/arm/gic/v3/gicv3_helpers.c \
|
||||
plat/common/plat_gicv3.c \
|
||||
plat/arm/common/arm_gicv3.c
|
||||
|
||||
# Choose the GIC sources depending upon the how the FVP will be invoked
|
||||
ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
|
||||
FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES}
|
||||
else ifeq (${FVP_USE_GIC_DRIVER},FVP_GIC600)
|
||||
FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES} \
|
||||
drivers/arm/gic/v3/gic600.c
|
||||
else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2)
|
||||
FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
|
||||
drivers/arm/gic/v2/gicv2_main.c \
|
||||
|
|
Loading…
Reference in New Issue