1464ce2bbSSoby Mathew /* 27fabe1a8SRoberto 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> 127fabe1a8SRoberto 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; 97*3fea9c8bSAntonio Nino Diaz num_ints = (num_ints + 1U) << 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 */ 103*3fea9c8bSAntonio Nino Diaz for (index = MIN_SPI_ID; index < num_ints; index += 32U) 104464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, index, ~0U); 105464ce2bbSSoby Mathew 106464ce2bbSSoby Mathew /* Setup the default SPI priorities doing four at a time */ 107*3fea9c8bSAntonio Nino Diaz for (index = MIN_SPI_ID; index < num_ints; index += 4U) 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 */ 113*3fea9c8bSAntonio Nino Diaz for (index = MIN_SPI_ID; index < num_ints; index += 16U) 114*3fea9c8bSAntonio Nino Diaz gicd_write_icfgr(gicd_base, index, 0U); 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 */ 128*3fea9c8bSAntonio Nino Diaz if (num_ints != 0U) 129*3fea9c8bSAntonio Nino Diaz assert(sec_intr_list != NULL); 130464ce2bbSSoby Mathew 131464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 132464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 133464ce2bbSSoby Mathew if (irq_num >= MIN_SPI_ID) { 134464ce2bbSSoby Mathew /* Configure this interrupt as a secure interrupt */ 135464ce2bbSSoby Mathew gicd_clr_igroupr(gicd_base, irq_num); 136464ce2bbSSoby Mathew 137464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 13838a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 139464ce2bbSSoby Mathew irq_num, 140464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 141464ce2bbSSoby Mathew 142464ce2bbSSoby Mathew /* Target the secure interrupts to primary CPU */ 143464ce2bbSSoby Mathew gicd_set_itargetsr(gicd_base, irq_num, 144464ce2bbSSoby Mathew gicv2_get_cpuif_id(gicd_base)); 145464ce2bbSSoby Mathew 146464ce2bbSSoby Mathew /* Enable this interrupt */ 147464ce2bbSSoby Mathew gicd_set_isenabler(gicd_base, irq_num); 148464ce2bbSSoby Mathew } 149464ce2bbSSoby Mathew } 150464ce2bbSSoby Mathew 151464ce2bbSSoby Mathew } 152c639e8ebSJeenu Viswambharan #endif 153464ce2bbSSoby Mathew 154464ce2bbSSoby Mathew /******************************************************************************* 155c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SPIs. 156c639e8ebSJeenu Viswambharan ******************************************************************************/ 157c639e8ebSJeenu Viswambharan void gicv2_secure_spis_configure_props(uintptr_t gicd_base, 158c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 159c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 160c639e8ebSJeenu Viswambharan { 161c639e8ebSJeenu Viswambharan unsigned int i; 162c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 163c639e8ebSJeenu Viswambharan 164c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 165*3fea9c8bSAntonio Nino Diaz if (interrupt_props_num != 0U) 166*3fea9c8bSAntonio Nino Diaz assert(interrupt_props != NULL); 167c639e8ebSJeenu Viswambharan 168c639e8ebSJeenu Viswambharan for (i = 0; i < interrupt_props_num; i++) { 169c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 170c639e8ebSJeenu Viswambharan 171c639e8ebSJeenu Viswambharan if (prop_desc->intr_num < MIN_SPI_ID) 172c639e8ebSJeenu Viswambharan continue; 173c639e8ebSJeenu Viswambharan 174c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 175c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 176c639e8ebSJeenu Viswambharan gicd_clr_igroupr(gicd_base, prop_desc->intr_num); 177c639e8ebSJeenu Viswambharan 178c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 179c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 180c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 181c639e8ebSJeenu Viswambharan 182c639e8ebSJeenu Viswambharan /* Target the secure interrupts to primary CPU */ 183c639e8ebSJeenu Viswambharan gicd_set_itargetsr(gicd_base, prop_desc->intr_num, 184c639e8ebSJeenu Viswambharan gicv2_get_cpuif_id(gicd_base)); 185c639e8ebSJeenu Viswambharan 186c639e8ebSJeenu Viswambharan /* Set interrupt configuration */ 187c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 188c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 189c639e8ebSJeenu Viswambharan 190c639e8ebSJeenu Viswambharan /* Enable this interrupt */ 191c639e8ebSJeenu Viswambharan gicd_set_isenabler(gicd_base, prop_desc->intr_num); 192c639e8ebSJeenu Viswambharan } 193c639e8ebSJeenu Viswambharan } 194c639e8ebSJeenu Viswambharan 195c639e8ebSJeenu Viswambharan #if !ERROR_DEPRECATED 196c639e8ebSJeenu Viswambharan /******************************************************************************* 197464ce2bbSSoby Mathew * Helper function to configure secure G0 SGIs and PPIs. 198464ce2bbSSoby Mathew ******************************************************************************/ 199464ce2bbSSoby Mathew void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, 200464ce2bbSSoby Mathew unsigned int num_ints, 201464ce2bbSSoby Mathew const unsigned int *sec_intr_list) 202464ce2bbSSoby Mathew { 203464ce2bbSSoby Mathew unsigned int index, irq_num, sec_ppi_sgi_mask = 0; 204464ce2bbSSoby Mathew 205464ce2bbSSoby Mathew /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 206464ce2bbSSoby Mathew assert(num_ints ? (uintptr_t)sec_intr_list : 1); 207464ce2bbSSoby Mathew 208464ce2bbSSoby Mathew /* 209464ce2bbSSoby Mathew * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 210464ce2bbSSoby Mathew * more scalable approach as it avoids clearing the enable bits in the 211464ce2bbSSoby Mathew * GICD_CTLR. 212464ce2bbSSoby Mathew */ 213464ce2bbSSoby Mathew gicd_write_icenabler(gicd_base, 0, ~0); 214464ce2bbSSoby Mathew 215464ce2bbSSoby Mathew /* Setup the default PPI/SGI priorities doing four at a time */ 216464ce2bbSSoby Mathew for (index = 0; index < MIN_SPI_ID; index += 4) 217464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 218464ce2bbSSoby Mathew index, 219464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 220464ce2bbSSoby Mathew 221464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 222464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 223464ce2bbSSoby Mathew if (irq_num < MIN_SPI_ID) { 224464ce2bbSSoby Mathew /* We have an SGI or a PPI. They are Group0 at reset */ 225464ce2bbSSoby Mathew sec_ppi_sgi_mask |= 1U << irq_num; 226464ce2bbSSoby Mathew 227464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 22838a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 229464ce2bbSSoby Mathew irq_num, 230464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 231464ce2bbSSoby Mathew } 232464ce2bbSSoby Mathew } 233464ce2bbSSoby Mathew 234464ce2bbSSoby Mathew /* 235464ce2bbSSoby Mathew * Invert the bitmask to create a mask for non-secure PPIs and 236464ce2bbSSoby Mathew * SGIs. Program the GICD_IGROUPR0 with this bit mask. 237464ce2bbSSoby Mathew */ 238464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 239464ce2bbSSoby Mathew 240464ce2bbSSoby Mathew /* Enable the Group 0 SGIs and PPIs */ 241464ce2bbSSoby Mathew gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 242464ce2bbSSoby Mathew } 243c639e8ebSJeenu Viswambharan #endif 244c639e8ebSJeenu Viswambharan 245c639e8ebSJeenu Viswambharan /******************************************************************************* 246c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SGIs and PPIs. 247c639e8ebSJeenu Viswambharan ******************************************************************************/ 248c639e8ebSJeenu Viswambharan void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, 249c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 250c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 251c639e8ebSJeenu Viswambharan { 252c639e8ebSJeenu Viswambharan unsigned int i; 253c639e8ebSJeenu Viswambharan uint32_t sec_ppi_sgi_mask = 0; 254c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 255c639e8ebSJeenu Viswambharan 256c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 257*3fea9c8bSAntonio Nino Diaz if (interrupt_props_num != 0U) 258*3fea9c8bSAntonio Nino Diaz assert(interrupt_props != NULL); 259c639e8ebSJeenu Viswambharan 260c639e8ebSJeenu Viswambharan /* 261c639e8ebSJeenu Viswambharan * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 262c639e8ebSJeenu Viswambharan * more scalable approach as it avoids clearing the enable bits in the 263c639e8ebSJeenu Viswambharan * GICD_CTLR. 264c639e8ebSJeenu Viswambharan */ 265*3fea9c8bSAntonio Nino Diaz gicd_write_icenabler(gicd_base, 0U, ~0U); 266c639e8ebSJeenu Viswambharan 267c639e8ebSJeenu Viswambharan /* Setup the default PPI/SGI priorities doing four at a time */ 268*3fea9c8bSAntonio Nino Diaz for (i = 0U; i < MIN_SPI_ID; i += 4U) 269c639e8ebSJeenu Viswambharan gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); 270c639e8ebSJeenu Viswambharan 271*3fea9c8bSAntonio Nino Diaz for (i = 0U; i < interrupt_props_num; i++) { 272c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 273c639e8ebSJeenu Viswambharan 274c639e8ebSJeenu Viswambharan if (prop_desc->intr_num >= MIN_SPI_ID) 275c639e8ebSJeenu Viswambharan continue; 276c639e8ebSJeenu Viswambharan 277c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 278c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 279c639e8ebSJeenu Viswambharan 280c639e8ebSJeenu Viswambharan /* 281c639e8ebSJeenu Viswambharan * Set interrupt configuration for PPIs. Configuration for SGIs 282c639e8ebSJeenu Viswambharan * are ignored. 283c639e8ebSJeenu Viswambharan */ 284c639e8ebSJeenu Viswambharan if ((prop_desc->intr_num >= MIN_PPI_ID) && 285c639e8ebSJeenu Viswambharan (prop_desc->intr_num < MIN_SPI_ID)) { 286c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 287c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 288c639e8ebSJeenu Viswambharan } 289c639e8ebSJeenu Viswambharan 290c639e8ebSJeenu Viswambharan /* We have an SGI or a PPI. They are Group0 at reset */ 291c639e8ebSJeenu Viswambharan sec_ppi_sgi_mask |= (1u << prop_desc->intr_num); 292c639e8ebSJeenu Viswambharan 293c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 294c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 295c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 296c639e8ebSJeenu Viswambharan } 297c639e8ebSJeenu Viswambharan 298c639e8ebSJeenu Viswambharan /* 299c639e8ebSJeenu Viswambharan * Invert the bitmask to create a mask for non-secure PPIs and SGIs. 300c639e8ebSJeenu Viswambharan * Program the GICD_IGROUPR0 with this bit mask. 301c639e8ebSJeenu Viswambharan */ 302c639e8ebSJeenu Viswambharan gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 303c639e8ebSJeenu Viswambharan 304c639e8ebSJeenu Viswambharan /* Enable the Group 0 SGIs and PPIs */ 305c639e8ebSJeenu Viswambharan gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 306c639e8ebSJeenu Viswambharan } 307