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