summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/kernel.c14
-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
-rw-r--r--firmware/target/arm/crt0.S29
-rw-r--r--firmware/target/arm/system-arm.h10
8 files changed, 105 insertions, 48 deletions
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 155205749f..0b39e29126 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -1195,9 +1195,7 @@ int semaphore_wait(struct semaphore *s, int timeout)
1195 * in 'semaphore_init'. */ 1195 * in 'semaphore_init'. */
1196void semaphore_release(struct semaphore *s) 1196void semaphore_release(struct semaphore *s)
1197{ 1197{
1198#if defined(HAVE_PRIORITY_SCHEDULING) && defined(irq_enabled_checkval)
1199 unsigned int result = THREAD_NONE; 1198 unsigned int result = THREAD_NONE;
1200#endif
1201 int oldlevel; 1199 int oldlevel;
1202 1200
1203 oldlevel = disable_irq_save(); 1201 oldlevel = disable_irq_save();
@@ -1209,11 +1207,7 @@ void semaphore_release(struct semaphore *s)
1209 KERNEL_ASSERT(s->count == 0, 1207 KERNEL_ASSERT(s->count == 0,
1210 "semaphore_release->threads queued but count=%d!\n", s->count); 1208 "semaphore_release->threads queued but count=%d!\n", s->count);
1211 s->queue->retval = OBJ_WAIT_SUCCEEDED; /* indicate explicit wake */ 1209 s->queue->retval = OBJ_WAIT_SUCCEEDED; /* indicate explicit wake */
1212#if defined(HAVE_PRIORITY_SCHEDULING) && defined(irq_enabled_checkval)
1213 result = wakeup_thread(&s->queue); 1210 result = wakeup_thread(&s->queue);
1214#else
1215 wakeup_thread(&s->queue);
1216#endif
1217 } 1211 }
1218 else 1212 else
1219 { 1213 {
@@ -1228,11 +1222,11 @@ void semaphore_release(struct semaphore *s)
1228 corelock_unlock(&s->cl); 1222 corelock_unlock(&s->cl);
1229 restore_irq(oldlevel); 1223 restore_irq(oldlevel);
1230 1224
1231#if defined(HAVE_PRIORITY_SCHEDULING) && defined(irq_enabled_checkval) 1225#if defined(HAVE_PRIORITY_SCHEDULING) && defined(is_thread_context)
1232 /* No thread switch if IRQ disabled - it's probably called via ISR. 1226 /* No thread switch if not thread context */
1233 * switch_thread would as well enable them anyway. */ 1227 if((result & THREAD_SWITCH) && is_thread_context())
1234 if((result & THREAD_SWITCH) && irq_enabled_checkval(oldlevel))
1235 switch_thread(); 1228 switch_thread();
1236#endif 1229#endif
1230 (void)result;
1237} 1231}
1238#endif /* HAVE_SEMAPHORE_OBJECTS */ 1232#endif /* HAVE_SEMAPHORE_OBJECTS */
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)
diff --git a/firmware/target/arm/crt0.S b/firmware/target/arm/crt0.S
index f75f37006d..7befecb593 100644
--- a/firmware/target/arm/crt0.S
+++ b/firmware/target/arm/crt0.S
@@ -100,17 +100,23 @@ newstart:
100 strhi r4, [r2], #4 100 strhi r4, [r2], #4
101 bhi 1b 101 bhi 1b
102 102
103 /* Set up stack for IRQ mode */ 103 /* Set up stack for IRQ mode */
104 msr cpsr_c, #0xd2 104 msr cpsr_c, #0xd2
105 ldr sp, =irq_stack 105 ldr sp, =irq_stack
106 106
107 /* Set up stack for FIQ mode */
108 msr cpsr_c, #0xd1
109 ldr sp, =fiq_stack
110
111 /* Let svc, abort and undefined modes use irq stack */
112 msr cpsr_c, #0xd3 107 msr cpsr_c, #0xd3
108#if CONFIG_CPU == AS3525 || CONFIG_CPU == AS3525v2
109 /* Let abort and undefined modes use irq stack */
110 /* svc stack is for interrupt processing */
111 ldr sp, =svc_stack
112#else
113 /* Let svc, abort and undefined modes use irq stack */
113 ldr sp, =irq_stack 114 ldr sp, =irq_stack
115
116 /* Set up stack for FIQ mode */
117 msr cpsr_c, #0xd1
118 ldr sp, =fiq_stack
119#endif
114 msr cpsr_c, #0xd7 120 msr cpsr_c, #0xd7
115 ldr sp, =irq_stack 121 ldr sp, =irq_stack
116 msr cpsr_c, #0xdb 122 msr cpsr_c, #0xdb
@@ -159,15 +165,20 @@ prefetch_abort_handler:
159 b UIE 165 b UIE
160 166
161data_abort_handler: 167data_abort_handler:
162 sub r0, lr, #8 168 sub r0, lr, #8
163 mov r1, #2 169 mov r1, #2
164 b UIE 170 b UIE
165 171
172/* Cache-align interrupt stacks */
173.balign 32
174
166/* 256 words of IRQ stack */ 175/* 256 words of IRQ stack */
167 .space 256*4 176 .space 256*4
168irq_stack: 177irq_stack:
169 178
170/* 256 words of FIQ stack */ 179/* 256 words of FIQ/SVC stack */
171 .space 256*4 180 .space 256*4
172fiq_stack: 181fiq_stack:
173end: 182svc_stack:
183
184end: \ No newline at end of file
diff --git a/firmware/target/arm/system-arm.h b/firmware/target/arm/system-arm.h
index b3630a8473..ffce77a176 100644
--- a/firmware/target/arm/system-arm.h
+++ b/firmware/target/arm/system-arm.h
@@ -76,6 +76,9 @@ void __div0(void);
76#define ints_enabled_checkval(val) \ 76#define ints_enabled_checkval(val) \
77 (((val) & IRQ_FIQ_STATUS) == 0) 77 (((val) & IRQ_FIQ_STATUS) == 0)
78 78
79/* We run in SYS mode */
80#define is_thread_context() \
81 (get_processor_mode() == 0x1f)
79 82
80/* Core-level interrupt masking */ 83/* Core-level interrupt masking */
81 84
@@ -109,6 +112,13 @@ static inline bool interrupt_enabled(int status)
109 return (cpsr & status) == 0; 112 return (cpsr & status) == 0;
110} 113}
111 114
115static inline unsigned long get_processor_mode(void)
116{
117 unsigned long cpsr;
118 asm ("mrs %0, cpsr" : "=r"(cpsr));
119 return cpsr & 0x1f;
120}
121
112/* ARM_ARCH version section for architecture*/ 122/* ARM_ARCH version section for architecture*/
113 123
114#if ARM_ARCH >= 6 124#if ARM_ARCH >= 6