diff options
Diffstat (limited to 'openpicc/application/pio_irq.c')
-rw-r--r-- | openpicc/application/pio_irq.c | 52 |
1 files changed, 49 insertions, 3 deletions
diff --git a/openpicc/application/pio_irq.c b/openpicc/application/pio_irq.c index a92ceaa..04763a3 100644 --- a/openpicc/application/pio_irq.c +++ b/openpicc/application/pio_irq.c @@ -1,5 +1,6 @@ /* PIO IRQ Implementation for OpenPCD * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de> + * (C) 2007 Henryk Plötz <henryk@ploetzli.ch> * * 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 @@ -40,6 +41,37 @@ struct pioirq_state { static struct pioirq_state pirqs; static unsigned long count = 0; +/* This FIQ implementation of pio data change works in close cooperation with function my_fiq_handler + * in os/boot/boot.s + * This code uses fast forcing for the PIOA irq so that each PIOA data change triggers + * a FIQ. The FreeRTOS code has been modified to not mask FIQ ever. This means that the FIQ + * code will run asynchronously with regards to the other code and especially might invade critical + * sections. The actual FIQ code must therefore be as short as possible and may not call into the + * FreeRTOS API (or parts of the application that call into the FreeRTOS API). + * Instead a trick will be attempted: The PIOA IRQ will be set to fast forcing with my_fiq_handler + * as handler and the FIQ handler then does the absolutely time critical tasks without calling any + * other code. Additionally a second, normal IRQ handler is set up for a reserved IRQ on the AIC + * that is not connected to any peripherals (see #define of PIO_SECONDARY_IRQ). After handling + * the time critical tasks the FIQ handler will then manually assert this IRQ which will then + * be handled by the AIC and priority controller and also execute synchronized with regards to + * critical sections. + * Potential problem: look for race conditions between PIO data change FIQ and handling + * of PIO_SECONDARY_IRQ. + * + * Note: Originally I wanted to use 15 for the PIO_SECONDARY_IRQ but it turns out that that + * won't work (the identifier is marked as reserved). Use 31 (external IRQ1) instead. Another + * candidate would be 7 (USART1). + */ +#define USE_FIQ +#define PIO_SECONDARY_IRQ 31 +extern void my_fiq_handler(void); +extern void fiq_handler(void); + +/* Will be used in pio_irq_demux_secondary below and contains the PIO_ISR value + * from when the FIQ was raised */ +u_int32_t pio_irq_isr_value; + + /* low-level handler, used by Cstartup_app.S PIOA fast forcing and * by regular interrupt handler below */ void __ramfunc __pio_irq_demux(u_int32_t pio) @@ -94,6 +126,16 @@ static void pio_irq_demux(void) portRESTORE_CONTEXT(); } +/* nearly regular interrupt handler, in case fast forcing for PIOA is enabled and the secondary irq hack used */ +static void pio_irq_demux_secondary(void) __attribute__ ((naked)); +static void pio_irq_demux_secondary(void) +{ + portSAVE_CONTEXT(); + __pio_irq_demux(pio_irq_isr_value); + AT91F_AIC_ClearIt(PIO_SECONDARY_IRQ); + portRESTORE_CONTEXT(); +} + void pio_irq_enable(u_int32_t pio) { AT91F_PIO_InterruptEnable(AT91C_BASE_PIOA, pio); @@ -147,9 +189,6 @@ void pio_irq_init_once(void) if(!initialized) pio_irq_init(); } -#define USE_FIQ -extern void my_fiq_handler(void); -extern void fiq_handler(void); void pio_irq_init(void) { @@ -161,6 +200,13 @@ void pio_irq_init(void) 0, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &my_fiq_handler); /* enable fast forcing for PIOA interrupt */ *AT91C_AIC_FFER = (1 << AT91C_ID_PIOA); + + /* Set up a regular IRQ handler to be triggered from within the FIQ */ + AT91F_AIC_ConfigureIt(PIO_SECONDARY_IRQ, + OPENPICC_IRQ_PRIO_PIO, + AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE, &pio_irq_demux_secondary); + AT91F_AIC_ClearIt(PIO_SECONDARY_IRQ); + AT91F_AIC_EnableIt(PIO_SECONDARY_IRQ); #else AT91F_AIC_ConfigureIt(AT91C_ID_PIOA, OPENPICC_IRQ_PRIO_PIO, |