1464ce2bbSSoby Mathew /* 2*fc529feeSJeenu Viswambharan * Copyright (c) 2015-2017, 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> 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 * Get the current CPU bit mask from GICD_ITARGETSR0 77464ce2bbSSoby Mathew ******************************************************************************/ 78464ce2bbSSoby Mathew unsigned int gicv2_get_cpuif_id(uintptr_t base) 79464ce2bbSSoby Mathew { 80464ce2bbSSoby Mathew unsigned int val; 81464ce2bbSSoby Mathew 82464ce2bbSSoby Mathew val = gicd_read_itargetsr(base, 0); 83464ce2bbSSoby Mathew return val & GIC_TARGET_CPU_MASK; 84464ce2bbSSoby Mathew } 85464ce2bbSSoby Mathew 86464ce2bbSSoby Mathew /******************************************************************************* 87464ce2bbSSoby Mathew * Helper function to configure the default attributes of SPIs. 88464ce2bbSSoby Mathew ******************************************************************************/ 89464ce2bbSSoby Mathew void gicv2_spis_configure_defaults(uintptr_t gicd_base) 90464ce2bbSSoby Mathew { 91464ce2bbSSoby Mathew unsigned int index, num_ints; 92464ce2bbSSoby Mathew 93464ce2bbSSoby Mathew num_ints = gicd_read_typer(gicd_base); 94464ce2bbSSoby Mathew num_ints &= TYPER_IT_LINES_NO_MASK; 95464ce2bbSSoby Mathew num_ints = (num_ints + 1) << 5; 96464ce2bbSSoby Mathew 97464ce2bbSSoby Mathew /* 98464ce2bbSSoby Mathew * Treat all SPIs as G1NS by default. The number of interrupts is 99464ce2bbSSoby Mathew * calculated as 32 * (IT_LINES + 1). We do 32 at a time. 100464ce2bbSSoby Mathew */ 101464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 32) 102464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, index, ~0U); 103464ce2bbSSoby Mathew 104464ce2bbSSoby Mathew /* Setup the default SPI priorities doing four at a time */ 105464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 4) 106464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 107464ce2bbSSoby Mathew index, 108464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 109464ce2bbSSoby Mathew 110464ce2bbSSoby Mathew /* Treat all SPIs as level triggered by default, 16 at a time */ 111464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 16) 112464ce2bbSSoby Mathew gicd_write_icfgr(gicd_base, index, 0); 113464ce2bbSSoby Mathew } 114464ce2bbSSoby Mathew 115464ce2bbSSoby Mathew /******************************************************************************* 116464ce2bbSSoby Mathew * Helper function to configure secure G0 SPIs. 117464ce2bbSSoby Mathew ******************************************************************************/ 118464ce2bbSSoby Mathew void gicv2_secure_spis_configure(uintptr_t gicd_base, 119464ce2bbSSoby Mathew unsigned int num_ints, 120464ce2bbSSoby Mathew const unsigned int *sec_intr_list) 121464ce2bbSSoby Mathew { 122464ce2bbSSoby Mathew unsigned int index, irq_num; 123464ce2bbSSoby Mathew 124464ce2bbSSoby Mathew /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 125464ce2bbSSoby Mathew assert(num_ints ? (uintptr_t)sec_intr_list : 1); 126464ce2bbSSoby Mathew 127464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 128464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 129464ce2bbSSoby Mathew if (irq_num >= MIN_SPI_ID) { 130464ce2bbSSoby Mathew /* Configure this interrupt as a secure interrupt */ 131464ce2bbSSoby Mathew gicd_clr_igroupr(gicd_base, irq_num); 132464ce2bbSSoby Mathew 133464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 13438a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 135464ce2bbSSoby Mathew irq_num, 136464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 137464ce2bbSSoby Mathew 138464ce2bbSSoby Mathew /* Target the secure interrupts to primary CPU */ 139464ce2bbSSoby Mathew gicd_set_itargetsr(gicd_base, irq_num, 140464ce2bbSSoby Mathew gicv2_get_cpuif_id(gicd_base)); 141464ce2bbSSoby Mathew 142464ce2bbSSoby Mathew /* Enable this interrupt */ 143464ce2bbSSoby Mathew gicd_set_isenabler(gicd_base, irq_num); 144464ce2bbSSoby Mathew } 145464ce2bbSSoby Mathew } 146464ce2bbSSoby Mathew 147464ce2bbSSoby Mathew } 148464ce2bbSSoby Mathew 149464ce2bbSSoby Mathew /******************************************************************************* 150464ce2bbSSoby Mathew * Helper function to configure secure G0 SGIs and PPIs. 151464ce2bbSSoby Mathew ******************************************************************************/ 152464ce2bbSSoby Mathew void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, 153464ce2bbSSoby Mathew unsigned int num_ints, 154464ce2bbSSoby Mathew const unsigned int *sec_intr_list) 155464ce2bbSSoby Mathew { 156464ce2bbSSoby Mathew unsigned int index, irq_num, sec_ppi_sgi_mask = 0; 157464ce2bbSSoby Mathew 158464ce2bbSSoby Mathew /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 159464ce2bbSSoby Mathew assert(num_ints ? (uintptr_t)sec_intr_list : 1); 160464ce2bbSSoby Mathew 161464ce2bbSSoby Mathew /* 162464ce2bbSSoby Mathew * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 163464ce2bbSSoby Mathew * more scalable approach as it avoids clearing the enable bits in the 164464ce2bbSSoby Mathew * GICD_CTLR. 165464ce2bbSSoby Mathew */ 166464ce2bbSSoby Mathew gicd_write_icenabler(gicd_base, 0, ~0); 167464ce2bbSSoby Mathew 168464ce2bbSSoby Mathew /* Setup the default PPI/SGI priorities doing four at a time */ 169464ce2bbSSoby Mathew for (index = 0; index < MIN_SPI_ID; index += 4) 170464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 171464ce2bbSSoby Mathew index, 172464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 173464ce2bbSSoby Mathew 174464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 175464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 176464ce2bbSSoby Mathew if (irq_num < MIN_SPI_ID) { 177464ce2bbSSoby Mathew /* We have an SGI or a PPI. They are Group0 at reset */ 178464ce2bbSSoby Mathew sec_ppi_sgi_mask |= 1U << irq_num; 179464ce2bbSSoby Mathew 180464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 18138a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 182464ce2bbSSoby Mathew irq_num, 183464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 184464ce2bbSSoby Mathew } 185464ce2bbSSoby Mathew } 186464ce2bbSSoby Mathew 187464ce2bbSSoby Mathew /* 188464ce2bbSSoby Mathew * Invert the bitmask to create a mask for non-secure PPIs and 189464ce2bbSSoby Mathew * SGIs. Program the GICD_IGROUPR0 with this bit mask. 190464ce2bbSSoby Mathew */ 191464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 192464ce2bbSSoby Mathew 193464ce2bbSSoby Mathew /* Enable the Group 0 SGIs and PPIs */ 194464ce2bbSSoby Mathew gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 195464ce2bbSSoby Mathew } 196