ARM: add support for Allwinner A10 interrupt controller

Untested so far.

Change-Id: I3453115599cf2112858a194173212401ae4ac1b7
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5104
Reviewed-by: Fredrik Holmqvist <[email protected]>
Reviewed-by: David Karoly <[email protected]>
Reviewed-by: Alex von Gluck IV <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Adrien Destugues
2022-04-25 20:50:04 +00:00
committed by waddlesplash
parent 41ed7a1ed6
commit cda13c638d
6 changed files with 121 additions and 0 deletions
@@ -14,6 +14,7 @@
#define INTC_KIND_GICV2 "gicv2"
#define INTC_KIND_OMAP3 "omap3"
#define INTC_KIND_PXA "pxa"
#define INTC_KIND_SUN4I "sun4i"
typedef struct {
@@ -28,6 +28,7 @@ const struct supported_interrupt_controllers {
{ "arm,gic-400", INTC_KIND_GICV2 },
{ "ti,omap3-intc", INTC_KIND_OMAP3 },
{ "marvell,pxa-intc", INTC_KIND_PXA },
{ "allwinner,sun4i-a10-ic", INTC_KIND_SUN4I },
};
+1
View File
@@ -42,6 +42,7 @@ KernelMergeObject kernel_arch_arm.o :
soc.cpp
soc_pxa.cpp
soc_omap3.cpp
soc_sun4i.cpp
# paging
arm_physical_page_mapper_large_memory.cpp
+7
View File
@@ -41,6 +41,7 @@
#include "soc_pxa.h"
#include "soc_omap3.h"
#include "soc_sun4i.h"
#define TRACE_ARCH_INT
#ifdef TRACE_ARCH_INT
@@ -180,6 +181,12 @@ arch_int_init_post_vm(kernel_args *args)
args->arch_args.interrupt_controller.regs1.start);
if (ic == NULL)
return B_NO_MEMORY;
} else if (strncmp(args->arch_args.interrupt_controller.kind, INTC_KIND_SUN4I,
sizeof(args->arch_args.interrupt_controller.kind)) == 0) {
InterruptController *ic = new(std::nothrow) Sun4iInterruptController(
args->arch_args.interrupt_controller.regs1.start);
if (ic == NULL)
return B_NO_MEMORY;
} else {
panic("No interrupt controllers found!\n");
}
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright 2022, Adrien Destugues, [email protected]
* Distributed under the terms of the MIT License.
*/
#include <vm/vm.h>
#include "soc_sun4i.h"
#define SUN4I_INTC_PEND_REG0 0x10
#define SUN4I_INTC_PEND_REG1 0x14
#define SUN4I_INTC_PEND_REG2 0x18
#define SUN4I_INTC_MASK_REG0 0x50
#define SUN4I_INTC_MASK_REG1 0x54
#define SUN4I_INTC_MASK_REG2 0x58
void
Sun4iInterruptController::EnableInterrupt(int irq)
{
if (irq <= 31) {
fRegBase[SUN4I_INTC_MASK_REG0] |= 1 << irq;
return;
}
if (irq <= 63) {
fRegBase[SUN4I_INTC_MASK_REG1] |= 1 << (irq - 32);
return;
}
fRegBase[SUN4I_INTC_MASK_REG2] |= 1 << (irq - 64);
}
void
Sun4iInterruptController::DisableInterrupt(int irq)
{
if (irq <= 31) {
fRegBase[SUN4I_INTC_MASK_REG0] &= ~(1 << irq);
return;
}
if (irq <= 63) {
fRegBase[SUN4I_INTC_MASK_REG1] &= ~(1 << (irq - 32));
return;
}
fRegBase[SUN4I_INTC_MASK_REG1] &= ~(1 << (irq - 64));
}
void
Sun4iInterruptController::HandleInterrupt()
{
// FIXME can we use the hardware managed interrupt vector instead?
for (int i=0; i < 32; i++) {
if (fRegBase[SUN4I_INTC_PEND_REG0] & (1 << i))
int_io_interrupt_handler(i, true);
}
for (int i=0; i < 32; i++) {
if (fRegBase[SUN4I_INTC_PEND_REG1] & (1 << i))
int_io_interrupt_handler(i + 32, true);
}
for (int i=0; i < 32; i++) {
if (fRegBase[SUN4I_INTC_PEND_REG2] & (1 << i))
int_io_interrupt_handler(i + 64, true);
}
}
Sun4iInterruptController::Sun4iInterruptController(uint32_t reg_base)
{
fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-sun4i", (void**)&fRegBase,
B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
reg_base, false);
if (fRegArea < 0)
panic("Sun4iInterruptController: cannot map registers!");
fRegBase[SUN4I_INTC_MASK_REG0] = 0;
fRegBase[SUN4I_INTC_MASK_REG1] = 0;
fRegBase[SUN4I_INTC_MASK_REG2] = 0;
}
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright 2022, Adrien Destugues, [email protected]
* Distributed under the terms of the MIT License.
*/
#ifndef ARCH_ARM_SOC_SUN4I_H
#define ARCH_ARM_SOC_SUN4I_H
#include "soc.h"
class Sun4iInterruptController : public InterruptController {
public:
Sun4iInterruptController(uint32_t reg_base);
void EnableInterrupt(int irq);
void DisableInterrupt(int irq);
void HandleInterrupt();
protected:
area_id fRegArea;
uint32 *fRegBase;
};
#endif /* !SOC_SUN4I_H */