1 /* 2 * Copyright 2021-2022 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 #include <int.h> 6 #include <interrupt_controller.h> 7 #include <kernel.h> 8 #include <vm/vm.h> 9 10 #include "arch_int_gicv2.h" 11 #include "gicv2_regs.h" 12 13 14 GICv2InterruptController::GICv2InterruptController(uint32_t gicd_addr, uint32_t gicc_addr) 15 : InterruptController() 16 { 17 reserve_io_interrupt_vectors(1020, 0, INTERRUPT_TYPE_IRQ); 18 19 area_id gicd_area = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-gicv2-gicd", 20 (void**)&fGicdRegs, B_ANY_KERNEL_ADDRESS, GICD_REG_SIZE, 21 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 22 gicd_addr ? gicd_addr : GICD_REG_START, false); 23 if (gicd_area < 0) { 24 panic("not able to map the memory area for gicd\n"); 25 } 26 27 area_id gicc_area = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-gicv2-gicc", 28 (void**)&fGiccRegs, B_ANY_KERNEL_ADDRESS, GICC_REG_SIZE, 29 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 30 gicc_addr ? gicc_addr : GICC_REG_START, false); 31 if (gicc_area < 0) { 32 panic("not able to map the memory area for gicc\n"); 33 } 34 35 // disable GICD 36 fGicdRegs[GICD_REG_CTLR] = 0; 37 38 // disable GICC 39 fGiccRegs[GICC_REG_CTLR] = 0; 40 41 // TODO: disable all interrupts 42 fGicdRegs[GICD_REG_ICENABLER] = 0xffffffff; 43 fGicdRegs[GICD_REG_ICENABLER+1] = 0xffffffff; 44 45 // set PMR and BPR 46 fGiccRegs[GICC_REG_PMR] = 0xff; 47 fGiccRegs[GICC_REG_BPR] = 0x07; 48 49 // enable GICC 50 fGiccRegs[GICC_REG_CTLR] = 0x03; 51 52 // enable GICD 53 fGicdRegs[GICD_REG_CTLR] = 0x03; 54 } 55 56 57 void GICv2InterruptController::EnableInterrupt(int irq) 58 { 59 uint32_t ena_reg = GICD_REG_ISENABLER + irq / 32; 60 uint32_t ena_val = 1 << (irq % 32); 61 fGicdRegs[ena_reg] = ena_val; 62 63 uint32_t prio_reg = GICD_REG_IPRIORITYR + irq / 4; 64 uint32_t prio_val = fGicdRegs[prio_reg]; 65 prio_val |= 0x80 << (irq % 4 * 8); 66 fGicdRegs[prio_reg] = prio_val; 67 } 68 69 70 void GICv2InterruptController::DisableInterrupt(int irq) 71 { 72 fGicdRegs[GICD_REG_ICENABLER + irq / 32] = 1 << (irq % 32); 73 } 74 75 76 void GICv2InterruptController::HandleInterrupt() 77 { 78 uint32_t iar = fGiccRegs[GICC_REG_IAR]; 79 uint32_t irqnr = iar & 0x3FF; 80 if ((irqnr == 1022) || (irqnr == 1023)) { 81 dprintf("spurious interrupt\n"); 82 } else { 83 int_io_interrupt_handler(irqnr, true); 84 } 85 86 fGiccRegs[GICC_REG_EOIR] = iar; 87 } 88