X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Farm%2Fdrv%2Fsysirq_at91.c;fp=bertos%2Fcpu%2Farm%2Fdrv%2Fsysirq_at91.c;h=281c7963f8afdbee1fb0fc472ca961a3171cd921;hb=345f93de1963f49bdb194d2b06c8c5d7ba0a3e5f;hp=0000000000000000000000000000000000000000;hpb=791e167e053bdd9250d34a9a5ccae6ccde4d6679;p=bertos.git diff --git a/bertos/cpu/arm/drv/sysirq_at91.c b/bertos/cpu/arm/drv/sysirq_at91.c new file mode 100644 index 00000000..281c7963 --- /dev/null +++ b/bertos/cpu/arm/drv/sysirq_at91.c @@ -0,0 +1,171 @@ +/** + * \file + * + * + * \version $Id$ + * + * \author Francesco Sacchi + * + * \brief System IRQ handler for Atmel AT91 ARM7 processors. + * + * In Atmel AT91 ARM7TDMI processors, there are various + * peripheral interrupt sources. + * In general, every source has its own interrupt vector, so it + * is possible to assign a specific handler for each interrupt + * independently. + * However, there are a few sources called "system sources" that + * share a common IRQ line and vector, called "system IRQ". + * So a unique system IRQ dispatcher is implemented here. + * This module also contains an interface to manage every source + * independently. It is possible to assign to every system IRQ + * a specific IRQ handler. + * + * \see sysirq_setHandler + * \see sysirq_setEnable + */ + +#include "sysirq_at91.h" +#include +#include +#include +#include +#include + +/** + * Enable/disable the Periodic Interrupt Timer + * interrupt. + */ +INLINE void pit_setEnable(bool enable) +{ + if (enable) + PIT_MR |= BV(PITIEN); + else + PIT_MR &= ~BV(PITIEN); +} + +/** + * Table containing all system irqs. + */ +static SysIrq sysirq_tab[] = +{ + /* PIT, Periodic Interval Timer (System timer)*/ + { + .enabled = false, + .setEnable = pit_setEnable, + .handler = NULL, + }, + /* TODO: add other system sources here */ +}; + +STATIC_ASSERT(countof(sysirq_tab) == SYSIRQ_CNT); + +/** + * System IRQ dispatcher. + * This is the entry point for all system IRQs in AT91. + * This function checks for interrupt enable state of + * various sources (system timer, etc..) and calls + * the corresponding handler. + */ +static void sysirq_dispatcher(void) __attribute__ ((interrupt)); +static void sysirq_dispatcher(void) +{ + for (unsigned i = 0; i < countof(sysirq_tab); i++) + { + if (sysirq_tab[i].enabled + && sysirq_tab[i].handler) + sysirq_tab[i].handler(); + } + + /* Inform hw that we have served the IRQ */ + AIC_EOICR = 0; +} + +#define SYSIRQ_PRIORITY 0 ///< default priority for system irqs. + + +MOD_DEFINE(sysirq); + +/** + * Init system IRQ handling. + * \note all system interrupts are disabled. + */ +void sysirq_init(void) +{ + cpuflags_t flags; + IRQ_SAVE_DISABLE(flags); + + /* Disable all system interrupts */ + for (unsigned i = 0; i < countof(sysirq_tab); i++) + sysirq_tab[i].setEnable(false); + + /* Set the vector. */ + AIC_SVR(SYSC_ID) = sysirq_dispatcher; + /* Initialize to edge triggered with defined priority. */ + AIC_SMR(SYSC_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED | SYSIRQ_PRIORITY; + /* Clear pending interrupt */ + AIC_ICCR = BV(SYSC_ID); + /* Enable the system IRQ */ + AIC_IECR = BV(SYSC_ID); + + IRQ_RESTORE(flags); + MOD_INIT(sysirq); +} + + +/** + * Helper function used to set handler for system IRQ \a irq. + */ +void sysirq_setHandler(sysirq_t irq, sysirq_handler_t handler) +{ + ASSERT(irq < SYSIRQ_CNT); + sysirq_tab[irq].handler = handler; +} + +/** + * Helper function used to enable/disable system IRQ \a irq. + */ +void sysirq_setEnable(sysirq_t irq, bool enable) +{ + ASSERT(irq < SYSIRQ_CNT); + + sysirq_tab[irq].setEnable(enable); + sysirq_tab[irq].enabled = enable; +} + +/** + * Helper function used to get system IRQ \a irq state. + */ +bool sysirq_enabled(sysirq_t irq) +{ + ASSERT(irq < SYSIRQ_CNT); + + return sysirq_tab[irq].enabled; +}