kernel/arch/arm/int: add initialization code for GICv2

Change-Id: I4f98a4e0277ce37e758cabbb04806cf13f351f1e
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4674
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
David Karoly
2021-12-07 10:58:24 +00:00
committed by Adrien Destugues
parent 354655e136
commit 36d65a7890
6 changed files with 168 additions and 16 deletions
+2
View File
@@ -35,6 +35,8 @@ KernelMergeObject kernel_arch_arm.o :
arch_atomic64.cpp
arch_atomic32.cpp
arch_int_gicv2.cpp
# SoC minimal kernel-required support
# (timers, interrupts, rtc?)
soc.cpp
+10 -8
View File
@@ -32,6 +32,7 @@
#include <string.h>
#include <drivers/bus/FDT.h>
#include "arch_int_gicv2.h"
#include "soc.h"
#include "soc_pxa.h"
@@ -170,15 +171,16 @@ arch_int_init_post_vm(kernel_args *args)
dprintf("Enabled high vectors\n");
}
#if 0
status_t rc = get_module(B_FDT_MODULE_NAME, (module_info**)&sFdtModule);
if (rc != B_OK)
panic("Unable to get FDT module: %08lx!\n", rc);
rc = sFdtModule->setup_devices(intc_table, intc_count, NULL);
if (rc != B_OK)
if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_GICV2,
sizeof(args->arch_args.interrupt_controller.kind)) == 0) {
InterruptController *ic = new(std::nothrow) GICv2InterruptController(
args->arch_args.interrupt_controller.regs1.start,
args->arch_args.interrupt_controller.regs2.start);
if (ic == NULL)
return B_NO_MEMORY;
} else {
panic("No interrupt controllers found!\n");
#endif
}
return B_OK;
}
@@ -0,0 +1,90 @@
/*
* Copyright 2021 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <int.h>
#include <interrupt_controller.h>
#include <kernel.h>
#include <vm/vm.h>
#include "arch_int_gicv2.h"
#include "gicv2_regs.h"
#define GIC_SPI_IRQ_START 32
GICv2InterruptController::GICv2InterruptController(uint32_t gicd_addr, uint32_t gicc_addr)
: InterruptController()
{
area_id gicd_area = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-gicv2-gicd",
(void**)&fGicdRegs, B_ANY_KERNEL_ADDRESS, GICD_REG_SIZE,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
gicd_addr ? gicd_addr : GICD_REG_START, false);
if (gicd_area < 0) {
panic("not able to map the memory area for gicd\n");
}
area_id gicc_area = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-gicv2-gicc",
(void**)&fGiccRegs, B_ANY_KERNEL_ADDRESS, GICC_REG_SIZE,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
gicc_addr ? gicc_addr : GICC_REG_START, false);
if (gicc_area < 0) {
panic("not able to map the memory area for gicc\n");
}
// disable GICD
fGicdRegs[GICD_REG_CTLR] = 0;
// disable GICC
fGiccRegs[GICC_REG_CTLR] = 0;
// TODO: disable all interrupts
fGicdRegs[GICD_REG_ICENABLER] = 0xffffffff;
fGicdRegs[GICD_REG_ICENABLER+1] = 0xffffffff;
// set PMR and BPR
fGiccRegs[GICC_REG_PMR] = 0xff;
fGiccRegs[GICC_REG_BPR] = 0x07;
// enable GICC
fGiccRegs[GICC_REG_CTLR] = 0x03;
// enable GICD
fGicdRegs[GICD_REG_CTLR] = 0x03;
}
void GICv2InterruptController::EnableInterrupt(int irq)
{
irq += GIC_SPI_IRQ_START;
uint32_t ena_reg = GICD_REG_ISENABLER + irq / 32;
uint32_t ena_val = 1 << (irq % 32);
fGicdRegs[ena_reg] = ena_val;
uint32_t prio_reg = GICD_REG_IPRIORITYR + irq / 4;
uint32_t prio_val = fGicdRegs[prio_reg];
prio_val |= 0x80 << (irq % 4 * 8);
fGicdRegs[prio_reg] = prio_val;
}
void GICv2InterruptController::DisableInterrupt(int irq)
{
irq += GIC_SPI_IRQ_START;
fGicdRegs[GICD_REG_ICENABLER + irq / 32] = 1 << (irq % 32);
}
void GICv2InterruptController::HandleInterrupt()
{
uint32_t iar = fGiccRegs[GICC_REG_IAR];
uint32_t irqnr = iar & 0x3FF;
if ((irqnr == 1022) || (irqnr == 1023)) {
dprintf("spurious interrupt\n");
} else {
int_io_interrupt_handler(irqnr-GIC_SPI_IRQ_START, true);
}
fGiccRegs[GICC_REG_EOIR] = iar;
}
@@ -0,0 +1,23 @@
/*
* Copyright 2021 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef ARCH_ARM_GICV2_H
#define ARCH_ARM_GICV2_H
#include <SupportDefs.h>
#include "soc.h"
class GICv2InterruptController : public InterruptController {
public:
GICv2InterruptController(uint32_t gicd_regs = 0, uint32_t gicc_regs = 0);
void EnableInterrupt(int irq);
void DisableInterrupt(int irq);
void HandleInterrupt();
private:
volatile uint32_t *fGicdRegs;
volatile uint32_t *fGiccRegs;
};
#endif /* ARCH_ARM_GICV2_H */
+41
View File
@@ -0,0 +1,41 @@
#ifndef ARCH_ARM_GIC_REGS_H
#define ARCH_ARM_GIC_REGS_H
#define GICD_REG_START 0x08000000
#define GICD_REG_SIZE 0x00010000
#define GICD_REG_CTLR 0
#define GICD_REG_TYPER 1
#define GICD_REG_IIDR 2
#define GICD_REG_IGROUP 32
#define GICD_REG_ISENABLER 64
#define GICD_REG_ICENABLER 96
#define GICD_REG_ISPENDR 128
#define GICD_REG_ICPENDR 160
#define GICD_REG_ISACTIVER 192
#define GICD_REG_ICACTIVER 224
#define GICD_REG_IPRIORITYR 256
#define GICD_REG_ITARGETSR 512
#define GICD_REG_ICPIDR0 1016
#define GICD_REG_ICPIDR1 1017
#define GICD_REG_ICPIDR2 1018
#define GICD_REG_SGIR 960
#define GICC_REG_START 0x08010000
#define GICC_REG_SIZE 0x00010000
#define GICC_REG_CTLR 0
#define GICC_REG_PMR 1
#define GICC_REG_BPR 2
#define GICC_REG_IAR 3
#define GICC_REG_EOIR 4
#define GICC_REG_RPR 5
#define GICC_REG_HPPIR 6
#define GICC_REG_IIDR 63
#define GICC_REG_DIR 1024
#endif
+2 -8
View File
@@ -21,20 +21,14 @@ public:
}
protected:
#if 0
InterruptController(fdt_module_info *fdtModule, fdt_device_node node)
: fFDT(fdtModule), fNode(node) {
InterruptController()
{
if (sInstance) {
panic("Multiple InterruptController objects created; that is currently unsupported!");
}
sInstance = this;
}
// Keep our node around as we might want to grab attributes from it
fdt_module_info *fFDT;
fdt_device_node fNode;
#endif
static InterruptController *sInstance;
};