1/* 2 * Copyright (c) 2016, 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, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <kernel.h> 11#include <sysreg.h> 12#include <dev/armv8_dev.h> 13#include <dev/gic_v3_dist_dev.h> 14#include <dev/gic_v3_redist_dev.h> 15#include <platform.h> 16#include <paging_kernel_arch.h> 17#include <arch/armv8/gic_v3.h> 18 19static gic_v3_dist_t gic_v3_dist_dev; 20static gic_v3_redist_t gic_v3_redist_dev; 21 22lpaddr_t platform_gic_cpu_base = 0; // no memory-mapped cpu interface 23 24/* 25 * Initialize the global interrupt controller 26 * 27 * There are three types of interrupts 28 * 1) Software generated Interrupts (SGI) - IDs 0-15 29 * 2) Private Peripheral Interrupts (PPI) - IDs 16-31 30 * 3) Shared Peripheral Interrups (SPI) - IDs 32-1019 31 * 4) Special - IDs 1020-1023 32 * 5) Locality-specific Peripheral Interrups (LPI) - IDs 8192-... 33 */ 34void gic_init(void) 35{ 36 printk(LOG_NOTE, "GICv3: Initializing\n"); 37 lvaddr_t gic_dist = local_phys_to_mem(platform_gic_dist_base); 38 gic_v3_dist_initialize(&gic_v3_dist_dev, (char *)gic_dist); 39 40 printf("%s: dist:%lx\n", __func__, gic_dist); 41 42 printk(LOG_NOTE, "GICD IIDR " 43 "implementer=0x%x, revision=0x%x, variant=0x%x,prodid=0x%x\n", 44 gic_v3_dist_GICD_IIDR_Implementer_rdf(&gic_v3_dist_dev), 45 gic_v3_dist_GICD_IIDR_Revision_rdf(&gic_v3_dist_dev), 46 gic_v3_dist_GICD_IIDR_Variant_rdf(&gic_v3_dist_dev), 47 gic_v3_dist_GICD_IIDR_ProductID_rdf(&gic_v3_dist_dev) 48 ); 49 50 uint32_t itlines = gic_v3_dist_GICD_TYPER_ITLinesNumber_rdf(&gic_v3_dist_dev); 51 itlines = (itlines + 1) * 32; 52 if (itlines > 1020) 53 itlines = 1020; 54 printk(LOG_NOTE, "gic: #INTIDs supported: %" PRIu32 "\n", itlines); 55 56 // Put all interrupts into Group 1 and enable them 57 #define MASK_32 0xffffffff 58 for (int i = 0; i * 32 < itlines; i++) { 59 // Clear 60 gic_v3_dist_GICD_ICACTIVER_wr(&gic_v3_dist_dev, i, MASK_32); 61 // Enable 62 gic_v3_dist_GICD_ISENABLER_wr(&gic_v3_dist_dev, i, MASK_32); 63 // And put in group 1 64 gic_v3_dist_GICD_IGROUPR_rawwr(&gic_v3_dist_dev, i, MASK_32); 65 } 66 gic_v3_dist_GICD_CTLR_secure_t ctrl = 0; 67 // Set affinity routing (redundant on CN88xx) 68 ctrl = gic_v3_dist_GICD_CTLR_secure_ARE_NS_insert(ctrl, 1); 69 // Enable group 1 interrupts 70 ctrl = gic_v3_dist_GICD_CTLR_secure_EnableGrp1NS_insert(ctrl, 1); 71 gic_v3_dist_GICD_CTLR_secure_wr(&gic_v3_dist_dev, ctrl); 72 73 printk(LOG_NOTE, "GICv3: Initialized\n"); 74} 75 76/* 77 * Returns active interrupt of group 1 78 */ 79uint32_t gic_get_active_irq(void) 80{ 81 return armv8_ICC_IAR1_EL1_INTID_rdf(NULL); 82} 83 84/* 85 * ACKs group 1 interrupt 86 */ 87void gic_ack_irq(uint32_t irq) 88{ 89 armv8_ICC_EOIR1_EL1_rawwr(NULL, irq); 90} 91 92/* 93 * Raise an SGI on a core. 94 */ 95void gic_raise_softirq(coreid_t cpuid, uint8_t irq) 96{ 97 assert(irq <= 15); 98 armv8_ICC_SGI1R_EL1_t reg = 0; 99 reg = armv8_ICC_SGI1R_EL1_INTID_insert(reg, 1); 100 // TODO: make that work for cpuids > 15 101 reg = armv8_ICC_SGI1R_EL1_TargetList_insert(reg, 1<<cpuid); 102 reg = armv8_ICC_SGI1R_EL1_Aff3_insert(reg, 0); 103 reg = armv8_ICC_SGI1R_EL1_Aff2_insert(reg, 0); 104 reg = armv8_ICC_SGI1R_EL1_Aff1_insert(reg, 0); 105 armv8_ICC_SGI1R_EL1_wr(NULL, reg); 106} 107 108/* 109 * Enable GIC CPU-IF and a redistributor 110 */ 111void gic_cpu_interface_enable(void) 112{ 113 printk(LOG_NOTE, "GICv3: Enabling CPU interface\n"); 114 115 lvaddr_t gic_redist = local_phys_to_mem(platform_gic_redist_base); 116 117 // Enable system register access 118 armv8_ICC_SRE_EL1_SRE_wrf(NULL, 1); 119 120 gic_v3_redist_initialize(&gic_v3_redist_dev, (char *)gic_redist + 0x20000 * my_core_id); 121 printf("%s: redist:%lx\n", __func__, (char *)gic_redist + 0x20000 * my_core_id); 122 123 // Linux does: 124 // sets priority mode: PMR to 0xf0 125 armv8_ICC_PMR_EL1_wr(NULL, 0xf0); 126 // Set binary point to 1, 6 group priority bits, 2 subpriority bits 127 armv8_ICC_BPR1_EL1_wr(NULL, 1); 128 129 //Enable group 1 130 armv8_ICC_IGRPEN1_EL1_wr(NULL, 0x1); 131 132 gic_v3_redist_GICR_TYPER_t gicr_typer; 133 gicr_typer = gic_v3_redist_GICR_TYPER_rd(&gic_v3_redist_dev); 134 printf("%s: GICR_TYPER: affinity:%x cpu_no:%x\n", __func__, gic_v3_redist_GICR_TYPER_Affinity_Value_extract(gicr_typer), gic_v3_redist_GICR_TYPER_Processor_Number_extract(gicr_typer)); 135 136 gic_v3_redist_GICR_ICACTIVER0_rawwr(&gic_v3_redist_dev, MASK_32); 137 gic_v3_redist_GICR_ISENABLER0_rawwr(&gic_v3_redist_dev, MASK_32); 138 139 gic_v3_redist_GICR_IGROUPR0_rawwr(&gic_v3_redist_dev, MASK_32); 140 gic_v3_redist_GICR_IGRPMODR0_rawwr(&gic_v3_redist_dev, 0); 141 142 printk(LOG_NOTE, "GICv3: CPU interface enabled\n"); 143} 144 145/** 146 * \brief Enable an interrupt 147 * 148 * \see ARM Generic Interrupt Controller Architecture Specification v1.0 149 * 150 * \param int_id 151 * \param cpu_targets 8 Bit mask. One bit for each core in the system. 152 * (chapter 4.3.11) 153 * \param prio Priority of the interrupt (lower is higher). We allow 0..15. 154 * The number of priority bits is implementation specific, but at least 16 155 * (using bits [7:4] of the priority field, chapter 3.3) 156 * \param 0 is level-sensitive, 1 is edge-triggered 157 * \param 0 is N-to-N, 1 is 1-N 158 */ 159void gic_enable_interrupt(uint32_t int_id, uint8_t cpu_targets, uint16_t prio, 160 bool edge_triggered, bool one_to_n) 161{ 162} 163 164errval_t platform_gic_init(void) { 165 gic_init(); 166 return SYS_ERR_OK; 167} 168 169errval_t platform_gic_cpu_interface_enable(void) { 170 gic_cpu_interface_enable(); 171 return SYS_ERR_OK; 172} 173