1/* 2 * Copyright (c) 2012, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich. 8 */ 9 10#include <kernel.h> 11 12#include <dev/pl130_gic_dev.h> 13#include <arch/arm/gic.h> 14#include <platform.h> 15#include <paging_kernel_arch.h> 16 17static pl130_gic_t gic; 18static uint32_t it_num_lines; 19static pl130_gic_ICDICTR_t gic_config; 20static uint8_t cpu_number; 21 22#define MSG(format, ...) printk( LOG_NOTE, "GIC: "format, ## __VA_ARGS__ ) 23 24enum IrqType { 25 IrqType_SGI, 26 IrqType_PPI, 27 IrqType_SPI 28}; 29 30#define DIST_SIZE 0x1000 31#define CPU_SIZE 0x1000 32 33/** 34 * \brief Returns the IRQ type based on the interrupt ID 35 * 36 * We have three types of interrupts 37 * 1) Software generated Interrupts (SGI): IDs 0-15 38 * 2) Private Peripheral Interrupts (PPI): IDs 16-31 39 * 3) Shared Peripheral Interrups (SPI): IDs 32- 40 * 41 * \return The type of the interrupt. 42 */ 43static enum IrqType get_irq_type(uint32_t int_id) 44{ 45 if (int_id < 16) { 46 return IrqType_SGI; 47 } else if (int_id < 32) { 48 return IrqType_PPI; 49 } else { 50 return IrqType_SPI; 51 } 52} 53 54/* 55 * Initialize the global interrupt controller 56 * 57 * There are three types of interrupts 58 * 1) Software generated Interrupts (SGI) - IDs 0-15 59 * 2) Private Peripheral Interrupts (PPI) - IDs 16-31 60 * 3) Shared Peripheral Interrups (SPI) - IDs 32... 61 */ 62void gic_init(void) 63{ 64 lvaddr_t gic_dist_base = 65 paging_map_device( platform_get_distributor_address(), DIST_SIZE ); 66 lvaddr_t gic_cpu_base = 67 paging_map_device( platform_get_gic_cpu_address(), CPU_SIZE ); 68 pl130_gic_initialize(&gic, (mackerel_addr_t)gic_dist_base, 69 (mackerel_addr_t)gic_cpu_base ); 70 71 // read GIC configuration 72 gic_config = pl130_gic_ICDICTR_rd(&gic); 73 74 // ARM GIC 2.0 TRM, Table 4-6 75 // This is the number of ICDISERs, i.e. #SPIs 76 // Number of SGIs (0-15) and PPIs (16-31) is fixed 77 uint32_t it_num_lines_tmp = 78 pl130_gic_ICDICTR_it_lines_num_extract(gic_config); 79 it_num_lines = 32*(it_num_lines_tmp + 1); 80 81 MSG("%d interrupt lines detected\n", it_num_lines); 82 83 cpu_number = pl130_gic_ICDICTR_cpu_number_extract(gic_config) + 1; 84 85 // set priority mask of cpu interface, currently set to lowest priority 86 // to accept all interrupts 87 pl130_gic_ICCPMR_wr(&gic, 0xff); 88 89 // set binary point to define split of group- and subpriority 90 // currently we allow for 8 subpriorities 91 pl130_gic_ICCBPR_wr(&gic, 0x2); 92 93 // enable interrupt forwarding to processor 94 pl130_gic_ICCICR_enable_wrf(&gic, 0x1); 95 96 // Distributor: 97 // enable interrupt forwarding from distributor to cpu interface 98 pl130_gic_ICDDCR_enable_wrf(&gic, 0x1); 99 MSG("gic_init done\n"); 100} 101 102size_t 103gic_cpu_count(void) { 104 return cpu_number; 105} 106 107void __attribute__((noreturn)) gic_disable_all_irqs(void) 108{ 109 panic("gic_disable_all_irqs NYI for armv7"); 110 // XXX Rewrite according to pl130 interface changes! 111 // ALSO remove noreturn option 112 113 /* //disable PPI interrupts */ 114 /* pl130_gic_PPI_ICDICER_wr(&gic, (uint16_t)0xffff); */ 115 116 /* //disable SPI interrupts */ 117 /* for(uint8_t i=0; i < it_num_lines; i++) { */ 118 /* pl130_gic_SPI_ICDICER_wr(&gic, i, (uint32_t)0xffffffff); */ 119 /* } */ 120} 121 122uint32_t gic_get_active_irq(void) 123{ 124 uint32_t regval = pl130_gic_ICCIAR_rd(&gic); 125 126 return regval; 127} 128 129void gic_raise_softirq(uint8_t cpumask, uint8_t irq) 130{ 131 uint32_t regval = (cpumask << 16) | irq; 132 pl130_gic_ICDSGIR_wr(&gic, regval); 133} 134 135void gic_ack_irq(uint32_t irq) 136{ 137 pl130_gic_ICCEOIR_rawwr(&gic, irq); 138} 139 140//enable interrupt forwarding to processor 141void gic_cpu_interface_enable(void) 142{ 143 pl130_gic_ICCICR_wr(&gic, 0x1); 144} 145 146 147/** 148 * \brief Enable an interrupt 149 * 150 * \see ARM Generic Interrupt Controller Architecture Specification v1.0 151 * 152 * \param int_id 153 * \param cpu_targets 8 Bit mask. One bit for each core in the system. 154 * (chapter 4.3.11) 155 * \param prio Priority of the interrupt (lower is higher). We allow 0..15. 156 * The number of priority bits is implementation specific, but at least 16 157 * (using bits [7:4] of the priority field, chapter 3.3) 158 * \param 0 is level-sensitive, 1 is edge-triggered 159 * \param 0 is N-to-N, 1 is 1-N 160 */ 161void gic_enable_interrupt(uint32_t int_id, uint8_t cpu_targets, uint16_t prio, 162 bool edge_triggered, bool one_to_n) 163{ 164 // Set Interrupt Set-Enable Register 165 uint32_t ind = int_id / 32; 166 uint32_t bit_mask = (1U << (int_id % 32)); 167 uint32_t regval; 168 169 MSG("gic_enable_interrupt for id=0x%"PRIx32", " 170 "offset=0x%"PRIx32", index=0x%"PRIx32"\n", 171 int_id, bit_mask, ind); 172 173 enum IrqType irq_type = get_irq_type(int_id); 174 175 // Set the Interrupt Set Enable register to enable the interupt 176 // See ARM GIC TRM 177 if (irq_type == IrqType_SGI) { 178 MSG("unhandled SGI IRQ %d\n", int_id); 179 return; // Do nothing for SGI interrupts 180 } 181 182 // XXX: check what we need to do if int_id > it_num_lines 183 // -SG, 2012/12/13 184 assert(int_id <= it_num_lines); 185 186 // Enable 187 // 1 Bit per interrupt 188 regval = pl130_gic_ICDISER_rd(&gic, ind); 189 regval |= bit_mask; 190 pl130_gic_ICDISER_wr(&gic, ind, regval); 191 192 // TODO: cleanup pl130 mackerel file so that we don't need bit magic 193 // here. -SG, 2012/12/13 194 195 // Priority 196 // 8 Bit per interrupt 197 // chp 4.3.10 198 ind = int_id/4; 199 // XXX: check that priorities work properly, -SG, 2012/12/13 200 prio = (prio & 0xF)<<4; 201 switch(int_id % 4) { 202 case 0: 203 pl130_gic_ICDIPR_prio_off0_wrf(&gic, ind, prio); 204 break; 205 case 1: 206 pl130_gic_ICDIPR_prio_off1_wrf(&gic, ind, prio); 207 break; 208 case 2: 209 pl130_gic_ICDIPR_prio_off2_wrf(&gic, ind, prio); 210 break; 211 case 3: 212 pl130_gic_ICDIPR_prio_off3_wrf(&gic, ind, prio); 213 break; 214 } 215 216 // Target processors (only SPIs) 217 // 8 Bit per interrupt 218 ind = int_id/4; 219 if (irq_type == IrqType_SPI) { // rest is ro 220 switch (int_id % 4) { 221 case 0: 222 pl130_gic_ICDIPTR_targets_off0_wrf(&gic, ind, cpu_targets); 223 break; 224 case 1: 225 pl130_gic_ICDIPTR_targets_off1_wrf(&gic, ind, cpu_targets); 226 break; 227 case 2: 228 pl130_gic_ICDIPTR_targets_off2_wrf(&gic, ind, cpu_targets); 229 break; 230 case 3: 231 pl130_gic_ICDIPTR_targets_off3_wrf(&gic, ind, cpu_targets); 232 break; 233 } 234 } 235 236 // Configuration registers 237 // 2 Bit per IRQ 238 ind = int_id/16; 239 uint8_t val = ((edge_triggered&0x1) << 1) | (one_to_n&0x1); 240 switch (int_id % 16) { 241 case 0: 242 pl130_gic_ICDICR_conf0_wrf(&gic, ind, val); 243 break; 244 case 1: 245 pl130_gic_ICDICR_conf1_wrf(&gic, ind, val); 246 break; 247 case 2: 248 pl130_gic_ICDICR_conf2_wrf(&gic, ind, val); 249 break; 250 case 3: 251 pl130_gic_ICDICR_conf3_wrf(&gic, ind, val); 252 break; 253 case 4: 254 pl130_gic_ICDICR_conf4_wrf(&gic, ind, val); 255 break; 256 case 5: 257 pl130_gic_ICDICR_conf5_wrf(&gic, ind, val); 258 break; 259 case 6: 260 pl130_gic_ICDICR_conf6_wrf(&gic, ind, val); 261 break; 262 case 7: 263 pl130_gic_ICDICR_conf7_wrf(&gic, ind, val); 264 break; 265 case 8: 266 pl130_gic_ICDICR_conf8_wrf(&gic, ind, val); 267 break; 268 case 9: 269 pl130_gic_ICDICR_conf9_wrf(&gic, ind, val); 270 break; 271 case 10: 272 pl130_gic_ICDICR_conf10_wrf(&gic, ind, val); 273 break; 274 case 11: 275 pl130_gic_ICDICR_conf11_wrf(&gic, ind, val); 276 break; 277 case 12: 278 pl130_gic_ICDICR_conf12_wrf(&gic, ind, val); 279 break; 280 case 13: 281 pl130_gic_ICDICR_conf13_wrf(&gic, ind, val); 282 break; 283 case 14: 284 pl130_gic_ICDICR_conf14_wrf(&gic, ind, val); 285 break; 286 case 15: 287 pl130_gic_ICDICR_conf15_wrf(&gic, ind, val); 288 break; 289 } 290} 291 292