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:
committed by
Adrien Destugues
parent
354655e136
commit
36d65a7890
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user