1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * This software may be distributed and modified according to the terms of 5 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 6 * See "LICENSE_GPLv2.txt" for details. 7 * 8 * @TAG(GD_GPL) 9 */ 10 11#include <config.h> 12#include <arch/machine/gic_pl390.h> 13 14#define TARGET_CPU_ALLINT(CPU) ( \ 15 ( ((CPU)&0xff)<<0u ) |\ 16 ( ((CPU)&0xff)<<8u ) |\ 17 ( ((CPU)&0xff)<<16u ) |\ 18 ( ((CPU)&0xff)<<24u ) \ 19 ) 20#define TARGET_CPU0_ALLINT TARGET_CPU_ALLINT(BIT(0)) 21 22/* Use this to forward interrupts to all CPUs when debugging */ 23#define TARGET_CPU_ALL_ALLINT TARGET_CPU_ALLINT(0xff) 24 25#define IRQ_SET_ALL 0xffffffff; 26 27/* Shift positions for GICD_SGIR register */ 28#define GICD_SGIR_SGIINTID_SHIFT 0 29#define GICD_SGIR_CPUTARGETLIST_SHIFT 16 30#define GICD_SGIR_TARGETLISTFILTER_SHIFT 24 31 32#ifndef GIC_PL390_DISTRIBUTOR_PPTR 33#error GIC_PL390_DISTRIBUTOR_PPTR must be defined for virtual memory access to the gic distributer 34#else /* GIC_DISTRIBUTOR_PPTR */ 35volatile struct gic_dist_map * const gic_dist = 36 (volatile struct gic_dist_map*)(GIC_PL390_DISTRIBUTOR_PPTR); 37#endif /* GIC_DISTRIBUTOR_PPTR */ 38 39#ifndef GIC_PL390_CONTROLLER_PPTR 40#error GIC_PL390_CONTROLLER_PPTR must be defined for virtual memory access to the gic cpu interface 41#else /* GIC_CONTROLLER_PPTR */ 42volatile struct gic_cpu_iface_map * const gic_cpuiface = 43 (volatile struct gic_cpu_iface_map*)(GIC_PL390_CONTROLLER_PPTR); 44#endif /* GIC_CONTROLLER_PPTR */ 45 46uint32_t active_irq[CONFIG_MAX_NUM_NODES] = {IRQ_NONE}; 47 48/* Get the target id for this processor. We rely on the constraint that the registers 49 * for PPI are read only and return only the current processor as the target. 50 * If this doesn't lead to a valid ID, we emit a warning and default to core 0. 51 */ 52BOOT_CODE static uint8_t 53infer_cpu_gic_id(int nirqs) 54{ 55 word_t i; 56 uint32_t target = 0; 57 for (i = 0; i < nirqs; i += 4) { 58 target = gic_dist->targets[i >> 2]; 59 target |= target >> 16; 60 target |= target >> 8; 61 if (target) { 62 break; 63 } 64 } 65 if (!target) { 66 printf("Warning: Could not infer GIC interrupt target ID, assuming 0.\n"); 67 target = BIT(0); 68 } 69 return target & 0xff; 70} 71 72BOOT_CODE static void 73dist_init(void) 74{ 75 word_t i; 76 int nirqs = 32 * ((gic_dist->ic_type & 0x1f) + 1); 77 gic_dist->enable = 0; 78 79 for (i = 0; i < nirqs; i += 32) { 80 /* disable */ 81 gic_dist->enable_clr[i >> 5] = IRQ_SET_ALL; 82 /* clear pending */ 83 gic_dist->pending_clr[i >> 5] = IRQ_SET_ALL; 84 } 85 86 /* reset interrupts priority */ 87 for (i = 32; i < nirqs; i += 4) { 88 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) { 89 gic_dist->priority[i >> 2] = 0x80808080; 90 } else { 91 gic_dist->priority[i >> 2] = 0; 92 } 93 } 94 95 /* 96 * reset int target to current cpu 97 * We query which id that the GIC uses for us and use that. 98 */ 99 uint8_t target = infer_cpu_gic_id(nirqs); 100 for (i = 0; i < nirqs; i += 4) { 101 gic_dist->targets[i >> 2] = TARGET_CPU_ALLINT(target); 102 } 103 104 /* level-triggered, 1-N */ 105 for (i = 64; i < nirqs; i += 32) { 106 gic_dist->config[i >> 5] = 0x55555555; 107 } 108 109 /* group 0 for secure; group 1 for non-secure */ 110 for (i = 0; i < nirqs; i += 32) { 111 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) { 112 gic_dist->security[i >> 5] = 0xffffffff; 113 } else { 114 gic_dist->security[i >> 5] = 0; 115 } 116 } 117 /* enable the int controller */ 118 gic_dist->enable = 1; 119} 120 121BOOT_CODE static void 122cpu_iface_init(void) 123{ 124 uint32_t i; 125 126 /* For non-Exynos4, the registers are banked per CPU, need to clear them */ 127 gic_dist->enable_clr[0] = IRQ_SET_ALL; 128 gic_dist->pending_clr[0] = IRQ_SET_ALL; 129 130 /* put everything in group 0; group 1 if in hyp mode */ 131 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) { 132 gic_dist->security[0] = 0xffffffff; 133 gic_dist->priority[0] = 0x80808080; 134 } else { 135 gic_dist->security[0] = 0; 136 gic_dist->priority[0] = 0x0; 137 } 138 139 /* clear any software generated interrupts */ 140 for (i = 0; i < 16; i += 4) { 141 gic_dist->sgi_pending_clr[i >> 2] = IRQ_SET_ALL; 142 } 143 144 gic_cpuiface->icontrol = 0; 145 /* the write to priority mask is ignored if the kernel is 146 * in non-secure mode and the priority mask is already configured 147 * by secure mode software. the elfloader should config the 148 * interrupt routing properly to ensure that the hyp-mode kernel 149 * can get interrupts 150 */ 151 gic_cpuiface->pri_msk_c = 0x000000f0; 152 gic_cpuiface->pb_c = 0x00000003; 153 154 i = gic_cpuiface->int_ack; 155 while ((i & IRQ_MASK) != IRQ_NONE) { 156 gic_cpuiface->eoi = i; 157 i = gic_cpuiface->int_ack; 158 } 159 gic_cpuiface->icontrol = 1; 160} 161 162void setIRQTrigger(irq_t irq, bool_t trigger) 163{ 164 /* in the gic_config, there is a 2 bit field for each irq, 165 * setting the most significant bit of this field makes the irq edge-triggered, 166 * while 0 indicates that it is level-triggered */ 167 word_t index = irq / 16u; 168 word_t offset = (irq % 16u) * 2; 169 if (trigger) { 170 /* set the bit */ 171 gic_dist->config[index] |= BIT(offset + 1); 172 } else { 173 gic_dist->config[index] &= ~BIT(offset + 1); 174 } 175} 176 177BOOT_CODE void 178initIRQController(void) 179{ 180 dist_init(); 181} 182 183BOOT_CODE void cpu_initLocalIRQController(void) 184{ 185 cpu_iface_init(); 186} 187 188#ifdef ENABLE_SMP_SUPPORT 189/* 190* 25-24: target lister filter 191* 0b00 - send the ipi to the CPU interfaces specified in the CPU target list 192* 0b01 - send the ipi to all CPU interfaces except the cpu interface. 193* that requrested teh ipi 194* 0b10 - send the ipi only to the CPU interface that requested the IPI. 195* 0b11 - reserved 196*. 197* 23-16: CPU targets list 198* each bit of CPU target list [7:0] refers to the corresponding CPU interface. 199* 3-0: SGIINTID 200* software generated interrupt id, from 0 to 15... 201*/ 202void ipiBroadcast(irq_t irq, bool_t includeSelfCPU) 203{ 204 gic_dist->sgi_control = (!includeSelfCPU << GICD_SGIR_TARGETLISTFILTER_SHIFT) | (irq << GICD_SGIR_SGIINTID_SHIFT); 205} 206 207void ipi_send_target(irq_t irq, word_t cpuTargetList) 208{ 209 gic_dist->sgi_control = (cpuTargetList << GICD_SGIR_CPUTARGETLIST_SHIFT) | (irq << GICD_SGIR_SGIINTID_SHIFT); 210} 211#endif /* ENABLE_SMP_SUPPORT */ 212 213#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT 214 215#ifndef GIC_PL400_VCPUCTRL_PPTR 216#error GIC_PL400_VCPUCTRL_PPTR must be defined for virtual memory access to the gic virtual cpu interface control 217#else /* GIC_PL400_GICVCPUCTRL_PPTR */ 218volatile struct gich_vcpu_ctrl_map *gic_vcpu_ctrl = 219 (volatile struct gich_vcpu_ctrl_map*)(GIC_PL400_VCPUCTRL_PPTR); 220#endif /* GIC_PL400_GICVCPUCTRL_PPTR */ 221 222unsigned int gic_vcpu_num_list_regs; 223 224#endif /* End of CONFIG_ARM_HYPERVISOR_SUPPORT */ 225