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 "../common/gic_common_private.h" 37 #include "gicv2_private.h" 38 39 /* 40 * Accessor to read the GIC Distributor ITARGETSR corresponding to the 41 * interrupt `id`, 4 interrupt IDs at a time. 42 */ 43 unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id) 44 { 45 unsigned n = id >> ITARGETSR_SHIFT; 46 return mmio_read_32(base + GICD_ITARGETSR + (n << 2)); 47 } 48 49 /* 50 * Accessor to read the GIC Distributor CPENDSGIR corresponding to the 51 * interrupt `id`, 4 interrupt IDs at a time. 52 */ 53 unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id) 54 { 55 unsigned n = id >> CPENDSGIR_SHIFT; 56 return mmio_read_32(base + GICD_CPENDSGIR + (n << 2)); 57 } 58 59 /* 60 * Accessor to read the GIC Distributor SPENDSGIR corresponding to the 61 * interrupt `id`, 4 interrupt IDs at a time. 62 */ 63 unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id) 64 { 65 unsigned n = id >> SPENDSGIR_SHIFT; 66 return mmio_read_32(base + GICD_SPENDSGIR + (n << 2)); 67 } 68 69 /* 70 * Accessor to write the GIC Distributor ITARGETSR corresponding to the 71 * interrupt `id`, 4 interrupt IDs at a time. 72 */ 73 void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val) 74 { 75 unsigned n = id >> ITARGETSR_SHIFT; 76 mmio_write_32(base + GICD_ITARGETSR + (n << 2), val); 77 } 78 79 /* 80 * Accessor to write the GIC Distributor CPENDSGIR corresponding to the 81 * interrupt `id`, 4 interrupt IDs at a time. 82 */ 83 void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val) 84 { 85 unsigned n = id >> CPENDSGIR_SHIFT; 86 mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val); 87 } 88 89 /* 90 * Accessor to write the GIC Distributor SPENDSGIR corresponding to the 91 * interrupt `id`, 4 interrupt IDs at a time. 92 */ 93 void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) 94 { 95 unsigned n = id >> SPENDSGIR_SHIFT; 96 mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); 97 } 98 99 /* 100 * Accessor to write the GIC Distributor ITARGETSR corresponding to the 101 * interrupt `id`. 102 */ 103 void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target) 104 { 105 mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK); 106 } 107 108 /******************************************************************************* 109 * Get the current CPU bit mask from GICD_ITARGETSR0 110 ******************************************************************************/ 111 unsigned int gicv2_get_cpuif_id(uintptr_t base) 112 { 113 unsigned int val; 114 115 val = gicd_read_itargetsr(base, 0); 116 return val & GIC_TARGET_CPU_MASK; 117 } 118 119 /******************************************************************************* 120 * Helper function to configure the default attributes of SPIs. 121 ******************************************************************************/ 122 void gicv2_spis_configure_defaults(uintptr_t gicd_base) 123 { 124 unsigned int index, num_ints; 125 126 num_ints = gicd_read_typer(gicd_base); 127 num_ints &= TYPER_IT_LINES_NO_MASK; 128 num_ints = (num_ints + 1) << 5; 129 130 /* 131 * Treat all SPIs as G1NS by default. The number of interrupts is 132 * calculated as 32 * (IT_LINES + 1). We do 32 at a time. 133 */ 134 for (index = MIN_SPI_ID; index < num_ints; index += 32) 135 gicd_write_igroupr(gicd_base, index, ~0U); 136 137 /* Setup the default SPI priorities doing four at a time */ 138 for (index = MIN_SPI_ID; index < num_ints; index += 4) 139 gicd_write_ipriorityr(gicd_base, 140 index, 141 GICD_IPRIORITYR_DEF_VAL); 142 143 /* Treat all SPIs as level triggered by default, 16 at a time */ 144 for (index = MIN_SPI_ID; index < num_ints; index += 16) 145 gicd_write_icfgr(gicd_base, index, 0); 146 } 147 148 /******************************************************************************* 149 * Helper function to configure secure G0 SPIs. 150 ******************************************************************************/ 151 void gicv2_secure_spis_configure(uintptr_t gicd_base, 152 unsigned int num_ints, 153 const unsigned int *sec_intr_list) 154 { 155 unsigned int index, irq_num; 156 157 /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 158 assert(num_ints ? (uintptr_t)sec_intr_list : 1); 159 160 for (index = 0; index < num_ints; index++) { 161 irq_num = sec_intr_list[index]; 162 if (irq_num >= MIN_SPI_ID) { 163 /* Configure this interrupt as a secure interrupt */ 164 gicd_clr_igroupr(gicd_base, irq_num); 165 166 /* Set the priority of this interrupt */ 167 gicd_set_ipriorityr(gicd_base, 168 irq_num, 169 GIC_HIGHEST_SEC_PRIORITY); 170 171 /* Target the secure interrupts to primary CPU */ 172 gicd_set_itargetsr(gicd_base, irq_num, 173 gicv2_get_cpuif_id(gicd_base)); 174 175 /* Enable this interrupt */ 176 gicd_set_isenabler(gicd_base, irq_num); 177 } 178 } 179 180 } 181 182 /******************************************************************************* 183 * Helper function to configure secure G0 SGIs and PPIs. 184 ******************************************************************************/ 185 void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, 186 unsigned int num_ints, 187 const unsigned int *sec_intr_list) 188 { 189 unsigned int index, irq_num, sec_ppi_sgi_mask = 0; 190 191 /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 192 assert(num_ints ? (uintptr_t)sec_intr_list : 1); 193 194 /* 195 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 196 * more scalable approach as it avoids clearing the enable bits in the 197 * GICD_CTLR. 198 */ 199 gicd_write_icenabler(gicd_base, 0, ~0); 200 201 /* Setup the default PPI/SGI priorities doing four at a time */ 202 for (index = 0; index < MIN_SPI_ID; index += 4) 203 gicd_write_ipriorityr(gicd_base, 204 index, 205 GICD_IPRIORITYR_DEF_VAL); 206 207 for (index = 0; index < num_ints; index++) { 208 irq_num = sec_intr_list[index]; 209 if (irq_num < MIN_SPI_ID) { 210 /* We have an SGI or a PPI. They are Group0 at reset */ 211 sec_ppi_sgi_mask |= 1U << irq_num; 212 213 /* Set the priority of this interrupt */ 214 gicd_set_ipriorityr(gicd_base, 215 irq_num, 216 GIC_HIGHEST_SEC_PRIORITY); 217 } 218 } 219 220 /* 221 * Invert the bitmask to create a mask for non-secure PPIs and 222 * SGIs. Program the GICD_IGROUPR0 with this bit mask. 223 */ 224 gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 225 226 /* Enable the Group 0 SGIs and PPIs */ 227 gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 228 } 229