1 /* 2 * Copyright (c) 2015-2016, 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 "../common/gic_common_private.h" 38 #include "gicv2_private.h" 39 40 static const gicv2_driver_data_t *driver_data; 41 42 /******************************************************************************* 43 * Enable secure interrupts and use FIQs to route them. Disable legacy bypass 44 * and set the priority mask register to allow all interrupts to trickle in. 45 ******************************************************************************/ 46 void gicv2_cpuif_enable(void) 47 { 48 unsigned int val; 49 50 assert(driver_data); 51 assert(driver_data->gicc_base); 52 53 /* 54 * Enable the Group 0 interrupts, FIQEn and disable Group 0/1 55 * bypass. 56 */ 57 val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0; 58 val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1; 59 60 /* Program the idle priority in the PMR */ 61 gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK); 62 gicc_write_ctlr(driver_data->gicc_base, val); 63 } 64 65 /******************************************************************************* 66 * Place the cpu interface in a state where it can never make a cpu exit wfi as 67 * as result of an asserted interrupt. This is critical for powering down a cpu 68 ******************************************************************************/ 69 void gicv2_cpuif_disable(void) 70 { 71 unsigned int val; 72 73 assert(driver_data); 74 assert(driver_data->gicc_base); 75 76 /* Disable secure, non-secure interrupts and disable their bypass */ 77 val = gicc_read_ctlr(driver_data->gicc_base); 78 val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT); 79 val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0; 80 val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1; 81 gicc_write_ctlr(driver_data->gicc_base, val); 82 } 83 84 /******************************************************************************* 85 * Per cpu gic distributor setup which will be done by all cpus after a cold 86 * boot/hotplug. This marks out the secure SPIs and PPIs & enables them. 87 ******************************************************************************/ 88 void gicv2_pcpu_distif_init(void) 89 { 90 assert(driver_data); 91 assert(driver_data->gicd_base); 92 assert(driver_data->g0_interrupt_array); 93 94 gicv2_secure_ppi_sgi_setup(driver_data->gicd_base, 95 driver_data->g0_interrupt_num, 96 driver_data->g0_interrupt_array); 97 } 98 99 /******************************************************************************* 100 * Global gic distributor init which will be done by the primary cpu after a 101 * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It 102 * then enables the secure GIC distributor interface. 103 ******************************************************************************/ 104 void gicv2_distif_init(void) 105 { 106 unsigned int ctlr; 107 108 assert(driver_data); 109 assert(driver_data->gicd_base); 110 assert(driver_data->g0_interrupt_array); 111 112 /* Disable the distributor before going further */ 113 ctlr = gicd_read_ctlr(driver_data->gicd_base); 114 gicd_write_ctlr(driver_data->gicd_base, 115 ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT)); 116 117 /* Set the default attribute of all SPIs */ 118 gicv2_spis_configure_defaults(driver_data->gicd_base); 119 120 /* Configure the G0 SPIs */ 121 gicv2_secure_spis_configure(driver_data->gicd_base, 122 driver_data->g0_interrupt_num, 123 driver_data->g0_interrupt_array); 124 125 /* Re-enable the secure SPIs now that they have been configured */ 126 gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT); 127 } 128 129 /******************************************************************************* 130 * Initialize the ARM GICv2 driver with the provided platform inputs 131 ******************************************************************************/ 132 void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data) 133 { 134 unsigned int gic_version; 135 assert(plat_driver_data); 136 assert(plat_driver_data->gicd_base); 137 assert(plat_driver_data->gicc_base); 138 139 /* 140 * The platform should provide a list of atleast one type of 141 * interrupts 142 */ 143 assert(plat_driver_data->g0_interrupt_array); 144 145 /* 146 * If there are no interrupts of a particular type, then the number of 147 * interrupts of that type should be 0 and vice-versa. 148 */ 149 assert(plat_driver_data->g0_interrupt_array ? 150 plat_driver_data->g0_interrupt_num : 151 plat_driver_data->g0_interrupt_num == 0); 152 153 /* Ensure that this is a GICv2 system */ 154 gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); 155 gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT) 156 & PIDR2_ARCH_REV_MASK; 157 assert(gic_version == ARCH_REV_GICV2); 158 159 driver_data = plat_driver_data; 160 161 INFO("ARM GICv2 driver initialized\n"); 162 } 163 164 /****************************************************************************** 165 * This function returns whether FIQ is enabled in the GIC CPU interface. 166 *****************************************************************************/ 167 unsigned int gicv2_is_fiq_enabled(void) 168 { 169 unsigned int gicc_ctlr; 170 171 assert(driver_data); 172 assert(driver_data->gicc_base); 173 174 gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base); 175 return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1; 176 } 177 178 /******************************************************************************* 179 * This function returns the type of the highest priority pending interrupt at 180 * the GIC cpu interface. The return values can be one of the following : 181 * PENDING_G1_INTID : The interrupt type is non secure Group 1. 182 * 0 - 1019 : The interrupt type is secure Group 0. 183 * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with 184 * sufficient priority to be signaled 185 ******************************************************************************/ 186 unsigned int gicv2_get_pending_interrupt_type(void) 187 { 188 assert(driver_data); 189 assert(driver_data->gicc_base); 190 191 return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; 192 } 193 194 /******************************************************************************* 195 * This function returns the id of the highest priority pending interrupt at 196 * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no 197 * interrupt pending. 198 ******************************************************************************/ 199 unsigned int gicv2_get_pending_interrupt_id(void) 200 { 201 unsigned int id; 202 203 assert(driver_data); 204 assert(driver_data->gicc_base); 205 206 id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; 207 208 /* 209 * Find out which non-secure interrupt it is under the assumption that 210 * the GICC_CTLR.AckCtl bit is 0. 211 */ 212 if (id == PENDING_G1_INTID) 213 id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK; 214 215 return id; 216 } 217 218 /******************************************************************************* 219 * This functions reads the GIC cpu interface Interrupt Acknowledge register 220 * to start handling the pending secure 0 interrupt. It returns the 221 * contents of the IAR. 222 ******************************************************************************/ 223 unsigned int gicv2_acknowledge_interrupt(void) 224 { 225 assert(driver_data); 226 assert(driver_data->gicc_base); 227 228 return gicc_read_IAR(driver_data->gicc_base); 229 } 230 231 /******************************************************************************* 232 * This functions writes the GIC cpu interface End Of Interrupt register with 233 * the passed value to finish handling the active secure group 0 interrupt. 234 ******************************************************************************/ 235 void gicv2_end_of_interrupt(unsigned int id) 236 { 237 assert(driver_data); 238 assert(driver_data->gicc_base); 239 240 gicc_write_EOIR(driver_data->gicc_base, id); 241 } 242 243 /******************************************************************************* 244 * This function returns the type of the interrupt id depending upon the group 245 * this interrupt has been configured under by the interrupt controller i.e. 246 * group0 secure or group1 non secure. It returns zero for Group 0 secure and 247 * one for Group 1 non secure interrupt. 248 ******************************************************************************/ 249 unsigned int gicv2_get_interrupt_group(unsigned int id) 250 { 251 assert(driver_data); 252 assert(driver_data->gicd_base); 253 254 return gicd_get_igroupr(driver_data->gicd_base, id); 255 } 256