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