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
GICv2InterruptController(uint32_t gicd_addr,uint32_t gicc_addr)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
EnableInterrupt(int32 irq)57 void GICv2InterruptController::EnableInterrupt(int32 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
DisableInterrupt(int32 irq)70 void GICv2InterruptController::DisableInterrupt(int32 irq)
71 {
72 fGicdRegs[GICD_REG_ICENABLER + irq / 32] = 1 << (irq % 32);
73 }
74
75
HandleInterrupt()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