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