sam7fc/src/at91_sysc.c

155 lines
4.9 KiB
C

/***************************************************************************
* Copyright (C) 01/2008 by Olaf Rempel *
* razzor@kopf-tisch.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; version 2 of the License *
* *
* 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. *
***************************************************************************/
#include "AT91SAM7S256.h"
#include "at91_sysc.h"
#include "board.h"
static SYSCISR *sysc_isrs[AT91_SYSIRQ_COUNT];
struct _irq_regs {
AT91_REG *mask_register;
uint32_t mask;
AT91_REG *status_register;
uint32_t status;
};
/* same IDs as sysc_isrs enum! */
static const struct _irq_regs irq_regs[] = {
/*
* PIT (Periodic Intervall Timer)
* ISR must read AT91C_PITC_PIVR to clear interrupt
* - PITIEN (Periodic Intervall Timer Interrupt Enable)
*/
{ AT91C_PITC_PIMR, AT91C_PITC_PITIEN,
AT91C_PITC_PISR, AT91C_PITC_PITS
},
/*
* DBGU (Debug Unit)
* TODO: must use AT91C_DBGU_IDR to fault disable interrupt
* - 12 Interrupt sources
*/
{ AT91C_DBGU_IMR, (AT91C_US_RXRDY | AT91C_US_TXRDY |
AT91C_US_ENDRX | AT91C_US_ENDTX |
AT91C_US_OVRE | AT91C_US_FRAME |
AT91C_US_PARE | AT91C_US_TXEMPTY |
AT91C_US_TXBUFE | AT91C_US_RXBUFF |
AT91C_US_COMM_TX | AT91C_US_COMM_RX),
AT91C_DBGU_CSR, (AT91C_US_RXRDY | AT91C_US_TXRDY |
AT91C_US_ENDRX | AT91C_US_ENDTX |
AT91C_US_OVRE | AT91C_US_FRAME |
AT91C_US_PARE | AT91C_US_TXEMPTY |
AT91C_US_TXBUFE | AT91C_US_RXBUFF |
AT91C_US_COMM_TX | AT91C_US_COMM_RX)
},
/*
* EFC (Embedded Flash Controller / Memory Controller)
*/
{ AT91C_MC_FMR, (AT91C_MC_FRDY | AT91C_MC_LOCKE | AT91C_MC_PROGE),
AT91C_MC_FSR, (AT91C_MC_FRDY | AT91C_MC_LOCKE | AT91C_MC_PROGE)
},
/*
* WDT (Watchdog Timer)
* WDMR can be written only once (no fault disable)
* - WDFIEN (Watchdog Fault Interrupt Enable)
*/
{ AT91C_WDTC_WDMR, AT91C_WDTC_WDFIEN,
AT91C_WDTC_WDSR, (AT91C_WDTC_WDUNF | AT91C_WDTC_WDERR)
},
/*
* RTT (Real-Time Timer)
* Interrupts must be disabled during ISR?!
* - ALMIEN (Alarm Interrupt Enable)
* - RTTCINCIEN (Real-Time Timer Increment Interrupt Enable)
*/
{ AT91C_RTTC_RTMR, (AT91C_RTTC_ALMIEN | AT91C_RTTC_RTTINCIEN),
AT91C_RTTC_RTSR, (AT91C_RTTC_ALMS | AT91C_RTTC_RTTINC)
},
/*
* RSTC (Reset Controller)
* - AT91C_RSTC_URSTIEN (User Reset Interrupt Enable)
* - AT91C_RSTC_BODIEN (Brownout Detection Interrupt Enable)
*/
{ AT91C_RSTC_RMR, (AT91C_RSTC_URSTIEN | AT91C_RSTC_BODIEN),
AT91C_RSTC_RSR, (AT91C_RSTC_URSTS | AT91C_RSTC_BODSTS)
},
/*
* PMC (Power Managment Controller)
* TODO: must use AT91C_PMC_IDR to fault disable interrupt
* - 6 Interrupt sources
*/
{ AT91C_PMC_IMR, (AT91C_PMC_MOSCS | AT91C_PMC_LOCK |
AT91C_PMC_MCKRDY | AT91C_PMC_PCK0RDY |
AT91C_PMC_PCK1RDY | AT91C_PMC_PCK2RDY),
AT91C_PMC_SR, (AT91C_PMC_MOSCS | AT91C_PMC_LOCK |
AT91C_PMC_MCKRDY | AT91C_PMC_PCK0RDY |
AT91C_PMC_PCK1RDY | AT91C_PMC_PCK2RDY)
},
};
/* check Interrupts from internal hardware */
static void at91_sysc_isr(void)
{
uint32_t id;
for (id = 0; id < AT91_SYSIRQ_COUNT; id++) {
/* check if interrups are enabled */
if (*(irq_regs[id].mask_register) & irq_regs[id].mask) {
/* check if interrupts are active */
uint32_t status = *(irq_regs[id].status_register);
if (status & irq_regs[id].status) {
/* execute handler */
if (sysc_isrs[id]) {
sysc_isrs[id](status);
} else {
/* disable interrupts */
*(irq_regs[id].mask_register) &= ~irq_regs[id].mask;
}
}
}
}
}
void at91_sysc_init(void)
{
/* high priority, level triggered, own vector */
AT91S_AIC *aic = AT91C_BASE_AIC;
aic->AIC_SMR[AT91C_ID_SYS] = IRQPRIO_SYSC |
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL;
aic->AIC_SVR[AT91C_ID_SYS] = (uint32_t)at91_sysc_isr;
aic->AIC_IECR = (1<<AT91C_ID_SYS);
}
void sysc_register_isr(enum syscirqs irq, SYSCISR *isr)
{
if (irq >= AT91_SYSIRQ_COUNT)
return;
sysc_isrs[irq] = isr;
}