1464ce2bbSSoby Mathew /* 2a91e12fbSSoby Mathew * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. 3464ce2bbSSoby Mathew * 4464ce2bbSSoby Mathew * Redistribution and use in source and binary forms, with or without 5464ce2bbSSoby Mathew * modification, are permitted provided that the following conditions are met: 6464ce2bbSSoby Mathew * 7464ce2bbSSoby Mathew * Redistributions of source code must retain the above copyright notice, this 8464ce2bbSSoby Mathew * list of conditions and the following disclaimer. 9464ce2bbSSoby Mathew * 10464ce2bbSSoby Mathew * Redistributions in binary form must reproduce the above copyright notice, 11464ce2bbSSoby Mathew * this list of conditions and the following disclaimer in the documentation 12464ce2bbSSoby Mathew * and/or other materials provided with the distribution. 13464ce2bbSSoby Mathew * 14464ce2bbSSoby Mathew * Neither the name of ARM nor the names of its contributors may be used 15464ce2bbSSoby Mathew * to endorse or promote products derived from this software without specific 16464ce2bbSSoby Mathew * prior written permission. 17464ce2bbSSoby Mathew * 18464ce2bbSSoby Mathew * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19464ce2bbSSoby Mathew * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20464ce2bbSSoby Mathew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21464ce2bbSSoby Mathew * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22464ce2bbSSoby Mathew * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23464ce2bbSSoby Mathew * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24464ce2bbSSoby Mathew * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25464ce2bbSSoby Mathew * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26464ce2bbSSoby Mathew * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27464ce2bbSSoby Mathew * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28464ce2bbSSoby Mathew * POSSIBILITY OF SUCH DAMAGE. 29464ce2bbSSoby Mathew */ 30464ce2bbSSoby Mathew 31464ce2bbSSoby Mathew #include <arch.h> 32464ce2bbSSoby Mathew #include <arch_helpers.h> 33464ce2bbSSoby Mathew #include <assert.h> 34464ce2bbSSoby Mathew #include <debug.h> 35464ce2bbSSoby Mathew #include <gic_common.h> 36*e9ec3cecSSoby Mathew #include "../common/gic_common_private.h" 37464ce2bbSSoby Mathew #include "gicv2_private.h" 38464ce2bbSSoby Mathew 39464ce2bbSSoby Mathew /* 40464ce2bbSSoby Mathew * Accessor to read the GIC Distributor ITARGETSR corresponding to the 41464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 42464ce2bbSSoby Mathew */ 43464ce2bbSSoby Mathew unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id) 44464ce2bbSSoby Mathew { 45464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 46464ce2bbSSoby Mathew return mmio_read_32(base + GICD_ITARGETSR + (n << 2)); 47464ce2bbSSoby Mathew } 48464ce2bbSSoby Mathew 49464ce2bbSSoby Mathew /* 50464ce2bbSSoby Mathew * Accessor to read the GIC Distributor CPENDSGIR corresponding to the 51464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 52464ce2bbSSoby Mathew */ 53464ce2bbSSoby Mathew unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id) 54464ce2bbSSoby Mathew { 55464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 56464ce2bbSSoby Mathew return mmio_read_32(base + GICD_CPENDSGIR + (n << 2)); 57464ce2bbSSoby Mathew } 58464ce2bbSSoby Mathew 59464ce2bbSSoby Mathew /* 60464ce2bbSSoby Mathew * Accessor to read the GIC Distributor SPENDSGIR corresponding to the 61464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 62464ce2bbSSoby Mathew */ 63464ce2bbSSoby Mathew unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id) 64464ce2bbSSoby Mathew { 65464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 66464ce2bbSSoby Mathew return mmio_read_32(base + GICD_SPENDSGIR + (n << 2)); 67464ce2bbSSoby Mathew } 68464ce2bbSSoby Mathew 69464ce2bbSSoby Mathew /* 70464ce2bbSSoby Mathew * Accessor to write the GIC Distributor ITARGETSR corresponding to the 71464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 72464ce2bbSSoby Mathew */ 73464ce2bbSSoby Mathew void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val) 74464ce2bbSSoby Mathew { 75464ce2bbSSoby Mathew unsigned n = id >> ITARGETSR_SHIFT; 76464ce2bbSSoby Mathew mmio_write_32(base + GICD_ITARGETSR + (n << 2), val); 77464ce2bbSSoby Mathew } 78464ce2bbSSoby Mathew 79464ce2bbSSoby Mathew /* 80464ce2bbSSoby Mathew * Accessor to write the GIC Distributor CPENDSGIR corresponding to the 81464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 82464ce2bbSSoby Mathew */ 83464ce2bbSSoby Mathew void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val) 84464ce2bbSSoby Mathew { 85464ce2bbSSoby Mathew unsigned n = id >> CPENDSGIR_SHIFT; 86464ce2bbSSoby Mathew mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val); 87464ce2bbSSoby Mathew } 88464ce2bbSSoby Mathew 89464ce2bbSSoby Mathew /* 90464ce2bbSSoby Mathew * Accessor to write the GIC Distributor SPENDSGIR corresponding to the 91464ce2bbSSoby Mathew * interrupt `id`, 4 interrupt IDs at a time. 92464ce2bbSSoby Mathew */ 93464ce2bbSSoby Mathew void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) 94464ce2bbSSoby Mathew { 95464ce2bbSSoby Mathew unsigned n = id >> SPENDSGIR_SHIFT; 96464ce2bbSSoby Mathew mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); 97464ce2bbSSoby Mathew } 98464ce2bbSSoby Mathew 99464ce2bbSSoby Mathew /* 100464ce2bbSSoby Mathew * Accessor to write the GIC Distributor ITARGETSR corresponding to the 101464ce2bbSSoby Mathew * interrupt `id`. 102464ce2bbSSoby Mathew */ 103464ce2bbSSoby Mathew void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target) 104464ce2bbSSoby Mathew { 105a91e12fbSSoby Mathew mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK); 106464ce2bbSSoby Mathew } 107464ce2bbSSoby Mathew 108464ce2bbSSoby Mathew /******************************************************************************* 109464ce2bbSSoby Mathew * Get the current CPU bit mask from GICD_ITARGETSR0 110464ce2bbSSoby Mathew ******************************************************************************/ 111464ce2bbSSoby Mathew unsigned int gicv2_get_cpuif_id(uintptr_t base) 112464ce2bbSSoby Mathew { 113464ce2bbSSoby Mathew unsigned int val; 114464ce2bbSSoby Mathew 115464ce2bbSSoby Mathew val = gicd_read_itargetsr(base, 0); 116464ce2bbSSoby Mathew return val & GIC_TARGET_CPU_MASK; 117464ce2bbSSoby Mathew } 118464ce2bbSSoby Mathew 119464ce2bbSSoby Mathew /******************************************************************************* 120464ce2bbSSoby Mathew * Helper function to configure the default attributes of SPIs. 121464ce2bbSSoby Mathew ******************************************************************************/ 122464ce2bbSSoby Mathew void gicv2_spis_configure_defaults(uintptr_t gicd_base) 123464ce2bbSSoby Mathew { 124464ce2bbSSoby Mathew unsigned int index, num_ints; 125464ce2bbSSoby Mathew 126464ce2bbSSoby Mathew num_ints = gicd_read_typer(gicd_base); 127464ce2bbSSoby Mathew num_ints &= TYPER_IT_LINES_NO_MASK; 128464ce2bbSSoby Mathew num_ints = (num_ints + 1) << 5; 129464ce2bbSSoby Mathew 130464ce2bbSSoby Mathew /* 131464ce2bbSSoby Mathew * Treat all SPIs as G1NS by default. The number of interrupts is 132464ce2bbSSoby Mathew * calculated as 32 * (IT_LINES + 1). We do 32 at a time. 133464ce2bbSSoby Mathew */ 134464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 32) 135464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, index, ~0U); 136464ce2bbSSoby Mathew 137464ce2bbSSoby Mathew /* Setup the default SPI priorities doing four at a time */ 138464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 4) 139464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 140464ce2bbSSoby Mathew index, 141464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 142464ce2bbSSoby Mathew 143464ce2bbSSoby Mathew /* Treat all SPIs as level triggered by default, 16 at a time */ 144464ce2bbSSoby Mathew for (index = MIN_SPI_ID; index < num_ints; index += 16) 145464ce2bbSSoby Mathew gicd_write_icfgr(gicd_base, index, 0); 146464ce2bbSSoby Mathew } 147464ce2bbSSoby Mathew 148464ce2bbSSoby Mathew /******************************************************************************* 149464ce2bbSSoby Mathew * Helper function to configure secure G0 SPIs. 150464ce2bbSSoby Mathew ******************************************************************************/ 151464ce2bbSSoby Mathew void gicv2_secure_spis_configure(uintptr_t gicd_base, 152464ce2bbSSoby Mathew unsigned int num_ints, 153464ce2bbSSoby Mathew const unsigned int *sec_intr_list) 154464ce2bbSSoby Mathew { 155464ce2bbSSoby Mathew unsigned int index, irq_num; 156464ce2bbSSoby Mathew 157464ce2bbSSoby Mathew /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 158464ce2bbSSoby Mathew assert(num_ints ? (uintptr_t)sec_intr_list : 1); 159464ce2bbSSoby Mathew 160464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 161464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 162464ce2bbSSoby Mathew if (irq_num >= MIN_SPI_ID) { 163464ce2bbSSoby Mathew /* Configure this interrupt as a secure interrupt */ 164464ce2bbSSoby Mathew gicd_clr_igroupr(gicd_base, irq_num); 165464ce2bbSSoby Mathew 166464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 16738a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 168464ce2bbSSoby Mathew irq_num, 169464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 170464ce2bbSSoby Mathew 171464ce2bbSSoby Mathew /* Target the secure interrupts to primary CPU */ 172464ce2bbSSoby Mathew gicd_set_itargetsr(gicd_base, irq_num, 173464ce2bbSSoby Mathew gicv2_get_cpuif_id(gicd_base)); 174464ce2bbSSoby Mathew 175464ce2bbSSoby Mathew /* Enable this interrupt */ 176464ce2bbSSoby Mathew gicd_set_isenabler(gicd_base, irq_num); 177464ce2bbSSoby Mathew } 178464ce2bbSSoby Mathew } 179464ce2bbSSoby Mathew 180464ce2bbSSoby Mathew } 181464ce2bbSSoby Mathew 182464ce2bbSSoby Mathew /******************************************************************************* 183464ce2bbSSoby Mathew * Helper function to configure secure G0 SGIs and PPIs. 184464ce2bbSSoby Mathew ******************************************************************************/ 185464ce2bbSSoby Mathew void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, 186464ce2bbSSoby Mathew unsigned int num_ints, 187464ce2bbSSoby Mathew const unsigned int *sec_intr_list) 188464ce2bbSSoby Mathew { 189464ce2bbSSoby Mathew unsigned int index, irq_num, sec_ppi_sgi_mask = 0; 190464ce2bbSSoby Mathew 191464ce2bbSSoby Mathew /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ 192464ce2bbSSoby Mathew assert(num_ints ? (uintptr_t)sec_intr_list : 1); 193464ce2bbSSoby Mathew 194464ce2bbSSoby Mathew /* 195464ce2bbSSoby Mathew * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a 196464ce2bbSSoby Mathew * more scalable approach as it avoids clearing the enable bits in the 197464ce2bbSSoby Mathew * GICD_CTLR. 198464ce2bbSSoby Mathew */ 199464ce2bbSSoby Mathew gicd_write_icenabler(gicd_base, 0, ~0); 200464ce2bbSSoby Mathew 201464ce2bbSSoby Mathew /* Setup the default PPI/SGI priorities doing four at a time */ 202464ce2bbSSoby Mathew for (index = 0; index < MIN_SPI_ID; index += 4) 203464ce2bbSSoby Mathew gicd_write_ipriorityr(gicd_base, 204464ce2bbSSoby Mathew index, 205464ce2bbSSoby Mathew GICD_IPRIORITYR_DEF_VAL); 206464ce2bbSSoby Mathew 207464ce2bbSSoby Mathew for (index = 0; index < num_ints; index++) { 208464ce2bbSSoby Mathew irq_num = sec_intr_list[index]; 209464ce2bbSSoby Mathew if (irq_num < MIN_SPI_ID) { 210464ce2bbSSoby Mathew /* We have an SGI or a PPI. They are Group0 at reset */ 211464ce2bbSSoby Mathew sec_ppi_sgi_mask |= 1U << irq_num; 212464ce2bbSSoby Mathew 213464ce2bbSSoby Mathew /* Set the priority of this interrupt */ 21438a78614SSoby Mathew gicd_set_ipriorityr(gicd_base, 215464ce2bbSSoby Mathew irq_num, 216464ce2bbSSoby Mathew GIC_HIGHEST_SEC_PRIORITY); 217464ce2bbSSoby Mathew } 218464ce2bbSSoby Mathew } 219464ce2bbSSoby Mathew 220464ce2bbSSoby Mathew /* 221464ce2bbSSoby Mathew * Invert the bitmask to create a mask for non-secure PPIs and 222464ce2bbSSoby Mathew * SGIs. Program the GICD_IGROUPR0 with this bit mask. 223464ce2bbSSoby Mathew */ 224464ce2bbSSoby Mathew gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); 225464ce2bbSSoby Mathew 226464ce2bbSSoby Mathew /* Enable the Group 0 SGIs and PPIs */ 227464ce2bbSSoby Mathew gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); 228464ce2bbSSoby Mathew } 229