1/*
2 * Copyright 2022, Adrien Destugues, pulkomandy@pulkomandy.tk
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <vm/vm.h>
7
8#include "soc_sun4i.h"
9
10
11#define SUN4I_INTC_PEND_REG0	0x10
12#define SUN4I_INTC_PEND_REG1	0x14
13#define SUN4I_INTC_PEND_REG2	0x18
14#define SUN4I_INTC_MASK_REG0	0x50
15#define SUN4I_INTC_MASK_REG1	0x54
16#define SUN4I_INTC_MASK_REG2	0x58
17
18
19void
20Sun4iInterruptController::EnableInterrupt(int32 irq)
21{
22	if (irq <= 31) {
23		fRegBase[SUN4I_INTC_MASK_REG0] |= 1 << irq;
24		return;
25	}
26
27	if (irq <= 63) {
28		fRegBase[SUN4I_INTC_MASK_REG1] |= 1 << (irq - 32);
29		return;
30	}
31
32	fRegBase[SUN4I_INTC_MASK_REG2] |= 1 << (irq - 64);
33}
34
35
36void
37Sun4iInterruptController::DisableInterrupt(int irq)
38{
39	if (irq <= 31) {
40		fRegBase[SUN4I_INTC_MASK_REG0] &= ~(1 << irq);
41		return;
42	}
43
44	if (irq <= 63) {
45		fRegBase[SUN4I_INTC_MASK_REG1] &= ~(1 << (irq - 32));
46		return;
47	}
48
49	fRegBase[SUN4I_INTC_MASK_REG1] &= ~(1 << (irq - 64));
50}
51
52
53void
54Sun4iInterruptController::HandleInterrupt()
55{
56	// FIXME can we use the hardware managed interrupt vector instead?
57	for (int i=0; i < 32; i++) {
58		if (fRegBase[SUN4I_INTC_PEND_REG0] & (1 << i))
59			int_io_interrupt_handler(i, true);
60	}
61
62	for (int i=0; i < 32; i++) {
63		if (fRegBase[SUN4I_INTC_PEND_REG1] & (1 << i))
64			int_io_interrupt_handler(i + 32, true);
65	}
66
67	for (int i=0; i < 32; i++) {
68		if (fRegBase[SUN4I_INTC_PEND_REG2] & (1 << i))
69			int_io_interrupt_handler(i + 64, true);
70	}
71}
72
73
74Sun4iInterruptController::Sun4iInterruptController(uint32_t reg_base)
75{
76	fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-sun4i", (void**)&fRegBase,
77		B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
78		reg_base, false);
79	if (fRegArea < 0)
80		panic("Sun4iInterruptController: cannot map registers!");
81
82	fRegBase[SUN4I_INTC_MASK_REG0] = 0;
83	fRegBase[SUN4I_INTC_MASK_REG1] = 0;
84	fRegBase[SUN4I_INTC_MASK_REG2] = 0;
85}
86