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 = { ¤t_tick, default_event_handler, default_event_handler_ex, - create_thread_on_core, + create_thread, remove_thread, reset_poweroff_timer, #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 { long* current_tick; long (*default_event_handler)(long event); long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); - struct thread_entry* (*create_thread)(unsigned int core, void (*function)(void), + struct thread_entry* (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name - IF_PRIO(, int priority)); + IF_PRIO(, int priority) + IF_COP(, unsigned int core, bool fallback)); void (*remove_thread)(struct thread_entry *thread); void (*reset_poweroff_timer)(void); #ifndef SIMULATOR diff --git a/apps/main.c b/apps/main.c index 6286b68ed1..e4d90bce61 100644 --- a/apps/main.c +++ b/apps/main.c @@ -296,6 +296,9 @@ static void init(void) #if CONFIG_CHARGING && (CONFIG_CPU == SH7034) /* if nobody initialized ATA before, I consider this a cold start */ bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */ +#endif +#ifdef CPU_PP + COP_CTL = PROC_WAKE; #endif system_init(); kernel_init(); @@ -549,19 +552,22 @@ void cop_main(void) so it should not be assumed that the coprocessor be usable even on platforms which support it. - At present the COP sleeps unless it receives a message from the CPU telling - it that we are loading a new kernel, so must reboot */ + A kernel thread runs on the coprocessor which waits for other threads to be + added, and gracefully handles RoLo */ #if CONFIG_CPU == PP5002 -/* 3G doesn't have Rolo support yet */ +/* 3G doesn't have Rolo or dual core support yet */ while(1) { COP_CTL = PROC_SLEEP; } #else extern volatile unsigned char cpu_message; + system_init(); + kernel_init(); + while(cpu_message != COP_REBOOT) { - COP_CTL = PROC_SLEEP; + sleep(HZ); } rolo_restart_cop(); #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; /* TBD: Split out "audio" and "playback" (ie. calling) threads */ /* Main state control */ -static volatile bool audio_codec_loaded; /* Is codec loaded? (C/A-) */ -static volatile bool playing; /* Is audio playing? (A) */ -static volatile bool paused; /* Is audio paused? (A/C-) */ +static volatile bool audio_codec_loaded NOCACHEBSS_ATTR;/* Codec loaded? (C/A-) */ +static volatile bool playing NOCACHEBSS_ATTR; /* Is audio playing? (A) */ +static volatile bool paused NOCACHEBSS_ATTR; /* Is audio paused? (A/C-) */ static volatile bool filling IDATA_ATTR; /* Is file buffer refilling? (A/C-) */ /* Ring buffer where compressed audio and codecs are loaded */ @@ -290,7 +290,7 @@ static void audio_reset_buffer(size_t pcmbufsize); /* Codec thread */ extern struct codec_api ci; -static struct event_queue codec_queue; +static struct event_queue codec_queue NOCACHEBSS_ATTR; static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] IBSS_ATTR; static const char codec_thread_name[] = "codec"; @@ -304,7 +304,7 @@ static volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */ extern struct codec_api ci_voice; static struct thread_entry *voice_thread_p = NULL; -static struct event_queue voice_queue; +static struct event_queue voice_queue NOCACHEBSS_ATTR; static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] IBSS_ATTR_VOICE_STACK; static const char voice_thread_name[] = "voice codec"; @@ -324,12 +324,12 @@ static unsigned char *iram_buf[2] = { NULL, NULL }; /* Pointer to DRAM buffers for normal/voice codecs */ static unsigned char *dram_buf[2] = { NULL, NULL }; /* Mutex to control which codec (normal/voice) is running */ -static struct mutex mutex_codecthread; +static struct mutex mutex_codecthread NOCACHEBSS_ATTR; /* Voice state */ static volatile bool voice_thread_start; /* Triggers voice playback (A/V) */ -static volatile bool voice_is_playing; /* Is voice currently playing? (V) */ -static volatile bool voice_codec_loaded; /* Is voice codec loaded (V/A-) */ +static volatile bool voice_is_playing NOCACHEBSS_ATTR; /* Is voice currently playing? (V) */ +static volatile bool voice_codec_loaded NOCACHEBSS_ATTR; /* Is voice codec loaded (V/A-) */ static char *voicebuf; static size_t voice_remaining; @@ -863,7 +863,8 @@ void audio_preinit(void) queue_init(&codec_queue, true); create_thread(audio_thread, audio_stack, sizeof(audio_stack), - audio_thread_name IF_PRIO(, PRIORITY_BUFFERING)); + audio_thread_name IF_PRIO(, PRIORITY_BUFFERING) + IF_COP(, CPU, false)); } void audio_init(void) @@ -888,7 +889,7 @@ void voice_init(void) queue_init(&voice_queue, true); voice_thread_p = create_thread(voice_thread, voice_stack, sizeof(voice_stack), voice_thread_name - IF_PRIO(, PRIORITY_PLAYBACK)); + IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU, false)); while (!voice_codec_loaded) yield(); @@ -3533,7 +3534,8 @@ static void audio_playback_init(void) codec_thread_p = create_thread( codec_thread, codec_stack, sizeof(codec_stack), - codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)); + codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK) + IF_COP(, COP, true)); while (1) { 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) memset(playlist->filenames, 0, playlist->max_playlist_size * sizeof(int)); create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), - playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND)); + playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND) + IF_COP(, CPU, false)); queue_init(&playlist_queue, true); #endif } 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 = { sound_default, pcm_record_more, #endif - create_thread_on_core, #ifdef IRIVER_H100_SERIES /* 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 { long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); struct thread_entry* (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name - IF_PRIO(, int priority)); + IF_PRIO(, int priority) + IF_COP(, unsigned int core, bool fallback)); void (*remove_thread)(struct thread_entry *thread); void (*reset_poweroff_timer)(void); #ifndef SIMULATOR @@ -595,11 +596,6 @@ struct plugin_api { void (*pcm_record_more)(void *start, size_t size); #endif - struct thread_entry*(*create_thread_on_core)( - unsigned int core, void (*function)(void), - void* stack, int stack_size, - const char *name IF_PRIO(, int priority)); - #ifdef IRIVER_H100_SERIES /* Routines for the iriver_flash -plugin. */ 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) rb->memset(&gTread, 0, sizeof(gTread)); gTread.foreground = true; rb->create_thread(thread, stack, stacksize, "CDC" - IF_PRIO(, PRIORITY_BACKGROUND)); + IF_PRIO(, PRIORITY_BACKGROUND) + IF_COP(, CPU, false)); #ifdef DEBUG 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) rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */ if(rb->create_thread(thread, thread_stack, sizeof(thread_stack), "Battery Benchmark" - IF_PRIO(, PRIORITY_BACKGROUND)) == NULL) + IF_PRIO(, PRIORITY_BACKGROUND) + IF_COP(, CPU, false)) == NULL) { rb->splash(HZ,true,"Cannot create thread!"); 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) videostatus = STREAM_PLAYING; /* We put the video thread on the second processor for multi-core targets. */ -#if NUM_CORES > 1 - if ((videothread_id = rb->create_thread_on_core(COP,decode_mpeg2, -#else if ((videothread_id = rb->create_thread(decode_mpeg2, -#endif - (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK))) == NULL) + (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) + IF_COP(, COP, true))) == NULL) { rb->splash(HZ,true,"Cannot create video thread!"); return PLUGIN_ERROR; } if ((audiothread_id = rb->create_thread(mad_decode, - (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK))) == NULL) + (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK) + IF_COP(, CPU, false))) == NULL) { rb->splash(HZ,true,"Cannot create audio thread!"); 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) queue_init(&tagcache_queue, true); create_thread(tagcache_thread, tagcache_stack, sizeof(tagcache_stack), tagcache_thread_name - IF_PRIO(, PRIORITY_BACKGROUND)); + IF_PRIO(, PRIORITY_BACKGROUND) + IF_COP(, CPU, false)); #else tc_stat.initialized = true; 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 SYS_USB_CONNECTED. Else do nothing and return 0. int create_thread(void* function, void* stack, int stack_size, - const char *name); + const char *name IF_PRIO(int priority) + IF_COP(, unsigned int core, bool fallback)); Create a thread. ??? (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) create_thread(backlight_thread, backlight_stack, sizeof(backlight_stack), backlight_thread_name - IF_PRIO(, PRIORITY_SYSTEM)); + IF_PRIO(, PRIORITY_SYSTEM) + IF_COP(, CPU, false)); tick_add_task(backlight_tick); } 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) queue_init(&dircache_queue, true); create_thread(dircache_thread, dircache_stack, - sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND)); + sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND) + IF_COP(, CPU, false)); } /** 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) last_disk_activity = current_tick; create_thread(ata_thread, ata_stack, sizeof(ata_stack), ata_thread_name - IF_PRIO(, PRIORITY_SYSTEM)); + IF_PRIO(, PRIORITY_SYSTEM) + IF_COP(, CPU, false)); initialized = true; } 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) queue_init(&mmc_queue, true); create_thread(mmc_thread, mmc_stack, - sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM)); + sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM) + IF_COP(, CPU, false)); tick_add_task(mmc_tick); initialized = true; } 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) create_thread(scroll_thread, scroll_stack, sizeof(scroll_stack), scroll_name - IF_PRIO(, PRIORITY_USER_INTERFACE)); + IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU, false)); } /*** 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) /* Call device specific init */ lcd_init_device(); create_thread(scroll_thread, scroll_stack, - sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); + sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU, false)); } /*** 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) /* Call device specific init */ lcd_init_device(); create_thread(scroll_thread, scroll_stack, - sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); + sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU, false)); } /*** 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) /* Call device specific init */ lcd_init_device(); create_thread(scroll_thread, scroll_stack, - sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); + sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU, false)); } /*** 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) lcd_set_contrast(lcd_default_contrast()); create_thread(scroll_thread, scroll_stack, - sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); + sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU, false)); } void 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) queue_init(&remote_scroll_queue, false); #endif create_thread(scroll_thread, scroll_stack, - sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); + sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU, false)); } 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) queue_init(&remote_scroll_queue, false); #endif create_thread(scroll_thread, scroll_stack, - sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); + sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU, false)); } 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 @@ /* define for all cpus from PP family */ #if (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020) || (CONFIG_CPU == PP5024) #define CPU_PP - -/* PP family has dual cores */ -#if 0 -/* Keep it as single core until dual core support is ready */ -#define NUM_CORES 2 -#define CURRENT_CORE current_core() -#endif - -#define NUM_CORES 1 -#define CURRENT_CORE 0 - -#define COP_REBOOT 0x00000001 -#else -#define NUM_CORES 1 -#define CURRENT_CORE 0 #endif /* define for all cpus from ARM family */ @@ -348,4 +333,28 @@ #define IRAM_LCDFRAMEBUFFER #endif +/* Dual core support - not yet working on the 3G iPod */ +#if defined(CPU_PP) && CONFIG_CPU != PP5002 +#define NUM_CORES 2 +#define CURRENT_CORE current_core() +/* Hopefully at some point we will learn how to mark areas of main memory as + * not to be cached. Until then, use IRAM for variables shared across cores */ +#define NOCACHEBSS_ATTR IBSS_ATTR +#define NOCACHEDATA_ATTR IDATA_ATTR + +#define IF_COP(empty, x, y) , x, y + +/* Defines for inter-core messaging */ +#define COP_REBOOT 1 + +#else +#define NUM_CORES 1 +#define CURRENT_CORE CPU +#define NOCACHEBSS_ATTR +#define NOCACHEDATA_ATTR + +#define IF_COP(empty, x, y) + +#endif /* Processor specific */ + #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 @@ #define CPU_INT_STAT (*(volatile unsigned long*)(0xcf001000)) #define CPU_INT_EN (*(volatile unsigned long*)(0xcf001024)) #define CPU_INT_CLR (*(volatile unsigned long*)(0xcf001028)) +#define COP_INT_STAT (*(volatile unsigned long*)(0xcf001010)) /* A guess */ +#define COP_INT_EN (*(volatile unsigned long*)(0xcf001034)) +#define COP_INT_CLR (*(volatile unsigned long*)(0xcf001038)) #define USB2D_IDENT (*(volatile unsigned long*)(0xc5000000)) #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 @@ #define PROC_ID_CPU 0x55 #define PROC_ID_COP 0xaa +/* Mailboxes */ +/* Each processor has two mailboxes it can write to and two which + it can read from. We define the first to be for sending messages + and the second for replying to messages */ +#define CPU_MESSAGE (*(volatile unsigned long *)(0x60001000)) +#define COP_MESSAGE (*(volatile unsigned long *)(0x60001004)) +#define CPU_REPLY (*(volatile unsigned long *)(0x60001008)) +#define COP_REPLY (*(volatile unsigned long *)(0x6000100c)) + /* Interrupts */ #define CPU_INT_STAT (*(volatile unsigned long*)(0x64004000)) #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 { struct thread_entry* create_thread(void (*function)(void), void* stack, int stack_size, - const char *name IF_PRIO(, int priority)); - -struct thread_entry* - create_thread_on_core(unsigned int core, void (*function)(void), - void* stack, int stack_size, - const char *name - IF_PRIO(, int priority)); + const char *name IF_PRIO(, int priority) + IF_COP(, unsigned int core, bool fallback)); #ifdef HAVE_SCHEDULER_BOOSTCTRL void 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 @@ #include "panic.h" #if !defined(CPU_PP) || !defined(BOOTLOADER) -long current_tick = 0; +long current_tick NOCACHEDATA_ATTR = 0; #endif static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); @@ -45,10 +45,13 @@ void kernel_init(void) /* Init the threading API */ init_threads(); - memset(tick_funcs, 0, sizeof(tick_funcs)); + if(CURRENT_CORE == CPU) + { + memset(tick_funcs, 0, sizeof(tick_funcs)); - num_queues = 0; - memset(all_queues, 0, sizeof(all_queues)); + num_queues = 0; + memset(all_queues, 0, sizeof(all_queues)); + } tick_start(1000/HZ); } @@ -496,28 +499,36 @@ void TIMER1(void) int i; TIMER1_VAL; /* Read value to ack IRQ */ - /* Run through the list of tick tasks */ - for (i = 0;i < MAX_NUM_TICK_TASKS;i++) + /* Run through the list of tick tasks (using main core) */ + if (CURRENT_CORE == CPU) { - if (tick_funcs[i]) + for (i = 0;i < MAX_NUM_TICK_TASKS;i++) { - tick_funcs[i](); + if (tick_funcs[i]) + { + tick_funcs[i](); + } } - } - current_tick++; + current_tick++; + } } #endif void tick_start(unsigned int interval_in_ms) { #ifndef BOOTLOADER - TIMER1_CFG = 0x0; - TIMER1_VAL; - /* enable timer */ - TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1); - /* unmask interrupt source */ - CPU_INT_EN = TIMER1_MASK; + if(CURRENT_CORE == CPU) + { + TIMER1_CFG = 0x0; + TIMER1_VAL; + /* enable timer */ + TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1); + /* unmask interrupt source */ + CPU_INT_EN = TIMER1_MASK; + } else { + COP_INT_EN = TIMER1_MASK; + } #else /* We don't enable interrupts in the bootloader */ (void)interval_in_ms; @@ -645,6 +656,29 @@ void mutex_init(struct mutex *m) m->thread = NULL; } +#ifdef CPU_PP +/* PortalPlayer chips have 2 cores, therefore need atomic mutexes */ + +static inline bool test_and_set(bool *x, bool v) +{ + asm volatile ( + "swpb %0, %0, [%1]\n" + : "+r"(v) + : "r"(x) + ); + return v; +} + +void mutex_lock(struct mutex *m) +{ + if (test_and_set(&m->locked,true)) + { + /* Wait until the lock is open... */ + block_thread(&m->thread); + } +} + +#else void mutex_lock(struct mutex *m) { if (m->locked) @@ -656,6 +690,7 @@ void mutex_lock(struct mutex *m) /* ...and lock it */ m->locked = true; } +#endif void mutex_unlock(struct mutex *m) { 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) queue_init(&mpeg_queue, true); #endif /* !SIMULATOR */ create_thread(mpeg_thread, mpeg_stack, - sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM)); + sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM) + IF_COP(, CPU, false)); memset(trackdata, sizeof(trackdata), 0); 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) queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send); pcmrec_thread_p = create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), - pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)); + pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING) + IF_COP(, CPU, false)); } /* pcm_rec_init */ /** 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) /* init history to 0 */ memset(power_history, 0x00, sizeof(power_history)); create_thread(power_thread, power_stack, sizeof(power_stack), - power_thread_name IF_PRIO(, PRIORITY_SYSTEM)); + power_thread_name IF_PRIO(, PRIORITY_SYSTEM) + IF_COP(, CPU, false)); } #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); void irq(void) { - if (CPU_INT_STAT & TIMER1_MASK) - TIMER1(); - else if (CPU_INT_STAT & TIMER2_MASK) - TIMER2(); - else if (CPU_HI_INT_STAT & GPIO_MASK) - ipod_mini_button_int(); + if(CURRENT_CORE == CPU) + { + if (CPU_INT_STAT & TIMER1_MASK) + TIMER1(); + else if (CPU_INT_STAT & TIMER2_MASK) + TIMER2(); + else if (CPU_HI_INT_STAT & GPIO_MASK) + ipod_mini_button_int(); + } else { + if (COP_INT_STAT & TIMER1_MASK) + TIMER1(); + else if (COP_INT_STAT & TIMER2_MASK) + TIMER2(); + else if (COP_HI_INT_STAT & GPIO_MASK) + ipod_mini_button_int(); + } } #elif (defined IRIVER_H10) || (defined IRIVER_H10_5GB) || defined(ELIO_TPJ1022) \ || (defined SANSA_E200) @@ -626,22 +636,40 @@ void irq(void) /* TODO: Even if it isn't in the target tree, this should be the default case */ void irq(void) { - if (CPU_INT_STAT & TIMER1_MASK) - TIMER1(); - else if (CPU_INT_STAT & TIMER2_MASK) - TIMER2(); + if(CURRENT_CORE == CPU) + { + if (CPU_INT_STAT & TIMER1_MASK) + TIMER1(); + else if (CPU_INT_STAT & TIMER2_MASK) + TIMER2(); + } else { + if (COP_INT_STAT & TIMER1_MASK) + TIMER1(); + else if (COP_INT_STAT & TIMER2_MASK) + TIMER2(); + } } #else extern void ipod_4g_button_int(void); void irq(void) { - if (CPU_INT_STAT & TIMER1_MASK) - TIMER1(); - else if (CPU_INT_STAT & TIMER2_MASK) - TIMER2(); - else if (CPU_HI_INT_STAT & I2C_MASK) - ipod_4g_button_int(); + if(CURRENT_CORE == CPU) + { + if (CPU_INT_STAT & TIMER1_MASK) + TIMER1(); + else if (CPU_INT_STAT & TIMER2_MASK) + TIMER2(); + else if (CPU_HI_INT_STAT & I2C_MASK) + ipod_4g_button_int(); + } else { + if (COP_INT_STAT & TIMER1_MASK) + TIMER1(); + else if (COP_INT_STAT & TIMER2_MASK) + TIMER2(); + else if (COP_HI_INT_STAT & I2C_MASK) + ipod_4g_button_int(); + } } #endif #endif /* BOOTLOADER */ @@ -694,43 +722,47 @@ void set_cpu_frequency(long frequency) { unsigned long postmult; - if (frequency == CPUFREQ_NORMAL) - postmult = CPUFREQ_NORMAL_MULT; - else if (frequency == CPUFREQ_MAX) - postmult = CPUFREQ_MAX_MULT; - else - postmult = CPUFREQ_DEFAULT_MULT; - cpu_frequency = frequency; + if (CURRENT_CORE == CPU) + { + if (frequency == CPUFREQ_NORMAL) + postmult = CPUFREQ_NORMAL_MULT; + else if (frequency == CPUFREQ_MAX) + postmult = CPUFREQ_MAX_MULT; + else + postmult = CPUFREQ_DEFAULT_MULT; + cpu_frequency = frequency; - /* Enable PLL? */ - outl(inl(0x70000020) | (1<<30), 0x70000020); + /* Enable PLL? */ + outl(inl(0x70000020) | (1<<30), 0x70000020); - /* Select 24MHz crystal as clock source? */ - outl((inl(0x60006020) & 0x0fffff0f) | 0x20000020, 0x60006020); + /* Select 24MHz crystal as clock source? */ + outl((inl(0x60006020) & 0x0fffff0f) | 0x20000020, 0x60006020); - /* Clock frequency = (24/8)*postmult */ - outl(0xaa020000 | 8 | (postmult << 8), 0x60006034); + /* Clock frequency = (24/8)*postmult */ + outl(0xaa020000 | 8 | (postmult << 8), 0x60006034); - /* Wait for PLL relock? */ - udelay(2000); + /* Wait for PLL relock? */ + udelay(2000); - /* Select PLL as clock source? */ - outl((inl(0x60006020) & 0x0fffff0f) | 0x20000070, 0x60006020); + /* Select PLL as clock source? */ + outl((inl(0x60006020) & 0x0fffff0f) | 0x20000070, 0x60006020); #if defined(IPOD_COLOR) || defined(IPOD_4G) || defined(IPOD_MINI) || defined(IRIVER_H10) || defined(IRIVER_H10_5GB) - /* We don't know why the timer interrupt gets disabled on the PP5020 - based ipods, but without the following line, the 4Gs will freeze - when CPU frequency changing is enabled. + /* We don't know why the timer interrupt gets disabled on the PP5020 + based ipods, but without the following line, the 4Gs will freeze + when CPU frequency changing is enabled. - Note also that a simple "CPU_INT_EN = TIMER1_MASK;" (as used - elsewhere to enable interrupts) doesn't work, we need "|=". + Note also that a simple "CPU_INT_EN = TIMER1_MASK;" (as used + elsewhere to enable interrupts) doesn't work, we need "|=". - It's not needed on the PP5021 and PP5022 ipods. - */ + It's not needed on the PP5021 and PP5022 ipods. + */ - /* unmask interrupt source */ - CPU_INT_EN |= TIMER1_MASK; + /* unmask interrupt source */ + CPU_INT_EN |= TIMER1_MASK; + COP_INT_EN |= TIMER1_MASK; #endif + } } #elif !defined(BOOTLOADER) void ipod_set_cpu_frequency(void) @@ -754,24 +786,33 @@ void ipod_set_cpu_frequency(void) void system_init(void) { #ifndef BOOTLOADER - /* Remap the flash ROM from 0x00000000 to 0x20000000. */ - MMAP3_LOGICAL = 0x20000000 | 0x3a00; - MMAP3_PHYSICAL = 0x00000000 | 0x3f84; + if (CURRENT_CORE == CPU) + { + /* Remap the flash ROM from 0x00000000 to 0x20000000. */ + MMAP3_LOGICAL = 0x20000000 | 0x3a00; + MMAP3_PHYSICAL = 0x00000000 | 0x3f84; - /* The hw revision is written to the last 4 bytes of SDRAM by the - bootloader - we save it before Rockbox overwrites it. */ - ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc))); + /* The hw revision is written to the last 4 bytes of SDRAM by the + bootloader - we save it before Rockbox overwrites it. */ + ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc))); - /* disable all irqs */ - outl(-1, 0x60001138); - outl(-1, 0x60001128); - outl(-1, 0x6000111c); + /* disable all irqs */ + outl(-1, 0x60001138); + outl(-1, 0x60001128); + outl(-1, 0x6000111c); - outl(-1, 0x60001038); - outl(-1, 0x60001028); - outl(-1, 0x6000101c); -#ifndef HAVE_ADJUSTABLE_CPU_FREQ - ipod_set_cpu_frequency(); + outl(-1, 0x60001038); + outl(-1, 0x60001028); + outl(-1, 0x6000101c); +#if (!defined HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES == 1) + ipod_set_cpu_frequency(); +#endif + } +#if (!defined HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1) + else + { + ipod_set_cpu_frequency(); + } #endif ipod_init_cache(); #endif @@ -796,10 +837,18 @@ extern void TIMER2(void); void irq(void) { - if (CPU_INT_STAT & TIMER1_MASK) - TIMER1(); - else if (CPU_INT_STAT & TIMER2_MASK) - TIMER2(); + if(CURRENT_CORE == CPU) + { + if (CPU_INT_STAT & TIMER1_MASK) + TIMER1(); + else if (CPU_INT_STAT & TIMER2_MASK) + TIMER2(); + } else { + if (COP_INT_STAT & TIMER1_MASK) + TIMER1(); + else if (COP_INT_STAT & TIMER2_MASK) + TIMER2(); + } } #endif @@ -848,29 +897,32 @@ void set_cpu_frequency(long frequency) { unsigned long postmult; - if (frequency == CPUFREQ_NORMAL) - postmult = CPUFREQ_NORMAL_MULT; - else if (frequency == CPUFREQ_MAX) - postmult = CPUFREQ_MAX_MULT; - else - postmult = CPUFREQ_DEFAULT_MULT; - cpu_frequency = frequency; + if (CURRENT_CORE == CPU) + { + if (frequency == CPUFREQ_NORMAL) + postmult = CPUFREQ_NORMAL_MULT; + else if (frequency == CPUFREQ_MAX) + postmult = CPUFREQ_MAX_MULT; + else + postmult = CPUFREQ_DEFAULT_MULT; + cpu_frequency = frequency; - outl(0x02, 0xcf005008); - outl(0x55, 0xcf00500c); - outl(0x6000, 0xcf005010); + outl(0x02, 0xcf005008); + outl(0x55, 0xcf00500c); + outl(0x6000, 0xcf005010); - /* Clock frequency = (24/8)*postmult */ - outl(8, 0xcf005018); - outl(postmult, 0xcf00501c); + /* Clock frequency = (24/8)*postmult */ + outl(8, 0xcf005018); + outl(postmult, 0xcf00501c); - outl(0xe000, 0xcf005010); + outl(0xe000, 0xcf005010); - /* Wait for PLL relock? */ - udelay(2000); + /* Wait for PLL relock? */ + udelay(2000); - /* Select PLL as clock source? */ - outl(0xa8, 0xcf00500c); + /* Select PLL as clock source? */ + outl(0xa8, 0xcf00500c); + } } #elif !defined(BOOTLOADER) static void ipod_set_cpu_speed(void) @@ -901,17 +953,20 @@ static void ipod_set_cpu_speed(void) void system_init(void) { #ifndef BOOTLOADER - /* Remap the flash ROM from 0x00000000 to 0x20000000. */ - MMAP3_LOGICAL = 0x20000000 | 0x3a00; - MMAP3_PHYSICAL = 0x00000000 | 0x3f84; + if (CURRENT_CORE == CPU) + { + /* Remap the flash ROM from 0x00000000 to 0x20000000. */ + MMAP3_LOGICAL = 0x20000000 | 0x3a00; + MMAP3_PHYSICAL = 0x00000000 | 0x3f84; - ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc))); - outl(-1, 0xcf00101c); - outl(-1, 0xcf001028); - outl(-1, 0xcf001038); + ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc))); + outl(-1, 0xcf00101c); + outl(-1, 0xcf001028); + outl(-1, 0xcf001038); #ifndef HAVE_ADJUSTABLE_CPU_FREQ - ipod_set_cpu_speed(); + ipod_set_cpu_speed(); #endif + } ipod_init_cache(); #endif } 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: strhi r4, [r2], #4 bhi 2b + /* Set up stack for IRQ mode */ + msr cpsr_c, #0xd2 + ldr sp, =cop_irq_stack + /* Set up stack for FIQ mode */ + msr cpsr_c, #0xd1 + ldr sp, =fiq_stack + + /* Let abort and undefined modes use IRQ stack */ + msr cpsr_c, #0xd7 + ldr sp, =cop_irq_stack + msr cpsr_c, #0xdb + ldr sp, =cop_irq_stack + ldr sp, =cop_stackend /* Run cop_main() in apps/main.c */ @@ -307,6 +320,10 @@ UIE: .space 256*4 irq_stack: +/* 256 words of COP IRQ stack */ + .space 256*4 +cop_irq_stack: + /* 256 words of FIQ stack */ .space 256*4 fiq_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) { queue_init(&sd_queue, true); create_thread(sd_thread, sd_stack, - sizeof(sd_stack), sd_thread_name IF_PRIO(, PRIORITY_SYSTEM)); + sizeof(sd_stack), sd_thread_name IF_PRIO(, PRIORITY_SYSTEM) + IF_COP(, CPU, false)); initialized = true; } 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; #endif #endif +#if (NUM_CORES > 1) +bool IDATA_ATTR kernel_running_on_cop = false; +#endif + /* Conserve IRAM static void add_to_list(struct thread_entry **list, struct thread_entry *thread) ICODE_ATTR; @@ -316,10 +320,13 @@ static inline void sleep_core(void) #elif CONFIG_CPU == SH7034 and_b(0x7F, &SBYCR); asm volatile ("sleep"); -#elif CONFIG_CPU == PP5020 +#elif defined (CPU_PP) /* This should sleep the CPU. It appears to wake by itself on interrupts */ - CPU_CTL = 0x80000000; + if (CURRENT_CORE == CPU) + CPU_CTL = PROC_SLEEP; + else + COP_CTL = PROC_SLEEP; #elif CONFIG_CPU == S3C2440 CLKCON |= (1 << 2); /* set IDLE bit */ for(i=0; i<10; i++); /* wait for IDLE */ @@ -608,27 +615,16 @@ void wakeup_thread(struct thread_entry **list) } /*--------------------------------------------------------------------------- - * Create thread on the current core. - * Return ID if context area could be allocated, else -1. + * Create a thread + * If using a dual core architecture, specify which core to start the thread + * on, and whether to fall back to the other core if it can't be created + * Return ID if context area could be allocated, else NULL. *--------------------------------------------------------------------------- */ struct thread_entry* create_thread(void (*function)(void), void* stack, int stack_size, - const char *name IF_PRIO(, int priority)) -{ - return create_thread_on_core(CURRENT_CORE, function, stack, stack_size, - name IF_PRIO(, priority)); -} - -/*--------------------------------------------------------------------------- - * Create thread on a specific core. - * Return ID if context area could be allocated, else -1. - *--------------------------------------------------------------------------- - */ -struct thread_entry* - create_thread_on_core(unsigned int core, void (*function)(void), - void* stack, int stack_size, - const char *name IF_PRIO(, int priority)) + const char *name IF_PRIO(, int priority) + IF_COP(, unsigned int core, bool fallback)) { unsigned int i; unsigned int stacklen; @@ -637,6 +633,29 @@ struct thread_entry* struct regs *regs; struct thread_entry *thread; +/***** + * Ugly code alert! + * To prevent ifdef hell while keeping the binary size down, we define + * core here if it hasn't been passed as a parameter + *****/ +#if NUM_CORES == 1 +#define core CPU +#endif + +#if NUM_CORES > 1 +/* If the kernel hasn't initialised on the COP (most likely due to an old + * bootloader) then refuse to start threads on the COP + */ + if((core == COP) && !kernel_running_on_cop) + { + if (fallback) + return create_thread(function, stack, stack_size, name + IF_PRIO(, priority) IF_COP(, CPU, false)); + else + return NULL; + } +#endif + for (n = 0; n < MAXTHREADS; n++) { if (cores[core].threads[n].name == NULL) @@ -644,8 +663,15 @@ struct thread_entry* } if (n == MAXTHREADS) - return NULL; - + { +#if NUM_CORES > 1 + if (fallback) + return create_thread(function, stack, stack_size, name + IF_PRIO(, priority) IF_COP(, 1 - core, fallback)); + else +#endif + return NULL; + } /* Munge the stack to make it easy to spot stack overflows */ stacklen = stack_size / sizeof(int); @@ -677,6 +703,9 @@ struct thread_entry* THREAD_CPU_INIT(core, thread); return thread; +#if NUM_CORES == 1 +#undef core +#endif } #ifdef HAVE_SCHEDULER_BOOSTCTRL @@ -751,7 +780,8 @@ void init_threads(void) { unsigned int core = CURRENT_CORE; - memset(cores, 0, sizeof cores); + if (core == CPU) + memset(cores, 0, sizeof cores); cores[core].sleeping = NULL; cores[core].running = NULL; cores[core].threads[0].name = main_thread_name; @@ -779,6 +809,10 @@ void init_threads(void) #endif } cores[core].threads[0].context.start = 0; /* thread 0 already running */ +#if NUM_CORES > 1 + if(core == COP) + kernel_running_on_cop = true; /* can we use context.start for this? */ +#endif } int 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) #ifndef BOOTLOADER queue_init(&usb_queue, true); create_thread(usb_thread, usb_stack, sizeof(usb_stack), - usb_thread_name IF_PRIO(, PRIORITY_SYSTEM)); + usb_thread_name IF_PRIO(, PRIORITY_SYSTEM) + IF_COP(, CPU, false)); tick_add_task(usb_tick); #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) (void)threadnum; } -void remove_thread_on_core(unsigned int core, int threadnum) -{ - (void)core; - (void)threadnum; -} - /* assure an unused place to direct virtual pointers to */ #define VIRT_SIZE 0xFFFF /* more than enough for our string ID range */ unsigned 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) return 0; } -int create_thread_on_core(void (*core)(void), void (*fp)(void), void* sp, int stk_size) -{ - (void)core; - return create_thread(fp, sp, stk_size); -} - void init_threads(void) { m = SDL_CreateMutex();