1464ce2bbSSoby Mathew /* 2*e6937287SZelalem * 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 */ 1043fea9c8bSAntonio Nino Diaz for (index = MIN_SPI_ID; index < num_ints; index += 32U) 105464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, index, ~0U); 106464ce2bbSSoby Mathew 107464ce2bbSSoby Mathew /* Setup the default SPI priorities doing four at a time */ 1083fea9c8bSAntonio Nino Diaz 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); 112464ce2bbSSoby Mathew 113464ce2bbSSoby Mathew /* Treat all SPIs as level triggered by default, 16 at a time */ 1143fea9c8bSAntonio Nino Diaz for (index = MIN_SPI_ID; index < num_ints; index += 16U) 1153fea9c8bSAntonio Nino Diaz gicd_write_icfgr(gicd_base, index, 0U); 116464ce2bbSSoby Mathew } 117464ce2bbSSoby Mathew 118464ce2bbSSoby Mathew /******************************************************************************* 119c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SPIs. 120c639e8ebSJeenu Viswambharan ******************************************************************************/ 121c639e8ebSJeenu Viswambharan void gicv2_secure_spis_configure_props(uintptr_t gicd_base, 122c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 123c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 124c639e8ebSJeenu Viswambharan { 125c639e8ebSJeenu Viswambharan unsigned int i; 126c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 127c639e8ebSJeenu Viswambharan 128c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 1293fea9c8bSAntonio Nino Diaz if (interrupt_props_num != 0U) 1303fea9c8bSAntonio Nino Diaz assert(interrupt_props != NULL); 131c639e8ebSJeenu Viswambharan 132c639e8ebSJeenu Viswambharan for (i = 0; i < interrupt_props_num; i++) { 133c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 134c639e8ebSJeenu Viswambharan 135c639e8ebSJeenu Viswambharan if (prop_desc->intr_num < MIN_SPI_ID) 136c639e8ebSJeenu Viswambharan continue; 137c639e8ebSJeenu Viswambharan 138c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 139c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 140c639e8ebSJeenu Viswambharan gicd_clr_igroupr(gicd_base, prop_desc->intr_num); 141c639e8ebSJeenu Viswambharan 142c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 143c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 144c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 145c639e8ebSJeenu Viswambharan 146c639e8ebSJeenu Viswambharan /* Target the secure interrupts to primary CPU */ 147c639e8ebSJeenu Viswambharan gicd_set_itargetsr(gicd_base, prop_desc->intr_num, 148c639e8ebSJeenu Viswambharan gicv2_get_cpuif_id(gicd_base)); 149c639e8ebSJeenu Viswambharan 150c639e8ebSJeenu Viswambharan /* Set interrupt configuration */ 151c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 152c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 153c639e8ebSJeenu Viswambharan 154c639e8ebSJeenu Viswambharan /* Enable this interrupt */ 155c639e8ebSJeenu Viswambharan gicd_set_isenabler(gicd_base, prop_desc->intr_num); 156c639e8ebSJeenu Viswambharan } 157c639e8ebSJeenu Viswambharan } 158c639e8ebSJeenu Viswambharan 159c639e8ebSJeenu Viswambharan /******************************************************************************* 160c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SGIs and PPIs. 161c639e8ebSJeenu Viswambharan ******************************************************************************/ 162c639e8ebSJeenu Viswambharan void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, 163c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 164c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 165c639e8ebSJeenu Viswambharan { 166c639e8ebSJeenu Viswambharan unsigned int i; 167c639e8ebSJeenu Viswambharan uint32_t sec_ppi_sgi_mask = 0; 168c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 169c639e8ebSJeenu Viswambharan 170c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 1713fea9c8bSAntonio Nino Diaz if (interrupt_props_num != 0U) 1723fea9c8bSAntonio Nino Diaz assert(interrupt_props != NULL); 173c639e8ebSJeenu Viswambharan 174c639e8ebSJeenu Viswambharan /* 175c639e8ebSJeenu Viswambharan * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 176c639e8ebSJeenu Viswambharan * more scalable approach as it avoids clearing the enable bits in the 177c639e8ebSJeenu Viswambharan * GICD_CTLR. 178c639e8ebSJeenu Viswambharan */ 1793fea9c8bSAntonio Nino Diaz gicd_write_icenabler(gicd_base, 0U, ~0U); 180c639e8ebSJeenu Viswambharan 181c639e8ebSJeenu Viswambharan /* Setup the default PPI/SGI priorities doing four at a time */ 1823fea9c8bSAntonio Nino Diaz for (i = 0U; i < MIN_SPI_ID; i += 4U) 183c639e8ebSJeenu Viswambharan gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); 184c639e8ebSJeenu Viswambharan 1853fea9c8bSAntonio Nino Diaz for (i = 0U; i < interrupt_props_num; i++) { 186c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 187c639e8ebSJeenu Viswambharan 188c639e8ebSJeenu Viswambharan if (prop_desc->intr_num >= MIN_SPI_ID) 189c639e8ebSJeenu Viswambharan continue; 190c639e8ebSJeenu Viswambharan 191c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 192c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 193c639e8ebSJeenu Viswambharan 194c639e8ebSJeenu Viswambharan /* 195c639e8ebSJeenu Viswambharan * Set interrupt configuration for PPIs. Configuration for SGIs 196c639e8ebSJeenu Viswambharan * are ignored. 197c639e8ebSJeenu Viswambharan */ 198c639e8ebSJeenu Viswambharan if ((prop_desc->intr_num >= MIN_PPI_ID) && 199c639e8ebSJeenu Viswambharan (prop_desc->intr_num < MIN_SPI_ID)) { 200c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 201c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 202c639e8ebSJeenu Viswambharan } 203c639e8ebSJeenu Viswambharan 204c639e8ebSJeenu Viswambharan /* We have an SGI or a PPI. They are Group0 at reset */ 205c639e8ebSJeenu Viswambharan sec_ppi_sgi_mask |= (1u << prop_desc->intr_num); 206c639e8ebSJeenu Viswambharan 207c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 208c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 209c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 210c639e8ebSJeenu Viswambharan } 211c639e8ebSJeenu Viswambharan 212c639e8ebSJeenu Viswambharan /* 213c639e8ebSJeenu Viswambharan * Invert the bitmask to create a mask for non-secure PPIs and SGIs. 214c639e8ebSJeenu Viswambharan * Program the GICD_IGROUPR0 with this bit mask. 215c639e8ebSJeenu Viswambharan */ 216c639e8ebSJeenu Viswambharan gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 217c639e8ebSJeenu Viswambharan 218c639e8ebSJeenu Viswambharan /* Enable the Group 0 SGIs and PPIs */ 219c639e8ebSJeenu Viswambharan gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 220c639e8ebSJeenu Viswambharan } 221