diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/pp/system-pp502x.c | 81 |
1 files changed, 56 insertions, 25 deletions
diff --git a/firmware/target/arm/pp/system-pp502x.c b/firmware/target/arm/pp/system-pp502x.c index ad0577c38f..686e2ac3bd 100644 --- a/firmware/target/arm/pp/system-pp502x.c +++ b/firmware/target/arm/pp/system-pp502x.c | |||
@@ -29,6 +29,21 @@ | |||
29 | #include "button-target.h" | 29 | #include "button-target.h" |
30 | #include "usb_drv.h" | 30 | #include "usb_drv.h" |
31 | 31 | ||
32 | /* Bit 0 - 20: Cached Address */ | ||
33 | #define CACHE_ADDRESS_MASK ((1<<21)-1) | ||
34 | /* Bit 22: Cache line dirty */ | ||
35 | #define CACHE_LINE_DIRTY (1<<22) | ||
36 | /* Bit 23: Cache line valid */ | ||
37 | #define CACHE_LINE_VALID (1<<23) | ||
38 | /* Cache Size - 8K*/ | ||
39 | #define CACHE_SIZE 0x2000 | ||
40 | |||
41 | /*Initial memory address used to prime cache | ||
42 | * could be targeted to a more 'important' address | ||
43 | * Note: Don't start at 0x0, as the compiler thinks it's a | ||
44 | * null pointer dereference and will helpfully blow up the code. */ | ||
45 | #define CACHED_INIT_ADDR CACHEALIGN_UP(0x2000) | ||
46 | |||
32 | #if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) | 47 | #if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE) |
33 | extern void TIMER1(void); | 48 | extern void TIMER1(void); |
34 | extern void TIMER2(void); | 49 | extern void TIMER2(void); |
@@ -44,7 +59,7 @@ unsigned char probed_ramsize; | |||
44 | 59 | ||
45 | void __attribute__((interrupt("IRQ"))) irq_handler(void) | 60 | void __attribute__((interrupt("IRQ"))) irq_handler(void) |
46 | { | 61 | { |
47 | if(CURRENT_CORE == CPU) | 62 | if(IF_COP_CORE(CPU) == CPU) |
48 | { | 63 | { |
49 | if (CPU_INT_STAT & TIMER1_MASK) { | 64 | if (CPU_INT_STAT & TIMER1_MASK) { |
50 | TIMER1(); | 65 | TIMER1(); |
@@ -218,6 +233,39 @@ void ICODE_ATTR commit_dcache(void) | |||
218 | } | 233 | } |
219 | } | 234 | } |
220 | 235 | ||
236 | static void ICODE_ATTR cache_invalidate_special(void) | ||
237 | { | ||
238 | /* Cache lines which are not marked as valid can cause memory | ||
239 | * corruption when there are many writes to and code fetches from | ||
240 | * cached memory. This workaround points all cache status to the | ||
241 | * maximum line address and marked valid but not dirty. Since that area | ||
242 | * is never accessed, the cache lines don't affect anything, and | ||
243 | * they're effectively discarded. Interrupts must be disabled here | ||
244 | * because any change they make to cached memory could be discarded. | ||
245 | * A status word is 32 bits and is mirrored four times for each cache line | ||
246 | bit 0-20 line_address >> 11 | ||
247 | bit 21 unused? | ||
248 | bit 22 line_dirty | ||
249 | bit 23 line_valid | ||
250 | bit 24-31 unused? | ||
251 | */ | ||
252 | register volatile unsigned long *p; | ||
253 | if (IF_COP_CORE(CPU) == CPU) | ||
254 | { | ||
255 | for (p = &CACHE_STATUS_BASE_CPU; | ||
256 | p < (&CACHE_STATUS_BASE_CPU) + CACHE_SIZE; | ||
257 | p += CACHEALIGN_BITS) /* sizeof(p) * CACHEALIGN_BITS */ | ||
258 | *p = CACHE_LINE_VALID | CACHE_ADDRESS_MASK; | ||
259 | } | ||
260 | else | ||
261 | { | ||
262 | for (p = &CACHE_STATUS_BASE_COP; | ||
263 | p < (&CACHE_STATUS_BASE_COP) + CACHE_SIZE; | ||
264 | p += CACHEALIGN_BITS) | ||
265 | *p = CACHE_LINE_VALID | CACHE_ADDRESS_MASK; | ||
266 | } | ||
267 | } | ||
268 | |||
221 | void ICODE_ATTR commit_discard_idcache(void) | 269 | void ICODE_ATTR commit_discard_idcache(void) |
222 | { | 270 | { |
223 | if (CACHE_CTL & CACHE_CTL_ENABLE) | 271 | if (CACHE_CTL & CACHE_CTL_ENABLE) |
@@ -225,21 +273,7 @@ void ICODE_ATTR commit_discard_idcache(void) | |||
225 | register int istat = disable_interrupt_save(IRQ_FIQ_STATUS); | 273 | register int istat = disable_interrupt_save(IRQ_FIQ_STATUS); |
226 | 274 | ||
227 | commit_dcache(); | 275 | commit_dcache(); |
228 | 276 | cache_invalidate_special(); | |
229 | /* Cache lines which are not marked as valid can cause memory | ||
230 | * corruption when there are many writes to and code fetches from | ||
231 | * cached memory. This workaround points all cache status words past | ||
232 | * end of RAM and marks them as valid, but not dirty. Since that area | ||
233 | * is never accessed, the cache lines don't affect anything, and | ||
234 | * they're effectively discarded. Interrupts must be disabled here | ||
235 | * because any change they make to cached memory could be discarded. | ||
236 | */ | ||
237 | |||
238 | register volatile unsigned long *p; | ||
239 | for (p = &CACHE_STATUS_BASE; | ||
240 | p < (&CACHE_STATUS_BASE) + 512*16/sizeof(*p); | ||
241 | p += 16/sizeof(*p)) | ||
242 | *p = ((MEMORYSIZE*0x100000) >> 11) | 0x800000; | ||
243 | 277 | ||
244 | restore_interrupt(istat); | 278 | restore_interrupt(istat); |
245 | } | 279 | } |
@@ -258,7 +292,7 @@ static void init_cache(void) | |||
258 | 292 | ||
259 | #ifndef BOOTLOADER | 293 | #ifndef BOOTLOADER |
260 | /* what's this do? */ | 294 | /* what's this do? */ |
261 | CACHE_PRIORITY |= CURRENT_CORE == CPU ? 0x10 : 0x20; | 295 | CACHE_PRIORITY |= IF_COP_CORE(CPU) == CPU ? 0x10 : 0x20; |
262 | #endif | 296 | #endif |
263 | 297 | ||
264 | /* Cache if (addr & mask) >> 16 == (mask & match) >> 16: | 298 | /* Cache if (addr & mask) >> 16 == (mask & match) >> 16: |
@@ -278,11 +312,8 @@ static void init_cache(void) | |||
278 | * can run from cached RAM, rewriting of cache status words may not | 312 | * can run from cached RAM, rewriting of cache status words may not |
279 | * be safe and the cache is filled instead by reading. */ | 313 | * be safe and the cache is filled instead by reading. */ |
280 | 314 | ||
281 | /* Note: Don't start at 0x0, as the compiler thinks it's a | 315 | register volatile char *p = (volatile char *)CACHED_INIT_ADDR; |
282 | null pointer dereference and will helpfully blow up the code. */ | 316 | for (;p < (volatile char *)CACHED_INIT_ADDR + CACHE_SIZE; p += CACHEALIGN_SIZE) |
283 | |||
284 | register volatile char *p; | ||
285 | for (p = (volatile char *)0x1000; p < (volatile char *)0x3000; p += 0x10) | ||
286 | (void)*p; | 317 | (void)*p; |
287 | } | 318 | } |
288 | #endif /* BOOTLOADER || HAVE_BOOTLOADER_USB_MODE */ | 319 | #endif /* BOOTLOADER || HAVE_BOOTLOADER_USB_MODE */ |
@@ -293,7 +324,7 @@ static void init_cache(void) | |||
293 | void scale_suspend_core(bool suspend) ICODE_ATTR; | 324 | void scale_suspend_core(bool suspend) ICODE_ATTR; |
294 | void scale_suspend_core(bool suspend) | 325 | void scale_suspend_core(bool suspend) |
295 | { | 326 | { |
296 | unsigned int core = CURRENT_CORE; | 327 | unsigned int core = IF_COP_CORE(CPU); |
297 | IF_COP( unsigned int othercore = 1 - core; ) | 328 | IF_COP( unsigned int othercore = 1 - core; ) |
298 | static int oldstatus IBSS_ATTR; | 329 | static int oldstatus IBSS_ATTR; |
299 | 330 | ||
@@ -442,7 +473,7 @@ static void pp_set_cpu_frequency(long frequency) | |||
442 | #ifndef BOOTLOADER | 473 | #ifndef BOOTLOADER |
443 | void system_init(void) | 474 | void system_init(void) |
444 | { | 475 | { |
445 | if (CURRENT_CORE == CPU) | 476 | if (IF_COP_CORE(CPU) == CPU) |
446 | { | 477 | { |
447 | #if defined (IRIVER_H10) || defined(IRIVER_H10_5GB) || defined(IPOD_COLOR) | 478 | #if defined (IRIVER_H10) || defined(IRIVER_H10_5GB) || defined(IPOD_COLOR) |
448 | /* set minimum startup configuration */ | 479 | /* set minimum startup configuration */ |
@@ -628,7 +659,7 @@ void system_exception_wait(void) | |||
628 | COP_INT_DIS = -1; | 659 | COP_INT_DIS = -1; |
629 | 660 | ||
630 | /* Halt */ | 661 | /* Halt */ |
631 | PROC_CTL(CURRENT_CORE) = 0x40000000; | 662 | PROC_CTL(IF_COP_CORE(CPU)) = 0x40000000; |
632 | while (1); | 663 | while (1); |
633 | } | 664 | } |
634 | 665 | ||