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