Files
beaglefw/omap35x_intc.cc
2013-07-13 21:09:30 +02:00

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);
}