summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2012-01-08 22:29:25 +0000
committerMichael Sevakis <jethead71@rockbox.org>2012-01-08 22:29:25 +0000
commit307cb049485cc20140b85aa78f8e2677e8df5851 (patch)
treeeaadfd7266e4e97e69bccd68655140dd9f1ef061 /firmware/target/arm/as3525
parent5e21bbf5757163725f4bd2909fc7aaa548f61fc3 (diff)
downloadrockbox-307cb049485cc20140b85aa78f8e2677e8df5851.tar.gz
rockbox-307cb049485cc20140b85aa78f8e2677e8df5851.zip
AS3525v1/2: Enable nested handling of interrupts
Mostly for the sake of reducing latency for audio servicing where other service routines can take a long time to complete, leading to occasional drops of a few samples, especially in recording, where they are fairly frequent. One mystery that remains is GPIOA IRQ being interrupted causes strange undefined instruction exceptions, most easily produced on my Fuze V2 with a scrollwheel. Making GPIOA the top ISR for now, thus not interruptible, cures it. SVC mode is used during the actual calls. Hopefully the SVC stack size is sufficient. Prologue and epilogue code only uses the IRQ stack and is large enough. Any routine code that should not be interrupted should disable IRQ itself from here on in. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31642 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/as3525')
-rw-r--r--firmware/target/arm/as3525/fmradio-i2c-as3525.c2
-rw-r--r--firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c34
-rw-r--r--firmware/target/arm/as3525/sd-as3525.c6
-rw-r--r--firmware/target/arm/as3525/sd-as3525v2.c6
-rw-r--r--firmware/target/arm/as3525/system-as3525.c52
5 files changed, 71 insertions, 29 deletions
diff --git a/firmware/target/arm/as3525/fmradio-i2c-as3525.c b/firmware/target/arm/as3525/fmradio-i2c-as3525.c
index 3da42e31b2..5d05956799 100644
--- a/firmware/target/arm/as3525/fmradio-i2c-as3525.c
+++ b/firmware/target/arm/as3525/fmradio-i2c-as3525.c
@@ -195,8 +195,8 @@ void tuner_isr(void)
195 /* read and clear the interrupt */ 195 /* read and clear the interrupt */
196 if (GPIOA_MIS & (1<<4)) { 196 if (GPIOA_MIS & (1<<4)) {
197 semaphore_release(&rds_sema); 197 semaphore_release(&rds_sema);
198 GPIOA_IC = (1<<4);
198 } 199 }
199 GPIOA_IC = (1<<4);
200} 200}
201 201
202/* Captures RDS data and processes it */ 202/* Captures RDS data and processes it */
diff --git a/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c b/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
index 7f82b692c7..8244c475fa 100644
--- a/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
+++ b/firmware/target/arm/as3525/sansa-fuzev2/button-fuzev2.c
@@ -30,6 +30,7 @@ static bool hold_button = false;
30 30
31#ifdef HAVE_SCROLLWHEEL 31#ifdef HAVE_SCROLLWHEEL
32#define SCROLLWHEEL_BITS (1<<7|1<<6) 32#define SCROLLWHEEL_BITS (1<<7|1<<6)
33#define SCROLLWHEEL_BITS_POS 6
33 /* TIMER units */ 34 /* TIMER units */
34#define TIMER_TICK (KERNEL_TIMER_FREQ/HZ)/* how long a tick lasts */ 35#define TIMER_TICK (KERNEL_TIMER_FREQ/HZ)/* how long a tick lasts */
35#define TIMER_MS (TIMER_TICK/(1000/HZ))/* how long a ms lasts */ 36#define TIMER_MS (TIMER_TICK/(1000/HZ))/* how long a ms lasts */
@@ -78,10 +79,17 @@ static void scrollwheel(unsigned int wheel_value)
78 79
79 unsigned int btn = BUTTON_NONE; 80 unsigned int btn = BUTTON_NONE;
80 81
81 if (old_wheel_value == wheel_tbl[0][wheel_value]) 82 if (hold_button)
83 {
84 }
85 else if (old_wheel_value == wheel_tbl[0][wheel_value])
86 {
82 btn = BUTTON_SCROLL_FWD; 87 btn = BUTTON_SCROLL_FWD;
88 }
83 else if (old_wheel_value == wheel_tbl[1][wheel_value]) 89 else if (old_wheel_value == wheel_tbl[1][wheel_value])
90 {
84 btn = BUTTON_SCROLL_BACK; 91 btn = BUTTON_SCROLL_BACK;
92 }
85 93
86 if (btn == BUTTON_NONE) 94 if (btn == BUTTON_NONE)
87 { 95 {
@@ -200,11 +208,13 @@ void button_gpioa_isr(void)
200{ 208{
201#if defined(HAVE_SCROLLWHEEL) 209#if defined(HAVE_SCROLLWHEEL)
202 /* scroll wheel handling */ 210 /* scroll wheel handling */
203 if (GPIOA_MIS & SCROLLWHEEL_BITS) 211 unsigned long bits = GPIOA_MIS & SCROLLWHEEL_BITS;
204 scrollwheel(GPIOA_PIN_MASK(0xc0) >> 6);
205 212
206 /* ack interrupt */ 213 if (bits)
207 GPIOA_IC = SCROLLWHEEL_BITS; 214 {
215 scrollwheel(GPIOA_PIN_MASK(SCROLLWHEEL_BITS) >> SCROLLWHEEL_BITS_POS);
216 GPIOA_IC = bits; /* ack interrupt */
217 }
208#endif 218#endif
209} 219}
210 220
@@ -225,8 +235,10 @@ int button_read_device(void)
225 int delay = 30; 235 int delay = 30;
226 while(delay--) nop; 236 while(delay--) nop;
227 237
238 disable_irq();
239
228 bool ccu_io_bit12 = CCU_IO & (1<<12); 240 bool ccu_io_bit12 = CCU_IO & (1<<12);
229 bitclr32(&CCU_IO, 1<<12); 241 CCU_IO &= ~(1<<12);
230 242
231 /* B1 is shared with FM i2c */ 243 /* B1 is shared with FM i2c */
232 bool gpiob_pin0_dir = GPIOB_DIR & (1<<1); 244 bool gpiob_pin0_dir = GPIOB_DIR & (1<<1);
@@ -256,7 +268,9 @@ int button_read_device(void)
256 GPIOB_DIR |= 1<<1; 268 GPIOB_DIR |= 1<<1;
257 269
258 if(ccu_io_bit12) 270 if(ccu_io_bit12)
259 bitset32(&CCU_IO, 1<<12); 271 CCU_IO |= (1<<12);
272
273 enable_irq();
260 274
261#ifdef HAS_BUTTON_HOLD 275#ifdef HAS_BUTTON_HOLD
262#ifndef BOOTLOADER 276#ifndef BOOTLOADER
@@ -265,12 +279,6 @@ int button_read_device(void)
265 { 279 {
266 hold_button = hold; 280 hold_button = hold;
267 backlight_hold_changed(hold); 281 backlight_hold_changed(hold);
268 /* mask scrollwheel irq so we don't need to check for
269 * the hold button in the isr */
270 if (hold)
271 GPIOA_IE &= ~SCROLLWHEEL_BITS;
272 else
273 GPIOA_IE |= SCROLLWHEEL_BITS;
274 } 282 }
275#else 283#else
276 hold_button = hold; 284 hold_button = hold;
diff --git a/firmware/target/arm/as3525/sd-as3525.c b/firmware/target/arm/as3525/sd-as3525.c
index 17f1bfa11d..5bed36e51e 100644
--- a/firmware/target/arm/as3525/sd-as3525.c
+++ b/firmware/target/arm/as3525/sd-as3525.c
@@ -178,10 +178,12 @@ static int sd1_oneshot_callback(struct timeout *tmo)
178void sd_gpioa_isr(void) 178void sd_gpioa_isr(void)
179{ 179{
180 static struct timeout sd1_oneshot; 180 static struct timeout sd1_oneshot;
181
181 if (GPIOA_MIS & EXT_SD_BITS) 182 if (GPIOA_MIS & EXT_SD_BITS)
183 {
182 timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0); 184 timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
183 /* acknowledge interrupt */ 185 GPIOA_IC = EXT_SD_BITS; /* acknowledge interrupt */
184 GPIOA_IC = EXT_SD_BITS; 186 }
185} 187}
186#endif /* HAVE_HOTSWAP */ 188#endif /* HAVE_HOTSWAP */
187 189
diff --git a/firmware/target/arm/as3525/sd-as3525v2.c b/firmware/target/arm/as3525/sd-as3525v2.c
index 717d5dd744..9edc598edf 100644
--- a/firmware/target/arm/as3525/sd-as3525v2.c
+++ b/firmware/target/arm/as3525/sd-as3525v2.c
@@ -1041,10 +1041,12 @@ static int sd1_oneshot_callback(struct timeout *tmo)
1041void sd_gpioa_isr(void) 1041void sd_gpioa_isr(void)
1042{ 1042{
1043 static struct timeout sd1_oneshot; 1043 static struct timeout sd1_oneshot;
1044
1044 if (GPIOA_MIS & EXT_SD_BITS) 1045 if (GPIOA_MIS & EXT_SD_BITS)
1046 {
1045 timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0); 1047 timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0);
1046 /* acknowledge interrupt */ 1048 GPIOA_IC = EXT_SD_BITS; /* acknowledge interrupt */
1047 GPIOA_IC = EXT_SD_BITS; 1049 }
1048} 1050}
1049#endif /* HAVE_HOTSWAP */ 1051#endif /* HAVE_HOTSWAP */
1050 1052
diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c
index 01aaeaccbe..f0ed75d2bd 100644
--- a/firmware/target/arm/as3525/system-as3525.c
+++ b/firmware/target/arm/as3525/system-as3525.c
@@ -51,7 +51,7 @@
51 extern __attribute__((weak,alias("UIRQ"))) void name (void) 51 extern __attribute__((weak,alias("UIRQ"))) void name (void)
52 52
53static void UIRQ (void) __attribute__((interrupt ("IRQ"))); 53static void UIRQ (void) __attribute__((interrupt ("IRQ")));
54void irq_handler(void) __attribute__((interrupt ("IRQ"))); 54void irq_handler(void) __attribute__((naked, interrupt ("IRQ")));
55void fiq_handler(void) __attribute__((interrupt ("FIQ"))); 55void fiq_handler(void) __attribute__((interrupt ("FIQ")));
56 56
57default_interrupt(INT_WATCHDOG); 57default_interrupt(INT_WATCHDOG);
@@ -121,6 +121,11 @@ static void UIRQ(void)
121static const struct { int source; void (*isr) (void); } vec_int_srcs[] = 121static const struct { int source; void (*isr) (void); } vec_int_srcs[] =
122{ 122{
123 /* Highest priority at the top of the list */ 123 /* Highest priority at the top of the list */
124#if defined(HAVE_HOTSWAP) || defined(HAVE_RDS_CAP) || \
125 (defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING)
126 /* If GPIOA ISR is interrupted, things seem to go wonky ?? */
127 { INT_SRC_GPIOA, INT_GPIOA },
128#endif
124#ifdef HAVE_RECORDING 129#ifdef HAVE_RECORDING
125 { INT_SRC_I2SIN, INT_I2SIN }, /* For recording */ 130 { INT_SRC_I2SIN, INT_I2SIN }, /* For recording */
126#endif 131#endif
@@ -134,29 +139,26 @@ static const struct { int source; void (*isr) (void); } vec_int_srcs[] =
134 { INT_SRC_TIMER2, INT_TIMER2 }, 139 { INT_SRC_TIMER2, INT_TIMER2 },
135 { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO }, 140 { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO },
136 { INT_SRC_AUDIO, INT_AUDIO }, 141 { INT_SRC_AUDIO, INT_AUDIO },
137#if defined(HAVE_HOTSWAP) || \
138 (defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING)
139 { INT_SRC_GPIOA, INT_GPIOA, },
140#endif
141 /* Lowest priority at the end of the list */ 142 /* Lowest priority at the end of the list */
142}; 143};
143 144
144static void setup_vic(void) 145static void setup_vic(void)
145{ 146{
146 const unsigned int n = sizeof(vec_int_srcs)/sizeof(vec_int_srcs[0]);
147 unsigned int i;
148
149 CGU_PERI |= CGU_VIC_CLOCK_ENABLE; /* enable VIC */ 147 CGU_PERI |= CGU_VIC_CLOCK_ENABLE; /* enable VIC */
150 VIC_INT_EN_CLEAR = 0xffffffff; /* disable all interrupt lines */ 148 VIC_INT_EN_CLEAR = 0xffffffff; /* disable all interrupt lines */
151 VIC_INT_SELECT = 0; /* only IRQ, no FIQ */ 149 VIC_INT_SELECT = 0; /* only IRQ, no FIQ */
152 150
153 *VIC_DEF_VECT_ADDR = UIRQ; 151 *VIC_DEF_VECT_ADDR = UIRQ;
154 152
155 for(i = 0; i < n; i++) 153 for(unsigned int i = 0; i < ARRAYLEN(vec_int_srcs); i++)
156 { 154 {
157 VIC_VECT_ADDRS[i] = vec_int_srcs[i].isr; 155 VIC_VECT_ADDRS[i] = vec_int_srcs[i].isr;
158 VIC_VECT_CNTLS[i] = (1<<5) | vec_int_srcs[i].source; 156 VIC_VECT_CNTLS[i] = (1<<5) | vec_int_srcs[i].source;
159 } 157 }
158
159 /* Reset priority hardware */
160 for(unsigned int i = 0; i < 32; i++)
161 *VIC_VECT_ADDR = 0;
160} 162}
161 163
162void INT_GPIOA(void) 164void INT_GPIOA(void)
@@ -177,8 +179,36 @@ void INT_GPIOA(void)
177 179
178void irq_handler(void) 180void irq_handler(void)
179{ 181{
180 (*VIC_VECT_ADDR)(); /* call the isr */ 182 /* Worst-case IRQ stack usage with 10 vectors:
181 *VIC_VECT_ADDR = (void*)VIC_VECT_ADDR; /* any write will ack the irq */ 183 * 10*4*10 = 400 bytes (100 words)
184 *
185 * No SVC stack is used by pro/epi-logue code
186 */
187 asm volatile (
188 "sub lr, lr, #4 \n" /* Create return address */
189 "stmfd sp!, { r0-r5, r12, lr } \n" /* Save what gets clobbered */
190 "ldr r0, =0xc6010030 \n" /* Obtain VIC address (before SPSR read!) */
191 "ldr r12, [r0] \n" /* Load Vector */
192 "mrs r1, spsr \n" /* Save SPSR_irq */
193 "stmfd sp!, { r0-r1 } \n" /* Must have something bet. mrs and msr */
194 "msr cpsr_c, #0x13 \n" /* Switch to SVC mode, enable IRQ */
195 "and r4, sp, #4 \n" /* Align SVC stack to 8 bytes, save */
196 "sub sp, sp, r4 \n"
197 "mov r5, lr \n" /* Save lr_SVC */
198#if ARM_ARCH >= 5
199 "blx r12 \n" /* Call handler */
200#else
201 "mov lr, pc \n"
202 "bx r12 \n"
203#endif
204 "add sp, sp, r4 \n" /* Undo alignment fudge */
205 "mov lr, r5 \n" /* Restore lr_SVC */
206 "msr cpsr_c, #0x92 \n" /* Mask IRQ, return to IRQ mode */
207 "ldmfd sp!, { r0-r1 } \n" /* Pop VIC address, SPSR_irq */
208 "str r0, [r0] \n" /* Ack end of ISR to VIC */
209 "msr spsr_cxsf, r1 \n" /* Restore SPSR_irq */
210 "ldmfd sp!, { r0-r5, r12, pc }^ \n" /* Restore regs, and RFE */
211 );
182} 212}
183 213
184void fiq_handler(void) 214void fiq_handler(void)