1464ce2bbSSoby Mathew /* 2fc529feeSJeenu Viswambharan * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. 3464ce2bbSSoby Mathew * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5464ce2bbSSoby Mathew */ 6464ce2bbSSoby Mathew 7464ce2bbSSoby Mathew #include <arch.h> 8464ce2bbSSoby Mathew #include <arch_helpers.h> 9464ce2bbSSoby Mathew #include <assert.h> 10464ce2bbSSoby Mathew #include <debug.h> 11464ce2bbSSoby Mathew #include <gic_common.h> 12*c639e8ebSJeenu Viswambharan #include <interrupt_props.h> 13e9ec3cecSSoby Mathew #include "../common/gic_common_private.h" 14464ce2bbSSoby Mathew #include "gicv2_private.h" 15464ce2bbSSoby Mathew 16464ce2bbSSoby Mathew /* 17464ce2bbSSoby Mathew * Accessor to read the GIC Distributor ITARGETSR corresponding to the 18464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 19464ce2bbSSoby Mathew */ 20464ce2bbSSoby Mathew unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id) 21464ce2bbSSoby Mathew { 22464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 23464ce2bbSSoby Mathew return mmio_read_32(base + GICD_ITARGETSR + (n << 2)); 24464ce2bbSSoby Mathew } 25464ce2bbSSoby Mathew 26464ce2bbSSoby Mathew /* 27464ce2bbSSoby Mathew * Accessor to read the GIC Distributor CPENDSGIR corresponding to the 28464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 29464ce2bbSSoby Mathew */ 30464ce2bbSSoby Mathew unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id) 31464ce2bbSSoby Mathew { 32464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 33464ce2bbSSoby Mathew return mmio_read_32(base + GICD_CPENDSGIR + (n << 2)); 34464ce2bbSSoby Mathew } 35464ce2bbSSoby Mathew 36464ce2bbSSoby Mathew /* 37464ce2bbSSoby Mathew * Accessor to read the GIC Distributor SPENDSGIR corresponding to the 38464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 39464ce2bbSSoby Mathew */ 40464ce2bbSSoby Mathew unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id) 41464ce2bbSSoby Mathew { 42464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 43464ce2bbSSoby Mathew return mmio_read_32(base + GICD_SPENDSGIR + (n << 2)); 44464ce2bbSSoby Mathew } 45464ce2bbSSoby Mathew 46464ce2bbSSoby Mathew /* 47464ce2bbSSoby Mathew * Accessor to write the GIC Distributor ITARGETSR corresponding to the 48464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 49464ce2bbSSoby Mathew */ 50464ce2bbSSoby Mathew void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val) 51464ce2bbSSoby Mathew { 52464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 53464ce2bbSSoby Mathew mmio_write_32(base + GICD_ITARGETSR + (n << 2), val); 54464ce2bbSSoby Mathew } 55464ce2bbSSoby Mathew 56464ce2bbSSoby Mathew /* 57464ce2bbSSoby Mathew * Accessor to write the GIC Distributor CPENDSGIR corresponding to the 58464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 59464ce2bbSSoby Mathew */ 60464ce2bbSSoby Mathew void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val) 61464ce2bbSSoby Mathew { 62464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 63464ce2bbSSoby Mathew mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val); 64464ce2bbSSoby Mathew } 65464ce2bbSSoby Mathew 66464ce2bbSSoby Mathew /* 67464ce2bbSSoby Mathew * Accessor to write the GIC Distributor SPENDSGIR corresponding to the 68464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 69464ce2bbSSoby Mathew */ 70464ce2bbSSoby Mathew void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) 71464ce2bbSSoby Mathew { 72464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 73464ce2bbSSoby Mathew mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); 74464ce2bbSSoby Mathew } 75464ce2bbSSoby Mathew 76464ce2bbSSoby Mathew /******************************************************************************* 77464ce2bbSSoby Mathew * Get the current CPU bit mask from GICD_ITARGETSR0 78464ce2bbSSoby Mathew ******************************************************************************/ 79464ce2bbSSoby Mathew unsigned int gicv2_get_cpuif_id(uintptr_t base) 80464ce2bbSSoby Mathew { 81464ce2bbSSoby Mathew unsigned int val; 82464ce2bbSSoby Mathew 83464ce2bbSSoby Mathew val = gicd_read_itargetsr(base, 0); 84464ce2bbSSoby Mathew return val & GIC_TARGET_CPU_MASK; 85464ce2bbSSoby Mathew } 86464ce2bbSSoby Mathew 87464ce2bbSSoby Mathew /******************************************************************************* 88464ce2bbSSoby Mathew * Helper function to configure the default attributes of SPIs. 89464ce2bbSSoby Mathew ******************************************************************************/ 90464ce2bbSSoby Mathew void gicv2_spis_configure_defaults(uintptr_t gicd_base) 91464ce2bbSSoby Mathew { 92464ce2bbSSoby Mathew unsigned int index, num_ints; 93464ce2bbSSoby Mathew 94464ce2bbSSoby Mathew num_ints = gicd_read_typer(gicd_base); 95464ce2bbSSoby Mathew num_ints &= TYPER_IT_LINES_NO_MASK; 96464ce2bbSSoby Mathew num_ints = (num_ints + 1) << 5; 97464ce2bbSSoby Mathew 98464ce2bbSSoby Mathew /* 99464ce2bbSSoby Mathew * Treat all SPIs as G1NS by default. The number of interrupts is 100464ce2bbSSoby Mathew * calculated as 32 * (IT_LINES + 1). We do 32 at a time. 101464ce2bbSSoby Mathew */ 102464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 32) 103464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, index, ~0U); 104464ce2bbSSoby Mathew 105464ce2bbSSoby Mathew /* Setup the default SPI priorities doing four at a time */ 106464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 4) 107464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 108464ce2bbSSoby Mathew index, 109464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 110464ce2bbSSoby Mathew 111464ce2bbSSoby Mathew /* Treat all SPIs as level triggered by default, 16 at a time */ 112464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 16) 113464ce2bbSSoby Mathew gicd_write_icfgr(gicd_base, index, 0); 114464ce2bbSSoby Mathew } 115464ce2bbSSoby Mathew 116*c639e8ebSJeenu Viswambharan #if !ERROR_DEPRECATED 117464ce2bbSSoby Mathew /******************************************************************************* 118464ce2bbSSoby Mathew * Helper function to configure secure G0 SPIs. 119464ce2bbSSoby Mathew ******************************************************************************/ 120464ce2bbSSoby Mathew void gicv2_secure_spis_configure(uintptr_t gicd_base, 121464ce2bbSSoby Mathew unsigned int num_ints, 122464ce2bbSSoby Mathew const unsigned int *sec_intr_list) 123464ce2bbSSoby Mathew { 124464ce2bbSSoby Mathew unsigned int index, irq_num; 125464ce2bbSSoby Mathew 126464ce2bbSSoby Mathew /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 127464ce2bbSSoby Mathew assert(num_ints ? (uintptr_t)sec_intr_list : 1); 128464ce2bbSSoby Mathew 129464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 130464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 131464ce2bbSSoby Mathew if (irq_num >= MIN_SPI_ID) { 132464ce2bbSSoby Mathew /* Configure this interrupt as a secure interrupt */ 133464ce2bbSSoby Mathew gicd_clr_igroupr(gicd_base, irq_num); 134464ce2bbSSoby Mathew 135464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 13638a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 137464ce2bbSSoby Mathew irq_num, 138464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 139464ce2bbSSoby Mathew 140464ce2bbSSoby Mathew /* Target the secure interrupts to primary CPU */ 141464ce2bbSSoby Mathew gicd_set_itargetsr(gicd_base, irq_num, 142464ce2bbSSoby Mathew gicv2_get_cpuif_id(gicd_base)); 143464ce2bbSSoby Mathew 144464ce2bbSSoby Mathew /* Enable this interrupt */ 145464ce2bbSSoby Mathew gicd_set_isenabler(gicd_base, irq_num); 146464ce2bbSSoby Mathew } 147464ce2bbSSoby Mathew } 148464ce2bbSSoby Mathew 149464ce2bbSSoby Mathew } 150*c639e8ebSJeenu Viswambharan #endif 151464ce2bbSSoby Mathew 152464ce2bbSSoby Mathew /******************************************************************************* 153*c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SPIs. 154*c639e8ebSJeenu Viswambharan ******************************************************************************/ 155*c639e8ebSJeenu Viswambharan void gicv2_secure_spis_configure_props(uintptr_t gicd_base, 156*c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 157*c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 158*c639e8ebSJeenu Viswambharan { 159*c639e8ebSJeenu Viswambharan unsigned int i; 160*c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 161*c639e8ebSJeenu Viswambharan 162*c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 163*c639e8ebSJeenu Viswambharan assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1); 164*c639e8ebSJeenu Viswambharan 165*c639e8ebSJeenu Viswambharan for (i = 0; i < interrupt_props_num; i++) { 166*c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 167*c639e8ebSJeenu Viswambharan 168*c639e8ebSJeenu Viswambharan if (prop_desc->intr_num < MIN_SPI_ID) 169*c639e8ebSJeenu Viswambharan continue; 170*c639e8ebSJeenu Viswambharan 171*c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 172*c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 173*c639e8ebSJeenu Viswambharan gicd_clr_igroupr(gicd_base, prop_desc->intr_num); 174*c639e8ebSJeenu Viswambharan 175*c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 176*c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 177*c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 178*c639e8ebSJeenu Viswambharan 179*c639e8ebSJeenu Viswambharan /* Target the secure interrupts to primary CPU */ 180*c639e8ebSJeenu Viswambharan gicd_set_itargetsr(gicd_base, prop_desc->intr_num, 181*c639e8ebSJeenu Viswambharan gicv2_get_cpuif_id(gicd_base)); 182*c639e8ebSJeenu Viswambharan 183*c639e8ebSJeenu Viswambharan /* Set interrupt configuration */ 184*c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 185*c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 186*c639e8ebSJeenu Viswambharan 187*c639e8ebSJeenu Viswambharan /* Enable this interrupt */ 188*c639e8ebSJeenu Viswambharan gicd_set_isenabler(gicd_base, prop_desc->intr_num); 189*c639e8ebSJeenu Viswambharan } 190*c639e8ebSJeenu Viswambharan } 191*c639e8ebSJeenu Viswambharan 192*c639e8ebSJeenu Viswambharan #if !ERROR_DEPRECATED 193*c639e8ebSJeenu Viswambharan /******************************************************************************* 194464ce2bbSSoby Mathew * Helper function to configure secure G0 SGIs and PPIs. 195464ce2bbSSoby Mathew ******************************************************************************/ 196464ce2bbSSoby Mathew void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, 197464ce2bbSSoby Mathew unsigned int num_ints, 198464ce2bbSSoby Mathew const unsigned int *sec_intr_list) 199464ce2bbSSoby Mathew { 200464ce2bbSSoby Mathew unsigned int index, irq_num, sec_ppi_sgi_mask = 0; 201464ce2bbSSoby Mathew 202464ce2bbSSoby Mathew /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 203464ce2bbSSoby Mathew assert(num_ints ? (uintptr_t)sec_intr_list : 1); 204464ce2bbSSoby Mathew 205464ce2bbSSoby Mathew /* 206464ce2bbSSoby Mathew * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 207464ce2bbSSoby Mathew * more scalable approach as it avoids clearing the enable bits in the 208464ce2bbSSoby Mathew * GICD_CTLR. 209464ce2bbSSoby Mathew */ 210464ce2bbSSoby Mathew gicd_write_icenabler(gicd_base, 0, ~0); 211464ce2bbSSoby Mathew 212464ce2bbSSoby Mathew /* Setup the default PPI/SGI priorities doing four at a time */ 213464ce2bbSSoby Mathew for (index = 0; index < MIN_SPI_ID; index += 4) 214464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 215464ce2bbSSoby Mathew index, 216464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 217464ce2bbSSoby Mathew 218464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 219464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 220464ce2bbSSoby Mathew if (irq_num < MIN_SPI_ID) { 221464ce2bbSSoby Mathew /* We have an SGI or a PPI. They are Group0 at reset */ 222464ce2bbSSoby Mathew sec_ppi_sgi_mask |= 1U << irq_num; 223464ce2bbSSoby Mathew 224464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 22538a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 226464ce2bbSSoby Mathew irq_num, 227464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 228464ce2bbSSoby Mathew } 229464ce2bbSSoby Mathew } 230464ce2bbSSoby Mathew 231464ce2bbSSoby Mathew /* 232464ce2bbSSoby Mathew * Invert the bitmask to create a mask for non-secure PPIs and 233464ce2bbSSoby Mathew * SGIs. Program the GICD_IGROUPR0 with this bit mask. 234464ce2bbSSoby Mathew */ 235464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 236464ce2bbSSoby Mathew 237464ce2bbSSoby Mathew /* Enable the Group 0 SGIs and PPIs */ 238464ce2bbSSoby Mathew gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 239464ce2bbSSoby Mathew } 240*c639e8ebSJeenu Viswambharan #endif 241*c639e8ebSJeenu Viswambharan 242*c639e8ebSJeenu Viswambharan /******************************************************************************* 243*c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SGIs and PPIs. 244*c639e8ebSJeenu Viswambharan ******************************************************************************/ 245*c639e8ebSJeenu Viswambharan void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, 246*c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 247*c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 248*c639e8ebSJeenu Viswambharan { 249*c639e8ebSJeenu Viswambharan unsigned int i; 250*c639e8ebSJeenu Viswambharan uint32_t sec_ppi_sgi_mask = 0; 251*c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 252*c639e8ebSJeenu Viswambharan 253*c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 254*c639e8ebSJeenu Viswambharan assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1); 255*c639e8ebSJeenu Viswambharan 256*c639e8ebSJeenu Viswambharan /* 257*c639e8ebSJeenu Viswambharan * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 258*c639e8ebSJeenu Viswambharan * more scalable approach as it avoids clearing the enable bits in the 259*c639e8ebSJeenu Viswambharan * GICD_CTLR. 260*c639e8ebSJeenu Viswambharan */ 261*c639e8ebSJeenu Viswambharan gicd_write_icenabler(gicd_base, 0, ~0); 262*c639e8ebSJeenu Viswambharan 263*c639e8ebSJeenu Viswambharan /* Setup the default PPI/SGI priorities doing four at a time */ 264*c639e8ebSJeenu Viswambharan for (i = 0; i < MIN_SPI_ID; i += 4) 265*c639e8ebSJeenu Viswambharan gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); 266*c639e8ebSJeenu Viswambharan 267*c639e8ebSJeenu Viswambharan for (i = 0; i < interrupt_props_num; i++) { 268*c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 269*c639e8ebSJeenu Viswambharan 270*c639e8ebSJeenu Viswambharan if (prop_desc->intr_num >= MIN_SPI_ID) 271*c639e8ebSJeenu Viswambharan continue; 272*c639e8ebSJeenu Viswambharan 273*c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 274*c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 275*c639e8ebSJeenu Viswambharan 276*c639e8ebSJeenu Viswambharan /* 277*c639e8ebSJeenu Viswambharan * Set interrupt configuration for PPIs. Configuration for SGIs 278*c639e8ebSJeenu Viswambharan * are ignored. 279*c639e8ebSJeenu Viswambharan */ 280*c639e8ebSJeenu Viswambharan if ((prop_desc->intr_num >= MIN_PPI_ID) && 281*c639e8ebSJeenu Viswambharan (prop_desc->intr_num < MIN_SPI_ID)) { 282*c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 283*c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 284*c639e8ebSJeenu Viswambharan } 285*c639e8ebSJeenu Viswambharan 286*c639e8ebSJeenu Viswambharan /* We have an SGI or a PPI. They are Group0 at reset */ 287*c639e8ebSJeenu Viswambharan sec_ppi_sgi_mask |= (1u << prop_desc->intr_num); 288*c639e8ebSJeenu Viswambharan 289*c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 290*c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 291*c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 292*c639e8ebSJeenu Viswambharan } 293*c639e8ebSJeenu Viswambharan 294*c639e8ebSJeenu Viswambharan /* 295*c639e8ebSJeenu Viswambharan * Invert the bitmask to create a mask for non-secure PPIs and SGIs. 296*c639e8ebSJeenu Viswambharan * Program the GICD_IGROUPR0 with this bit mask. 297*c639e8ebSJeenu Viswambharan */ 298*c639e8ebSJeenu Viswambharan gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 299*c639e8ebSJeenu Viswambharan 300*c639e8ebSJeenu Viswambharan /* Enable the Group 0 SGIs and PPIs */ 301*c639e8ebSJeenu Viswambharan gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 302*c639e8ebSJeenu Viswambharan } 303