124 lines
3.8 KiB
C++
124 lines
3.8 KiB
C++
#include <cstdio>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
#include <array>
|
|
|
|
#include "cortexa8.hh"
|
|
#include "mmio.hh"
|
|
#include "util.hh"
|
|
#include "omap35x_intc.hh"
|
|
|
|
|
|
extern "C" void _omap35x_intc_handler();
|
|
static OMAP35x_intc_impl* intc = nullptr;
|
|
|
|
class OMAP35x_intc_impl {
|
|
public:
|
|
OMAP35x_intc_impl(uintptr_t base) : base_{base} {
|
|
// Interrupts should (still) be disabled from boot
|
|
assert(!cortexa8_get_int());
|
|
|
|
// This is something like a singleton
|
|
assert(!intc);
|
|
intc = this;
|
|
|
|
r_sysconfig() = 0x1; // Autoidle = 1
|
|
r_idle() = 0x2; // Turbo = 1, Funcidle = 0
|
|
|
|
// Disable all ints
|
|
for(int i = 0;i <= 2;++i)
|
|
r_mir_set(i) = 0xffffffff;
|
|
}
|
|
|
|
void register_handler(int irq, int_handler_t const& handler, int prio) {
|
|
assert(irq >= 0 && irq <= 95);
|
|
assert(prio >= 0 && prio <= 63);
|
|
|
|
handler_tbl_[irq] = handler;
|
|
r_ilr(irq) = prio<<2;
|
|
}
|
|
|
|
void enable_int(int irq) {
|
|
assert(irq >= 0 && irq <= 95);
|
|
assert(handler_tbl_[irq]);
|
|
int i = irq/32, j = irq%32;
|
|
|
|
r_mir_clear(i) = (1<<j);
|
|
}
|
|
|
|
void disable_int(int irq) {
|
|
assert(irq >= 0 && irq <= 95);
|
|
int i = irq/32, j = irq%32;
|
|
|
|
r_mir_set(i) = (1<<j);
|
|
}
|
|
|
|
private:
|
|
friend void _omap35x_intc_handler();
|
|
void handler() {
|
|
uint32_t sir = r_sir_irq();
|
|
int irq = sir&0x7f;
|
|
|
|
if(sir&0xffffff80) {
|
|
printf("WARNING: Spurious interrupt (%.8lx)\n", sir);
|
|
return;
|
|
}
|
|
|
|
assert(irq >= 0 && irq <= 95);
|
|
assert(handler_tbl_[irq]);
|
|
|
|
handler_tbl_[irq]();
|
|
|
|
r_control() = 0x1;
|
|
__asm__ __volatile__ ("dsb");
|
|
}
|
|
|
|
uint32_t volatile& r_sysconfig() {return _reg32(base_.get_virt(), 0x10); }
|
|
uint32_t volatile& r_sysstatus() {return _reg32(base_.get_virt(), 0x14); }
|
|
uint32_t volatile& r_sir_irq() {return _reg32(base_.get_virt(), 0x40); }
|
|
uint32_t volatile& r_sir_fiq() {return _reg32(base_.get_virt(), 0x44); }
|
|
uint32_t volatile& r_control() {return _reg32(base_.get_virt(), 0x48); }
|
|
uint32_t volatile& r_protection() {return _reg32(base_.get_virt(), 0x4c); }
|
|
uint32_t volatile& r_idle() {return _reg32(base_.get_virt(), 0x50); }
|
|
uint32_t volatile& r_irq_priority() {return _reg32(base_.get_virt(), 0x60); }
|
|
uint32_t volatile& r_fiq_priority() {return _reg32(base_.get_virt(), 0x64); }
|
|
uint32_t volatile& r_threshold() {return _reg32(base_.get_virt(), 0x68); }
|
|
uint32_t volatile& r_itr(int n) {assert(n >= 0 && n <= 2); return _reg32(base_.get_virt(), 0x80+0x20*n); }
|
|
uint32_t volatile& r_mir(int n) {assert(n >= 0 && n <= 2); return _reg32(base_.get_virt(), 0x84+0x20*n); }
|
|
uint32_t volatile& r_mir_clear(int n) {assert(n >= 0 && n <= 2); return _reg32(base_.get_virt(), 0x88+0x20*n); }
|
|
uint32_t volatile& r_mir_set(int n) {assert(n >= 0 && n <= 2); return _reg32(base_.get_virt(), 0x8c+0x20*n); }
|
|
uint32_t volatile& r_isr_set(int n) {assert(n >= 0 && n <= 2); return _reg32(base_.get_virt(), 0x90+0x20*n); }
|
|
uint32_t volatile& r_isr_clear(int n) {assert(n >= 0 && n <= 2); return _reg32(base_.get_virt(), 0x94+0x20*n); }
|
|
uint32_t volatile& r_pending_irq(int n) {assert(n >= 0 && n <= 2); return _reg32(base_.get_virt(), 0x98+0x20*n); }
|
|
uint32_t volatile& r_pending_fiq(int n) {assert(n >= 0 && n <= 2); return _reg32(base_.get_virt(), 0x9c+0x20*n); }
|
|
uint32_t volatile& r_ilr(int m) {assert(m >= 0 && m <= 95); return _reg32(base_.get_virt(), 0x100+0x4*m); }
|
|
|
|
MMIO_alloc base_;
|
|
std::array<int_handler_t, 96> handler_tbl_;
|
|
};
|
|
|
|
void _omap35x_intc_handler() {
|
|
if(intc)
|
|
intc->handler();
|
|
}
|
|
|
|
|
|
|
|
OMAP35x_intc::OMAP35x_intc(uintptr_t base) : impl_{new OMAP35x_intc_impl{base}} {
|
|
}
|
|
|
|
OMAP35x_intc::~OMAP35x_intc() {
|
|
}
|
|
|
|
void OMAP35x_intc::register_handler(int irq, int_handler_t const& handler, int prio) {
|
|
impl_->register_handler(irq, handler, prio);
|
|
}
|
|
|
|
void OMAP35x_intc::enable_int(int irq) {
|
|
impl_->enable_int(irq);
|
|
}
|
|
|
|
void OMAP35x_intc::disable_int(int irq) {
|
|
impl_->disable_int(irq);
|
|
}
|