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