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> 14*bec4a2c9SNithin G #include <lib/utils_def.h> 1509d40e0eSAntonio Nino Diaz 16e9ec3cecSSoby Mathew #include "../common/gic_common_private.h" 17464ce2bbSSoby Mathew #include "gicv2_private.h" 18464ce2bbSSoby Mathew 19464ce2bbSSoby Mathew /* 20464ce2bbSSoby Mathew * Accessor to read the GIC Distributor ITARGETSR corresponding to the 21464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 22464ce2bbSSoby Mathew */ 23464ce2bbSSoby Mathew unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id) 24464ce2bbSSoby Mathew { 25464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 26464ce2bbSSoby Mathew return mmio_read_32(base + GICD_ITARGETSR + (n << 2)); 27464ce2bbSSoby Mathew } 28464ce2bbSSoby Mathew 29464ce2bbSSoby Mathew /* 30464ce2bbSSoby Mathew * Accessor to read the GIC Distributor CPENDSGIR corresponding to the 31464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 32464ce2bbSSoby Mathew */ 33464ce2bbSSoby Mathew unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id) 34464ce2bbSSoby Mathew { 35464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 36464ce2bbSSoby Mathew return mmio_read_32(base + GICD_CPENDSGIR + (n << 2)); 37464ce2bbSSoby Mathew } 38464ce2bbSSoby Mathew 39464ce2bbSSoby Mathew /* 40464ce2bbSSoby Mathew * Accessor to read the GIC Distributor SPENDSGIR corresponding to the 41464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 42464ce2bbSSoby Mathew */ 43464ce2bbSSoby Mathew unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id) 44464ce2bbSSoby Mathew { 45464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 46464ce2bbSSoby Mathew return mmio_read_32(base + GICD_SPENDSGIR + (n << 2)); 47464ce2bbSSoby Mathew } 48464ce2bbSSoby Mathew 49464ce2bbSSoby Mathew /* 50464ce2bbSSoby Mathew * Accessor to write the GIC Distributor ITARGETSR corresponding to the 51464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 52464ce2bbSSoby Mathew */ 53464ce2bbSSoby Mathew void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val) 54464ce2bbSSoby Mathew { 55464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 56464ce2bbSSoby Mathew mmio_write_32(base + GICD_ITARGETSR + (n << 2), val); 57464ce2bbSSoby Mathew } 58464ce2bbSSoby Mathew 59464ce2bbSSoby Mathew /* 60464ce2bbSSoby Mathew * Accessor to write the GIC Distributor CPENDSGIR corresponding to the 61464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 62464ce2bbSSoby Mathew */ 63464ce2bbSSoby Mathew void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val) 64464ce2bbSSoby Mathew { 65464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 66464ce2bbSSoby Mathew mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val); 67464ce2bbSSoby Mathew } 68464ce2bbSSoby Mathew 69464ce2bbSSoby Mathew /* 70464ce2bbSSoby Mathew * Accessor to write the GIC Distributor SPENDSGIR corresponding to the 71464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 72464ce2bbSSoby Mathew */ 73464ce2bbSSoby Mathew void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) 74464ce2bbSSoby Mathew { 75464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 76464ce2bbSSoby Mathew mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); 77464ce2bbSSoby Mathew } 78464ce2bbSSoby Mathew 79464ce2bbSSoby Mathew /******************************************************************************* 80464ce2bbSSoby Mathew * Get the current CPU bit mask from GICD_ITARGETSR0 81464ce2bbSSoby Mathew ******************************************************************************/ 82464ce2bbSSoby Mathew unsigned int gicv2_get_cpuif_id(uintptr_t base) 83464ce2bbSSoby Mathew { 84464ce2bbSSoby Mathew unsigned int val; 85464ce2bbSSoby Mathew 86464ce2bbSSoby Mathew val = gicd_read_itargetsr(base, 0); 87464ce2bbSSoby Mathew return val & GIC_TARGET_CPU_MASK; 88464ce2bbSSoby Mathew } 89464ce2bbSSoby Mathew 90464ce2bbSSoby Mathew /******************************************************************************* 91464ce2bbSSoby Mathew * Helper function to configure the default attributes of SPIs. 92464ce2bbSSoby Mathew ******************************************************************************/ 93464ce2bbSSoby Mathew void gicv2_spis_configure_defaults(uintptr_t gicd_base) 94464ce2bbSSoby Mathew { 95464ce2bbSSoby Mathew unsigned int index, num_ints; 96464ce2bbSSoby Mathew 97464ce2bbSSoby Mathew num_ints = gicd_read_typer(gicd_base); 98464ce2bbSSoby Mathew num_ints &= TYPER_IT_LINES_NO_MASK; 993fea9c8bSAntonio Nino Diaz num_ints = (num_ints + 1U) << 5; 100464ce2bbSSoby Mathew 101464ce2bbSSoby Mathew /* 102464ce2bbSSoby Mathew * Treat all SPIs as G1NS by default. The number of interrupts is 103464ce2bbSSoby Mathew * calculated as 32 * (IT_LINES + 1). We do 32 at a time. 104464ce2bbSSoby Mathew */ 10503c6bb0eSMaheedhar Bollapalli for (index = MIN_SPI_ID; index < num_ints; index += 32U) { 106464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, index, ~0U); 10703c6bb0eSMaheedhar Bollapalli } 108464ce2bbSSoby Mathew /* Setup the default SPI priorities doing four at a time */ 10903c6bb0eSMaheedhar Bollapalli for (index = MIN_SPI_ID; index < num_ints; index += 4U) { 110464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 111464ce2bbSSoby Mathew index, 112464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 11303c6bb0eSMaheedhar Bollapalli } 114464ce2bbSSoby Mathew /* Treat all SPIs as level triggered by default, 16 at a time */ 11503c6bb0eSMaheedhar Bollapalli for (index = MIN_SPI_ID; index < num_ints; index += 16U) { 1163fea9c8bSAntonio Nino Diaz gicd_write_icfgr(gicd_base, index, 0U); 117464ce2bbSSoby Mathew } 11803c6bb0eSMaheedhar Bollapalli } 119464ce2bbSSoby Mathew 120464ce2bbSSoby Mathew /******************************************************************************* 121c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SPIs. 122c639e8ebSJeenu Viswambharan ******************************************************************************/ 123c639e8ebSJeenu Viswambharan void gicv2_secure_spis_configure_props(uintptr_t gicd_base, 124c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 125c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 126c639e8ebSJeenu Viswambharan { 127c639e8ebSJeenu Viswambharan unsigned int i; 128c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 129c639e8ebSJeenu Viswambharan 130c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 13103c6bb0eSMaheedhar Bollapalli if (interrupt_props_num != 0U) { 1323fea9c8bSAntonio Nino Diaz assert(interrupt_props != NULL); 13303c6bb0eSMaheedhar Bollapalli } 134c639e8ebSJeenu Viswambharan for (i = 0; i < interrupt_props_num; i++) { 135c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 136c639e8ebSJeenu Viswambharan 13703c6bb0eSMaheedhar Bollapalli if (prop_desc->intr_num < MIN_SPI_ID) { 138c639e8ebSJeenu Viswambharan continue; 13903c6bb0eSMaheedhar Bollapalli } 140c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 141c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 142c639e8ebSJeenu Viswambharan gicd_clr_igroupr(gicd_base, prop_desc->intr_num); 143c639e8ebSJeenu Viswambharan 144c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 145c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 146c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 147c639e8ebSJeenu Viswambharan 148c639e8ebSJeenu Viswambharan /* Target the secure interrupts to primary CPU */ 149c639e8ebSJeenu Viswambharan gicd_set_itargetsr(gicd_base, prop_desc->intr_num, 150c639e8ebSJeenu Viswambharan gicv2_get_cpuif_id(gicd_base)); 151c639e8ebSJeenu Viswambharan 152c639e8ebSJeenu Viswambharan /* Set interrupt configuration */ 153c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 154c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 155c639e8ebSJeenu Viswambharan 156c639e8ebSJeenu Viswambharan /* Enable this interrupt */ 157c639e8ebSJeenu Viswambharan gicd_set_isenabler(gicd_base, prop_desc->intr_num); 158c639e8ebSJeenu Viswambharan } 159c639e8ebSJeenu Viswambharan } 160c639e8ebSJeenu Viswambharan 161c639e8ebSJeenu Viswambharan /******************************************************************************* 162c639e8ebSJeenu Viswambharan * Helper function to configure properties of secure G0 SGIs and PPIs. 163c639e8ebSJeenu Viswambharan ******************************************************************************/ 164c639e8ebSJeenu Viswambharan void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, 165c639e8ebSJeenu Viswambharan const interrupt_prop_t *interrupt_props, 166c639e8ebSJeenu Viswambharan unsigned int interrupt_props_num) 167c639e8ebSJeenu Viswambharan { 168c639e8ebSJeenu Viswambharan unsigned int i; 169c639e8ebSJeenu Viswambharan uint32_t sec_ppi_sgi_mask = 0; 170c639e8ebSJeenu Viswambharan const interrupt_prop_t *prop_desc; 171c639e8ebSJeenu Viswambharan 172c639e8ebSJeenu Viswambharan /* Make sure there's a valid property array */ 17303c6bb0eSMaheedhar Bollapalli if (interrupt_props_num != 0U) { 1743fea9c8bSAntonio Nino Diaz assert(interrupt_props != NULL); 17503c6bb0eSMaheedhar Bollapalli } 176c639e8ebSJeenu Viswambharan /* 177c639e8ebSJeenu Viswambharan * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 178c639e8ebSJeenu Viswambharan * more scalable approach as it avoids clearing the enable bits in the 179c639e8ebSJeenu Viswambharan * GICD_CTLR. 180c639e8ebSJeenu Viswambharan */ 1813fea9c8bSAntonio Nino Diaz gicd_write_icenabler(gicd_base, 0U, ~0U); 182c639e8ebSJeenu Viswambharan 183c639e8ebSJeenu Viswambharan /* Setup the default PPI/SGI priorities doing four at a time */ 18403c6bb0eSMaheedhar Bollapalli for (i = 0U; i < MIN_SPI_ID; i += 4U) { 185c639e8ebSJeenu Viswambharan gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); 18603c6bb0eSMaheedhar Bollapalli } 1873fea9c8bSAntonio Nino Diaz for (i = 0U; i < interrupt_props_num; i++) { 188c639e8ebSJeenu Viswambharan prop_desc = &interrupt_props[i]; 189c639e8ebSJeenu Viswambharan 19003c6bb0eSMaheedhar Bollapalli if (prop_desc->intr_num >= MIN_SPI_ID) { 191c639e8ebSJeenu Viswambharan continue; 19203c6bb0eSMaheedhar Bollapalli } 193c639e8ebSJeenu Viswambharan /* Configure this interrupt as a secure interrupt */ 194c639e8ebSJeenu Viswambharan assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); 195c639e8ebSJeenu Viswambharan 196c639e8ebSJeenu Viswambharan /* 197c639e8ebSJeenu Viswambharan * Set interrupt configuration for PPIs. Configuration for SGIs 198c639e8ebSJeenu Viswambharan * are ignored. 199c639e8ebSJeenu Viswambharan */ 200c639e8ebSJeenu Viswambharan if ((prop_desc->intr_num >= MIN_PPI_ID) && 201c639e8ebSJeenu Viswambharan (prop_desc->intr_num < MIN_SPI_ID)) { 202c639e8ebSJeenu Viswambharan gicd_set_icfgr(gicd_base, prop_desc->intr_num, 203c639e8ebSJeenu Viswambharan prop_desc->intr_cfg); 204c639e8ebSJeenu Viswambharan } 205c639e8ebSJeenu Viswambharan 206c639e8ebSJeenu Viswambharan /* We have an SGI or a PPI. They are Group0 at reset */ 207*bec4a2c9SNithin G sec_ppi_sgi_mask |= BIT_32((uint32_t)prop_desc->intr_num); 208c639e8ebSJeenu Viswambharan 209c639e8ebSJeenu Viswambharan /* Set the priority of this interrupt */ 210c639e8ebSJeenu Viswambharan gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, 211c639e8ebSJeenu Viswambharan prop_desc->intr_pri); 212c639e8ebSJeenu Viswambharan } 213c639e8ebSJeenu Viswambharan 214c639e8ebSJeenu Viswambharan /* 215c639e8ebSJeenu Viswambharan * Invert the bitmask to create a mask for non-secure PPIs and SGIs. 216c639e8ebSJeenu Viswambharan * Program the GICD_IGROUPR0 with this bit mask. 217c639e8ebSJeenu Viswambharan */ 218c639e8ebSJeenu Viswambharan gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 219c639e8ebSJeenu Viswambharan 220c639e8ebSJeenu Viswambharan /* Enable the Group 0 SGIs and PPIs */ 221c639e8ebSJeenu Viswambharan gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 222c639e8ebSJeenu Viswambharan } 223