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_atomic64.cpp
|
||||||
arch_atomic32.cpp
|
arch_atomic32.cpp
|
||||||
|
|
||||||
|
arch_int_gicv2.cpp
|
||||||
|
|
||||||
# SoC minimal kernel-required support
|
# SoC minimal kernel-required support
|
||||||
# (timers, interrupts, rtc?)
|
# (timers, interrupts, rtc?)
|
||||||
soc.cpp
|
soc.cpp
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <drivers/bus/FDT.h>
|
#include <drivers/bus/FDT.h>
|
||||||
|
#include "arch_int_gicv2.h"
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
|
|
||||||
#include "soc_pxa.h"
|
#include "soc_pxa.h"
|
||||||
@@ -170,15 +171,16 @@ arch_int_init_post_vm(kernel_args *args)
|
|||||||
dprintf("Enabled high vectors\n");
|
dprintf("Enabled high vectors\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_GICV2,
|
||||||
status_t rc = get_module(B_FDT_MODULE_NAME, (module_info**)&sFdtModule);
|
sizeof(args->arch_args.interrupt_controller.kind)) == 0) {
|
||||||
if (rc != B_OK)
|
InterruptController *ic = new(std::nothrow) GICv2InterruptController(
|
||||||
panic("Unable to get FDT module: %08lx!\n", rc);
|
args->arch_args.interrupt_controller.regs1.start,
|
||||||
|
args->arch_args.interrupt_controller.regs2.start);
|
||||||
rc = sFdtModule->setup_devices(intc_table, intc_count, NULL);
|
if (ic == NULL)
|
||||||
if (rc != B_OK)
|
return B_NO_MEMORY;
|
||||||
|
} else {
|
||||||
panic("No interrupt controllers found!\n");
|
panic("No interrupt controllers found!\n");
|
||||||
#endif
|
}
|
||||||
|
|
||||||
return B_OK;
|
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:
|
protected:
|
||||||
#if 0
|
InterruptController()
|
||||||
InterruptController(fdt_module_info *fdtModule, fdt_device_node node)
|
{
|
||||||
: fFDT(fdtModule), fNode(node) {
|
|
||||||
if (sInstance) {
|
if (sInstance) {
|
||||||
panic("Multiple InterruptController objects created; that is currently unsupported!");
|
panic("Multiple InterruptController objects created; that is currently unsupported!");
|
||||||
}
|
}
|
||||||
sInstance = this;
|
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;
|
static InterruptController *sInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user