xref: /haiku/src/system/kernel/arch/arm/arch_int_gicv2.cpp (revision 02463fb461904c264e5d559f6ec1de92cf35e436)
136d65a78SDavid Karoly /*
26a1f9758SDavid Karoly  * Copyright 2021-2022 Haiku, Inc. All rights reserved.
336d65a78SDavid Karoly  * Distributed under the terms of the MIT License.
436d65a78SDavid Karoly  */
536d65a78SDavid Karoly #include <int.h>
636d65a78SDavid Karoly #include <interrupt_controller.h>
736d65a78SDavid Karoly #include <kernel.h>
836d65a78SDavid Karoly #include <vm/vm.h>
936d65a78SDavid Karoly 
1036d65a78SDavid Karoly #include "arch_int_gicv2.h"
1136d65a78SDavid Karoly #include "gicv2_regs.h"
1236d65a78SDavid Karoly 
1336d65a78SDavid Karoly 
GICv2InterruptController(uint32_t gicd_addr,uint32_t gicc_addr)1436d65a78SDavid Karoly GICv2InterruptController::GICv2InterruptController(uint32_t gicd_addr, uint32_t gicc_addr)
1536d65a78SDavid Karoly : InterruptController()
1636d65a78SDavid Karoly {
1755212b95SDavid Karoly 	reserve_io_interrupt_vectors(1020, 0, INTERRUPT_TYPE_IRQ);
1855212b95SDavid Karoly 
1936d65a78SDavid Karoly 	area_id gicd_area = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-gicv2-gicd",
2036d65a78SDavid Karoly 		(void**)&fGicdRegs, B_ANY_KERNEL_ADDRESS, GICD_REG_SIZE,
2136d65a78SDavid Karoly 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
2236d65a78SDavid Karoly 		gicd_addr ? gicd_addr : GICD_REG_START, false);
2336d65a78SDavid Karoly 	if (gicd_area < 0) {
2436d65a78SDavid Karoly 		panic("not able to map the memory area for gicd\n");
2536d65a78SDavid Karoly 	}
2636d65a78SDavid Karoly 
2736d65a78SDavid Karoly 	area_id gicc_area = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-gicv2-gicc",
2836d65a78SDavid Karoly 		(void**)&fGiccRegs, B_ANY_KERNEL_ADDRESS, GICC_REG_SIZE,
2936d65a78SDavid Karoly 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
3036d65a78SDavid Karoly 		gicc_addr ? gicc_addr : GICC_REG_START, false);
3136d65a78SDavid Karoly 	if (gicc_area < 0) {
3236d65a78SDavid Karoly 		panic("not able to map the memory area for gicc\n");
3336d65a78SDavid Karoly 	}
3436d65a78SDavid Karoly 
3536d65a78SDavid Karoly 	// disable GICD
3636d65a78SDavid Karoly 	fGicdRegs[GICD_REG_CTLR] = 0;
3736d65a78SDavid Karoly 
3836d65a78SDavid Karoly 	// disable GICC
3936d65a78SDavid Karoly 	fGiccRegs[GICC_REG_CTLR] = 0;
4036d65a78SDavid Karoly 
4136d65a78SDavid Karoly 	// TODO: disable all interrupts
4236d65a78SDavid Karoly 	fGicdRegs[GICD_REG_ICENABLER] = 0xffffffff;
4336d65a78SDavid Karoly 	fGicdRegs[GICD_REG_ICENABLER+1] = 0xffffffff;
4436d65a78SDavid Karoly 
4536d65a78SDavid Karoly 	// set PMR and BPR
4636d65a78SDavid Karoly 	fGiccRegs[GICC_REG_PMR] = 0xff;
4736d65a78SDavid Karoly 	fGiccRegs[GICC_REG_BPR] = 0x07;
4836d65a78SDavid Karoly 
4936d65a78SDavid Karoly 	// enable GICC
5036d65a78SDavid Karoly 	fGiccRegs[GICC_REG_CTLR] = 0x03;
5136d65a78SDavid Karoly 
5236d65a78SDavid Karoly 	// enable GICD
5336d65a78SDavid Karoly 	fGicdRegs[GICD_REG_CTLR] = 0x03;
5436d65a78SDavid Karoly }
5536d65a78SDavid Karoly 
5636d65a78SDavid Karoly 
EnableInterrupt(int32 irq)57*02463fb4SX512 void GICv2InterruptController::EnableInterrupt(int32 irq)
5836d65a78SDavid Karoly {
5936d65a78SDavid Karoly 	uint32_t ena_reg = GICD_REG_ISENABLER + irq / 32;
6036d65a78SDavid Karoly 	uint32_t ena_val = 1 << (irq % 32);
6136d65a78SDavid Karoly 	fGicdRegs[ena_reg] = ena_val;
6236d65a78SDavid Karoly 
6336d65a78SDavid Karoly 	uint32_t prio_reg = GICD_REG_IPRIORITYR + irq / 4;
6436d65a78SDavid Karoly 	uint32_t prio_val = fGicdRegs[prio_reg];
6536d65a78SDavid Karoly 	prio_val |= 0x80 << (irq % 4 * 8);
6636d65a78SDavid Karoly 	fGicdRegs[prio_reg] = prio_val;
6736d65a78SDavid Karoly }
6836d65a78SDavid Karoly 
6936d65a78SDavid Karoly 
DisableInterrupt(int32 irq)70*02463fb4SX512 void GICv2InterruptController::DisableInterrupt(int32 irq)
7136d65a78SDavid Karoly {
7236d65a78SDavid Karoly 	fGicdRegs[GICD_REG_ICENABLER + irq / 32] = 1 << (irq % 32);
7336d65a78SDavid Karoly }
7436d65a78SDavid Karoly 
7536d65a78SDavid Karoly 
HandleInterrupt()7636d65a78SDavid Karoly void GICv2InterruptController::HandleInterrupt()
7736d65a78SDavid Karoly {
7836d65a78SDavid Karoly 	uint32_t iar = fGiccRegs[GICC_REG_IAR];
7936d65a78SDavid Karoly 	uint32_t irqnr = iar & 0x3FF;
8036d65a78SDavid Karoly 	if ((irqnr == 1022) || (irqnr == 1023)) {
8136d65a78SDavid Karoly 		dprintf("spurious interrupt\n");
8236d65a78SDavid Karoly 	} else {
836a1f9758SDavid Karoly 		int_io_interrupt_handler(irqnr, true);
8436d65a78SDavid Karoly 	}
8536d65a78SDavid Karoly 
8636d65a78SDavid Karoly 	fGiccRegs[GICC_REG_EOIR] = iar;
8736d65a78SDavid Karoly }
88