From bfff30bfec74c508e3f8904f8732799f30e6829d Mon Sep 17 00:00:00 2001 From: laforge Date: Sun, 1 Oct 2006 21:45:43 +0000 Subject: - 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 --- firmware/src/openpcd.h | 2 + firmware/src/os/dbgu.c | 12 ++-- firmware/src/os/main.c | 3 +- firmware/src/os/pit.c | 12 ++-- firmware/src/os/system_irq.c | 161 +++++++++++++++++++++++++++++++++++++++++++ firmware/src/os/system_irq.h | 22 ++++++ firmware/src/os/wdt.c | 4 +- 7 files changed, 200 insertions(+), 16 deletions(-) create mode 100644 firmware/src/os/system_irq.c create mode 100644 firmware/src/os/system_irq.h (limited to 'firmware/src') diff --git a/firmware/src/openpcd.h b/firmware/src/openpcd.h index 9ad7288..f17b16e 100644 --- a/firmware/src/openpcd.h +++ b/firmware/src/openpcd.h @@ -161,6 +161,8 @@ #define OPENPCD_IRQ_PRIO_SPI AT91C_AIC_PRIOR_HIGHEST #define OPENPCD_IRQ_PRIO_SSC (AT91C_AIC_PRIOR_HIGHEST-1) +#define OPENPCD_IRQ_PRIO_SYS (AT91C_AIC_PRIOR_HIGHEST-2) +#define OPENPCD_IRQ_PRIO_TC_FDT (AT91C_AIC_PRIOR_LOWEST+3) #define OPENPCD_IRQ_PRIO_UDP (AT91C_AIC_PRIOR_LOWEST+2) #define OPENPCD_IRQ_PRIO_PIT (AT91C_AIC_PRIOR_LOWEST+1) #define OPENPCD_IRQ_PRIO_RC632 AT91C_AIC_PRIOR_LOWEST diff --git a/firmware/src/os/dbgu.c b/firmware/src/os/dbgu.c index 458aa4e..a3a5941 100644 --- a/firmware/src/os/dbgu.c +++ b/firmware/src/os/dbgu.c @@ -40,6 +40,7 @@ #include "../openpcd.h" #include #include +#include #include #include @@ -72,10 +73,10 @@ static void Send_reset(void) //*---------------------------------------------------------------------------- //* Function Name : DBGU_irq_handler -//* Object : C handler interrupt function called by the interrupts -//* assembling routine +//* Object : C handler interrupt function called by the sysirq +//* demultiplexer //*---------------------------------------------------------------------------- -static void DBGU_irq_handler(void) +static void DBGU_irq_handler(u_int32_t sr) { static char value; @@ -140,10 +141,7 @@ void AT91F_DBGU_Init(void) AT91F_US_EnableIt((AT91PS_USART) AT91C_BASE_DBGU, AT91C_US_RXRDY); //* open interrupt - AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, USART_SYS_LEVEL, - AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, - DBGU_irq_handler); - AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS); + sysirq_register(AT91SAM7_SYSIRQ_DBGU, &DBGU_irq_handler); AT91F_DBGU_Printk("\n\r"); AT91F_DBGU_Printk("(C) 2006 by Harald Welte \n\r" diff --git a/firmware/src/os/main.c b/firmware/src/os/main.c index b9ed4dc..f39234b 100644 --- a/firmware/src/os/main.c +++ b/firmware/src/os/main.c @@ -41,11 +41,12 @@ int main(void) { /* initialize LED and debug unit */ led_init(); + sysirq_init(); AT91F_DBGU_Init(); AT91F_PIOA_CfgPMC(); - wdt_init(); + pit_init(); /* initialize USB */ req_ctx_init(); diff --git a/firmware/src/os/pit.c b/firmware/src/os/pit.c index 5c096cc..8bf13ba 100644 --- a/firmware/src/os/pit.c +++ b/firmware/src/os/pit.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "../openpcd.h" @@ -95,12 +96,12 @@ void timer_add(struct timer_list *tl) local_irq_restore(flags); } -static void pit_irq(void) +static void pit_irq(u_int32_t sr) { struct timer_list *tl; unsigned long flags; - jiffies++; + jiffies += *AT91C_PITC_PIVR; /* this is the most simple/stupid algorithm one can come up with, but * hey, we're on a small embedded platform with only a hand ful @@ -131,10 +132,7 @@ void pit_init(void) AT91F_PITInit(AT91C_BASE_PITC, 1000 /* uS */, 48 /* MHz */); - AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SYS, - OPENPCD_IRQ_PRIO_PIT, - AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE, - &pit_irq); + sysirq_register(AT91SAM7_SYSIRQ_PIT, &pit_irq); - //AT91F_PITEnableInt(AT91C_BASE_PITC); + AT91F_PITEnableInt(AT91C_BASE_PITC); } 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 + * + * 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 +#include +#include + +#include +#include + +#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); +} diff --git a/firmware/src/os/system_irq.h b/firmware/src/os/system_irq.h new file mode 100644 index 0000000..195b7b9 --- /dev/null +++ b/firmware/src/os/system_irq.h @@ -0,0 +1,22 @@ +#ifndef _SYSTEM_IRQ_H +#define _SYSTEM_IRQ_H + +#include + +enum sysirqs { + AT91SAM7_SYSIRQ_PIT = 0, + AT91SAM7_SYSIRQ_DBGU = 1, + AT91SAM7_SYSIRQ_EFC = 2, + AT91SAM7_SYSIRQ_WDT = 3, + AT91SAM7_SYSIRQ_RTT = 4, + AT91SAM7_SYSIRQ_RSTC = 5, + AT91SAM7_SYSIRQ_PMC = 6, + AT91SAM7_SYSIRQ_COUNT +}; + +typedef void sysirq_hdlr(u_int32_t sr); + +extern void sysirq_register(enum sysirqs irq, sysirq_hdlr *hdlr); +extern void sysirq_init(void); + +#endif diff --git a/firmware/src/os/wdt.c b/firmware/src/os/wdt.c index 5a3c809..55a0e70 100644 --- a/firmware/src/os/wdt.c +++ b/firmware/src/os/wdt.c @@ -21,10 +21,11 @@ #include #include +#include #define WDT_DEBUG -static void wdt_irq(void) +static void wdt_irq(u_int32_t sr) { DEBUGPCRF("================> WATCHDOG EXPIRED !!!!!"); } @@ -36,6 +37,7 @@ void wdt_restart(void) void wdt_init(void) { + sysirq_register(AT91SAM7_SYSIRQ_WDT, &wdt_irq); #ifdef WDT_DEBUG AT91F_WDTSetMode(AT91C_BASE_WDTC, (0xfff << 16) | AT91C_WDTC_WDDBGHLT | AT91C_WDTC_WDIDLEHLT | -- cgit v1.2.3