1*464ce2bbSSoby Mathew /* 2*464ce2bbSSoby Mathew * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 3*464ce2bbSSoby Mathew * 4*464ce2bbSSoby Mathew * Redistribution and use in source and binary forms, with or without 5*464ce2bbSSoby Mathew * modification, are permitted provided that the following conditions are met: 6*464ce2bbSSoby Mathew * 7*464ce2bbSSoby Mathew * Redistributions of source code must retain the above copyright notice, this 8*464ce2bbSSoby Mathew * list of conditions and the following disclaimer. 9*464ce2bbSSoby Mathew * 10*464ce2bbSSoby Mathew * Redistributions in binary form must reproduce the above copyright notice, 11*464ce2bbSSoby Mathew * this list of conditions and the following disclaimer in the documentation 12*464ce2bbSSoby Mathew * and/or other materials provided with the distribution. 13*464ce2bbSSoby Mathew * 14*464ce2bbSSoby Mathew * Neither the name of ARM nor the names of its contributors may be used 15*464ce2bbSSoby Mathew * to endorse or promote products derived from this software without specific 16*464ce2bbSSoby Mathew * prior written permission. 17*464ce2bbSSoby Mathew * 18*464ce2bbSSoby Mathew * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*464ce2bbSSoby Mathew * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*464ce2bbSSoby Mathew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*464ce2bbSSoby Mathew * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*464ce2bbSSoby Mathew * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*464ce2bbSSoby Mathew * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*464ce2bbSSoby Mathew * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*464ce2bbSSoby Mathew * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*464ce2bbSSoby Mathew * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*464ce2bbSSoby Mathew * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*464ce2bbSSoby Mathew * POSSIBILITY OF SUCH DAMAGE. 29*464ce2bbSSoby Mathew */ 30*464ce2bbSSoby Mathew 31*464ce2bbSSoby Mathew #include <arch.h> 32*464ce2bbSSoby Mathew #include <arch_helpers.h> 33*464ce2bbSSoby Mathew #include <assert.h> 34*464ce2bbSSoby Mathew #include <debug.h> 35*464ce2bbSSoby Mathew #include <gic_common.h> 36*464ce2bbSSoby Mathew #include <gicv2.h> 37*464ce2bbSSoby Mathew #include "gicv2_private.h" 38*464ce2bbSSoby Mathew 39*464ce2bbSSoby Mathew static const gicv2_driver_data_t *driver_data; 40*464ce2bbSSoby Mathew 41*464ce2bbSSoby Mathew /******************************************************************************* 42*464ce2bbSSoby Mathew * Enable secure interrupts and use FIQs to route them. Disable legacy bypass 43*464ce2bbSSoby Mathew * and set the priority mask register to allow all interrupts to trickle in. 44*464ce2bbSSoby Mathew ******************************************************************************/ 45*464ce2bbSSoby Mathew void gicv2_cpuif_enable(void) 46*464ce2bbSSoby Mathew { 47*464ce2bbSSoby Mathew unsigned int val; 48*464ce2bbSSoby Mathew 49*464ce2bbSSoby Mathew assert(driver_data); 50*464ce2bbSSoby Mathew assert(driver_data->gicc_base); 51*464ce2bbSSoby Mathew 52*464ce2bbSSoby Mathew /* 53*464ce2bbSSoby Mathew * Enable the Group 0 interrupts, FIQEn and disable Group 0/1 54*464ce2bbSSoby Mathew * bypass. 55*464ce2bbSSoby Mathew */ 56*464ce2bbSSoby Mathew val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0; 57*464ce2bbSSoby Mathew val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1; 58*464ce2bbSSoby Mathew 59*464ce2bbSSoby Mathew /* Program the idle priority in the PMR */ 60*464ce2bbSSoby Mathew gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK); 61*464ce2bbSSoby Mathew gicc_write_ctlr(driver_data->gicc_base, val); 62*464ce2bbSSoby Mathew } 63*464ce2bbSSoby Mathew 64*464ce2bbSSoby Mathew /******************************************************************************* 65*464ce2bbSSoby Mathew * Place the cpu interface in a state where it can never make a cpu exit wfi as 66*464ce2bbSSoby Mathew * as result of an asserted interrupt. This is critical for powering down a cpu 67*464ce2bbSSoby Mathew ******************************************************************************/ 68*464ce2bbSSoby Mathew void gicv2_cpuif_disable(void) 69*464ce2bbSSoby Mathew { 70*464ce2bbSSoby Mathew unsigned int val; 71*464ce2bbSSoby Mathew 72*464ce2bbSSoby Mathew assert(driver_data); 73*464ce2bbSSoby Mathew assert(driver_data->gicc_base); 74*464ce2bbSSoby Mathew 75*464ce2bbSSoby Mathew /* Disable secure, non-secure interrupts and disable their bypass */ 76*464ce2bbSSoby Mathew val = gicc_read_ctlr(driver_data->gicc_base); 77*464ce2bbSSoby Mathew val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT); 78*464ce2bbSSoby Mathew val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0; 79*464ce2bbSSoby Mathew val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1; 80*464ce2bbSSoby Mathew gicc_write_ctlr(driver_data->gicc_base, val); 81*464ce2bbSSoby Mathew } 82*464ce2bbSSoby Mathew 83*464ce2bbSSoby Mathew /******************************************************************************* 84*464ce2bbSSoby Mathew * Per cpu gic distributor setup which will be done by all cpus after a cold 85*464ce2bbSSoby Mathew * boot/hotplug. This marks out the secure SPIs and PPIs & enables them. 86*464ce2bbSSoby Mathew ******************************************************************************/ 87*464ce2bbSSoby Mathew void gicv2_pcpu_distif_init(void) 88*464ce2bbSSoby Mathew { 89*464ce2bbSSoby Mathew assert(driver_data); 90*464ce2bbSSoby Mathew assert(driver_data->gicd_base); 91*464ce2bbSSoby Mathew assert(driver_data->g0_interrupt_array); 92*464ce2bbSSoby Mathew 93*464ce2bbSSoby Mathew gicv2_secure_ppi_sgi_setup(driver_data->gicd_base, 94*464ce2bbSSoby Mathew driver_data->g0_interrupt_num, 95*464ce2bbSSoby Mathew driver_data->g0_interrupt_array); 96*464ce2bbSSoby Mathew } 97*464ce2bbSSoby Mathew 98*464ce2bbSSoby Mathew /******************************************************************************* 99*464ce2bbSSoby Mathew * Global gic distributor init which will be done by the primary cpu after a 100*464ce2bbSSoby Mathew * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It 101*464ce2bbSSoby Mathew * then enables the secure GIC distributor interface. 102*464ce2bbSSoby Mathew ******************************************************************************/ 103*464ce2bbSSoby Mathew void gicv2_distif_init(void) 104*464ce2bbSSoby Mathew { 105*464ce2bbSSoby Mathew unsigned int ctlr; 106*464ce2bbSSoby Mathew 107*464ce2bbSSoby Mathew assert(driver_data); 108*464ce2bbSSoby Mathew assert(driver_data->gicd_base); 109*464ce2bbSSoby Mathew assert(driver_data->g0_interrupt_array); 110*464ce2bbSSoby Mathew 111*464ce2bbSSoby Mathew /* Disable the distributor before going further */ 112*464ce2bbSSoby Mathew ctlr = gicd_read_ctlr(driver_data->gicd_base); 113*464ce2bbSSoby Mathew gicd_write_ctlr(driver_data->gicd_base, 114*464ce2bbSSoby Mathew ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT)); 115*464ce2bbSSoby Mathew 116*464ce2bbSSoby Mathew /* Set the default attribute of all SPIs */ 117*464ce2bbSSoby Mathew gicv2_spis_configure_defaults(driver_data->gicd_base); 118*464ce2bbSSoby Mathew 119*464ce2bbSSoby Mathew /* Configure the G0 SPIs */ 120*464ce2bbSSoby Mathew gicv2_secure_spis_configure(driver_data->gicd_base, 121*464ce2bbSSoby Mathew driver_data->g0_interrupt_num, 122*464ce2bbSSoby Mathew driver_data->g0_interrupt_array); 123*464ce2bbSSoby Mathew 124*464ce2bbSSoby Mathew /* Re-enable the secure SPIs now that they have been configured */ 125*464ce2bbSSoby Mathew gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT); 126*464ce2bbSSoby Mathew } 127*464ce2bbSSoby Mathew 128*464ce2bbSSoby Mathew /******************************************************************************* 129*464ce2bbSSoby Mathew * Initialize the ARM GICv2 driver with the provided platform inputs 130*464ce2bbSSoby Mathew ******************************************************************************/ 131*464ce2bbSSoby Mathew void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data) 132*464ce2bbSSoby Mathew { 133*464ce2bbSSoby Mathew unsigned int gic_version; 134*464ce2bbSSoby Mathew assert(plat_driver_data); 135*464ce2bbSSoby Mathew assert(plat_driver_data->gicd_base); 136*464ce2bbSSoby Mathew assert(plat_driver_data->gicc_base); 137*464ce2bbSSoby Mathew 138*464ce2bbSSoby Mathew /* 139*464ce2bbSSoby Mathew * The platform should provide a list of atleast one type of 140*464ce2bbSSoby Mathew * interrupts 141*464ce2bbSSoby Mathew */ 142*464ce2bbSSoby Mathew assert(plat_driver_data->g0_interrupt_array); 143*464ce2bbSSoby Mathew 144*464ce2bbSSoby Mathew /* 145*464ce2bbSSoby Mathew * If there are no interrupts of a particular type, then the number of 146*464ce2bbSSoby Mathew * interrupts of that type should be 0 and vice-versa. 147*464ce2bbSSoby Mathew */ 148*464ce2bbSSoby Mathew assert(plat_driver_data->g0_interrupt_array ? 149*464ce2bbSSoby Mathew plat_driver_data->g0_interrupt_num : 150*464ce2bbSSoby Mathew plat_driver_data->g0_interrupt_num == 0); 151*464ce2bbSSoby Mathew 152*464ce2bbSSoby Mathew /* Ensure that this is a GICv2 system */ 153*464ce2bbSSoby Mathew gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); 154*464ce2bbSSoby Mathew gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT) 155*464ce2bbSSoby Mathew & PIDR2_ARCH_REV_MASK; 156*464ce2bbSSoby Mathew assert(gic_version == ARCH_REV_GICV2); 157*464ce2bbSSoby Mathew 158*464ce2bbSSoby Mathew driver_data = plat_driver_data; 159*464ce2bbSSoby Mathew 160*464ce2bbSSoby Mathew INFO("ARM GICv2 driver initialized\n"); 161*464ce2bbSSoby Mathew } 162*464ce2bbSSoby Mathew 163*464ce2bbSSoby Mathew /****************************************************************************** 164*464ce2bbSSoby Mathew * This function returns whether FIQ is enabled in the GIC CPU interface. 165*464ce2bbSSoby Mathew *****************************************************************************/ 166*464ce2bbSSoby Mathew unsigned int gicv2_is_fiq_enabled(void) 167*464ce2bbSSoby Mathew { 168*464ce2bbSSoby Mathew unsigned int gicc_ctlr; 169*464ce2bbSSoby Mathew 170*464ce2bbSSoby Mathew assert(driver_data); 171*464ce2bbSSoby Mathew assert(driver_data->gicc_base); 172*464ce2bbSSoby Mathew 173*464ce2bbSSoby Mathew gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base); 174*464ce2bbSSoby Mathew return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1; 175*464ce2bbSSoby Mathew } 176*464ce2bbSSoby Mathew 177*464ce2bbSSoby Mathew /******************************************************************************* 178*464ce2bbSSoby Mathew * This function returns the type of the highest priority pending interrupt at 179*464ce2bbSSoby Mathew * the GIC cpu interface. The return values can be one of the following : 180*464ce2bbSSoby Mathew * PENDING_G1_INTID : The interrupt type is non secure Group 1. 181*464ce2bbSSoby Mathew * 0 - 1019 : The interrupt type is secure Group 0. 182*464ce2bbSSoby Mathew * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with 183*464ce2bbSSoby Mathew * sufficient priority to be signaled 184*464ce2bbSSoby Mathew ******************************************************************************/ 185*464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_type(void) 186*464ce2bbSSoby Mathew { 187*464ce2bbSSoby Mathew assert(driver_data); 188*464ce2bbSSoby Mathew assert(driver_data->gicc_base); 189*464ce2bbSSoby Mathew 190*464ce2bbSSoby Mathew return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; 191*464ce2bbSSoby Mathew } 192*464ce2bbSSoby Mathew 193*464ce2bbSSoby Mathew /******************************************************************************* 194*464ce2bbSSoby Mathew * This function returns the id of the highest priority pending interrupt at 195*464ce2bbSSoby Mathew * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no 196*464ce2bbSSoby Mathew * interrupt pending. 197*464ce2bbSSoby Mathew ******************************************************************************/ 198*464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_id(void) 199*464ce2bbSSoby Mathew { 200*464ce2bbSSoby Mathew unsigned int id; 201*464ce2bbSSoby Mathew 202*464ce2bbSSoby Mathew assert(driver_data); 203*464ce2bbSSoby Mathew assert(driver_data->gicc_base); 204*464ce2bbSSoby Mathew 205*464ce2bbSSoby Mathew id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; 206*464ce2bbSSoby Mathew 207*464ce2bbSSoby Mathew /* 208*464ce2bbSSoby Mathew * Find out which non-secure interrupt it is under the assumption that 209*464ce2bbSSoby Mathew * the GICC_CTLR.AckCtl bit is 0. 210*464ce2bbSSoby Mathew */ 211*464ce2bbSSoby Mathew if (id == PENDING_G1_INTID) 212*464ce2bbSSoby Mathew id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK; 213*464ce2bbSSoby Mathew 214*464ce2bbSSoby Mathew return id; 215*464ce2bbSSoby Mathew } 216*464ce2bbSSoby Mathew 217*464ce2bbSSoby Mathew /******************************************************************************* 218*464ce2bbSSoby Mathew * This functions reads the GIC cpu interface Interrupt Acknowledge register 219*464ce2bbSSoby Mathew * to start handling the pending secure 0 interrupt. It returns the 220*464ce2bbSSoby Mathew * contents of the IAR. 221*464ce2bbSSoby Mathew ******************************************************************************/ 222*464ce2bbSSoby Mathew unsigned int gicv2_acknowledge_interrupt(void) 223*464ce2bbSSoby Mathew { 224*464ce2bbSSoby Mathew assert(driver_data); 225*464ce2bbSSoby Mathew assert(driver_data->gicc_base); 226*464ce2bbSSoby Mathew 227*464ce2bbSSoby Mathew return gicc_read_IAR(driver_data->gicc_base); 228*464ce2bbSSoby Mathew } 229*464ce2bbSSoby Mathew 230*464ce2bbSSoby Mathew /******************************************************************************* 231*464ce2bbSSoby Mathew * This functions writes the GIC cpu interface End Of Interrupt register with 232*464ce2bbSSoby Mathew * the passed value to finish handling the active secure group 0 interrupt. 233*464ce2bbSSoby Mathew ******************************************************************************/ 234*464ce2bbSSoby Mathew void gicv2_end_of_interrupt(unsigned int id) 235*464ce2bbSSoby Mathew { 236*464ce2bbSSoby Mathew assert(driver_data); 237*464ce2bbSSoby Mathew assert(driver_data->gicc_base); 238*464ce2bbSSoby Mathew 239*464ce2bbSSoby Mathew gicc_write_EOIR(driver_data->gicc_base, id); 240*464ce2bbSSoby Mathew } 241*464ce2bbSSoby Mathew 242*464ce2bbSSoby Mathew /******************************************************************************* 243*464ce2bbSSoby Mathew * This function returns the type of the interrupt id depending upon the group 244*464ce2bbSSoby Mathew * this interrupt has been configured under by the interrupt controller i.e. 245*464ce2bbSSoby Mathew * group0 secure or group1 non secure. It returns zero for Group 0 secure and 246*464ce2bbSSoby Mathew * one for Group 1 non secure interrupt. 247*464ce2bbSSoby Mathew ******************************************************************************/ 248*464ce2bbSSoby Mathew unsigned int gicv2_get_interrupt_group(unsigned int id) 249*464ce2bbSSoby Mathew { 250*464ce2bbSSoby Mathew assert(driver_data); 251*464ce2bbSSoby Mathew assert(driver_data->gicd_base); 252*464ce2bbSSoby Mathew 253*464ce2bbSSoby Mathew return gicd_get_igroupr(driver_data->gicd_base, id); 254*464ce2bbSSoby Mathew } 255