xref: /haiku/src/system/kernel/arch/arm/arch_int_gicv2.cpp (revision 9f3bdf3d039430b5172c424def20ce5d9f7367d4)
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(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 
70 void GICv2InterruptController::DisableInterrupt(int32 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