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