Proper interrupt handlers

Proper interrupt handlers for timers (and new peripherals can use them
too).
Improved interrupt enabling.
Improved timer interrupts and fixed minor bugs.
This commit is contained in:
giomba 2019-01-07 15:57:16 +01:00
parent 06f000e19a
commit 92e1e261e7
8 changed files with 53 additions and 36 deletions

View File

@ -39,6 +39,7 @@ namespace GIC {
}; };
void enable(void); void enable(void);
void enableInterrupt(const uint16_t m, const TargetCPU target, const Sensitivity sensitivity);
} }
#endif #endif

View File

@ -3,10 +3,10 @@
#include <stdint.h> #include <stdint.h>
extern "C" void setVectorBAR(void);
extern "C" address_t* getVectorBAR(void);
extern "C" void fireswi(void); extern "C" void fireswi(void);
namespace interrupt {
extern void (*handler[])(const uint8_t cpuID, const uint16_t interruptID);
}
#endif #endif

View File

@ -43,8 +43,9 @@ namespace Timer {
class Timer { class Timer {
private: private:
uint8_t n; uint8_t n; /* Timer module number (0-5) */
TimerModule* module; uint16_t src; /* Timer interrupt source line (54-57, 99-100) */
TimerModule* module; /* Timer module MMIO config registers */
public: public:
/* Initialize class instance as timer n /* Initialize class instance as timer n
* where n is found on Allwinner datasheet */ * where n is found on Allwinner datasheet */
@ -57,6 +58,9 @@ namespace Timer {
void stop(void); void stop(void);
}; };
/* Interrupt handler */
extern void handler(const uint8_t cpuID, const uint16_t interruptID);
/* Vector of system's timers */ /* Vector of system's timers */
extern Timer timer[]; extern Timer timer[];

View File

@ -27,25 +27,9 @@ namespace GIC {
cpuInterface[1] = 0xff; cpuInterface[1] = 0xff;
} }
void printDistributorStatus(void) {
for (short i = 0; i < 1024; ++i) {
printk("Distributor "); printk(itoa(i * 4)); printk(" : ");
printkl(itoa(distributor[i]));
}
}
void printCPUInterfaceStatus(void) {
for (short i = 0; i < 64; ++i) {
printk("CPUInterface "); printk(itoa(i * 4)); printk(" : ");
printkl(itoa(cpuInterface[i]));
}
}
void enable(void) { void enable(void) {
enableInterrupt(54, CPU0T, EDGE); /* Timer0 */
/* Enable distributor and CPU interfaces /* Enable distributor and CPU interfaces
* Do this always at the end, * Call this function always at the end,
* since writing on GIC registers is not allowed when it is enabled */ * since writing on GIC registers is not allowed when it is enabled */
distributor[0] = distributor[GICD_CTLR] | 0x1; distributor[0] = distributor[GICD_CTLR] | 0x1;
cpuInterface[0] = cpuInterface[GICC_CTLR] | 0x1; cpuInterface[0] = cpuInterface[GICC_CTLR] | 0x1;

6
src/interrupt.cpp Normal file
View File

@ -0,0 +1,6 @@
#include <stdint.h>
namespace interrupt {
void (*handler[128])(const uint8_t cpuID, const uint16_t interruptID);
}

View File

@ -15,12 +15,14 @@ extern "C" int main(int argc, char** argv) {
printkl("Now firing test software interrupt..."); printkl("Now firing test software interrupt...");
fireswi(); fireswi();
printkl("Now enabling GIC interrupts...");
GIC::enable();
printkl("Now enabling timer..."); printkl("Now enabling timer...");
Timer::timer[0].set(0x80, Timer::CONTINUOUS, Timer::PRESCALER_128, Timer::LS_OSC); Timer::timer[0].set(0x100, Timer::CONTINUOUS, Timer::PRESCALER_128, Timer::LS_OSC);
Timer::timer[0].start(); Timer::timer[0].start();
Timer::timer[5].set(0x100, Timer::CONTINUOUS, Timer::PRESCALER_16, Timer::LS_OSC);
Timer::timer[5].start();
printkl("Now enabling GIC...");
GIC::enable();
printkl("Now going user..."); printkl("Now going user...");
go_usr(); go_usr();

View File

@ -1,16 +1,23 @@
#include <gic.h>
#include <interrupt.h>
#include <timer.h> #include <timer.h>
#include <dbg.h> #include <dbg.h>
namespace Timer { namespace Timer {
Timer timer[3] = { Timer(0), Timer(1), Timer(2) }; Timer timer[6] = { Timer(0), Timer(1), Timer(2), Timer(3), Timer(4), Timer(5) };
Timer::Timer(uint8_t n) { Timer::Timer(uint8_t n) {
this->n = n; this->n = n;
module = (TimerModule*)(TMR_MODULE_BASE + n); if (n >= 0 && n <= 3) this->src = 54 + n;
if (n >= 4 && n <= 5) this->src = 99 - 4 + n;
module = (TimerModule*)(TMR_MODULE_BASE + n * 4);
} }
void Timer::set(uint32_t interval, Mode mode, Prescaler prescaler, ClockSource source) { void Timer::set(uint32_t interval, Mode mode, Prescaler prescaler, ClockSource source) {
/* attach interrupt handler */
interrupt::handler[src] = handler;
/* zero fill control registers */ /* zero fill control registers */
module->TMR_CTLR_REG = 0; module->TMR_CTLR_REG = 0;
module->TMR_CUR_VALUE_REG = 0; module->TMR_CUR_VALUE_REG = 0;
@ -21,9 +28,9 @@ namespace Timer {
/* Set timer value */ /* Set timer value */
module->TMR_INTV_VALUE_REG = interval; module->TMR_INTV_VALUE_REG = interval;
/* Enable interrupt */ /* Enable interrupt in GIC and set interrupt handler */
GIC::enableInterrupt(src, GIC::CPU0T, GIC::EDGE);
peripheral->TMR_IRQ_EN_REG = peripheral->TMR_IRQ_EN_REG | (1 << n); peripheral->TMR_IRQ_EN_REG = peripheral->TMR_IRQ_EN_REG | (1 << n);
} }
void Timer::start(void) { void Timer::start(void) {
@ -36,4 +43,12 @@ namespace Timer {
module->TMR_CTLR_REG = module->TMR_CTLR_REG & 0xfffffffe; module->TMR_CTLR_REG = module->TMR_CTLR_REG & 0xfffffffe;
} }
void handler(const uint8_t cpuID, const uint16_t interruptID) {
uint16_t n;
if (interruptID >= 54 && interruptID <= 57) n = interruptID - 54;
if (interruptID >= 99 && interruptID <= 100) n = interruptID - 99 + 4;
peripheral->TMR_IRQ_STA_REG = peripheral->TMR_IRQ_STA_REG | (1 << n);
}
} }

View File

@ -1,23 +1,28 @@
#include <dbg.h> #include <dbg.h>
#include <interrupt.h>
#include <stdint.h> #include <stdint.h>
extern "C" uint32_t c_irq_handler(uint32_t iar) { extern "C" uint32_t c_irq_handler(uint32_t iar) {
uint8_t cpuID = (iar >> 10) & 0x7; uint8_t cpuID = (iar >> 10) & 0x7;
uint16_t interruptID = iar & 0x3ff; uint16_t interruptID = iar & 0x3ff;
printk("Serving IRQ #"); printkl(itoa(interruptID));
void (*handler)(const uint8_t, const uint16_t);
if (cpuID == 0) { if (cpuID == 0) {
/* for /* for
* SPI - Shared Peripheral Interrupt * SPI - Shared Peripheral Interrupt
* PPI - Private Peripheral Interrupt * PPI - Private Peripheral Interrupt
*/ */
switch (interruptID) { switch (interruptID) { /* Choose proper interrupt handler */
case 54: /* timer 0 */ /* TODO: improve this ugliness */ case 54: case 55: case 56: case 57: case 99: case 100:
uint32_t* const TMR_IRQ_STA_REG = (uint32_t* const)(0x01c20c04); handler = interrupt::handler[interruptID];
*TMR_IRQ_STA_REG = *TMR_IRQ_STA_REG | 0x1;
printk("Serving IRQ #");
printkl(itoa(interruptID));
break; break;
} }
/* Call interrupt handler */
handler(cpuID, interruptID);
} }
else { else {
/* for /* for