1464ce2bbSSoby Mathew /* 2311b1773SSoby Mathew * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. 3464ce2bbSSoby Mathew * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5464ce2bbSSoby Mathew */ 6464ce2bbSSoby Mathew 7464ce2bbSSoby Mathew #include <arch.h> 8464ce2bbSSoby Mathew #include <arch_helpers.h> 9464ce2bbSSoby Mathew #include <assert.h> 10464ce2bbSSoby Mathew #include <debug.h> 11464ce2bbSSoby Mathew #include <gic_common.h> 12464ce2bbSSoby Mathew #include <gicv2.h> 13e9ec3cecSSoby Mathew #include "../common/gic_common_private.h" 14464ce2bbSSoby Mathew #include "gicv2_private.h" 15464ce2bbSSoby Mathew 16464ce2bbSSoby Mathew static const gicv2_driver_data_t *driver_data; 17464ce2bbSSoby Mathew 18464ce2bbSSoby Mathew /******************************************************************************* 19464ce2bbSSoby Mathew * Enable secure interrupts and use FIQs to route them. Disable legacy bypass 20464ce2bbSSoby Mathew * and set the priority mask register to allow all interrupts to trickle in. 21464ce2bbSSoby Mathew ******************************************************************************/ 22464ce2bbSSoby Mathew void gicv2_cpuif_enable(void) 23464ce2bbSSoby Mathew { 24464ce2bbSSoby Mathew unsigned int val; 25464ce2bbSSoby Mathew 26464ce2bbSSoby Mathew assert(driver_data); 27464ce2bbSSoby Mathew assert(driver_data->gicc_base); 28464ce2bbSSoby Mathew 29464ce2bbSSoby Mathew /* 30464ce2bbSSoby Mathew * Enable the Group 0 interrupts, FIQEn and disable Group 0/1 31464ce2bbSSoby Mathew * bypass. 32464ce2bbSSoby Mathew */ 33464ce2bbSSoby Mathew val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0; 34464ce2bbSSoby Mathew val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1; 35464ce2bbSSoby Mathew 36464ce2bbSSoby Mathew /* Program the idle priority in the PMR */ 37464ce2bbSSoby Mathew gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK); 38464ce2bbSSoby Mathew gicc_write_ctlr(driver_data->gicc_base, val); 39464ce2bbSSoby Mathew } 40464ce2bbSSoby Mathew 41464ce2bbSSoby Mathew /******************************************************************************* 42464ce2bbSSoby Mathew * Place the cpu interface in a state where it can never make a cpu exit wfi as 43464ce2bbSSoby Mathew * as result of an asserted interrupt. This is critical for powering down a cpu 44464ce2bbSSoby Mathew ******************************************************************************/ 45464ce2bbSSoby Mathew void gicv2_cpuif_disable(void) 46464ce2bbSSoby Mathew { 47464ce2bbSSoby Mathew unsigned int val; 48464ce2bbSSoby Mathew 49464ce2bbSSoby Mathew assert(driver_data); 50464ce2bbSSoby Mathew assert(driver_data->gicc_base); 51464ce2bbSSoby Mathew 52464ce2bbSSoby Mathew /* Disable secure, non-secure interrupts and disable their bypass */ 53464ce2bbSSoby Mathew val = gicc_read_ctlr(driver_data->gicc_base); 54464ce2bbSSoby Mathew val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT); 55464ce2bbSSoby Mathew val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0; 56464ce2bbSSoby Mathew val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1; 57464ce2bbSSoby Mathew gicc_write_ctlr(driver_data->gicc_base, val); 58464ce2bbSSoby Mathew } 59464ce2bbSSoby Mathew 60464ce2bbSSoby Mathew /******************************************************************************* 61464ce2bbSSoby Mathew * Per cpu gic distributor setup which will be done by all cpus after a cold 62464ce2bbSSoby Mathew * boot/hotplug. This marks out the secure SPIs and PPIs & enables them. 63464ce2bbSSoby Mathew ******************************************************************************/ 64464ce2bbSSoby Mathew void gicv2_pcpu_distif_init(void) 65464ce2bbSSoby Mathew { 66464ce2bbSSoby Mathew assert(driver_data); 67464ce2bbSSoby Mathew assert(driver_data->gicd_base); 68464ce2bbSSoby Mathew assert(driver_data->g0_interrupt_array); 69464ce2bbSSoby Mathew 70464ce2bbSSoby Mathew gicv2_secure_ppi_sgi_setup(driver_data->gicd_base, 71464ce2bbSSoby Mathew driver_data->g0_interrupt_num, 72464ce2bbSSoby Mathew driver_data->g0_interrupt_array); 73464ce2bbSSoby Mathew } 74464ce2bbSSoby Mathew 75464ce2bbSSoby Mathew /******************************************************************************* 76464ce2bbSSoby Mathew * Global gic distributor init which will be done by the primary cpu after a 77464ce2bbSSoby Mathew * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It 78464ce2bbSSoby Mathew * then enables the secure GIC distributor interface. 79464ce2bbSSoby Mathew ******************************************************************************/ 80464ce2bbSSoby Mathew void gicv2_distif_init(void) 81464ce2bbSSoby Mathew { 82464ce2bbSSoby Mathew unsigned int ctlr; 83464ce2bbSSoby Mathew 84464ce2bbSSoby Mathew assert(driver_data); 85464ce2bbSSoby Mathew assert(driver_data->gicd_base); 86464ce2bbSSoby Mathew assert(driver_data->g0_interrupt_array); 87464ce2bbSSoby Mathew 88464ce2bbSSoby Mathew /* Disable the distributor before going further */ 89464ce2bbSSoby Mathew ctlr = gicd_read_ctlr(driver_data->gicd_base); 90464ce2bbSSoby Mathew gicd_write_ctlr(driver_data->gicd_base, 91464ce2bbSSoby Mathew ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT)); 92464ce2bbSSoby Mathew 93464ce2bbSSoby Mathew /* Set the default attribute of all SPIs */ 94464ce2bbSSoby Mathew gicv2_spis_configure_defaults(driver_data->gicd_base); 95464ce2bbSSoby Mathew 96464ce2bbSSoby Mathew /* Configure the G0 SPIs */ 97464ce2bbSSoby Mathew gicv2_secure_spis_configure(driver_data->gicd_base, 98464ce2bbSSoby Mathew driver_data->g0_interrupt_num, 99464ce2bbSSoby Mathew driver_data->g0_interrupt_array); 100464ce2bbSSoby Mathew 101464ce2bbSSoby Mathew /* Re-enable the secure SPIs now that they have been configured */ 102464ce2bbSSoby Mathew gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT); 103464ce2bbSSoby Mathew } 104464ce2bbSSoby Mathew 105464ce2bbSSoby Mathew /******************************************************************************* 106464ce2bbSSoby Mathew * Initialize the ARM GICv2 driver with the provided platform inputs 107464ce2bbSSoby Mathew ******************************************************************************/ 108464ce2bbSSoby Mathew void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data) 109464ce2bbSSoby Mathew { 110464ce2bbSSoby Mathew unsigned int gic_version; 111464ce2bbSSoby Mathew assert(plat_driver_data); 112464ce2bbSSoby Mathew assert(plat_driver_data->gicd_base); 113464ce2bbSSoby Mathew assert(plat_driver_data->gicc_base); 114464ce2bbSSoby Mathew 115464ce2bbSSoby Mathew /* 116464ce2bbSSoby Mathew * The platform should provide a list of atleast one type of 117464ce2bbSSoby Mathew * interrupts 118464ce2bbSSoby Mathew */ 119464ce2bbSSoby Mathew assert(plat_driver_data->g0_interrupt_array); 120464ce2bbSSoby Mathew 121464ce2bbSSoby Mathew /* 122464ce2bbSSoby Mathew * If there are no interrupts of a particular type, then the number of 123464ce2bbSSoby Mathew * interrupts of that type should be 0 and vice-versa. 124464ce2bbSSoby Mathew */ 125464ce2bbSSoby Mathew assert(plat_driver_data->g0_interrupt_array ? 126464ce2bbSSoby Mathew plat_driver_data->g0_interrupt_num : 127464ce2bbSSoby Mathew plat_driver_data->g0_interrupt_num == 0); 128464ce2bbSSoby Mathew 129464ce2bbSSoby Mathew /* Ensure that this is a GICv2 system */ 130464ce2bbSSoby Mathew gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); 131464ce2bbSSoby Mathew gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT) 132464ce2bbSSoby Mathew & PIDR2_ARCH_REV_MASK; 133464ce2bbSSoby Mathew assert(gic_version == ARCH_REV_GICV2); 134464ce2bbSSoby Mathew 135464ce2bbSSoby Mathew driver_data = plat_driver_data; 136464ce2bbSSoby Mathew 137311b1773SSoby Mathew /* 138311b1773SSoby Mathew * The GIC driver data is initialized by the primary CPU with caches 139311b1773SSoby Mathew * enabled. When the secondary CPU boots up, it initializes the 140311b1773SSoby Mathew * GICC/GICR interface with the caches disabled. Hence flush the 141311b1773SSoby Mathew * driver_data to ensure coherency. This is not required if the 142311b1773SSoby Mathew * platform has HW_ASSISTED_COHERENCY enabled. 143311b1773SSoby Mathew */ 144311b1773SSoby Mathew #if !HW_ASSISTED_COHERENCY 145311b1773SSoby Mathew flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data)); 146311b1773SSoby Mathew flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data)); 147311b1773SSoby Mathew #endif 148464ce2bbSSoby Mathew INFO("ARM GICv2 driver initialized\n"); 149464ce2bbSSoby Mathew } 150464ce2bbSSoby Mathew 151464ce2bbSSoby Mathew /****************************************************************************** 152464ce2bbSSoby Mathew * This function returns whether FIQ is enabled in the GIC CPU interface. 153464ce2bbSSoby Mathew *****************************************************************************/ 154464ce2bbSSoby Mathew unsigned int gicv2_is_fiq_enabled(void) 155464ce2bbSSoby Mathew { 156464ce2bbSSoby Mathew unsigned int gicc_ctlr; 157464ce2bbSSoby Mathew 158464ce2bbSSoby Mathew assert(driver_data); 159464ce2bbSSoby Mathew assert(driver_data->gicc_base); 160464ce2bbSSoby Mathew 161464ce2bbSSoby Mathew gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base); 162464ce2bbSSoby Mathew return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1; 163464ce2bbSSoby Mathew } 164464ce2bbSSoby Mathew 165464ce2bbSSoby Mathew /******************************************************************************* 166464ce2bbSSoby Mathew * This function returns the type of the highest priority pending interrupt at 167464ce2bbSSoby Mathew * the GIC cpu interface. The return values can be one of the following : 168464ce2bbSSoby Mathew * PENDING_G1_INTID : The interrupt type is non secure Group 1. 169464ce2bbSSoby Mathew * 0 - 1019 : The interrupt type is secure Group 0. 170464ce2bbSSoby Mathew * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with 171464ce2bbSSoby Mathew * sufficient priority to be signaled 172464ce2bbSSoby Mathew ******************************************************************************/ 173464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_type(void) 174464ce2bbSSoby Mathew { 175464ce2bbSSoby Mathew assert(driver_data); 176464ce2bbSSoby Mathew assert(driver_data->gicc_base); 177464ce2bbSSoby Mathew 178464ce2bbSSoby Mathew return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; 179464ce2bbSSoby Mathew } 180464ce2bbSSoby Mathew 181464ce2bbSSoby Mathew /******************************************************************************* 182464ce2bbSSoby Mathew * This function returns the id of the highest priority pending interrupt at 183464ce2bbSSoby Mathew * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no 184464ce2bbSSoby Mathew * interrupt pending. 185464ce2bbSSoby Mathew ******************************************************************************/ 186464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_id(void) 187464ce2bbSSoby Mathew { 188464ce2bbSSoby Mathew unsigned int id; 189464ce2bbSSoby Mathew 190464ce2bbSSoby Mathew assert(driver_data); 191464ce2bbSSoby Mathew assert(driver_data->gicc_base); 192464ce2bbSSoby Mathew 193464ce2bbSSoby Mathew id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; 194464ce2bbSSoby Mathew 195464ce2bbSSoby Mathew /* 196464ce2bbSSoby Mathew * Find out which non-secure interrupt it is under the assumption that 197464ce2bbSSoby Mathew * the GICC_CTLR.AckCtl bit is 0. 198464ce2bbSSoby Mathew */ 199464ce2bbSSoby Mathew if (id == PENDING_G1_INTID) 200464ce2bbSSoby Mathew id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK; 201464ce2bbSSoby Mathew 202464ce2bbSSoby Mathew return id; 203464ce2bbSSoby Mathew } 204464ce2bbSSoby Mathew 205464ce2bbSSoby Mathew /******************************************************************************* 206464ce2bbSSoby Mathew * This functions reads the GIC cpu interface Interrupt Acknowledge register 207464ce2bbSSoby Mathew * to start handling the pending secure 0 interrupt. It returns the 208464ce2bbSSoby Mathew * contents of the IAR. 209464ce2bbSSoby Mathew ******************************************************************************/ 210464ce2bbSSoby Mathew unsigned int gicv2_acknowledge_interrupt(void) 211464ce2bbSSoby Mathew { 212464ce2bbSSoby Mathew assert(driver_data); 213464ce2bbSSoby Mathew assert(driver_data->gicc_base); 214464ce2bbSSoby Mathew 215464ce2bbSSoby Mathew return gicc_read_IAR(driver_data->gicc_base); 216464ce2bbSSoby Mathew } 217464ce2bbSSoby Mathew 218464ce2bbSSoby Mathew /******************************************************************************* 219464ce2bbSSoby Mathew * This functions writes the GIC cpu interface End Of Interrupt register with 220464ce2bbSSoby Mathew * the passed value to finish handling the active secure group 0 interrupt. 221464ce2bbSSoby Mathew ******************************************************************************/ 222464ce2bbSSoby Mathew void gicv2_end_of_interrupt(unsigned int id) 223464ce2bbSSoby Mathew { 224464ce2bbSSoby Mathew assert(driver_data); 225464ce2bbSSoby Mathew assert(driver_data->gicc_base); 226464ce2bbSSoby Mathew 227464ce2bbSSoby Mathew gicc_write_EOIR(driver_data->gicc_base, id); 228464ce2bbSSoby Mathew } 229464ce2bbSSoby Mathew 230464ce2bbSSoby Mathew /******************************************************************************* 231464ce2bbSSoby Mathew * This function returns the type of the interrupt id depending upon the group 232464ce2bbSSoby Mathew * this interrupt has been configured under by the interrupt controller i.e. 233464ce2bbSSoby Mathew * group0 secure or group1 non secure. It returns zero for Group 0 secure and 234464ce2bbSSoby Mathew * one for Group 1 non secure interrupt. 235464ce2bbSSoby Mathew ******************************************************************************/ 236464ce2bbSSoby Mathew unsigned int gicv2_get_interrupt_group(unsigned int id) 237464ce2bbSSoby Mathew { 238464ce2bbSSoby Mathew assert(driver_data); 239464ce2bbSSoby Mathew assert(driver_data->gicd_base); 240464ce2bbSSoby Mathew 241464ce2bbSSoby Mathew return gicd_get_igroupr(driver_data->gicd_base, id); 242464ce2bbSSoby Mathew } 243*eb68ea9bSJeenu Viswambharan 244*eb68ea9bSJeenu Viswambharan /******************************************************************************* 245*eb68ea9bSJeenu Viswambharan * This function returns the priority of the interrupt the processor is 246*eb68ea9bSJeenu Viswambharan * currently servicing. 247*eb68ea9bSJeenu Viswambharan ******************************************************************************/ 248*eb68ea9bSJeenu Viswambharan unsigned int gicv2_get_running_priority(void) 249*eb68ea9bSJeenu Viswambharan { 250*eb68ea9bSJeenu Viswambharan assert(driver_data); 251*eb68ea9bSJeenu Viswambharan assert(driver_data->gicc_base); 252*eb68ea9bSJeenu Viswambharan 253*eb68ea9bSJeenu Viswambharan return gicc_read_rpr(driver_data->gicc_base); 254*eb68ea9bSJeenu Viswambharan } 255