ugfx/boards/base/RaspberryPi/FreeRTOS/interrupts.c
2014-10-06 17:05:16 +10:00

167 lines
3.9 KiB
C

/**
* Integrated Interrupt Controller for RaspberryPi.
* @author James Walmsley <james@fullfat-fs.co.uk>
**/
#include "interrupts.h"
#include "bcm2835_intc.h"
static INTERRUPT_VECTOR g_VectorTable[BCM2835_INTC_TOTAL_IRQ];
typedef struct {
unsigned long IRQBasic; // Pending 0
unsigned long Pending1;
unsigned long Pending2;
unsigned long FIQCtrl;
unsigned long Enable1;
unsigned long Enable2;
unsigned long EnableBasic;
unsigned long Disable1;
unsigned long Disable2;
unsigned long DisableBasic;
} BCM2835_INTC_REGS;
static volatile BCM2835_INTC_REGS * const pRegs = (BCM2835_INTC_REGS *) (BCM2835_BASE_INTC);
/**
* Enables all IRQ's in the CPU's CPSR register.
**/
static void irqEnable() {
__asm volatile("mrs r0,cpsr"); // Read in the cpsr register.
__asm volatile("bic r0,r0,#0x80"); // Clear bit 8, (0x80) -- Causes IRQs to be enabled.
__asm volatile("msr cpsr_c, r0"); // Write it back to the CPSR register
}
static void irqDisable() {
__asm volatile("mrs r0,cpsr"); // Read in the cpsr register.
__asm volatile("orr r0,r0,#0x80"); // Set bit 8, (0x80) -- Causes IRQs to be disabled.
__asm volatile("msr cpsr_c, r0"); // Write it back to the CPSR register.
}
#define clz(a) \
({ unsigned long __value, __arg = (a); \
asm ("clz\t%0, %1": "=r" (__value): "r" (__arg)); \
__value; })
/**
* This is the global IRQ handler on this platform!
* It is based on the assembler code found in the Broadcom datasheet.
*
**/
void irqHandler() {
register unsigned long ulMaskedStatus;
register unsigned long irqNumber;
ulMaskedStatus = pRegs->IRQBasic;
/* Bits 7 through 0 in IRQBasic represent interrupts 64-71 */
if (ulMaskedStatus & 0xFF) {
irqNumber=64 + 31;
}
/* Bit 8 in IRQBasic indicates interrupts in Pending1 (interrupts 31-0) */
else if(ulMaskedStatus & 0x100) {
ulMaskedStatus = pRegs->Pending1;
irqNumber = 0 + 31;
}
/* Bit 9 in IRQBasic indicates interrupts in Pending2 (interrupts 63-32) */
else if(ulMaskedStatus & 0x200) {
ulMaskedStatus = pRegs->Pending2;
irqNumber = 32 + 31;
}
else {
// No interrupt avaialbe, so just return.
return;
}
/* Keep only least significant bit, in case multiple interrupts have occured */
ulMaskedStatus&=-ulMaskedStatus;
/* Some magic to determine number of interrupt to serve */
irqNumber=irqNumber-clz(ulMaskedStatus);
/* Call interrupt handler */
g_VectorTable[irqNumber].pfnHandler(irqNumber, g_VectorTable[irqNumber].pParam);
}
static void stubHandler(int nIRQ, void *pParam) {
/**
* Actually if we get here, we should probably disable the IRQ,
* otherwise we could lock up this system, as there is nothing to
* ackknowledge the interrupt.
**/
}
int InitInterruptController() {
int i;
for(i = 0; i < BCM2835_INTC_TOTAL_IRQ; i++) {
g_VectorTable[i].pfnHandler = stubHandler;
g_VectorTable[i].pParam = (void *) 0;
}
return 0;
}
int RegisterInterrupt(int nIRQ, FN_INTERRUPT_HANDLER pfnHandler, void *pParam) {
if(nIRQ<0 || nIRQ>71)
return -1;
irqDisable();
{
g_VectorTable[nIRQ].pfnHandler = pfnHandler;
g_VectorTable[nIRQ].pParam = pParam;
}
irqEnable();
return 0;
}
int EnableInterrupt(int nIRQ) {
/* Datasheet says "All other bits are unaffected", and I'm counting on that. */
unsigned int mask=1<<(nIRQ%32);
if(nIRQ >=0 && nIRQ <=31) {
pRegs->Enable1 = mask;
} else
if(nIRQ >=32 && nIRQ <=63){
pRegs->Enable2 = mask;
} else
if(nIRQ >= 64 && nIRQ <= 71) { // Basic IRQ enables
pRegs->EnableBasic = mask;
} else
return -1;
return 0;
}
int DisableInterrupt(int nIRQ) {
/* Datasheet says "All other bits are unaffected", and I'm counting on that. */
unsigned int mask=1<<(nIRQ%32);
if(nIRQ >=0 && nIRQ <=31) {
pRegs->Disable1 = mask;
} else
if(nIRQ >=32 && nIRQ <=63){
pRegs->Disable2 = mask;
} else
if(nIRQ >= 64 && nIRQ <= 71) {
pRegs->DisableBasic = mask;
} else
return -1;
return 0;
}
int EnableInterrupts() {
irqEnable();
return 0;
}
int DisableInterrupts() {
irqDisable();
return 0;
}