1464ce2bbSSoby Mathew /* 2*311b1773SSoby Mathew * Copyright (c) 2015-2017, 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.h> 37e9ec3cecSSoby Mathew #include "../common/gic_common_private.h" 38464ce2bbSSoby Mathew #include "gicv2_private.h" 39464ce2bbSSoby Mathew 40464ce2bbSSoby Mathew static const gicv2_driver_data_t *driver_data; 41464ce2bbSSoby Mathew 42464ce2bbSSoby Mathew /******************************************************************************* 43464ce2bbSSoby Mathew * Enable secure interrupts and use FIQs to route them. Disable legacy bypass 44464ce2bbSSoby Mathew * and set the priority mask register to allow all interrupts to trickle in. 45464ce2bbSSoby Mathew ******************************************************************************/ 46464ce2bbSSoby Mathew void gicv2_cpuif_enable(void) 47464ce2bbSSoby Mathew { 48464ce2bbSSoby Mathew unsigned int val; 49464ce2bbSSoby Mathew 50464ce2bbSSoby Mathew assert(driver_data); 51464ce2bbSSoby Mathew assert(driver_data->gicc_base); 52464ce2bbSSoby Mathew 53464ce2bbSSoby Mathew /* 54464ce2bbSSoby Mathew * Enable the Group 0 interrupts, FIQEn and disable Group 0/1 55464ce2bbSSoby Mathew * bypass. 56464ce2bbSSoby Mathew */ 57464ce2bbSSoby Mathew val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0; 58464ce2bbSSoby Mathew val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1; 59464ce2bbSSoby Mathew 60464ce2bbSSoby Mathew /* Program the idle priority in the PMR */ 61464ce2bbSSoby Mathew gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK); 62464ce2bbSSoby Mathew gicc_write_ctlr(driver_data->gicc_base, val); 63464ce2bbSSoby Mathew } 64464ce2bbSSoby Mathew 65464ce2bbSSoby Mathew /******************************************************************************* 66464ce2bbSSoby Mathew * Place the cpu interface in a state where it can never make a cpu exit wfi as 67464ce2bbSSoby Mathew * as result of an asserted interrupt. This is critical for powering down a cpu 68464ce2bbSSoby Mathew ******************************************************************************/ 69464ce2bbSSoby Mathew void gicv2_cpuif_disable(void) 70464ce2bbSSoby Mathew { 71464ce2bbSSoby Mathew unsigned int val; 72464ce2bbSSoby Mathew 73464ce2bbSSoby Mathew assert(driver_data); 74464ce2bbSSoby Mathew assert(driver_data->gicc_base); 75464ce2bbSSoby Mathew 76464ce2bbSSoby Mathew /* Disable secure, non-secure interrupts and disable their bypass */ 77464ce2bbSSoby Mathew val = gicc_read_ctlr(driver_data->gicc_base); 78464ce2bbSSoby Mathew val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT); 79464ce2bbSSoby Mathew val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0; 80464ce2bbSSoby Mathew val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1; 81464ce2bbSSoby Mathew gicc_write_ctlr(driver_data->gicc_base, val); 82464ce2bbSSoby Mathew } 83464ce2bbSSoby Mathew 84464ce2bbSSoby Mathew /******************************************************************************* 85464ce2bbSSoby Mathew * Per cpu gic distributor setup which will be done by all cpus after a cold 86464ce2bbSSoby Mathew * boot/hotplug. This marks out the secure SPIs and PPIs & enables them. 87464ce2bbSSoby Mathew ******************************************************************************/ 88464ce2bbSSoby Mathew void gicv2_pcpu_distif_init(void) 89464ce2bbSSoby Mathew { 90464ce2bbSSoby Mathew assert(driver_data); 91464ce2bbSSoby Mathew assert(driver_data->gicd_base); 92464ce2bbSSoby Mathew assert(driver_data->g0_interrupt_array); 93464ce2bbSSoby Mathew 94464ce2bbSSoby Mathew gicv2_secure_ppi_sgi_setup(driver_data->gicd_base, 95464ce2bbSSoby Mathew driver_data->g0_interrupt_num, 96464ce2bbSSoby Mathew driver_data->g0_interrupt_array); 97464ce2bbSSoby Mathew } 98464ce2bbSSoby Mathew 99464ce2bbSSoby Mathew /******************************************************************************* 100464ce2bbSSoby Mathew * Global gic distributor init which will be done by the primary cpu after a 101464ce2bbSSoby Mathew * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It 102464ce2bbSSoby Mathew * then enables the secure GIC distributor interface. 103464ce2bbSSoby Mathew ******************************************************************************/ 104464ce2bbSSoby Mathew void gicv2_distif_init(void) 105464ce2bbSSoby Mathew { 106464ce2bbSSoby Mathew unsigned int ctlr; 107464ce2bbSSoby Mathew 108464ce2bbSSoby Mathew assert(driver_data); 109464ce2bbSSoby Mathew assert(driver_data->gicd_base); 110464ce2bbSSoby Mathew assert(driver_data->g0_interrupt_array); 111464ce2bbSSoby Mathew 112464ce2bbSSoby Mathew /* Disable the distributor before going further */ 113464ce2bbSSoby Mathew ctlr = gicd_read_ctlr(driver_data->gicd_base); 114464ce2bbSSoby Mathew gicd_write_ctlr(driver_data->gicd_base, 115464ce2bbSSoby Mathew ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT)); 116464ce2bbSSoby Mathew 117464ce2bbSSoby Mathew /* Set the default attribute of all SPIs */ 118464ce2bbSSoby Mathew gicv2_spis_configure_defaults(driver_data->gicd_base); 119464ce2bbSSoby Mathew 120464ce2bbSSoby Mathew /* Configure the G0 SPIs */ 121464ce2bbSSoby Mathew gicv2_secure_spis_configure(driver_data->gicd_base, 122464ce2bbSSoby Mathew driver_data->g0_interrupt_num, 123464ce2bbSSoby Mathew driver_data->g0_interrupt_array); 124464ce2bbSSoby Mathew 125464ce2bbSSoby Mathew /* Re-enable the secure SPIs now that they have been configured */ 126464ce2bbSSoby Mathew gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT); 127464ce2bbSSoby Mathew } 128464ce2bbSSoby Mathew 129464ce2bbSSoby Mathew /******************************************************************************* 130464ce2bbSSoby Mathew * Initialize the ARM GICv2 driver with the provided platform inputs 131464ce2bbSSoby Mathew ******************************************************************************/ 132464ce2bbSSoby Mathew void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data) 133464ce2bbSSoby Mathew { 134464ce2bbSSoby Mathew unsigned int gic_version; 135464ce2bbSSoby Mathew assert(plat_driver_data); 136464ce2bbSSoby Mathew assert(plat_driver_data->gicd_base); 137464ce2bbSSoby Mathew assert(plat_driver_data->gicc_base); 138464ce2bbSSoby Mathew 139464ce2bbSSoby Mathew /* 140464ce2bbSSoby Mathew * The platform should provide a list of atleast one type of 141464ce2bbSSoby Mathew * interrupts 142464ce2bbSSoby Mathew */ 143464ce2bbSSoby Mathew assert(plat_driver_data->g0_interrupt_array); 144464ce2bbSSoby Mathew 145464ce2bbSSoby Mathew /* 146464ce2bbSSoby Mathew * If there are no interrupts of a particular type, then the number of 147464ce2bbSSoby Mathew * interrupts of that type should be 0 and vice-versa. 148464ce2bbSSoby Mathew */ 149464ce2bbSSoby Mathew assert(plat_driver_data->g0_interrupt_array ? 150464ce2bbSSoby Mathew plat_driver_data->g0_interrupt_num : 151464ce2bbSSoby Mathew plat_driver_data->g0_interrupt_num == 0); 152464ce2bbSSoby Mathew 153464ce2bbSSoby Mathew /* Ensure that this is a GICv2 system */ 154464ce2bbSSoby Mathew gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); 155464ce2bbSSoby Mathew gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT) 156464ce2bbSSoby Mathew & PIDR2_ARCH_REV_MASK; 157464ce2bbSSoby Mathew assert(gic_version == ARCH_REV_GICV2); 158464ce2bbSSoby Mathew 159464ce2bbSSoby Mathew driver_data = plat_driver_data; 160464ce2bbSSoby Mathew 161*311b1773SSoby Mathew /* 162*311b1773SSoby Mathew * The GIC driver data is initialized by the primary CPU with caches 163*311b1773SSoby Mathew * enabled. When the secondary CPU boots up, it initializes the 164*311b1773SSoby Mathew * GICC/GICR interface with the caches disabled. Hence flush the 165*311b1773SSoby Mathew * driver_data to ensure coherency. This is not required if the 166*311b1773SSoby Mathew * platform has HW_ASSISTED_COHERENCY enabled. 167*311b1773SSoby Mathew */ 168*311b1773SSoby Mathew #if !HW_ASSISTED_COHERENCY 169*311b1773SSoby Mathew flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data)); 170*311b1773SSoby Mathew flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data)); 171*311b1773SSoby Mathew #endif 172464ce2bbSSoby Mathew INFO("ARM GICv2 driver initialized\n"); 173464ce2bbSSoby Mathew } 174464ce2bbSSoby Mathew 175464ce2bbSSoby Mathew /****************************************************************************** 176464ce2bbSSoby Mathew * This function returns whether FIQ is enabled in the GIC CPU interface. 177464ce2bbSSoby Mathew *****************************************************************************/ 178464ce2bbSSoby Mathew unsigned int gicv2_is_fiq_enabled(void) 179464ce2bbSSoby Mathew { 180464ce2bbSSoby Mathew unsigned int gicc_ctlr; 181464ce2bbSSoby Mathew 182464ce2bbSSoby Mathew assert(driver_data); 183464ce2bbSSoby Mathew assert(driver_data->gicc_base); 184464ce2bbSSoby Mathew 185464ce2bbSSoby Mathew gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base); 186464ce2bbSSoby Mathew return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1; 187464ce2bbSSoby Mathew } 188464ce2bbSSoby Mathew 189464ce2bbSSoby Mathew /******************************************************************************* 190464ce2bbSSoby Mathew * This function returns the type of the highest priority pending interrupt at 191464ce2bbSSoby Mathew * the GIC cpu interface. The return values can be one of the following : 192464ce2bbSSoby Mathew * PENDING_G1_INTID : The interrupt type is non secure Group 1. 193464ce2bbSSoby Mathew * 0 - 1019 : The interrupt type is secure Group 0. 194464ce2bbSSoby Mathew * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with 195464ce2bbSSoby Mathew * sufficient priority to be signaled 196464ce2bbSSoby Mathew ******************************************************************************/ 197464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_type(void) 198464ce2bbSSoby Mathew { 199464ce2bbSSoby Mathew assert(driver_data); 200464ce2bbSSoby Mathew assert(driver_data->gicc_base); 201464ce2bbSSoby Mathew 202464ce2bbSSoby Mathew return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; 203464ce2bbSSoby Mathew } 204464ce2bbSSoby Mathew 205464ce2bbSSoby Mathew /******************************************************************************* 206464ce2bbSSoby Mathew * This function returns the id of the highest priority pending interrupt at 207464ce2bbSSoby Mathew * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no 208464ce2bbSSoby Mathew * interrupt pending. 209464ce2bbSSoby Mathew ******************************************************************************/ 210464ce2bbSSoby Mathew unsigned int gicv2_get_pending_interrupt_id(void) 211464ce2bbSSoby Mathew { 212464ce2bbSSoby Mathew unsigned int id; 213464ce2bbSSoby Mathew 214464ce2bbSSoby Mathew assert(driver_data); 215464ce2bbSSoby Mathew assert(driver_data->gicc_base); 216464ce2bbSSoby Mathew 217464ce2bbSSoby Mathew id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; 218464ce2bbSSoby Mathew 219464ce2bbSSoby Mathew /* 220464ce2bbSSoby Mathew * Find out which non-secure interrupt it is under the assumption that 221464ce2bbSSoby Mathew * the GICC_CTLR.AckCtl bit is 0. 222464ce2bbSSoby Mathew */ 223464ce2bbSSoby Mathew if (id == PENDING_G1_INTID) 224464ce2bbSSoby Mathew id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK; 225464ce2bbSSoby Mathew 226464ce2bbSSoby Mathew return id; 227464ce2bbSSoby Mathew } 228464ce2bbSSoby Mathew 229464ce2bbSSoby Mathew /******************************************************************************* 230464ce2bbSSoby Mathew * This functions reads the GIC cpu interface Interrupt Acknowledge register 231464ce2bbSSoby Mathew * to start handling the pending secure 0 interrupt. It returns the 232464ce2bbSSoby Mathew * contents of the IAR. 233464ce2bbSSoby Mathew ******************************************************************************/ 234464ce2bbSSoby Mathew unsigned int gicv2_acknowledge_interrupt(void) 235464ce2bbSSoby Mathew { 236464ce2bbSSoby Mathew assert(driver_data); 237464ce2bbSSoby Mathew assert(driver_data->gicc_base); 238464ce2bbSSoby Mathew 239464ce2bbSSoby Mathew return gicc_read_IAR(driver_data->gicc_base); 240464ce2bbSSoby Mathew } 241464ce2bbSSoby Mathew 242464ce2bbSSoby Mathew /******************************************************************************* 243464ce2bbSSoby Mathew * This functions writes the GIC cpu interface End Of Interrupt register with 244464ce2bbSSoby Mathew * the passed value to finish handling the active secure group 0 interrupt. 245464ce2bbSSoby Mathew ******************************************************************************/ 246464ce2bbSSoby Mathew void gicv2_end_of_interrupt(unsigned int id) 247464ce2bbSSoby Mathew { 248464ce2bbSSoby Mathew assert(driver_data); 249464ce2bbSSoby Mathew assert(driver_data->gicc_base); 250464ce2bbSSoby Mathew 251464ce2bbSSoby Mathew gicc_write_EOIR(driver_data->gicc_base, id); 252464ce2bbSSoby Mathew } 253464ce2bbSSoby Mathew 254464ce2bbSSoby Mathew /******************************************************************************* 255464ce2bbSSoby Mathew * This function returns the type of the interrupt id depending upon the group 256464ce2bbSSoby Mathew * this interrupt has been configured under by the interrupt controller i.e. 257464ce2bbSSoby Mathew * group0 secure or group1 non secure. It returns zero for Group 0 secure and 258464ce2bbSSoby Mathew * one for Group 1 non secure interrupt. 259464ce2bbSSoby Mathew ******************************************************************************/ 260464ce2bbSSoby Mathew unsigned int gicv2_get_interrupt_group(unsigned int id) 261464ce2bbSSoby Mathew { 262464ce2bbSSoby Mathew assert(driver_data); 263464ce2bbSSoby Mathew assert(driver_data->gicd_base); 264464ce2bbSSoby Mathew 265464ce2bbSSoby Mathew return gicd_get_igroupr(driver_data->gicd_base, id); 266464ce2bbSSoby Mathew } 267