Commit c66f4ade authored by danh-arm's avatar danh-arm Committed by GitHub
Browse files

Merge pull request #961 from jeenu-arm/gic-600

Introduce ARM GIC-600 driver
parents 03dd6391 e1c59ab3
...@@ -638,6 +638,7 @@ map is explained in the [Firmware Design]. ...@@ -638,6 +638,7 @@ map is explained in the [Firmware Design].
if `FVP_CLUSTER_COUNT` > 2. if `FVP_CLUSTER_COUNT` > 2.
* `FVP_USE_GIC_DRIVER` : Selects the GIC driver to be built. Options: * `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_GICV2` : The GICv2 only driver is selected
- `FVP_GICV3` : The GICv3 only driver is selected (default option) - `FVP_GICV3` : The GICv3 only driver is selected (default option)
- `FVP_GICV3_LEGACY`: The Legacy GICv3 driver is selected (deprecated) - `FVP_GICV3_LEGACY`: The Legacy GICv3 driver is selected (deprecated)
......
/*
* 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 @@ ...@@ -8,12 +8,10 @@
#include <arch_helpers.h> #include <arch_helpers.h>
#include <assert.h> #include <assert.h>
#include <debug.h> #include <debug.h>
#include <gic_common.h>
#include <gicv3.h> #include <gicv3.h>
#include "../common/gic_common_private.h"
#include "gicv3_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; static unsigned int gicv2_compat;
/* /*
...@@ -90,18 +88,20 @@ void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) ...@@ -90,18 +88,20 @@ void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
plat_driver_data->gicr_base, plat_driver_data->gicr_base,
plat_driver_data->mpidr_to_core_pos); 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 * The GIC driver data is initialized by the primary CPU with caches
* enabled. When the secondary CPU boots up, it initializes the * enabled. When the secondary CPU boots up, it initializes the
* GICC/GICR interface with the caches disabled. Hence flush 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. * platform has HW_ASSISTED_COHERENCY enabled.
*/ */
#if !HW_ASSISTED_COHERENCY #if !HW_ASSISTED_COHERENCY
flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data)); flush_dcache_range((uintptr_t) &gicv3_driver_data,
flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data)); sizeof(gicv3_driver_data));
flush_dcache_range((uintptr_t) gicv3_driver_data,
sizeof(*gicv3_driver_data));
#endif #endif
INFO("GICv3 %s legacy support detected." INFO("GICv3 %s legacy support detected."
...@@ -117,10 +117,10 @@ void gicv3_distif_init(void) ...@@ -117,10 +117,10 @@ void gicv3_distif_init(void)
{ {
unsigned int bitmap = 0; unsigned int bitmap = 0;
assert(driver_data); assert(gicv3_driver_data);
assert(driver_data->gicd_base); assert(gicv3_driver_data->gicd_base);
assert(driver_data->g1s_interrupt_array || assert(gicv3_driver_data->g1s_interrupt_array ||
driver_data->g0_interrupt_array); gicv3_driver_data->g0_interrupt_array);
assert(IS_IN_EL3()); assert(IS_IN_EL3());
...@@ -129,39 +129,39 @@ void gicv3_distif_init(void) ...@@ -129,39 +129,39 @@ void gicv3_distif_init(void)
* the ARE_S bit. The Distributor might generate a system error * the ARE_S bit. The Distributor might generate a system error
* otherwise. * otherwise.
*/ */
gicd_clr_ctlr(driver_data->gicd_base, gicd_clr_ctlr(gicv3_driver_data->gicd_base,
CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G0_BIT |
CTLR_ENABLE_G1S_BIT | CTLR_ENABLE_G1S_BIT |
CTLR_ENABLE_G1NS_BIT, CTLR_ENABLE_G1NS_BIT,
RWP_TRUE); RWP_TRUE);
/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */ /* 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); CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
/* Set the default attribute of all SPIs */ /* 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 */ /* Configure the G1S SPIs */
if (driver_data->g1s_interrupt_array) { if (gicv3_driver_data->g1s_interrupt_array) {
gicv3_secure_spis_configure(driver_data->gicd_base, gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
driver_data->g1s_interrupt_num, gicv3_driver_data->g1s_interrupt_num,
driver_data->g1s_interrupt_array, gicv3_driver_data->g1s_interrupt_array,
INTR_GROUP1S); INTR_GROUP1S);
bitmap |= CTLR_ENABLE_G1S_BIT; bitmap |= CTLR_ENABLE_G1S_BIT;
} }
/* Configure the G0 SPIs */ /* Configure the G0 SPIs */
if (driver_data->g0_interrupt_array) { if (gicv3_driver_data->g0_interrupt_array) {
gicv3_secure_spis_configure(driver_data->gicd_base, gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
driver_data->g0_interrupt_num, gicv3_driver_data->g0_interrupt_num,
driver_data->g0_interrupt_array, gicv3_driver_data->g0_interrupt_array,
INTR_GROUP0); INTR_GROUP0);
bitmap |= CTLR_ENABLE_G0_BIT; bitmap |= CTLR_ENABLE_G0_BIT;
} }
/* Enable the secure SPIs now that they have been configured */ /* 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) ...@@ -173,37 +173,37 @@ void gicv3_rdistif_init(unsigned int proc_num)
{ {
uintptr_t gicr_base; uintptr_t gicr_base;
assert(driver_data); assert(gicv3_driver_data);
assert(proc_num < driver_data->rdistif_num); assert(proc_num < gicv3_driver_data->rdistif_num);
assert(driver_data->rdistif_base_addrs); assert(gicv3_driver_data->rdistif_base_addrs);
assert(driver_data->gicd_base); assert(gicv3_driver_data->gicd_base);
assert(gicd_read_ctlr(driver_data->gicd_base) & CTLR_ARE_S_BIT); assert(gicd_read_ctlr(gicv3_driver_data->gicd_base) & CTLR_ARE_S_BIT);
assert(driver_data->g1s_interrupt_array || assert(gicv3_driver_data->g1s_interrupt_array ||
driver_data->g0_interrupt_array); gicv3_driver_data->g0_interrupt_array);
assert(IS_IN_EL3()); assert(IS_IN_EL3());
/* Power on redistributor */ /* Power on redistributor */
gicv3_rdistif_on(proc_num); 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 */ /* Set the default attribute of all SGIs and PPIs */
gicv3_ppi_sgi_configure_defaults(gicr_base); gicv3_ppi_sgi_configure_defaults(gicr_base);
/* Configure the G1S SGIs/PPIs */ /* 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, gicv3_secure_ppi_sgi_configure(gicr_base,
driver_data->g1s_interrupt_num, gicv3_driver_data->g1s_interrupt_num,
driver_data->g1s_interrupt_array, gicv3_driver_data->g1s_interrupt_array,
INTR_GROUP1S); INTR_GROUP1S);
} }
/* Configure the G0 SGIs/PPIs */ /* 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, gicv3_secure_ppi_sgi_configure(gicr_base,
driver_data->g0_interrupt_num, gicv3_driver_data->g0_interrupt_num,
driver_data->g0_interrupt_array, gicv3_driver_data->g0_interrupt_array,
INTR_GROUP0); INTR_GROUP0);
} }
} }
...@@ -231,13 +231,13 @@ void gicv3_cpuif_enable(unsigned int proc_num) ...@@ -231,13 +231,13 @@ void gicv3_cpuif_enable(unsigned int proc_num)
unsigned int scr_el3; unsigned int scr_el3;
unsigned int icc_sre_el3; unsigned int icc_sre_el3;
assert(driver_data); assert(gicv3_driver_data);
assert(proc_num < driver_data->rdistif_num); assert(proc_num < gicv3_driver_data->rdistif_num);
assert(driver_data->rdistif_base_addrs); assert(gicv3_driver_data->rdistif_base_addrs);
assert(IS_IN_EL3()); assert(IS_IN_EL3());
/* Mark the connected core as awake */ /* 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); gicv3_rdistif_mark_core_awake(gicr_base);
/* Disable the legacy interrupt bypass */ /* Disable the legacy interrupt bypass */
...@@ -291,9 +291,9 @@ void gicv3_cpuif_disable(unsigned int proc_num) ...@@ -291,9 +291,9 @@ void gicv3_cpuif_disable(unsigned int proc_num)
{ {
uintptr_t gicr_base; uintptr_t gicr_base;
assert(driver_data); assert(gicv3_driver_data);
assert(proc_num < driver_data->rdistif_num); assert(proc_num < gicv3_driver_data->rdistif_num);
assert(driver_data->rdistif_base_addrs); assert(gicv3_driver_data->rdistif_base_addrs);
assert(IS_IN_EL3()); assert(IS_IN_EL3());
...@@ -314,7 +314,7 @@ void gicv3_cpuif_disable(unsigned int proc_num) ...@@ -314,7 +314,7 @@ void gicv3_cpuif_disable(unsigned int proc_num)
isb(); isb();
/* Mark the connected core as asleep */ /* 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); gicv3_rdistif_mark_core_asleep(gicr_base);
} }
...@@ -371,25 +371,25 @@ unsigned int gicv3_get_interrupt_type(unsigned int id, ...@@ -371,25 +371,25 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
uintptr_t gicr_base; uintptr_t gicr_base;
assert(IS_IN_EL3()); assert(IS_IN_EL3());
assert(driver_data); assert(gicv3_driver_data);
/* Ensure the parameters are valid */ /* Ensure the parameters are valid */
assert(id < PENDING_G1S_INTID || id >= MIN_LPI_ID); 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 */ /* All LPI interrupts are Group 1 non secure */
if (id >= MIN_LPI_ID) if (id >= MIN_LPI_ID)
return INTR_GROUP1NS; return INTR_GROUP1NS;
if (id < MIN_SPI_ID) { if (id < MIN_SPI_ID) {
assert(driver_data->rdistif_base_addrs); assert(gicv3_driver_data->rdistif_base_addrs);
gicr_base = driver_data->rdistif_base_addrs[proc_num]; gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
igroup = gicr_get_igroupr0(gicr_base, id); igroup = gicr_get_igroupr0(gicr_base, id);
grpmodr = gicr_get_igrpmodr0(gicr_base, id); grpmodr = gicr_get_igrpmodr0(gicr_base, id);
} else { } else {
assert(driver_data->gicd_base); assert(gicv3_driver_data->gicd_base);
igroup = gicd_get_igroupr(driver_data->gicd_base, id); igroup = gicd_get_igroupr(gicv3_driver_data->gicd_base, id);
grpmodr = gicd_get_igrpmodr(driver_data->gicd_base, id); grpmodr = gicd_get_igrpmodr(gicv3_driver_data->gicd_base, id);
} }
/* /*
......
/* /*
* 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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
...@@ -7,9 +7,11 @@ ...@@ -7,9 +7,11 @@
#ifndef __GICV3_PRIVATE_H__ #ifndef __GICV3_PRIVATE_H__
#define __GICV3_PRIVATE_H__ #define __GICV3_PRIVATE_H__
#include <gic_common.h>
#include <gicv3.h> #include <gicv3.h>
#include <mmio.h> #include <mmio.h>
#include <stdint.h> #include <stdint.h>
#include "../common/gic_common_private.h"
/******************************************************************************* /*******************************************************************************
* GICv3 private macro definitions * GICv3 private macro definitions
......
...@@ -31,13 +31,18 @@ endif ...@@ -31,13 +31,18 @@ endif
$(eval $(call add_define,FVP_INTERCONNECT_DRIVER)) $(eval $(call add_define,FVP_INTERCONNECT_DRIVER))
# Choose the GIC sources depending upon the how the FVP will be invoked FVP_GICV3_SOURCES := drivers/arm/gic/common/gic_common.c \
ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_main.c \
drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/gicv3_helpers.c \
plat/common/plat_gicv3.c \ plat/common/plat_gicv3.c \
plat/arm/common/arm_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) else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2)
FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_main.c \
......
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