summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/codecs.c2
-rw-r--r--apps/codecs.h5
-rw-r--r--apps/main.c14
-rw-r--r--apps/playback.c24
-rw-r--r--apps/playlist.c3
-rw-r--r--apps/plugin.c1
-rw-r--r--apps/plugin.h8
-rw-r--r--apps/plugins/alpine_cdc.c3
-rw-r--r--apps/plugins/battery_bench.c3
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c10
-rw-r--r--apps/tagcache.c3
-rw-r--r--docs/PLUGIN_API3
-rw-r--r--firmware/backlight.c3
-rw-r--r--firmware/common/dircache.c3
-rw-r--r--firmware/drivers/ata.c3
-rw-r--r--firmware/drivers/ata_mmc.c3
-rw-r--r--firmware/drivers/lcd-16bit.c3
-rw-r--r--firmware/drivers/lcd-1bit-vert.c3
-rw-r--r--firmware/drivers/lcd-2bit-horz.c3
-rw-r--r--firmware/drivers/lcd-2bit-vert.c3
-rw-r--r--firmware/drivers/lcd-player.c3
-rw-r--r--firmware/drivers/lcd-remote-1bit-v.c3
-rw-r--r--firmware/drivers/lcd-remote-2bit-vi.c3
-rw-r--r--firmware/export/config.h39
-rw-r--r--firmware/export/pp5002.h3
-rw-r--r--firmware/export/pp5020.h9
-rw-r--r--firmware/export/thread.h9
-rw-r--r--firmware/kernel.c67
-rw-r--r--firmware/mpeg.c3
-rw-r--r--firmware/pcm_record.c3
-rw-r--r--firmware/powermgmt.c3
-rw-r--r--firmware/system.c237
-rw-r--r--firmware/target/arm/crt0-pp.S17
-rw-r--r--firmware/target/arm/sandisk/sansa-e200/ata-e200.c3
-rw-r--r--firmware/thread.c78
-rw-r--r--firmware/usb.c3
-rw-r--r--uisimulator/common/stubs.c6
-rw-r--r--uisimulator/sdl/thread-sdl.c6
38 files changed, 383 insertions, 215 deletions
diff --git a/apps/codecs.c b/apps/codecs.c
index 0c6ddd0422..ccfa449d51 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -123,7 +123,7 @@ struct codec_api ci = {
123 &current_tick, 123 &current_tick,
124 default_event_handler, 124 default_event_handler,
125 default_event_handler_ex, 125 default_event_handler_ex,
126 create_thread_on_core, 126 create_thread,
127 remove_thread, 127 remove_thread,
128 reset_poweroff_timer, 128 reset_poweroff_timer,
129#ifndef SIMULATOR 129#ifndef SIMULATOR
diff --git a/apps/codecs.h b/apps/codecs.h
index 6710afdc8e..3c2b754dac 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -199,9 +199,10 @@ struct codec_api {
199 long* current_tick; 199 long* current_tick;
200 long (*default_event_handler)(long event); 200 long (*default_event_handler)(long event);
201 long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); 201 long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
202 struct thread_entry* (*create_thread)(unsigned int core, void (*function)(void), 202 struct thread_entry* (*create_thread)(void (*function)(void),
203 void* stack, int stack_size, const char *name 203 void* stack, int stack_size, const char *name
204 IF_PRIO(, int priority)); 204 IF_PRIO(, int priority)
205 IF_COP(, unsigned int core, bool fallback));
205 void (*remove_thread)(struct thread_entry *thread); 206 void (*remove_thread)(struct thread_entry *thread);
206 void (*reset_poweroff_timer)(void); 207 void (*reset_poweroff_timer)(void);
207#ifndef SIMULATOR 208#ifndef SIMULATOR
diff --git a/apps/main.c b/apps/main.c
index 6286b68ed1..e4d90bce61 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -297,6 +297,9 @@ static void init(void)
297 /* if nobody initialized ATA before, I consider this a cold start */ 297 /* if nobody initialized ATA before, I consider this a cold start */
298 bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */ 298 bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */
299#endif 299#endif
300#ifdef CPU_PP
301 COP_CTL = PROC_WAKE;
302#endif
300 system_init(); 303 system_init();
301 kernel_init(); 304 kernel_init();
302 305
@@ -549,19 +552,22 @@ void cop_main(void)
549 so it should not be assumed that the coprocessor be usable even on 552 so it should not be assumed that the coprocessor be usable even on
550 platforms which support it. 553 platforms which support it.
551 554
552 At present the COP sleeps unless it receives a message from the CPU telling 555 A kernel thread runs on the coprocessor which waits for other threads to be
553 it that we are loading a new kernel, so must reboot */ 556 added, and gracefully handles RoLo */
554 557
555#if CONFIG_CPU == PP5002 558#if CONFIG_CPU == PP5002
556/* 3G doesn't have Rolo support yet */ 559/* 3G doesn't have Rolo or dual core support yet */
557 while(1) { 560 while(1) {
558 COP_CTL = PROC_SLEEP; 561 COP_CTL = PROC_SLEEP;
559 } 562 }
560#else 563#else
561 extern volatile unsigned char cpu_message; 564 extern volatile unsigned char cpu_message;
562 565
566 system_init();
567 kernel_init();
568
563 while(cpu_message != COP_REBOOT) { 569 while(cpu_message != COP_REBOOT) {
564 COP_CTL = PROC_SLEEP; 570 sleep(HZ);
565 } 571 }
566 rolo_restart_cop(); 572 rolo_restart_cop();
567#endif /* PP5002 */ 573#endif /* PP5002 */
diff --git a/apps/playback.c b/apps/playback.c
index fe7a9f6ab1..89caec92aa 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -194,9 +194,9 @@ static bool audio_is_initialized = false;
194/* TBD: Split out "audio" and "playback" (ie. calling) threads */ 194/* TBD: Split out "audio" and "playback" (ie. calling) threads */
195 195
196/* Main state control */ 196/* Main state control */
197static volatile bool audio_codec_loaded; /* Is codec loaded? (C/A-) */ 197static volatile bool audio_codec_loaded NOCACHEBSS_ATTR;/* Codec loaded? (C/A-) */
198static volatile bool playing; /* Is audio playing? (A) */ 198static volatile bool playing NOCACHEBSS_ATTR; /* Is audio playing? (A) */
199static volatile bool paused; /* Is audio paused? (A/C-) */ 199static volatile bool paused NOCACHEBSS_ATTR; /* Is audio paused? (A/C-) */
200static volatile bool filling IDATA_ATTR; /* Is file buffer refilling? (A/C-) */ 200static volatile bool filling IDATA_ATTR; /* Is file buffer refilling? (A/C-) */
201 201
202/* Ring buffer where compressed audio and codecs are loaded */ 202/* Ring buffer where compressed audio and codecs are loaded */
@@ -290,7 +290,7 @@ static void audio_reset_buffer(size_t pcmbufsize);
290 290
291/* Codec thread */ 291/* Codec thread */
292extern struct codec_api ci; 292extern struct codec_api ci;
293static struct event_queue codec_queue; 293static struct event_queue codec_queue NOCACHEBSS_ATTR;
294static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 294static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
295IBSS_ATTR; 295IBSS_ATTR;
296static const char codec_thread_name[] = "codec"; 296static const char codec_thread_name[] = "codec";
@@ -304,7 +304,7 @@ static volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */
304extern struct codec_api ci_voice; 304extern struct codec_api ci_voice;
305 305
306static struct thread_entry *voice_thread_p = NULL; 306static struct thread_entry *voice_thread_p = NULL;
307static struct event_queue voice_queue; 307static struct event_queue voice_queue NOCACHEBSS_ATTR;
308static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 308static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
309IBSS_ATTR_VOICE_STACK; 309IBSS_ATTR_VOICE_STACK;
310static const char voice_thread_name[] = "voice codec"; 310static const char voice_thread_name[] = "voice codec";
@@ -324,12 +324,12 @@ static unsigned char *iram_buf[2] = { NULL, NULL };
324/* Pointer to DRAM buffers for normal/voice codecs */ 324/* Pointer to DRAM buffers for normal/voice codecs */
325static unsigned char *dram_buf[2] = { NULL, NULL }; 325static unsigned char *dram_buf[2] = { NULL, NULL };
326/* Mutex to control which codec (normal/voice) is running */ 326/* Mutex to control which codec (normal/voice) is running */
327static struct mutex mutex_codecthread; 327static struct mutex mutex_codecthread NOCACHEBSS_ATTR;
328 328
329/* Voice state */ 329/* Voice state */
330static volatile bool voice_thread_start; /* Triggers voice playback (A/V) */ 330static volatile bool voice_thread_start; /* Triggers voice playback (A/V) */
331static volatile bool voice_is_playing; /* Is voice currently playing? (V) */ 331static volatile bool voice_is_playing NOCACHEBSS_ATTR; /* Is voice currently playing? (V) */
332static volatile bool voice_codec_loaded; /* Is voice codec loaded (V/A-) */ 332static volatile bool voice_codec_loaded NOCACHEBSS_ATTR; /* Is voice codec loaded (V/A-) */
333static char *voicebuf; 333static char *voicebuf;
334static size_t voice_remaining; 334static size_t voice_remaining;
335 335
@@ -863,7 +863,8 @@ void audio_preinit(void)
863 queue_init(&codec_queue, true); 863 queue_init(&codec_queue, true);
864 864
865 create_thread(audio_thread, audio_stack, sizeof(audio_stack), 865 create_thread(audio_thread, audio_stack, sizeof(audio_stack),
866 audio_thread_name IF_PRIO(, PRIORITY_BUFFERING)); 866 audio_thread_name IF_PRIO(, PRIORITY_BUFFERING)
867 IF_COP(, CPU, false));
867} 868}
868 869
869void audio_init(void) 870void audio_init(void)
@@ -888,7 +889,7 @@ void voice_init(void)
888 queue_init(&voice_queue, true); 889 queue_init(&voice_queue, true);
889 voice_thread_p = create_thread(voice_thread, voice_stack, 890 voice_thread_p = create_thread(voice_thread, voice_stack,
890 sizeof(voice_stack), voice_thread_name 891 sizeof(voice_stack), voice_thread_name
891 IF_PRIO(, PRIORITY_PLAYBACK)); 892 IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU, false));
892 893
893 while (!voice_codec_loaded) 894 while (!voice_codec_loaded)
894 yield(); 895 yield();
@@ -3533,7 +3534,8 @@ static void audio_playback_init(void)
3533 3534
3534 codec_thread_p = create_thread( 3535 codec_thread_p = create_thread(
3535 codec_thread, codec_stack, sizeof(codec_stack), 3536 codec_thread, codec_stack, sizeof(codec_stack),
3536 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)); 3537 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
3538 IF_COP(, COP, true));
3537 3539
3538 while (1) 3540 while (1)
3539 { 3541 {
diff --git a/apps/playlist.c b/apps/playlist.c
index 6997b12675..0358b6adc4 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -1873,7 +1873,8 @@ void playlist_init(void)
1873 memset(playlist->filenames, 0, 1873 memset(playlist->filenames, 0,
1874 playlist->max_playlist_size * sizeof(int)); 1874 playlist->max_playlist_size * sizeof(int));
1875 create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), 1875 create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack),
1876 playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND)); 1876 playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
1877 IF_COP(, CPU, false));
1877 queue_init(&playlist_queue, true); 1878 queue_init(&playlist_queue, true);
1878#endif 1879#endif
1879} 1880}
diff --git a/apps/plugin.c b/apps/plugin.c
index 5bbff96b04..230b62b819 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -481,7 +481,6 @@ static const struct plugin_api rockbox_api = {
481 sound_default, 481 sound_default,
482 pcm_record_more, 482 pcm_record_more,
483#endif 483#endif
484 create_thread_on_core,
485 484
486#ifdef IRIVER_H100_SERIES 485#ifdef IRIVER_H100_SERIES
487 /* Routines for the iriver_flash -plugin. */ 486 /* Routines for the iriver_flash -plugin. */
diff --git a/apps/plugin.h b/apps/plugin.h
index 48e9c40196..1d161783a1 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -327,7 +327,8 @@ struct plugin_api {
327 long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); 327 long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
328 struct thread_entry* (*create_thread)(void (*function)(void), void* stack, 328 struct thread_entry* (*create_thread)(void (*function)(void), void* stack,
329 int stack_size, const char *name 329 int stack_size, const char *name
330 IF_PRIO(, int priority)); 330 IF_PRIO(, int priority)
331 IF_COP(, unsigned int core, bool fallback));
331 void (*remove_thread)(struct thread_entry *thread); 332 void (*remove_thread)(struct thread_entry *thread);
332 void (*reset_poweroff_timer)(void); 333 void (*reset_poweroff_timer)(void);
333#ifndef SIMULATOR 334#ifndef SIMULATOR
@@ -595,11 +596,6 @@ struct plugin_api {
595 void (*pcm_record_more)(void *start, size_t size); 596 void (*pcm_record_more)(void *start, size_t size);
596#endif 597#endif
597 598
598 struct thread_entry*(*create_thread_on_core)(
599 unsigned int core, void (*function)(void),
600 void* stack, int stack_size,
601 const char *name IF_PRIO(, int priority));
602
603#ifdef IRIVER_H100_SERIES 599#ifdef IRIVER_H100_SERIES
604 /* Routines for the iriver_flash -plugin. */ 600 /* Routines for the iriver_flash -plugin. */
605 bool (*detect_original_firmware)(void); 601 bool (*detect_original_firmware)(void);
diff --git a/apps/plugins/alpine_cdc.c b/apps/plugins/alpine_cdc.c
index 9c1bc8bd0b..9cc1f9cde4 100644
--- a/apps/plugins/alpine_cdc.c
+++ b/apps/plugins/alpine_cdc.c
@@ -1171,7 +1171,8 @@ int main(void* parameter)
1171 rb->memset(&gTread, 0, sizeof(gTread)); 1171 rb->memset(&gTread, 0, sizeof(gTread));
1172 gTread.foreground = true; 1172 gTread.foreground = true;
1173 rb->create_thread(thread, stack, stacksize, "CDC" 1173 rb->create_thread(thread, stack, stacksize, "CDC"
1174 IF_PRIO(, PRIORITY_BACKGROUND)); 1174 IF_PRIO(, PRIORITY_BACKGROUND)
1175 IF_COP(, CPU, false));
1175 1176
1176#ifdef DEBUG 1177#ifdef DEBUG
1177 do 1178 do
diff --git a/apps/plugins/battery_bench.c b/apps/plugins/battery_bench.c
index fff3c2fa57..6e3178237f 100644
--- a/apps/plugins/battery_bench.c
+++ b/apps/plugins/battery_bench.c
@@ -479,7 +479,8 @@ int main(void)
479 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */ 479 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
480 if(rb->create_thread(thread, thread_stack, 480 if(rb->create_thread(thread, thread_stack,
481 sizeof(thread_stack), "Battery Benchmark" 481 sizeof(thread_stack), "Battery Benchmark"
482 IF_PRIO(, PRIORITY_BACKGROUND)) == NULL) 482 IF_PRIO(, PRIORITY_BACKGROUND)
483 IF_COP(, CPU, false)) == NULL)
483 { 484 {
484 rb->splash(HZ,true,"Cannot create thread!"); 485 rb->splash(HZ,true,"Cannot create thread!");
485 return PLUGIN_ERROR; 486 return PLUGIN_ERROR;
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index 36f54dc224..684a491872 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -909,19 +909,17 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
909 videostatus = STREAM_PLAYING; 909 videostatus = STREAM_PLAYING;
910 910
911 /* We put the video thread on the second processor for multi-core targets. */ 911 /* We put the video thread on the second processor for multi-core targets. */
912#if NUM_CORES > 1
913 if ((videothread_id = rb->create_thread_on_core(COP,decode_mpeg2,
914#else
915 if ((videothread_id = rb->create_thread(decode_mpeg2, 912 if ((videothread_id = rb->create_thread(decode_mpeg2,
916#endif 913 (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK)
917 (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK))) == NULL) 914 IF_COP(, COP, true))) == NULL)
918 { 915 {
919 rb->splash(HZ,true,"Cannot create video thread!"); 916 rb->splash(HZ,true,"Cannot create video thread!");
920 return PLUGIN_ERROR; 917 return PLUGIN_ERROR;
921 } 918 }
922 919
923 if ((audiothread_id = rb->create_thread(mad_decode, 920 if ((audiothread_id = rb->create_thread(mad_decode,
924 (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK))) == NULL) 921 (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK)
922 IF_COP(, CPU, false))) == NULL)
925 { 923 {
926 rb->splash(HZ,true,"Cannot create audio thread!"); 924 rb->splash(HZ,true,"Cannot create audio thread!");
927 rb->remove_thread(videothread_id); 925 rb->remove_thread(videothread_id);
diff --git a/apps/tagcache.c b/apps/tagcache.c
index a6a0168353..6b891f1011 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -3941,7 +3941,8 @@ void tagcache_init(void)
3941 queue_init(&tagcache_queue, true); 3941 queue_init(&tagcache_queue, true);
3942 create_thread(tagcache_thread, tagcache_stack, 3942 create_thread(tagcache_thread, tagcache_stack,
3943 sizeof(tagcache_stack), tagcache_thread_name 3943 sizeof(tagcache_stack), tagcache_thread_name
3944 IF_PRIO(, PRIORITY_BACKGROUND)); 3944 IF_PRIO(, PRIORITY_BACKGROUND)
3945 IF_COP(, CPU, false));
3945#else 3946#else
3946 tc_stat.initialized = true; 3947 tc_stat.initialized = true;
3947 allocate_tempbuf(); 3948 allocate_tempbuf();
diff --git a/docs/PLUGIN_API b/docs/PLUGIN_API
index e24d70fece..feba0868fb 100644
--- a/docs/PLUGIN_API
+++ b/docs/PLUGIN_API
@@ -431,7 +431,8 @@ Kernel
431 SYS_USB_CONNECTED. Else do nothing and return 0. 431 SYS_USB_CONNECTED. Else do nothing and return 0.
432 432
433 int create_thread(void* function, void* stack, int stack_size, 433 int create_thread(void* function, void* stack, int stack_size,
434 const char *name); 434 const char *name IF_PRIO(int priority)
435 IF_COP(, unsigned int core, bool fallback));
435 436
436 Create a thread. 437 Create a thread.
437 ??? (see firmware/thread.c:145) 438 ??? (see firmware/thread.c:145)
diff --git a/firmware/backlight.c b/firmware/backlight.c
index a273b94a38..1e8dd46b2d 100644
--- a/firmware/backlight.c
+++ b/firmware/backlight.c
@@ -582,7 +582,8 @@ void backlight_init(void)
582 582
583 create_thread(backlight_thread, backlight_stack, 583 create_thread(backlight_thread, backlight_stack,
584 sizeof(backlight_stack), backlight_thread_name 584 sizeof(backlight_stack), backlight_thread_name
585 IF_PRIO(, PRIORITY_SYSTEM)); 585 IF_PRIO(, PRIORITY_SYSTEM)
586 IF_COP(, CPU, false));
586 tick_add_task(backlight_tick); 587 tick_add_task(backlight_tick);
587} 588}
588 589
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c
index fd9796c0d8..f78fa2d0cf 100644
--- a/firmware/common/dircache.c
+++ b/firmware/common/dircache.c
@@ -701,7 +701,8 @@ void dircache_init(void)
701 701
702 queue_init(&dircache_queue, true); 702 queue_init(&dircache_queue, true);
703 create_thread(dircache_thread, dircache_stack, 703 create_thread(dircache_thread, dircache_stack,
704 sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND)); 704 sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
705 IF_COP(, CPU, false));
705} 706}
706 707
707/** 708/**
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 21376ab9a7..76c0090a12 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -991,7 +991,8 @@ int ata_init(void)
991 last_disk_activity = current_tick; 991 last_disk_activity = current_tick;
992 create_thread(ata_thread, ata_stack, 992 create_thread(ata_thread, ata_stack,
993 sizeof(ata_stack), ata_thread_name 993 sizeof(ata_stack), ata_thread_name
994 IF_PRIO(, PRIORITY_SYSTEM)); 994 IF_PRIO(, PRIORITY_SYSTEM)
995 IF_COP(, CPU, false));
995 initialized = true; 996 initialized = true;
996 997
997 } 998 }
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c
index a549624b2c..377d2444bf 100644
--- a/firmware/drivers/ata_mmc.c
+++ b/firmware/drivers/ata_mmc.c
@@ -1173,7 +1173,8 @@ int ata_init(void)
1173 1173
1174 queue_init(&mmc_queue, true); 1174 queue_init(&mmc_queue, true);
1175 create_thread(mmc_thread, mmc_stack, 1175 create_thread(mmc_thread, mmc_stack,
1176 sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM)); 1176 sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM)
1177 IF_COP(, CPU, false));
1177 tick_add_task(mmc_tick); 1178 tick_add_task(mmc_tick);
1178 initialized = true; 1179 initialized = true;
1179 } 1180 }
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index d545bf3fe4..7269e54dcd 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -89,7 +89,8 @@ void lcd_init(void)
89 89
90 create_thread(scroll_thread, scroll_stack, 90 create_thread(scroll_thread, scroll_stack,
91 sizeof(scroll_stack), scroll_name 91 sizeof(scroll_stack), scroll_name
92 IF_PRIO(, PRIORITY_USER_INTERFACE)); 92 IF_PRIO(, PRIORITY_USER_INTERFACE)
93 IF_COP(, CPU, false));
93} 94}
94 95
95/*** parameter handling ***/ 96/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-1bit-vert.c b/firmware/drivers/lcd-1bit-vert.c
index 62dfab0180..64c1ace292 100644
--- a/firmware/drivers/lcd-1bit-vert.c
+++ b/firmware/drivers/lcd-1bit-vert.c
@@ -68,7 +68,8 @@ void lcd_init(void)
68 /* Call device specific init */ 68 /* Call device specific init */
69 lcd_init_device(); 69 lcd_init_device();
70 create_thread(scroll_thread, scroll_stack, 70 create_thread(scroll_thread, scroll_stack,
71 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); 71 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
72 IF_COP(, CPU, false));
72} 73}
73 74
74/*** parameter handling ***/ 75/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c
index 9ba52e1ba9..475e466c42 100644
--- a/firmware/drivers/lcd-2bit-horz.c
+++ b/firmware/drivers/lcd-2bit-horz.c
@@ -79,7 +79,8 @@ void lcd_init(void)
79 /* Call device specific init */ 79 /* Call device specific init */
80 lcd_init_device(); 80 lcd_init_device();
81 create_thread(scroll_thread, scroll_stack, 81 create_thread(scroll_thread, scroll_stack,
82 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); 82 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
83 IF_COP(, CPU, false));
83} 84}
84 85
85/*** parameter handling ***/ 86/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-2bit-vert.c b/firmware/drivers/lcd-2bit-vert.c
index 7b3352b9d6..7a49f35312 100644
--- a/firmware/drivers/lcd-2bit-vert.c
+++ b/firmware/drivers/lcd-2bit-vert.c
@@ -82,7 +82,8 @@ void lcd_init(void)
82 /* Call device specific init */ 82 /* Call device specific init */
83 lcd_init_device(); 83 lcd_init_device();
84 create_thread(scroll_thread, scroll_stack, 84 create_thread(scroll_thread, scroll_stack,
85 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); 85 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
86 IF_COP(, CPU, false));
86} 87}
87 88
88/*** parameter handling ***/ 89/*** parameter handling ***/
diff --git a/firmware/drivers/lcd-player.c b/firmware/drivers/lcd-player.c
index 8ca81473fc..c863c9f188 100644
--- a/firmware/drivers/lcd-player.c
+++ b/firmware/drivers/lcd-player.c
@@ -610,7 +610,8 @@ void lcd_init (void)
610 lcd_set_contrast(lcd_default_contrast()); 610 lcd_set_contrast(lcd_default_contrast());
611 611
612 create_thread(scroll_thread, scroll_stack, 612 create_thread(scroll_thread, scroll_stack,
613 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); 613 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
614 IF_COP(, CPU, false));
614} 615}
615 616
616void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */ 617void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
diff --git a/firmware/drivers/lcd-remote-1bit-v.c b/firmware/drivers/lcd-remote-1bit-v.c
index c81ccc83c9..0aa3d890f7 100644
--- a/firmware/drivers/lcd-remote-1bit-v.c
+++ b/firmware/drivers/lcd-remote-1bit-v.c
@@ -903,5 +903,6 @@ void lcd_remote_init(void)
903 queue_init(&remote_scroll_queue, false); 903 queue_init(&remote_scroll_queue, false);
904#endif 904#endif
905 create_thread(scroll_thread, scroll_stack, 905 create_thread(scroll_thread, scroll_stack,
906 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); 906 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
907 IF_COP(, CPU, false));
907} 908}
diff --git a/firmware/drivers/lcd-remote-2bit-vi.c b/firmware/drivers/lcd-remote-2bit-vi.c
index 281cbc2189..e0f6b35004 100644
--- a/firmware/drivers/lcd-remote-2bit-vi.c
+++ b/firmware/drivers/lcd-remote-2bit-vi.c
@@ -1241,5 +1241,6 @@ void lcd_remote_init(void)
1241 queue_init(&remote_scroll_queue, false); 1241 queue_init(&remote_scroll_queue, false);
1242#endif 1242#endif
1243 create_thread(scroll_thread, scroll_stack, 1243 create_thread(scroll_thread, scroll_stack,
1244 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); 1244 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
1245 IF_COP(, CPU, false));
1245} 1246}
diff --git a/firmware/export/config.h b/firmware/export/config.h
index d848d16155..13fb77661d 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -273,21 +273,6 @@
273/* define for all cpus from PP family */ 273/* define for all cpus from PP family */
274#if (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020) || (CONFIG_CPU == PP5024) 274#if (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020) || (CONFIG_CPU == PP5024)
275#define CPU_PP 275#define CPU_PP
276
277/* PP family has dual cores */
278#if 0
279/* Keep it as single core until dual core support is ready */
280#define NUM_CORES 2
281#define CURRENT_CORE current_core()
282#endif
283
284#define NUM_CORES 1
285#define CURRENT_CORE 0
286
287#define COP_REBOOT 0x00000001
288#else
289#define NUM_CORES 1
290#define CURRENT_CORE 0
291#endif 276#endif
292 277
293/* define for all cpus from ARM family */ 278/* define for all cpus from ARM family */
@@ -348,4 +333,28 @@
348#define IRAM_LCDFRAMEBUFFER 333#define IRAM_LCDFRAMEBUFFER
349#endif 334#endif
350 335
336/* Dual core support - not yet working on the 3G iPod */
337#if defined(CPU_PP) && CONFIG_CPU != PP5002
338#define NUM_CORES 2
339#define CURRENT_CORE current_core()
340/* Hopefully at some point we will learn how to mark areas of main memory as
341 * not to be cached. Until then, use IRAM for variables shared across cores */
342#define NOCACHEBSS_ATTR IBSS_ATTR
343#define NOCACHEDATA_ATTR IDATA_ATTR
344
345#define IF_COP(empty, x, y) , x, y
346
347/* Defines for inter-core messaging */
348#define COP_REBOOT 1
349
350#else
351#define NUM_CORES 1
352#define CURRENT_CORE CPU
353#define NOCACHEBSS_ATTR
354#define NOCACHEDATA_ATTR
355
356#define IF_COP(empty, x, y)
357
358#endif /* Processor specific */
359
351#endif 360#endif
diff --git a/firmware/export/pp5002.h b/firmware/export/pp5002.h
index ef131fe6d6..9636313390 100644
--- a/firmware/export/pp5002.h
+++ b/firmware/export/pp5002.h
@@ -73,6 +73,9 @@
73#define CPU_INT_STAT (*(volatile unsigned long*)(0xcf001000)) 73#define CPU_INT_STAT (*(volatile unsigned long*)(0xcf001000))
74#define CPU_INT_EN (*(volatile unsigned long*)(0xcf001024)) 74#define CPU_INT_EN (*(volatile unsigned long*)(0xcf001024))
75#define CPU_INT_CLR (*(volatile unsigned long*)(0xcf001028)) 75#define CPU_INT_CLR (*(volatile unsigned long*)(0xcf001028))
76#define COP_INT_STAT (*(volatile unsigned long*)(0xcf001010)) /* A guess */
77#define COP_INT_EN (*(volatile unsigned long*)(0xcf001034))
78#define COP_INT_CLR (*(volatile unsigned long*)(0xcf001038))
76 79
77#define USB2D_IDENT (*(volatile unsigned long*)(0xc5000000)) 80#define USB2D_IDENT (*(volatile unsigned long*)(0xc5000000))
78#define USB_STATUS (*(volatile unsigned long*)(0xc50001a4)) 81#define USB_STATUS (*(volatile unsigned long*)(0xc50001a4))
diff --git a/firmware/export/pp5020.h b/firmware/export/pp5020.h
index 3d205a0ea1..a34f1251c9 100644
--- a/firmware/export/pp5020.h
+++ b/firmware/export/pp5020.h
@@ -30,6 +30,15 @@
30#define PROC_ID_CPU 0x55 30#define PROC_ID_CPU 0x55
31#define PROC_ID_COP 0xaa 31#define PROC_ID_COP 0xaa
32 32
33/* Mailboxes */
34/* Each processor has two mailboxes it can write to and two which
35 it can read from. We define the first to be for sending messages
36 and the second for replying to messages */
37#define CPU_MESSAGE (*(volatile unsigned long *)(0x60001000))
38#define COP_MESSAGE (*(volatile unsigned long *)(0x60001004))
39#define CPU_REPLY (*(volatile unsigned long *)(0x60001008))
40#define COP_REPLY (*(volatile unsigned long *)(0x6000100c))
41
33/* Interrupts */ 42/* Interrupts */
34#define CPU_INT_STAT (*(volatile unsigned long*)(0x64004000)) 43#define CPU_INT_STAT (*(volatile unsigned long*)(0x64004000))
35#define COP_INT_STAT (*(volatile unsigned long*)(0x60004004)) 44#define COP_INT_STAT (*(volatile unsigned long*)(0x60004004))
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index bced98ea23..2ff4694159 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -124,13 +124,8 @@ struct core_entry {
124 124
125struct thread_entry* 125struct thread_entry*
126 create_thread(void (*function)(void), void* stack, int stack_size, 126 create_thread(void (*function)(void), void* stack, int stack_size,
127 const char *name IF_PRIO(, int priority)); 127 const char *name IF_PRIO(, int priority)
128 128 IF_COP(, unsigned int core, bool fallback));
129struct thread_entry*
130 create_thread_on_core(unsigned int core, void (*function)(void),
131 void* stack, int stack_size,
132 const char *name
133 IF_PRIO(, int priority));
134 129
135#ifdef HAVE_SCHEDULER_BOOSTCTRL 130#ifdef HAVE_SCHEDULER_BOOSTCTRL
136void trigger_cpu_boost(void); 131void trigger_cpu_boost(void);
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 75c6604682..313530ffba 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -26,7 +26,7 @@
26#include "panic.h" 26#include "panic.h"
27 27
28#if !defined(CPU_PP) || !defined(BOOTLOADER) 28#if !defined(CPU_PP) || !defined(BOOTLOADER)
29long current_tick = 0; 29long current_tick NOCACHEDATA_ATTR = 0;
30#endif 30#endif
31 31
32static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); 32static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
@@ -45,10 +45,13 @@ void kernel_init(void)
45 /* Init the threading API */ 45 /* Init the threading API */
46 init_threads(); 46 init_threads();
47 47
48 memset(tick_funcs, 0, sizeof(tick_funcs)); 48 if(CURRENT_CORE == CPU)
49 {
50 memset(tick_funcs, 0, sizeof(tick_funcs));
49 51
50 num_queues = 0; 52 num_queues = 0;
51 memset(all_queues, 0, sizeof(all_queues)); 53 memset(all_queues, 0, sizeof(all_queues));
54 }
52 55
53 tick_start(1000/HZ); 56 tick_start(1000/HZ);
54} 57}
@@ -496,28 +499,36 @@ void TIMER1(void)
496 int i; 499 int i;
497 500
498 TIMER1_VAL; /* Read value to ack IRQ */ 501 TIMER1_VAL; /* Read value to ack IRQ */
499 /* Run through the list of tick tasks */ 502 /* Run through the list of tick tasks (using main core) */
500 for (i = 0;i < MAX_NUM_TICK_TASKS;i++) 503 if (CURRENT_CORE == CPU)
501 { 504 {
502 if (tick_funcs[i]) 505 for (i = 0;i < MAX_NUM_TICK_TASKS;i++)
503 { 506 {
504 tick_funcs[i](); 507 if (tick_funcs[i])
508 {
509 tick_funcs[i]();
510 }
505 } 511 }
506 }
507 512
508 current_tick++; 513 current_tick++;
514 }
509} 515}
510#endif 516#endif
511 517
512void tick_start(unsigned int interval_in_ms) 518void tick_start(unsigned int interval_in_ms)
513{ 519{
514#ifndef BOOTLOADER 520#ifndef BOOTLOADER
515 TIMER1_CFG = 0x0; 521 if(CURRENT_CORE == CPU)
516 TIMER1_VAL; 522 {
517 /* enable timer */ 523 TIMER1_CFG = 0x0;
518 TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1); 524 TIMER1_VAL;
519 /* unmask interrupt source */ 525 /* enable timer */
520 CPU_INT_EN = TIMER1_MASK; 526 TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1);
527 /* unmask interrupt source */
528 CPU_INT_EN = TIMER1_MASK;
529 } else {
530 COP_INT_EN = TIMER1_MASK;
531 }
521#else 532#else
522 /* We don't enable interrupts in the bootloader */ 533 /* We don't enable interrupts in the bootloader */
523 (void)interval_in_ms; 534 (void)interval_in_ms;
@@ -645,6 +656,29 @@ void mutex_init(struct mutex *m)
645 m->thread = NULL; 656 m->thread = NULL;
646} 657}
647 658
659#ifdef CPU_PP
660/* PortalPlayer chips have 2 cores, therefore need atomic mutexes */
661
662static inline bool test_and_set(bool *x, bool v)
663{
664 asm volatile (
665 "swpb %0, %0, [%1]\n"
666 : "+r"(v)
667 : "r"(x)
668 );
669 return v;
670}
671
672void mutex_lock(struct mutex *m)
673{
674 if (test_and_set(&m->locked,true))
675 {
676 /* Wait until the lock is open... */
677 block_thread(&m->thread);
678 }
679}
680
681#else
648void mutex_lock(struct mutex *m) 682void mutex_lock(struct mutex *m)
649{ 683{
650 if (m->locked) 684 if (m->locked)
@@ -656,6 +690,7 @@ void mutex_lock(struct mutex *m)
656 /* ...and lock it */ 690 /* ...and lock it */
657 m->locked = true; 691 m->locked = true;
658} 692}
693#endif
659 694
660void mutex_unlock(struct mutex *m) 695void mutex_unlock(struct mutex *m)
661{ 696{
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index 9afa8a20bd..909a21dcda 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -2905,7 +2905,8 @@ void audio_init(void)
2905 queue_init(&mpeg_queue, true); 2905 queue_init(&mpeg_queue, true);
2906#endif /* !SIMULATOR */ 2906#endif /* !SIMULATOR */
2907 create_thread(mpeg_thread, mpeg_stack, 2907 create_thread(mpeg_thread, mpeg_stack,
2908 sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM)); 2908 sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM)
2909 IF_COP(, CPU, false));
2909 2910
2910 memset(trackdata, sizeof(trackdata), 0); 2911 memset(trackdata, sizeof(trackdata), 0);
2911 2912
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c
index 270bb354d2..3f4abc7be3 100644
--- a/firmware/pcm_record.c
+++ b/firmware/pcm_record.c
@@ -418,7 +418,8 @@ void pcm_rec_init(void)
418 queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send); 418 queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send);
419 pcmrec_thread_p = 419 pcmrec_thread_p =
420 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), 420 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack),
421 pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)); 421 pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)
422 IF_COP(, CPU, false));
422} /* pcm_rec_init */ 423} /* pcm_rec_init */
423 424
424/** audio_* group **/ 425/** audio_* group **/
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index c2f9ca0bca..1492c80bc4 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -1245,7 +1245,8 @@ void powermgmt_init(void)
1245 /* init history to 0 */ 1245 /* init history to 0 */
1246 memset(power_history, 0x00, sizeof(power_history)); 1246 memset(power_history, 0x00, sizeof(power_history));
1247 create_thread(power_thread, power_stack, sizeof(power_stack), 1247 create_thread(power_thread, power_stack, sizeof(power_stack),
1248 power_thread_name IF_PRIO(, PRIORITY_SYSTEM)); 1248 power_thread_name IF_PRIO(, PRIORITY_SYSTEM)
1249 IF_COP(, CPU, false));
1249} 1250}
1250 1251
1251#endif /* SIMULATOR */ 1252#endif /* SIMULATOR */
diff --git a/firmware/system.c b/firmware/system.c
index a86d945093..a9c9d9e350 100644
--- a/firmware/system.c
+++ b/firmware/system.c
@@ -612,12 +612,22 @@ extern void ipod_mini_button_int(void);
612 612
613void irq(void) 613void irq(void)
614{ 614{
615 if (CPU_INT_STAT & TIMER1_MASK) 615 if(CURRENT_CORE == CPU)
616 TIMER1(); 616 {
617 else if (CPU_INT_STAT & TIMER2_MASK) 617 if (CPU_INT_STAT & TIMER1_MASK)
618 TIMER2(); 618 TIMER1();
619 else if (CPU_HI_INT_STAT & GPIO_MASK) 619 else if (CPU_INT_STAT & TIMER2_MASK)
620 ipod_mini_button_int(); 620 TIMER2();
621 else if (CPU_HI_INT_STAT & GPIO_MASK)
622 ipod_mini_button_int();
623 } else {
624 if (COP_INT_STAT & TIMER1_MASK)
625 TIMER1();
626 else if (COP_INT_STAT & TIMER2_MASK)
627 TIMER2();
628 else if (COP_HI_INT_STAT & GPIO_MASK)
629 ipod_mini_button_int();
630 }
621} 631}
622#elif (defined IRIVER_H10) || (defined IRIVER_H10_5GB) || defined(ELIO_TPJ1022) \ 632#elif (defined IRIVER_H10) || (defined IRIVER_H10_5GB) || defined(ELIO_TPJ1022) \
623 || (defined SANSA_E200) 633 || (defined SANSA_E200)
@@ -626,22 +636,40 @@ void irq(void)
626/* TODO: Even if it isn't in the target tree, this should be the default case */ 636/* TODO: Even if it isn't in the target tree, this should be the default case */
627void irq(void) 637void irq(void)
628{ 638{
629 if (CPU_INT_STAT & TIMER1_MASK) 639 if(CURRENT_CORE == CPU)
630 TIMER1(); 640 {
631 else if (CPU_INT_STAT & TIMER2_MASK) 641 if (CPU_INT_STAT & TIMER1_MASK)
632 TIMER2(); 642 TIMER1();
643 else if (CPU_INT_STAT & TIMER2_MASK)
644 TIMER2();
645 } else {
646 if (COP_INT_STAT & TIMER1_MASK)
647 TIMER1();
648 else if (COP_INT_STAT & TIMER2_MASK)
649 TIMER2();
650 }
633} 651}
634#else 652#else
635extern void ipod_4g_button_int(void); 653extern void ipod_4g_button_int(void);
636 654
637void irq(void) 655void irq(void)
638{ 656{
639 if (CPU_INT_STAT & TIMER1_MASK) 657 if(CURRENT_CORE == CPU)
640 TIMER1(); 658 {
641 else if (CPU_INT_STAT & TIMER2_MASK) 659 if (CPU_INT_STAT & TIMER1_MASK)
642 TIMER2(); 660 TIMER1();
643 else if (CPU_HI_INT_STAT & I2C_MASK) 661 else if (CPU_INT_STAT & TIMER2_MASK)
644 ipod_4g_button_int(); 662 TIMER2();
663 else if (CPU_HI_INT_STAT & I2C_MASK)
664 ipod_4g_button_int();
665 } else {
666 if (COP_INT_STAT & TIMER1_MASK)
667 TIMER1();
668 else if (COP_INT_STAT & TIMER2_MASK)
669 TIMER2();
670 else if (COP_HI_INT_STAT & I2C_MASK)
671 ipod_4g_button_int();
672 }
645} 673}
646#endif 674#endif
647#endif /* BOOTLOADER */ 675#endif /* BOOTLOADER */
@@ -694,43 +722,47 @@ void set_cpu_frequency(long frequency)
694{ 722{
695 unsigned long postmult; 723 unsigned long postmult;
696 724
697 if (frequency == CPUFREQ_NORMAL) 725 if (CURRENT_CORE == CPU)
698 postmult = CPUFREQ_NORMAL_MULT; 726 {
699 else if (frequency == CPUFREQ_MAX) 727 if (frequency == CPUFREQ_NORMAL)
700 postmult = CPUFREQ_MAX_MULT; 728 postmult = CPUFREQ_NORMAL_MULT;
701 else 729 else if (frequency == CPUFREQ_MAX)
702 postmult = CPUFREQ_DEFAULT_MULT; 730 postmult = CPUFREQ_MAX_MULT;
703 cpu_frequency = frequency; 731 else
732 postmult = CPUFREQ_DEFAULT_MULT;
733 cpu_frequency = frequency;
704 734
705 /* Enable PLL? */ 735 /* Enable PLL? */
706 outl(inl(0x70000020) | (1<<30), 0x70000020); 736 outl(inl(0x70000020) | (1<<30), 0x70000020);
707 737
708 /* Select 24MHz crystal as clock source? */ 738 /* Select 24MHz crystal as clock source? */
709 outl((inl(0x60006020) & 0x0fffff0f) | 0x20000020, 0x60006020); 739 outl((inl(0x60006020) & 0x0fffff0f) | 0x20000020, 0x60006020);
710 740
711 /* Clock frequency = (24/8)*postmult */ 741 /* Clock frequency = (24/8)*postmult */
712 outl(0xaa020000 | 8 | (postmult << 8), 0x60006034); 742 outl(0xaa020000 | 8 | (postmult << 8), 0x60006034);
713 743
714 /* Wait for PLL relock? */ 744 /* Wait for PLL relock? */
715 udelay(2000); 745 udelay(2000);
716 746
717 /* Select PLL as clock source? */ 747 /* Select PLL as clock source? */
718 outl((inl(0x60006020) & 0x0fffff0f) | 0x20000070, 0x60006020); 748 outl((inl(0x60006020) & 0x0fffff0f) | 0x20000070, 0x60006020);
719 749
720#if defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IRIVER_H10) || defined(IRIVER_H10_5GB) 750#if defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
721 /* We don't know why the timer interrupt gets disabled on the PP5020 751 /* We don't know why the timer interrupt gets disabled on the PP5020
722 based ipods, but without the following line, the 4Gs will freeze 752 based ipods, but without the following line, the 4Gs will freeze
723 when CPU frequency changing is enabled. 753 when CPU frequency changing is enabled.
724 754
725 Note also that a simple "CPU_INT_EN = TIMER1_MASK;" (as used 755 Note also that a simple "CPU_INT_EN = TIMER1_MASK;" (as used
726 elsewhere to enable interrupts) doesn't work, we need "|=". 756 elsewhere to enable interrupts) doesn't work, we need "|=".
727 757
728 It's not needed on the PP5021 and PP5022 ipods. 758 It's not needed on the PP5021 and PP5022 ipods.
729 */ 759 */
730 760
731 /* unmask interrupt source */ 761 /* unmask interrupt source */
732 CPU_INT_EN |= TIMER1_MASK; 762 CPU_INT_EN |= TIMER1_MASK;
763 COP_INT_EN |= TIMER1_MASK;
733#endif 764#endif
765 }
734} 766}
735#elif !defined(BOOTLOADER) 767#elif !defined(BOOTLOADER)
736void ipod_set_cpu_frequency(void) 768void ipod_set_cpu_frequency(void)
@@ -754,24 +786,33 @@ void ipod_set_cpu_frequency(void)
754void system_init(void) 786void system_init(void)
755{ 787{
756#ifndef BOOTLOADER 788#ifndef BOOTLOADER
757 /* Remap the flash ROM from 0x00000000 to 0x20000000. */ 789 if (CURRENT_CORE == CPU)
758 MMAP3_LOGICAL = 0x20000000 | 0x3a00; 790 {
759 MMAP3_PHYSICAL = 0x00000000 | 0x3f84; 791 /* Remap the flash ROM from 0x00000000 to 0x20000000. */
760 792 MMAP3_LOGICAL = 0x20000000 | 0x3a00;
761 /* The hw revision is written to the last 4 bytes of SDRAM by the 793 MMAP3_PHYSICAL = 0x00000000 | 0x3f84;
762 bootloader - we save it before Rockbox overwrites it. */ 794
763 ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc))); 795 /* The hw revision is written to the last 4 bytes of SDRAM by the
764 796 bootloader - we save it before Rockbox overwrites it. */
765 /* disable all irqs */ 797 ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc)));
766 outl(-1, 0x60001138); 798
767 outl(-1, 0x60001128); 799 /* disable all irqs */
768 outl(-1, 0x6000111c); 800 outl(-1, 0x60001138);
769 801 outl(-1, 0x60001128);
770 outl(-1, 0x60001038); 802 outl(-1, 0x6000111c);
771 outl(-1, 0x60001028); 803
772 outl(-1, 0x6000101c); 804 outl(-1, 0x60001038);
773#ifndef HAVE_ADJUSTABLE_CPU_FREQ 805 outl(-1, 0x60001028);
774 ipod_set_cpu_frequency(); 806 outl(-1, 0x6000101c);
807#if (!defined HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES == 1)
808 ipod_set_cpu_frequency();
809#endif
810 }
811#if (!defined HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1)
812 else
813 {
814 ipod_set_cpu_frequency();
815 }
775#endif 816#endif
776 ipod_init_cache(); 817 ipod_init_cache();
777#endif 818#endif
@@ -796,10 +837,18 @@ extern void TIMER2(void);
796 837
797void irq(void) 838void irq(void)
798{ 839{
799 if (CPU_INT_STAT & TIMER1_MASK) 840 if(CURRENT_CORE == CPU)
800 TIMER1(); 841 {
801 else if (CPU_INT_STAT & TIMER2_MASK) 842 if (CPU_INT_STAT & TIMER1_MASK)
802 TIMER2(); 843 TIMER1();
844 else if (CPU_INT_STAT & TIMER2_MASK)
845 TIMER2();
846 } else {
847 if (COP_INT_STAT & TIMER1_MASK)
848 TIMER1();
849 else if (COP_INT_STAT & TIMER2_MASK)
850 TIMER2();
851 }
803} 852}
804 853
805#endif 854#endif
@@ -848,29 +897,32 @@ void set_cpu_frequency(long frequency)
848{ 897{
849 unsigned long postmult; 898 unsigned long postmult;
850 899
851 if (frequency == CPUFREQ_NORMAL) 900 if (CURRENT_CORE == CPU)
852 postmult = CPUFREQ_NORMAL_MULT; 901 {
853 else if (frequency == CPUFREQ_MAX) 902 if (frequency == CPUFREQ_NORMAL)
854 postmult = CPUFREQ_MAX_MULT; 903 postmult = CPUFREQ_NORMAL_MULT;
855 else 904 else if (frequency == CPUFREQ_MAX)
856 postmult = CPUFREQ_DEFAULT_MULT; 905 postmult = CPUFREQ_MAX_MULT;
857 cpu_frequency = frequency; 906 else
907 postmult = CPUFREQ_DEFAULT_MULT;
908 cpu_frequency = frequency;
858 909
859 outl(0x02, 0xcf005008); 910 outl(0x02, 0xcf005008);
860 outl(0x55, 0xcf00500c); 911 outl(0x55, 0xcf00500c);
861 outl(0x6000, 0xcf005010); 912 outl(0x6000, 0xcf005010);
862 913
863 /* Clock frequency = (24/8)*postmult */ 914 /* Clock frequency = (24/8)*postmult */
864 outl(8, 0xcf005018); 915 outl(8, 0xcf005018);
865 outl(postmult, 0xcf00501c); 916 outl(postmult, 0xcf00501c);
866 917
867 outl(0xe000, 0xcf005010); 918 outl(0xe000, 0xcf005010);
868 919
869 /* Wait for PLL relock? */ 920 /* Wait for PLL relock? */
870 udelay(2000); 921 udelay(2000);
871 922
872 /* Select PLL as clock source? */ 923 /* Select PLL as clock source? */
873 outl(0xa8, 0xcf00500c); 924 outl(0xa8, 0xcf00500c);
925 }
874} 926}
875#elif !defined(BOOTLOADER) 927#elif !defined(BOOTLOADER)
876static void ipod_set_cpu_speed(void) 928static void ipod_set_cpu_speed(void)
@@ -901,17 +953,20 @@ static void ipod_set_cpu_speed(void)
901void system_init(void) 953void system_init(void)
902{ 954{
903#ifndef BOOTLOADER 955#ifndef BOOTLOADER
904 /* Remap the flash ROM from 0x00000000 to 0x20000000. */ 956 if (CURRENT_CORE == CPU)
905 MMAP3_LOGICAL = 0x20000000 | 0x3a00; 957 {
906 MMAP3_PHYSICAL = 0x00000000 | 0x3f84; 958 /* Remap the flash ROM from 0x00000000 to 0x20000000. */
907 959 MMAP3_LOGICAL = 0x20000000 | 0x3a00;
908 ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc))); 960 MMAP3_PHYSICAL = 0x00000000 | 0x3f84;
909 outl(-1, 0xcf00101c); 961
910 outl(-1, 0xcf001028); 962 ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc)));
911 outl(-1, 0xcf001038); 963 outl(-1, 0xcf00101c);
964 outl(-1, 0xcf001028);
965 outl(-1, 0xcf001038);
912#ifndef HAVE_ADJUSTABLE_CPU_FREQ 966#ifndef HAVE_ADJUSTABLE_CPU_FREQ
913 ipod_set_cpu_speed(); 967 ipod_set_cpu_speed();
914#endif 968#endif
969 }
915 ipod_init_cache(); 970 ipod_init_cache();
916#endif 971#endif
917} 972}
diff --git a/firmware/target/arm/crt0-pp.S b/firmware/target/arm/crt0-pp.S
index e0d1034f74..bbeace1b60 100644
--- a/firmware/target/arm/crt0-pp.S
+++ b/firmware/target/arm/crt0-pp.S
@@ -222,6 +222,19 @@ cop_init:
222 strhi r4, [r2], #4 222 strhi r4, [r2], #4
223 bhi 2b 223 bhi 2b
224 224
225 /* Set up stack for IRQ mode */
226 msr cpsr_c, #0xd2
227 ldr sp, =cop_irq_stack
228 /* Set up stack for FIQ mode */
229 msr cpsr_c, #0xd1
230 ldr sp, =fiq_stack
231
232 /* Let abort and undefined modes use IRQ stack */
233 msr cpsr_c, #0xd7
234 ldr sp, =cop_irq_stack
235 msr cpsr_c, #0xdb
236 ldr sp, =cop_irq_stack
237
225 ldr sp, =cop_stackend 238 ldr sp, =cop_stackend
226 239
227 /* Run cop_main() in apps/main.c */ 240 /* Run cop_main() in apps/main.c */
@@ -307,6 +320,10 @@ UIE:
307 .space 256*4 320 .space 256*4
308irq_stack: 321irq_stack:
309 322
323/* 256 words of COP IRQ stack */
324 .space 256*4
325cop_irq_stack:
326
310/* 256 words of FIQ stack */ 327/* 256 words of FIQ stack */
311 .space 256*4 328 .space 256*4
312fiq_stack: 329fiq_stack:
diff --git a/firmware/target/arm/sandisk/sansa-e200/ata-e200.c b/firmware/target/arm/sandisk/sansa-e200/ata-e200.c
index cf05397a78..73a67d1ee6 100644
--- a/firmware/target/arm/sandisk/sansa-e200/ata-e200.c
+++ b/firmware/target/arm/sandisk/sansa-e200/ata-e200.c
@@ -687,7 +687,8 @@ int ata_init(void)
687 { 687 {
688 queue_init(&sd_queue, true); 688 queue_init(&sd_queue, true);
689 create_thread(sd_thread, sd_stack, 689 create_thread(sd_thread, sd_stack,
690 sizeof(sd_stack), sd_thread_name IF_PRIO(, PRIORITY_SYSTEM)); 690 sizeof(sd_stack), sd_thread_name IF_PRIO(, PRIORITY_SYSTEM)
691 IF_COP(, CPU, false));
691 initialized = true; 692 initialized = true;
692 } 693 }
693 694
diff --git a/firmware/thread.c b/firmware/thread.c
index 2281f43e53..281ab0fa54 100644
--- a/firmware/thread.c
+++ b/firmware/thread.c
@@ -64,6 +64,10 @@ int *cop_stackend = stackend;
64#endif 64#endif
65#endif 65#endif
66 66
67#if (NUM_CORES > 1)
68bool IDATA_ATTR kernel_running_on_cop = false;
69#endif
70
67/* Conserve IRAM 71/* Conserve IRAM
68static void add_to_list(struct thread_entry **list, 72static void add_to_list(struct thread_entry **list,
69 struct thread_entry *thread) ICODE_ATTR; 73 struct thread_entry *thread) ICODE_ATTR;
@@ -316,10 +320,13 @@ static inline void sleep_core(void)
316#elif CONFIG_CPU == SH7034 320#elif CONFIG_CPU == SH7034
317 and_b(0x7F, &SBYCR); 321 and_b(0x7F, &SBYCR);
318 asm volatile ("sleep"); 322 asm volatile ("sleep");
319#elif CONFIG_CPU == PP5020 323#elif defined (CPU_PP)
320 /* This should sleep the CPU. It appears to wake by itself on 324 /* This should sleep the CPU. It appears to wake by itself on
321 interrupts */ 325 interrupts */
322 CPU_CTL = 0x80000000; 326 if (CURRENT_CORE == CPU)
327 CPU_CTL = PROC_SLEEP;
328 else
329 COP_CTL = PROC_SLEEP;
323#elif CONFIG_CPU == S3C2440 330#elif CONFIG_CPU == S3C2440
324 CLKCON |= (1 << 2); /* set IDLE bit */ 331 CLKCON |= (1 << 2); /* set IDLE bit */
325 for(i=0; i<10; i++); /* wait for IDLE */ 332 for(i=0; i<10; i++); /* wait for IDLE */
@@ -608,27 +615,16 @@ void wakeup_thread(struct thread_entry **list)
608} 615}
609 616
610/*--------------------------------------------------------------------------- 617/*---------------------------------------------------------------------------
611 * Create thread on the current core. 618 * Create a thread
612 * Return ID if context area could be allocated, else -1. 619 * If using a dual core architecture, specify which core to start the thread
620 * on, and whether to fall back to the other core if it can't be created
621 * Return ID if context area could be allocated, else NULL.
613 *--------------------------------------------------------------------------- 622 *---------------------------------------------------------------------------
614 */ 623 */
615struct thread_entry* 624struct thread_entry*
616 create_thread(void (*function)(void), void* stack, int stack_size, 625 create_thread(void (*function)(void), void* stack, int stack_size,
617 const char *name IF_PRIO(, int priority)) 626 const char *name IF_PRIO(, int priority)
618{ 627 IF_COP(, unsigned int core, bool fallback))
619 return create_thread_on_core(CURRENT_CORE, function, stack, stack_size,
620 name IF_PRIO(, priority));
621}
622
623/*---------------------------------------------------------------------------
624 * Create thread on a specific core.
625 * Return ID if context area could be allocated, else -1.
626 *---------------------------------------------------------------------------
627 */
628struct thread_entry*
629 create_thread_on_core(unsigned int core, void (*function)(void),
630 void* stack, int stack_size,
631 const char *name IF_PRIO(, int priority))
632{ 628{
633 unsigned int i; 629 unsigned int i;
634 unsigned int stacklen; 630 unsigned int stacklen;
@@ -637,6 +633,29 @@ struct thread_entry*
637 struct regs *regs; 633 struct regs *regs;
638 struct thread_entry *thread; 634 struct thread_entry *thread;
639 635
636/*****
637 * Ugly code alert!
638 * To prevent ifdef hell while keeping the binary size down, we define
639 * core here if it hasn't been passed as a parameter
640 *****/
641#if NUM_CORES == 1
642#define core CPU
643#endif
644
645#if NUM_CORES > 1
646/* If the kernel hasn't initialised on the COP (most likely due to an old
647 * bootloader) then refuse to start threads on the COP
648 */
649 if((core == COP) && !kernel_running_on_cop)
650 {
651 if (fallback)
652 return create_thread(function, stack, stack_size, name
653 IF_PRIO(, priority) IF_COP(, CPU, false));
654 else
655 return NULL;
656 }
657#endif
658
640 for (n = 0; n < MAXTHREADS; n++) 659 for (n = 0; n < MAXTHREADS; n++)
641 { 660 {
642 if (cores[core].threads[n].name == NULL) 661 if (cores[core].threads[n].name == NULL)
@@ -644,8 +663,15 @@ struct thread_entry*
644 } 663 }
645 664
646 if (n == MAXTHREADS) 665 if (n == MAXTHREADS)
647 return NULL; 666 {
648 667#if NUM_CORES > 1
668 if (fallback)
669 return create_thread(function, stack, stack_size, name
670 IF_PRIO(, priority) IF_COP(, 1 - core, fallback));
671 else
672#endif
673 return NULL;
674 }
649 675
650 /* Munge the stack to make it easy to spot stack overflows */ 676 /* Munge the stack to make it easy to spot stack overflows */
651 stacklen = stack_size / sizeof(int); 677 stacklen = stack_size / sizeof(int);
@@ -677,6 +703,9 @@ struct thread_entry*
677 THREAD_CPU_INIT(core, thread); 703 THREAD_CPU_INIT(core, thread);
678 704
679 return thread; 705 return thread;
706#if NUM_CORES == 1
707#undef core
708#endif
680} 709}
681 710
682#ifdef HAVE_SCHEDULER_BOOSTCTRL 711#ifdef HAVE_SCHEDULER_BOOSTCTRL
@@ -751,7 +780,8 @@ void init_threads(void)
751{ 780{
752 unsigned int core = CURRENT_CORE; 781 unsigned int core = CURRENT_CORE;
753 782
754 memset(cores, 0, sizeof cores); 783 if (core == CPU)
784 memset(cores, 0, sizeof cores);
755 cores[core].sleeping = NULL; 785 cores[core].sleeping = NULL;
756 cores[core].running = NULL; 786 cores[core].running = NULL;
757 cores[core].threads[0].name = main_thread_name; 787 cores[core].threads[0].name = main_thread_name;
@@ -779,6 +809,10 @@ void init_threads(void)
779#endif 809#endif
780 } 810 }
781 cores[core].threads[0].context.start = 0; /* thread 0 already running */ 811 cores[core].threads[0].context.start = 0; /* thread 0 already running */
812#if NUM_CORES > 1
813 if(core == COP)
814 kernel_running_on_cop = true; /* can we use context.start for this? */
815#endif
782} 816}
783 817
784int thread_stack_usage(const struct thread_entry *thread) 818int thread_stack_usage(const struct thread_entry *thread)
diff --git a/firmware/usb.c b/firmware/usb.c
index ee08b04caa..cf4641950e 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -428,7 +428,8 @@ void usb_init(void)
428#ifndef BOOTLOADER 428#ifndef BOOTLOADER
429 queue_init(&usb_queue, true); 429 queue_init(&usb_queue, true);
430 create_thread(usb_thread, usb_stack, sizeof(usb_stack), 430 create_thread(usb_thread, usb_stack, sizeof(usb_stack),
431 usb_thread_name IF_PRIO(, PRIORITY_SYSTEM)); 431 usb_thread_name IF_PRIO(, PRIORITY_SYSTEM)
432 IF_COP(, CPU, false));
432 433
433 tick_add_task(usb_tick); 434 tick_add_task(usb_tick);
434#endif 435#endif
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index a993a9e0e8..8ea46824ce 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -258,12 +258,6 @@ void remove_thread(int threadnum)
258 (void)threadnum; 258 (void)threadnum;
259} 259}
260 260
261void remove_thread_on_core(unsigned int core, int threadnum)
262{
263 (void)core;
264 (void)threadnum;
265}
266
267/* assure an unused place to direct virtual pointers to */ 261/* assure an unused place to direct virtual pointers to */
268#define VIRT_SIZE 0xFFFF /* more than enough for our string ID range */ 262#define VIRT_SIZE 0xFFFF /* more than enough for our string ID range */
269unsigned char vp_dummy[VIRT_SIZE]; 263unsigned char vp_dummy[VIRT_SIZE];
diff --git a/uisimulator/sdl/thread-sdl.c b/uisimulator/sdl/thread-sdl.c
index 041ca3153d..21697699a5 100644
--- a/uisimulator/sdl/thread-sdl.c
+++ b/uisimulator/sdl/thread-sdl.c
@@ -75,12 +75,6 @@ int create_thread(void (*fp)(void), void* sp, int stk_size)
75 return 0; 75 return 0;
76} 76}
77 77
78int create_thread_on_core(void (*core)(void), void (*fp)(void), void* sp, int stk_size)
79{
80 (void)core;
81 return create_thread(fp, sp, stk_size);
82}
83
84void init_threads(void) 78void init_threads(void)
85{ 79{
86 m = SDL_CreateMutex(); 80 m = SDL_CreateMutex();