1464ce2bbSSoby Mathew /* 2e6937287SZelalem * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. 3464ce2bbSSoby Mathew * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5464ce2bbSSoby Mathew */ 6464ce2bbSSoby Mathew 709d40e0eSAntonio Nino Diaz #include <assert.h> 809d40e0eSAntonio Nino Diaz 9464ce2bbSSoby Mathew #include <arch.h> 1009d40e0eSAntonio Nino Diaz #include <common/debug.h> 1109d40e0eSAntonio Nino Diaz #include <common/interrupt_props.h> 1209d40e0eSAntonio Nino Diaz #include <drivers/arm/gic_common.h> 1309d40e0eSAntonio Nino Diaz #include <drivers/arm/gicv2.h> 1409d40e0eSAntonio Nino Diaz 15e9ec3cecSSoby Mathew #include "../common/gic_common_private.h" 16464ce2bbSSoby Mathew #include "gicv2_private.h" 17464ce2bbSSoby Mathew 18464ce2bbSSoby Mathew /* 19464ce2bbSSoby Mathew * Accessor to read the GIC Distributor ITARGETSR corresponding to the 20464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 21464ce2bbSSoby Mathew */ 22464ce2bbSSoby Mathew unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id) 23464ce2bbSSoby Mathew { 24464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 25464ce2bbSSoby Mathew return mmio_read_32(base + GICD_ITARGETSR + (n << 2)); 26464ce2bbSSoby Mathew } 27464ce2bbSSoby Mathew 28464ce2bbSSoby Mathew /* 29464ce2bbSSoby Mathew * Accessor to read the GIC Distributor CPENDSGIR corresponding to the 30464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 31464ce2bbSSoby Mathew */ 32464ce2bbSSoby Mathew unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id) 33464ce2bbSSoby Mathew { 34464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 35464ce2bbSSoby Mathew return mmio_read_32(base + GICD_CPENDSGIR + (n << 2)); 36464ce2bbSSoby Mathew } 37464ce2bbSSoby Mathew 38464ce2bbSSoby Mathew /* 39464ce2bbSSoby Mathew * Accessor to read the GIC Distributor SPENDSGIR corresponding to the 40464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 41464ce2bbSSoby Mathew */ 42464ce2bbSSoby Mathew unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id) 43464ce2bbSSoby Mathew { 44464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 45464ce2bbSSoby Mathew return mmio_read_32(base + GICD_SPENDSGIR + (n << 2)); 46464ce2bbSSoby Mathew } 47464ce2bbSSoby Mathew 48464ce2bbSSoby Mathew /* 49464ce2bbSSoby Mathew * Accessor to write the GIC Distributor ITARGETSR corresponding to the 50464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 51464ce2bbSSoby Mathew */ 52464ce2bbSSoby Mathew void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val) 53464ce2bbSSoby Mathew { 54464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 55464ce2bbSSoby Mathew mmio_write_32(base + GICD_ITARGETSR + (n << 2), val); 56464ce2bbSSoby Mathew } 57464ce2bbSSoby Mathew 58464ce2bbSSoby Mathew /* 59464ce2bbSSoby Mathew * Accessor to write the GIC Distributor CPENDSGIR corresponding to the 60464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 61464ce2bbSSoby Mathew */ 62464ce2bbSSoby Mathew void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val) 63464ce2bbSSoby Mathew { 64464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 65464ce2bbSSoby Mathew mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val); 66464ce2bbSSoby Mathew } 67464ce2bbSSoby Mathew 68464ce2bbSSoby Mathew /* 69464ce2bbSSoby Mathew * Accessor to write the GIC Distributor SPENDSGIR corresponding to the 70464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 71464ce2bbSSoby Mathew */ 72464ce2bbSSoby Mathew void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) 73464ce2bbSSoby Mathew { 74464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 75464ce2bbSSoby Mathew mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); 76464ce2bbSSoby Mathew } 77464ce2bbSSoby Mathew 78464ce2bbSSoby Mathew /******************************************************************************* 79464ce2bbSSoby Mathew * Get the current CPU bit mask from GICD_ITARGETSR0 80464ce2bbSSoby Mathew ******************************************************************************/ 81464ce2bbSSoby Mathew unsigned int gicv2_get_cpuif_id(uintptr_t base) 82464ce2bbSSoby Mathew { 83464ce2bbSSoby Mathew unsigned int val; 84464ce2bbSSoby Mathew 85464ce2bbSSoby Mathew val = gicd_read_itargetsr(base, 0); 86464ce2bbSSoby Mathew return val & GIC_TARGET_CPU_MASK; 87464ce2bbSSoby Mathew } 88464ce2bbSSoby Mathew 89464ce2bbSSoby Mathew /******************************************************************************* 90464ce2bbSSoby Mathew * Helper function to configure the default attributes of SPIs. 91464ce2bbSSoby Mathew ******************************************************************************/ 92464ce2bbSSoby Mathew void gicv2_spis_configure_defaults(uintptr_t gicd_base) 93464ce2bbSSoby Mathew { 94464ce2bbSSoby Mathew unsigned int index, num_ints; 95464ce2bbSSoby Mathew 96464ce2bbSSoby Mathew num_ints = gicd_read_typer(gicd_base); 97464ce2bbSSoby Mathew num_ints &= TYPER_IT_LINES_NO_MASK; 983fea9c8bSAntonio Nino Diaz num_ints = (num_ints + 1U) << 5; 99464ce2bbSSoby Mathew 100464ce2bbSSoby Mathew /* 101464ce2bbSSoby Mathew * Treat all SPIs as G1NS by default. The number of interrupts is 102464ce2bbSSoby Mathew * calculated as 32 * (IT_LINES + 1). We do 32 at a time. 103464ce2bbSSoby Mathew */ 104*03c6bb0eSMaheedhar Bollapalli for (index = MIN_SPI_ID; index < num_ints; index += 32U) { 105464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, index, ~0U); 106*03c6bb0eSMaheedhar Bollapalli } 107464ce2bbSSoby Mathew /* Setup the default SPI priorities doing four at a time */ 108*03c6bb0eSMaheedhar Bollapalli for (index = MIN_SPI_ID; index < num_ints; index += 4U) { 109464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 110464ce2bbSSoby Mathew index, 111464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 112*03c6bb0eSMaheedhar Bollapalli } 113464ce2bbSSoby Mathew /* Treat all SPIs as level triggered by default, 16 at a time */ 114*03c6bb0eSMaheedhar Bollapalli for (index = MIN_SPI_ID; index < num_ints; index += 16U) { 1153fea9c8bSAntonio Nino Diaz gicd_write_icfgr(gicd_base, index, 0U); 116464ce2bbSSoby Mathew } 117*03c6bb0eSMaheedhar Bollapalli } 118464ce2bbSSoby Mathew 119464ce2bbSSoby Mathew /******************************************************************************* 120c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SPIs. 121c639e8ebSJeenu Viswambharan ******************************************************************************/ 122c639e8ebSJeenu Viswambharan void gicv2_secure_spis_configure_props(uintptr_t gicd_base, 123c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 124c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 125c639e8ebSJeenu Viswambharan { 126c639e8ebSJeenu Viswambharan unsigned int i; 127c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 128c639e8ebSJeenu Viswambharan 129c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 130*03c6bb0eSMaheedhar Bollapalli if (interrupt_props_num != 0U) { 1313fea9c8bSAntonio Nino Diaz assert(interrupt_props != NULL); 132*03c6bb0eSMaheedhar Bollapalli } 133c639e8ebSJeenu Viswambharan for (i = 0; i < interrupt_props_num; i++) { 134c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 135c639e8ebSJeenu Viswambharan 136*03c6bb0eSMaheedhar Bollapalli if (prop_desc->intr_num < MIN_SPI_ID) { 137c639e8ebSJeenu Viswambharan continue; 138*03c6bb0eSMaheedhar Bollapalli } 139c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 140c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 141c639e8ebSJeenu Viswambharan gicd_clr_igroupr(gicd_base, prop_desc->intr_num); 142c639e8ebSJeenu Viswambharan 143c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 144c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 145c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 146c639e8ebSJeenu Viswambharan 147c639e8ebSJeenu Viswambharan /* Target the secure interrupts to primary CPU */ 148c639e8ebSJeenu Viswambharan gicd_set_itargetsr(gicd_base, prop_desc->intr_num, 149c639e8ebSJeenu Viswambharan gicv2_get_cpuif_id(gicd_base)); 150c639e8ebSJeenu Viswambharan 151c639e8ebSJeenu Viswambharan /* Set interrupt configuration */ 152c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 153c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 154c639e8ebSJeenu Viswambharan 155c639e8ebSJeenu Viswambharan /* Enable this interrupt */ 156c639e8ebSJeenu Viswambharan gicd_set_isenabler(gicd_base, prop_desc->intr_num); 157c639e8ebSJeenu Viswambharan } 158c639e8ebSJeenu Viswambharan } 159c639e8ebSJeenu Viswambharan 160c639e8ebSJeenu Viswambharan /******************************************************************************* 161c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SGIs and PPIs. 162c639e8ebSJeenu Viswambharan ******************************************************************************/ 163c639e8ebSJeenu Viswambharan void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, 164c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 165c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 166c639e8ebSJeenu Viswambharan { 167c639e8ebSJeenu Viswambharan unsigned int i; 168c639e8ebSJeenu Viswambharan uint32_t sec_ppi_sgi_mask = 0; 169c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 170c639e8ebSJeenu Viswambharan 171c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 172*03c6bb0eSMaheedhar Bollapalli if (interrupt_props_num != 0U) { 1733fea9c8bSAntonio Nino Diaz assert(interrupt_props != NULL); 174*03c6bb0eSMaheedhar Bollapalli } 175c639e8ebSJeenu Viswambharan /* 176c639e8ebSJeenu Viswambharan * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 177c639e8ebSJeenu Viswambharan * more scalable approach as it avoids clearing the enable bits in the 178c639e8ebSJeenu Viswambharan * GICD_CTLR. 179c639e8ebSJeenu Viswambharan */ 1803fea9c8bSAntonio Nino Diaz gicd_write_icenabler(gicd_base, 0U, ~0U); 181c639e8ebSJeenu Viswambharan 182c639e8ebSJeenu Viswambharan /* Setup the default PPI/SGI priorities doing four at a time */ 183*03c6bb0eSMaheedhar Bollapalli for (i = 0U; i < MIN_SPI_ID; i += 4U) { 184c639e8ebSJeenu Viswambharan gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); 185*03c6bb0eSMaheedhar Bollapalli } 1863fea9c8bSAntonio Nino Diaz for (i = 0U; i < interrupt_props_num; i++) { 187c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 188c639e8ebSJeenu Viswambharan 189*03c6bb0eSMaheedhar Bollapalli if (prop_desc->intr_num >= MIN_SPI_ID) { 190c639e8ebSJeenu Viswambharan continue; 191*03c6bb0eSMaheedhar Bollapalli } 192c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 193c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 194c639e8ebSJeenu Viswambharan 195c639e8ebSJeenu Viswambharan /* 196c639e8ebSJeenu Viswambharan * Set interrupt configuration for PPIs. Configuration for SGIs 197c639e8ebSJeenu Viswambharan * are ignored. 198c639e8ebSJeenu Viswambharan */ 199c639e8ebSJeenu Viswambharan if ((prop_desc->intr_num >= MIN_PPI_ID) && 200c639e8ebSJeenu Viswambharan (prop_desc->intr_num < MIN_SPI_ID)) { 201c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 202c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 203c639e8ebSJeenu Viswambharan } 204c639e8ebSJeenu Viswambharan 205c639e8ebSJeenu Viswambharan /* We have an SGI or a PPI. They are Group0 at reset */ 206c639e8ebSJeenu Viswambharan sec_ppi_sgi_mask |= (1u << prop_desc->intr_num); 207c639e8ebSJeenu Viswambharan 208c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 209c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 210c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 211c639e8ebSJeenu Viswambharan } 212c639e8ebSJeenu Viswambharan 213c639e8ebSJeenu Viswambharan /* 214c639e8ebSJeenu Viswambharan * Invert the bitmask to create a mask for non-secure PPIs and SGIs. 215c639e8ebSJeenu Viswambharan * Program the GICD_IGROUPR0 with this bit mask. 216c639e8ebSJeenu Viswambharan */ 217c639e8ebSJeenu Viswambharan gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 218c639e8ebSJeenu Viswambharan 219c639e8ebSJeenu Viswambharan /* Enable the Group 0 SGIs and PPIs */ 220c639e8ebSJeenu Viswambharan gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 221c639e8ebSJeenu Viswambharan } 222