diff options
author | laforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-10-01 21:45:43 +0000 |
---|---|---|
committer | laforge <laforge@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2006-10-01 21:45:43 +0000 |
commit | bfff30bfec74c508e3f8904f8732799f30e6829d (patch) | |
tree | c104e38c808859adf0c7edcfd76873ce07b75f3b /firmware/src/os/system_irq.c | |
parent | 2b55faec5a6e3a4d2130ad341f01cd55116b64c3 (diff) |
- add proper system interrupt (shared) demultiplexing code
- port debug unit, watchdog timer, periodic interval timer to system_irq.c
git-svn-id: https://svn.openpcd.org:2342/trunk@252 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'firmware/src/os/system_irq.c')
-rw-r--r-- | firmware/src/os/system_irq.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/firmware/src/os/system_irq.c b/firmware/src/os/system_irq.c new file mode 100644 index 0000000..455791c --- /dev/null +++ b/firmware/src/os/system_irq.c @@ -0,0 +1,161 @@ +/* SAM7S system interrupt demultiplexer + * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#undef DEBUG + +#include <sys/types.h> +#include <lib_AT91SAM7.h> +#include <AT91SAM7.h> + +#include <os/system_irq.h> +#include <os/dbgu.h> + +#include "../openpcd.h" + +static sysirq_hdlr *sysirq_hdlrs[AT91SAM7_SYSIRQ_COUNT]; + +static void sys_irq(void) +{ + u_int32_t sr; + DEBUGP("sys_irq: "); + + /* Somehow Atmel decided to do really stupid interrupt sharing + * for commonly-used interrupts such as the timer irq */ + + /* dbgu */ + if (*AT91C_DBGU_IMR) { + sr = *AT91C_DBGU_CSR; + DEBUGP("DBGU("); + if (sr & *AT91C_DBGU_IMR) { + DEBUGP("found "); + if (sysirq_hdlrs[AT91SAM7_SYSIRQ_DBGU]) { + DEBUGP("handler "); + sysirq_hdlrs[AT91SAM7_SYSIRQ_DBGU](sr); + } else { + *AT91C_DBGU_IDR = *AT91C_DBGU_IMR; + DEBUGP("no handler "); + } + } + DEBUGP(") "); + } + + /* pit_irq */ + if (*AT91C_PITC_PIMR & AT91C_PITC_PITIEN) { + sr = *AT91C_PITC_PISR; + DEBUGP("PIT("); + if (sr & AT91C_PITC_PITS) { + DEBUGP("found "); + if (sysirq_hdlrs[AT91SAM7_SYSIRQ_PIT]) { + DEBUGP("handler "); + sysirq_hdlrs[AT91SAM7_SYSIRQ_PIT](sr); + } else { + *AT91C_PITC_PIMR &= ~AT91C_PITC_PITIEN; + DEBUGP("no handler "); + } + } + DEBUGP(") "); + } + + /* rtt_irq */ + if (*AT91C_RTTC_RTMR & (AT91C_RTTC_ALMIEN|AT91C_RTTC_RTTINCIEN)) { + sr = *AT91C_RTTC_RTSR; + DEBUGP("RTT("); + if (sr) { + if (sysirq_hdlrs[AT91SAM7_SYSIRQ_RTT]) + sysirq_hdlrs[AT91SAM7_SYSIRQ_RTT](sr); + else + *AT91C_RTTC_RTMR &= ~(AT91C_RTTC_ALMIEN| + AT91C_RTTC_RTTINCIEN); + } + DEBUGP(") "); + } + + /* pmc_irq */ + if (*AT91C_PMC_IMR) { + sr = *AT91C_PMC_SR; + DEBUGP("PMC("); + if (sr & *AT91C_PMC_IMR) { + if (sysirq_hdlrs[AT91SAM7_SYSIRQ_PMC]) + sysirq_hdlrs[AT91SAM7_SYSIRQ_PMC](sr); + else + *AT91C_PMC_IDR = *AT91C_PMC_IMR; + } + DEBUGP(") "); + } + + /* rstc_irq */ + if (*AT91C_RSTC_RMR & (AT91C_RSTC_URSTIEN|AT91C_RSTC_BODIEN)) { + sr = *AT91C_RSTC_RSR; + DEBUGP("RSTC("); + if (sr & (AT91C_RSTC_URSTS|AT91C_RSTC_BODSTS)) { + if (sysirq_hdlrs[AT91SAM7_SYSIRQ_RSTC]) + sysirq_hdlrs[AT91SAM7_SYSIRQ_RSTC](sr); + else + *AT91C_RSTC_RMR &= ~(AT91C_RSTC_URSTIEN| + AT91C_RSTC_BODIEN); + } + DEBUGP(") "); + } + + /* mc_irq */ + if (*AT91C_MC_FMR & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) { + sr = *AT91C_MC_FSR; + DEBUGP("EFC("); + if ((*AT91C_MC_FMR & AT91C_MC_LOCKE && (sr & AT91C_MC_LOCKE))|| + (*AT91C_MC_FMR & AT91C_MC_PROGE && (sr & AT91C_MC_PROGE))){ + if (sysirq_hdlrs[AT91SAM7_SYSIRQ_EFC]) + sysirq_hdlrs[AT91SAM7_SYSIRQ_EFC](sr); + else + *AT91C_MC_FMR &= ~(AT91C_MC_LOCKE | + AT91C_MC_PROGE); + } + DEBUGP(") "); + } + + /* wdt_irq */ + if (*AT91C_WDTC_WDMR & AT91C_WDTC_WDFIEN) { + sr = *AT91C_WDTC_WDSR; + DEBUGP("WDT("); + if (sr) { + if (sysirq_hdlrs[AT91SAM7_SYSIRQ_WDT]) + sysirq_hdlrs[AT91SAM7_SYSIRQ_WDT](sr); + /* we can't disable it... */ + } + DEBUGP(") "); + } + AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_SYS); + DEBUGPCR(""); +} + +void sysirq_register(enum sysirqs irq, sysirq_hdlr *hdlr) +{ + if (irq >= AT91SAM7_SYSIRQ_COUNT) + return; + + sysirq_hdlrs[irq] = hdlr; +} + +void sysirq_init(void) +{ + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, + OPENPCD_IRQ_PRIO_SYS, + AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE, + &sys_irq); + AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS); +} |