1 /* 2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 #include <assert.h> 31 #include <gic_common.h> 32 #include <gicv2.h> 33 #include <interrupt_mgmt.h> 34 35 /* 36 * The following platform GIC functions are weakly defined. They 37 * provide typical implementations that may be re-used by multiple 38 * platforms but may also be overridden by a platform if required. 39 */ 40 #pragma weak plat_ic_get_pending_interrupt_id 41 #pragma weak plat_ic_get_pending_interrupt_type 42 #pragma weak plat_ic_acknowledge_interrupt 43 #pragma weak plat_ic_get_interrupt_type 44 #pragma weak plat_ic_end_of_interrupt 45 #pragma weak plat_interrupt_type_to_line 46 47 /* 48 * This function returns the highest priority pending interrupt at 49 * the Interrupt controller 50 */ 51 uint32_t plat_ic_get_pending_interrupt_id(void) 52 { 53 unsigned int id; 54 55 id = gicv2_get_pending_interrupt_id(); 56 if (id == GIC_SPURIOUS_INTERRUPT) 57 return INTR_ID_UNAVAILABLE; 58 59 return id; 60 } 61 62 /* 63 * This function returns the type of the highest priority pending interrupt 64 * at the Interrupt controller. In the case of GICv2, the Highest Priority 65 * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of 66 * the pending interrupt. The type of interrupt depends upon the id value 67 * as follows. 68 * 1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt 69 * 2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt. 70 * 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt 71 * type. 72 */ 73 uint32_t plat_ic_get_pending_interrupt_type(void) 74 { 75 unsigned int id; 76 77 id = gicv2_get_pending_interrupt_type(); 78 79 /* Assume that all secure interrupts are S-EL1 interrupts */ 80 if (id < PENDING_G1_INTID) 81 return INTR_TYPE_S_EL1; 82 83 if (id == GIC_SPURIOUS_INTERRUPT) 84 return INTR_TYPE_INVAL; 85 86 return INTR_TYPE_NS; 87 } 88 89 /* 90 * This function returns the highest priority pending interrupt at 91 * the Interrupt controller and indicates to the Interrupt controller 92 * that the interrupt processing has started. 93 */ 94 uint32_t plat_ic_acknowledge_interrupt(void) 95 { 96 return gicv2_acknowledge_interrupt(); 97 } 98 99 /* 100 * This function returns the type of the interrupt `id`, depending on how 101 * the interrupt has been configured in the interrupt controller 102 */ 103 uint32_t plat_ic_get_interrupt_type(uint32_t id) 104 { 105 unsigned int type; 106 107 type = gicv2_get_interrupt_group(id); 108 109 /* Assume that all secure interrupts are S-EL1 interrupts */ 110 return (type) ? INTR_TYPE_NS : INTR_TYPE_S_EL1; 111 } 112 113 /* 114 * This functions is used to indicate to the interrupt controller that 115 * the processing of the interrupt corresponding to the `id` has 116 * finished. 117 */ 118 void plat_ic_end_of_interrupt(uint32_t id) 119 { 120 gicv2_end_of_interrupt(id); 121 } 122 123 /* 124 * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins. 125 * The interrupt controller knows which pin/line it uses to signal a type of 126 * interrupt. It lets the interrupt management framework determine 127 * for a type of interrupt and security state, which line should be used in the 128 * SCR_EL3 to control its routing to EL3. The interrupt line is represented 129 * as the bit position of the IRQ or FIQ bit in the SCR_EL3. 130 */ 131 uint32_t plat_interrupt_type_to_line(uint32_t type, 132 uint32_t security_state) 133 { 134 assert(type == INTR_TYPE_S_EL1 || 135 type == INTR_TYPE_EL3 || 136 type == INTR_TYPE_NS); 137 138 /* Non-secure interrupts are signaled on the IRQ line always */ 139 if (type == INTR_TYPE_NS) 140 return __builtin_ctz(SCR_IRQ_BIT); 141 142 /* 143 * Secure interrupts are signaled using the IRQ line if the FIQ is 144 * not enabled else they are signaled using the FIQ line. 145 */ 146 return ((gicv2_is_fiq_enabled()) ? __builtin_ctz(SCR_FIQ_BIT) : 147 __builtin_ctz(SCR_IRQ_BIT)); 148 } 149