1464ce2bbSSoby Mathew /* 2a91e12fbSSoby Mathew * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. 3464ce2bbSSoby Mathew * 4*82cb2c1aSdp-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> 12e9ec3cecSSoby Mathew #include "../common/gic_common_private.h" 13464ce2bbSSoby Mathew #include "gicv2_private.h" 14464ce2bbSSoby Mathew 15464ce2bbSSoby Mathew /* 16464ce2bbSSoby Mathew * Accessor to read the GIC Distributor ITARGETSR corresponding to the 17464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 18464ce2bbSSoby Mathew */ 19464ce2bbSSoby Mathew unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id) 20464ce2bbSSoby Mathew { 21464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 22464ce2bbSSoby Mathew return mmio_read_32(base + GICD_ITARGETSR + (n << 2)); 23464ce2bbSSoby Mathew } 24464ce2bbSSoby Mathew 25464ce2bbSSoby Mathew /* 26464ce2bbSSoby Mathew * Accessor to read the GIC Distributor CPENDSGIR corresponding to the 27464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 28464ce2bbSSoby Mathew */ 29464ce2bbSSoby Mathew unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id) 30464ce2bbSSoby Mathew { 31464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 32464ce2bbSSoby Mathew return mmio_read_32(base + GICD_CPENDSGIR + (n << 2)); 33464ce2bbSSoby Mathew } 34464ce2bbSSoby Mathew 35464ce2bbSSoby Mathew /* 36464ce2bbSSoby Mathew * Accessor to read the GIC Distributor SPENDSGIR corresponding to the 37464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 38464ce2bbSSoby Mathew */ 39464ce2bbSSoby Mathew unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id) 40464ce2bbSSoby Mathew { 41464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 42464ce2bbSSoby Mathew return mmio_read_32(base + GICD_SPENDSGIR + (n << 2)); 43464ce2bbSSoby Mathew } 44464ce2bbSSoby Mathew 45464ce2bbSSoby Mathew /* 46464ce2bbSSoby Mathew * Accessor to write the GIC Distributor ITARGETSR corresponding to the 47464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 48464ce2bbSSoby Mathew */ 49464ce2bbSSoby Mathew void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val) 50464ce2bbSSoby Mathew { 51464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 52464ce2bbSSoby Mathew mmio_write_32(base + GICD_ITARGETSR + (n << 2), val); 53464ce2bbSSoby Mathew } 54464ce2bbSSoby Mathew 55464ce2bbSSoby Mathew /* 56464ce2bbSSoby Mathew * Accessor to write the GIC Distributor CPENDSGIR corresponding to the 57464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 58464ce2bbSSoby Mathew */ 59464ce2bbSSoby Mathew void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val) 60464ce2bbSSoby Mathew { 61464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 62464ce2bbSSoby Mathew mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val); 63464ce2bbSSoby Mathew } 64464ce2bbSSoby Mathew 65464ce2bbSSoby Mathew /* 66464ce2bbSSoby Mathew * Accessor to write the GIC Distributor SPENDSGIR corresponding to the 67464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 68464ce2bbSSoby Mathew */ 69464ce2bbSSoby Mathew void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) 70464ce2bbSSoby Mathew { 71464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 72464ce2bbSSoby Mathew mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); 73464ce2bbSSoby Mathew } 74464ce2bbSSoby Mathew 75464ce2bbSSoby Mathew /* 76464ce2bbSSoby Mathew * Accessor to write the GIC Distributor ITARGETSR corresponding to the 77464ce2bbSSoby Mathew * interrupt `id`. 78464ce2bbSSoby Mathew */ 79464ce2bbSSoby Mathew void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target) 80464ce2bbSSoby Mathew { 81a91e12fbSSoby Mathew mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK); 82464ce2bbSSoby Mathew } 83464ce2bbSSoby Mathew 84464ce2bbSSoby Mathew /******************************************************************************* 85464ce2bbSSoby Mathew * Get the current CPU bit mask from GICD_ITARGETSR0 86464ce2bbSSoby Mathew ******************************************************************************/ 87464ce2bbSSoby Mathew unsigned int gicv2_get_cpuif_id(uintptr_t base) 88464ce2bbSSoby Mathew { 89464ce2bbSSoby Mathew unsigned int val; 90464ce2bbSSoby Mathew 91464ce2bbSSoby Mathew val = gicd_read_itargetsr(base, 0); 92464ce2bbSSoby Mathew return val & GIC_TARGET_CPU_MASK; 93464ce2bbSSoby Mathew } 94464ce2bbSSoby Mathew 95464ce2bbSSoby Mathew /******************************************************************************* 96464ce2bbSSoby Mathew * Helper function to configure the default attributes of SPIs. 97464ce2bbSSoby Mathew ******************************************************************************/ 98464ce2bbSSoby Mathew void gicv2_spis_configure_defaults(uintptr_t gicd_base) 99464ce2bbSSoby Mathew { 100464ce2bbSSoby Mathew unsigned int index, num_ints; 101464ce2bbSSoby Mathew 102464ce2bbSSoby Mathew num_ints = gicd_read_typer(gicd_base); 103464ce2bbSSoby Mathew num_ints &= TYPER_IT_LINES_NO_MASK; 104464ce2bbSSoby Mathew num_ints = (num_ints + 1) << 5; 105464ce2bbSSoby Mathew 106464ce2bbSSoby Mathew /* 107464ce2bbSSoby Mathew * Treat all SPIs as G1NS by default. The number of interrupts is 108464ce2bbSSoby Mathew * calculated as 32 * (IT_LINES + 1). We do 32 at a time. 109464ce2bbSSoby Mathew */ 110464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 32) 111464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, index, ~0U); 112464ce2bbSSoby Mathew 113464ce2bbSSoby Mathew /* Setup the default SPI priorities doing four at a time */ 114464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 4) 115464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 116464ce2bbSSoby Mathew index, 117464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 118464ce2bbSSoby Mathew 119464ce2bbSSoby Mathew /* Treat all SPIs as level triggered by default, 16 at a time */ 120464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 16) 121464ce2bbSSoby Mathew gicd_write_icfgr(gicd_base, index, 0); 122464ce2bbSSoby Mathew } 123464ce2bbSSoby Mathew 124464ce2bbSSoby Mathew /******************************************************************************* 125464ce2bbSSoby Mathew * Helper function to configure secure G0 SPIs. 126464ce2bbSSoby Mathew ******************************************************************************/ 127464ce2bbSSoby Mathew void gicv2_secure_spis_configure(uintptr_t gicd_base, 128464ce2bbSSoby Mathew unsigned int num_ints, 129464ce2bbSSoby Mathew const unsigned int *sec_intr_list) 130464ce2bbSSoby Mathew { 131464ce2bbSSoby Mathew unsigned int index, irq_num; 132464ce2bbSSoby Mathew 133464ce2bbSSoby Mathew /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 134464ce2bbSSoby Mathew assert(num_ints ? (uintptr_t)sec_intr_list : 1); 135464ce2bbSSoby Mathew 136464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 137464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 138464ce2bbSSoby Mathew if (irq_num >= MIN_SPI_ID) { 139464ce2bbSSoby Mathew /* Configure this interrupt as a secure interrupt */ 140464ce2bbSSoby Mathew gicd_clr_igroupr(gicd_base, irq_num); 141464ce2bbSSoby Mathew 142464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 14338a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 144464ce2bbSSoby Mathew irq_num, 145464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 146464ce2bbSSoby Mathew 147464ce2bbSSoby Mathew /* Target the secure interrupts to primary CPU */ 148464ce2bbSSoby Mathew gicd_set_itargetsr(gicd_base, irq_num, 149464ce2bbSSoby Mathew gicv2_get_cpuif_id(gicd_base)); 150464ce2bbSSoby Mathew 151464ce2bbSSoby Mathew /* Enable this interrupt */ 152464ce2bbSSoby Mathew gicd_set_isenabler(gicd_base, irq_num); 153464ce2bbSSoby Mathew } 154464ce2bbSSoby Mathew } 155464ce2bbSSoby Mathew 156464ce2bbSSoby Mathew } 157464ce2bbSSoby Mathew 158464ce2bbSSoby Mathew /******************************************************************************* 159464ce2bbSSoby Mathew * Helper function to configure secure G0 SGIs and PPIs. 160464ce2bbSSoby Mathew ******************************************************************************/ 161464ce2bbSSoby Mathew void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, 162464ce2bbSSoby Mathew unsigned int num_ints, 163464ce2bbSSoby Mathew const unsigned int *sec_intr_list) 164464ce2bbSSoby Mathew { 165464ce2bbSSoby Mathew unsigned int index, irq_num, sec_ppi_sgi_mask = 0; 166464ce2bbSSoby Mathew 167464ce2bbSSoby Mathew /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 168464ce2bbSSoby Mathew assert(num_ints ? (uintptr_t)sec_intr_list : 1); 169464ce2bbSSoby Mathew 170464ce2bbSSoby Mathew /* 171464ce2bbSSoby Mathew * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 172464ce2bbSSoby Mathew * more scalable approach as it avoids clearing the enable bits in the 173464ce2bbSSoby Mathew * GICD_CTLR. 174464ce2bbSSoby Mathew */ 175464ce2bbSSoby Mathew gicd_write_icenabler(gicd_base, 0, ~0); 176464ce2bbSSoby Mathew 177464ce2bbSSoby Mathew /* Setup the default PPI/SGI priorities doing four at a time */ 178464ce2bbSSoby Mathew for (index = 0; index < MIN_SPI_ID; index += 4) 179464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 180464ce2bbSSoby Mathew index, 181464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 182464ce2bbSSoby Mathew 183464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 184464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 185464ce2bbSSoby Mathew if (irq_num < MIN_SPI_ID) { 186464ce2bbSSoby Mathew /* We have an SGI or a PPI. They are Group0 at reset */ 187464ce2bbSSoby Mathew sec_ppi_sgi_mask |= 1U << irq_num; 188464ce2bbSSoby Mathew 189464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 19038a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 191464ce2bbSSoby Mathew irq_num, 192464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 193464ce2bbSSoby Mathew } 194464ce2bbSSoby Mathew } 195464ce2bbSSoby Mathew 196464ce2bbSSoby Mathew /* 197464ce2bbSSoby Mathew * Invert the bitmask to create a mask for non-secure PPIs and 198464ce2bbSSoby Mathew * SGIs. Program the GICD_IGROUPR0 with this bit mask. 199464ce2bbSSoby Mathew */ 200464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 201464ce2bbSSoby Mathew 202464ce2bbSSoby Mathew /* Enable the Group 0 SGIs and PPIs */ 203464ce2bbSSoby Mathew gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 204464ce2bbSSoby Mathew } 205