diff --git a/src/system/kernel/arch/arm/Jamfile b/src/system/kernel/arch/arm/Jamfile index 3357d5c32f..b16b39235b 100644 --- a/src/system/kernel/arch/arm/Jamfile +++ b/src/system/kernel/arch/arm/Jamfile @@ -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 diff --git a/src/system/kernel/arch/arm/arch_int.cpp b/src/system/kernel/arch/arm/arch_int.cpp index 67aabe845e..146a0b9332 100644 --- a/src/system/kernel/arch/arm/arch_int.cpp +++ b/src/system/kernel/arch/arm/arch_int.cpp @@ -32,6 +32,7 @@ #include #include +#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; } diff --git a/src/system/kernel/arch/arm/arch_int_gicv2.cpp b/src/system/kernel/arch/arm/arch_int_gicv2.cpp new file mode 100644 index 0000000000..142bd42511 --- /dev/null +++ b/src/system/kernel/arch/arm/arch_int_gicv2.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2021 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#include +#include +#include +#include + +#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; +} diff --git a/src/system/kernel/arch/arm/arch_int_gicv2.h b/src/system/kernel/arch/arm/arch_int_gicv2.h new file mode 100644 index 0000000000..49b57c538a --- /dev/null +++ b/src/system/kernel/arch/arm/arch_int_gicv2.h @@ -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 + +#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 */ diff --git a/src/system/kernel/arch/arm/gicv2_regs.h b/src/system/kernel/arch/arm/gicv2_regs.h new file mode 100644 index 0000000000..c8c540281d --- /dev/null +++ b/src/system/kernel/arch/arm/gicv2_regs.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 diff --git a/src/system/kernel/arch/arm/soc.h b/src/system/kernel/arch/arm/soc.h index 890d2815ab..3bbfcb6131 100644 --- a/src/system/kernel/arch/arm/soc.h +++ b/src/system/kernel/arch/arm/soc.h @@ -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; };