Dual core support for PP502x players (iPod G4 and later, iriver h10, Sansa - iPod G3 will be coming soon.) This allows threads to be run on either core provided that all communications between the cores is done using uncached memory. There should be no significant change in battery life from doing this. Documentation (on the RockboxKernel wiki page) will follow shortly.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12601 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Daniel Ankers 2007-03-04 20:06:41 +00:00
parent 74e572c9d6
commit 82f9056988
38 changed files with 379 additions and 211 deletions

View file

@ -123,7 +123,7 @@ struct codec_api ci = {
&current_tick, &current_tick,
default_event_handler, default_event_handler,
default_event_handler_ex, default_event_handler_ex,
create_thread_on_core, create_thread,
remove_thread, remove_thread,
reset_poweroff_timer, reset_poweroff_timer,
#ifndef SIMULATOR #ifndef SIMULATOR

View file

@ -199,9 +199,10 @@ struct codec_api {
long* current_tick; long* current_tick;
long (*default_event_handler)(long event); long (*default_event_handler)(long event);
long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); 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 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 (*remove_thread)(struct thread_entry *thread);
void (*reset_poweroff_timer)(void); void (*reset_poweroff_timer)(void);
#ifndef SIMULATOR #ifndef SIMULATOR

View file

@ -296,6 +296,9 @@ static void init(void)
#if CONFIG_CHARGING && (CONFIG_CPU == SH7034) #if CONFIG_CHARGING && (CONFIG_CPU == SH7034)
/* if nobody initialized ATA before, I consider this a cold start */ /* if nobody initialized ATA before, I consider this a cold start */
bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */ bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */
#endif
#ifdef CPU_PP
COP_CTL = PROC_WAKE;
#endif #endif
system_init(); system_init();
kernel_init(); kernel_init();
@ -549,19 +552,22 @@ void cop_main(void)
so it should not be assumed that the coprocessor be usable even on so it should not be assumed that the coprocessor be usable even on
platforms which support it. platforms which support it.
At present the COP sleeps unless it receives a message from the CPU telling A kernel thread runs on the coprocessor which waits for other threads to be
it that we are loading a new kernel, so must reboot */ added, and gracefully handles RoLo */
#if CONFIG_CPU == PP5002 #if CONFIG_CPU == PP5002
/* 3G doesn't have Rolo support yet */ /* 3G doesn't have Rolo or dual core support yet */
while(1) { while(1) {
COP_CTL = PROC_SLEEP; COP_CTL = PROC_SLEEP;
} }
#else #else
extern volatile unsigned char cpu_message; extern volatile unsigned char cpu_message;
system_init();
kernel_init();
while(cpu_message != COP_REBOOT) { while(cpu_message != COP_REBOOT) {
COP_CTL = PROC_SLEEP; sleep(HZ);
} }
rolo_restart_cop(); rolo_restart_cop();
#endif /* PP5002 */ #endif /* PP5002 */

View file

@ -194,9 +194,9 @@ static bool audio_is_initialized = false;
/* TBD: Split out "audio" and "playback" (ie. calling) threads */ /* TBD: Split out "audio" and "playback" (ie. calling) threads */
/* Main state control */ /* Main state control */
static volatile bool audio_codec_loaded; /* Is codec loaded? (C/A-) */ static volatile bool audio_codec_loaded NOCACHEBSS_ATTR;/* Codec loaded? (C/A-) */
static volatile bool playing; /* Is audio playing? (A) */ static volatile bool playing NOCACHEBSS_ATTR; /* Is audio playing? (A) */
static volatile bool paused; /* Is audio paused? (A/C-) */ static volatile bool paused NOCACHEBSS_ATTR; /* Is audio paused? (A/C-) */
static volatile bool filling IDATA_ATTR; /* Is file buffer refilling? (A/C-) */ static volatile bool filling IDATA_ATTR; /* Is file buffer refilling? (A/C-) */
/* Ring buffer where compressed audio and codecs are loaded */ /* Ring buffer where compressed audio and codecs are loaded */
@ -290,7 +290,7 @@ static void audio_reset_buffer(size_t pcmbufsize);
/* Codec thread */ /* Codec thread */
extern struct codec_api ci; 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)] static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
IBSS_ATTR; IBSS_ATTR;
static const char codec_thread_name[] = "codec"; 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; extern struct codec_api ci_voice;
static struct thread_entry *voice_thread_p = NULL; 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)] static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
IBSS_ATTR_VOICE_STACK; IBSS_ATTR_VOICE_STACK;
static const char voice_thread_name[] = "voice codec"; 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 */ /* Pointer to DRAM buffers for normal/voice codecs */
static unsigned char *dram_buf[2] = { NULL, NULL }; static unsigned char *dram_buf[2] = { NULL, NULL };
/* Mutex to control which codec (normal/voice) is running */ /* Mutex to control which codec (normal/voice) is running */
static struct mutex mutex_codecthread; static struct mutex mutex_codecthread NOCACHEBSS_ATTR;
/* Voice state */ /* Voice state */
static volatile bool voice_thread_start; /* Triggers voice playback (A/V) */ 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_is_playing NOCACHEBSS_ATTR; /* Is voice currently playing? (V) */
static volatile bool voice_codec_loaded; /* Is voice codec loaded (V/A-) */ static volatile bool voice_codec_loaded NOCACHEBSS_ATTR; /* Is voice codec loaded (V/A-) */
static char *voicebuf; static char *voicebuf;
static size_t voice_remaining; static size_t voice_remaining;
@ -863,7 +863,8 @@ void audio_preinit(void)
queue_init(&codec_queue, true); queue_init(&codec_queue, true);
create_thread(audio_thread, audio_stack, sizeof(audio_stack), 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) void audio_init(void)
@ -888,7 +889,7 @@ void voice_init(void)
queue_init(&voice_queue, true); queue_init(&voice_queue, true);
voice_thread_p = create_thread(voice_thread, voice_stack, voice_thread_p = create_thread(voice_thread, voice_stack,
sizeof(voice_stack), voice_thread_name sizeof(voice_stack), voice_thread_name
IF_PRIO(, PRIORITY_PLAYBACK)); IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU, false));
while (!voice_codec_loaded) while (!voice_codec_loaded)
yield(); yield();
@ -3533,7 +3534,8 @@ static void audio_playback_init(void)
codec_thread_p = create_thread( codec_thread_p = create_thread(
codec_thread, codec_stack, sizeof(codec_stack), 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) while (1)
{ {

View file

@ -1873,7 +1873,8 @@ void playlist_init(void)
memset(playlist->filenames, 0, memset(playlist->filenames, 0,
playlist->max_playlist_size * sizeof(int)); playlist->max_playlist_size * sizeof(int));
create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), 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); queue_init(&playlist_queue, true);
#endif #endif
} }

View file

@ -481,7 +481,6 @@ static const struct plugin_api rockbox_api = {
sound_default, sound_default,
pcm_record_more, pcm_record_more,
#endif #endif
create_thread_on_core,
#ifdef IRIVER_H100_SERIES #ifdef IRIVER_H100_SERIES
/* Routines for the iriver_flash -plugin. */ /* Routines for the iriver_flash -plugin. */

View file

@ -327,7 +327,8 @@ struct plugin_api {
long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
struct thread_entry* (*create_thread)(void (*function)(void), void* stack, struct thread_entry* (*create_thread)(void (*function)(void), void* stack,
int stack_size, const char *name 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 (*remove_thread)(struct thread_entry *thread);
void (*reset_poweroff_timer)(void); void (*reset_poweroff_timer)(void);
#ifndef SIMULATOR #ifndef SIMULATOR
@ -595,11 +596,6 @@ struct plugin_api {
void (*pcm_record_more)(void *start, size_t size); void (*pcm_record_more)(void *start, size_t size);
#endif #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 #ifdef IRIVER_H100_SERIES
/* Routines for the iriver_flash -plugin. */ /* Routines for the iriver_flash -plugin. */
bool (*detect_original_firmware)(void); bool (*detect_original_firmware)(void);

View file

@ -1171,7 +1171,8 @@ int main(void* parameter)
rb->memset(&gTread, 0, sizeof(gTread)); rb->memset(&gTread, 0, sizeof(gTread));
gTread.foreground = true; gTread.foreground = true;
rb->create_thread(thread, stack, stacksize, "CDC" rb->create_thread(thread, stack, stacksize, "CDC"
IF_PRIO(, PRIORITY_BACKGROUND)); IF_PRIO(, PRIORITY_BACKGROUND)
IF_COP(, CPU, false));
#ifdef DEBUG #ifdef DEBUG
do do

View file

@ -479,7 +479,8 @@ int main(void)
rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */ rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
if(rb->create_thread(thread, thread_stack, if(rb->create_thread(thread, thread_stack,
sizeof(thread_stack), "Battery Benchmark" 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!"); rb->splash(HZ,true,"Cannot create thread!");
return PLUGIN_ERROR; return PLUGIN_ERROR;

View file

@ -909,19 +909,17 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
videostatus = STREAM_PLAYING; videostatus = STREAM_PLAYING;
/* We put the video thread on the second processor for multi-core targets. */ /* 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, if ((videothread_id = rb->create_thread(decode_mpeg2,
#endif (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK)
(uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK))) == NULL) IF_COP(, COP, true))) == NULL)
{ {
rb->splash(HZ,true,"Cannot create video thread!"); rb->splash(HZ,true,"Cannot create video thread!");
return PLUGIN_ERROR; return PLUGIN_ERROR;
} }
if ((audiothread_id = rb->create_thread(mad_decode, 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->splash(HZ,true,"Cannot create audio thread!");
rb->remove_thread(videothread_id); rb->remove_thread(videothread_id);

View file

@ -3941,7 +3941,8 @@ void tagcache_init(void)
queue_init(&tagcache_queue, true); queue_init(&tagcache_queue, true);
create_thread(tagcache_thread, tagcache_stack, create_thread(tagcache_thread, tagcache_stack,
sizeof(tagcache_stack), tagcache_thread_name sizeof(tagcache_stack), tagcache_thread_name
IF_PRIO(, PRIORITY_BACKGROUND)); IF_PRIO(, PRIORITY_BACKGROUND)
IF_COP(, CPU, false));
#else #else
tc_stat.initialized = true; tc_stat.initialized = true;
allocate_tempbuf(); allocate_tempbuf();

View file

@ -431,7 +431,8 @@ Kernel
SYS_USB_CONNECTED. Else do nothing and return 0. SYS_USB_CONNECTED. Else do nothing and return 0.
int create_thread(void* function, void* stack, int stack_size, 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. Create a thread.
??? (see firmware/thread.c:145) ??? (see firmware/thread.c:145)

View file

@ -582,7 +582,8 @@ void backlight_init(void)
create_thread(backlight_thread, backlight_stack, create_thread(backlight_thread, backlight_stack,
sizeof(backlight_stack), backlight_thread_name sizeof(backlight_stack), backlight_thread_name
IF_PRIO(, PRIORITY_SYSTEM)); IF_PRIO(, PRIORITY_SYSTEM)
IF_COP(, CPU, false));
tick_add_task(backlight_tick); tick_add_task(backlight_tick);
} }

View file

@ -701,7 +701,8 @@ void dircache_init(void)
queue_init(&dircache_queue, true); queue_init(&dircache_queue, true);
create_thread(dircache_thread, dircache_stack, 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));
} }
/** /**

View file

@ -991,7 +991,8 @@ int ata_init(void)
last_disk_activity = current_tick; last_disk_activity = current_tick;
create_thread(ata_thread, ata_stack, create_thread(ata_thread, ata_stack,
sizeof(ata_stack), ata_thread_name sizeof(ata_stack), ata_thread_name
IF_PRIO(, PRIORITY_SYSTEM)); IF_PRIO(, PRIORITY_SYSTEM)
IF_COP(, CPU, false));
initialized = true; initialized = true;
} }

View file

@ -1173,7 +1173,8 @@ int ata_init(void)
queue_init(&mmc_queue, true); queue_init(&mmc_queue, true);
create_thread(mmc_thread, mmc_stack, 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); tick_add_task(mmc_tick);
initialized = true; initialized = true;
} }

View file

@ -89,7 +89,8 @@ void lcd_init(void)
create_thread(scroll_thread, scroll_stack, create_thread(scroll_thread, scroll_stack,
sizeof(scroll_stack), scroll_name sizeof(scroll_stack), scroll_name
IF_PRIO(, PRIORITY_USER_INTERFACE)); IF_PRIO(, PRIORITY_USER_INTERFACE)
IF_COP(, CPU, false));
} }
/*** parameter handling ***/ /*** parameter handling ***/

View file

@ -68,7 +68,8 @@ void lcd_init(void)
/* Call device specific init */ /* Call device specific init */
lcd_init_device(); lcd_init_device();
create_thread(scroll_thread, scroll_stack, 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 ***/ /*** parameter handling ***/

View file

@ -79,7 +79,8 @@ void lcd_init(void)
/* Call device specific init */ /* Call device specific init */
lcd_init_device(); lcd_init_device();
create_thread(scroll_thread, scroll_stack, 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 ***/ /*** parameter handling ***/

View file

@ -82,7 +82,8 @@ void lcd_init(void)
/* Call device specific init */ /* Call device specific init */
lcd_init_device(); lcd_init_device();
create_thread(scroll_thread, scroll_stack, 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 ***/ /*** parameter handling ***/

View file

@ -610,7 +610,8 @@ void lcd_init (void)
lcd_set_contrast(lcd_default_contrast()); lcd_set_contrast(lcd_default_contrast());
create_thread(scroll_thread, scroll_stack, 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 */ void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */

View file

@ -903,5 +903,6 @@ void lcd_remote_init(void)
queue_init(&remote_scroll_queue, false); queue_init(&remote_scroll_queue, false);
#endif #endif
create_thread(scroll_thread, scroll_stack, 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));
} }

View file

@ -1241,5 +1241,6 @@ void lcd_remote_init(void)
queue_init(&remote_scroll_queue, false); queue_init(&remote_scroll_queue, false);
#endif #endif
create_thread(scroll_thread, scroll_stack, 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));
} }

View file

@ -273,21 +273,6 @@
/* define for all cpus from PP family */ /* define for all cpus from PP family */
#if (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020) || (CONFIG_CPU == PP5024) #if (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020) || (CONFIG_CPU == PP5024)
#define CPU_PP #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 #endif
/* define for all cpus from ARM family */ /* define for all cpus from ARM family */
@ -348,4 +333,28 @@
#define IRAM_LCDFRAMEBUFFER #define IRAM_LCDFRAMEBUFFER
#endif #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 #endif

View file

@ -73,6 +73,9 @@
#define CPU_INT_STAT (*(volatile unsigned long*)(0xcf001000)) #define CPU_INT_STAT (*(volatile unsigned long*)(0xcf001000))
#define CPU_INT_EN (*(volatile unsigned long*)(0xcf001024)) #define CPU_INT_EN (*(volatile unsigned long*)(0xcf001024))
#define CPU_INT_CLR (*(volatile unsigned long*)(0xcf001028)) #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 USB2D_IDENT (*(volatile unsigned long*)(0xc5000000))
#define USB_STATUS (*(volatile unsigned long*)(0xc50001a4)) #define USB_STATUS (*(volatile unsigned long*)(0xc50001a4))

View file

@ -30,6 +30,15 @@
#define PROC_ID_CPU 0x55 #define PROC_ID_CPU 0x55
#define PROC_ID_COP 0xaa #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 */ /* Interrupts */
#define CPU_INT_STAT (*(volatile unsigned long*)(0x64004000)) #define CPU_INT_STAT (*(volatile unsigned long*)(0x64004000))
#define COP_INT_STAT (*(volatile unsigned long*)(0x60004004)) #define COP_INT_STAT (*(volatile unsigned long*)(0x60004004))

View file

@ -124,13 +124,8 @@ struct core_entry {
struct thread_entry* struct thread_entry*
create_thread(void (*function)(void), void* stack, int stack_size, create_thread(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));
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 HAVE_SCHEDULER_BOOSTCTRL #ifdef HAVE_SCHEDULER_BOOSTCTRL
void trigger_cpu_boost(void); void trigger_cpu_boost(void);

View file

@ -26,7 +26,7 @@
#include "panic.h" #include "panic.h"
#if !defined(CPU_PP) || !defined(BOOTLOADER) #if !defined(CPU_PP) || !defined(BOOTLOADER)
long current_tick = 0; long current_tick NOCACHEDATA_ATTR = 0;
#endif #endif
static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
@ -45,10 +45,13 @@ void kernel_init(void)
/* Init the threading API */ /* Init the threading API */
init_threads(); init_threads();
if(CURRENT_CORE == CPU)
{
memset(tick_funcs, 0, sizeof(tick_funcs)); memset(tick_funcs, 0, sizeof(tick_funcs));
num_queues = 0; num_queues = 0;
memset(all_queues, 0, sizeof(all_queues)); memset(all_queues, 0, sizeof(all_queues));
}
tick_start(1000/HZ); tick_start(1000/HZ);
} }
@ -496,7 +499,9 @@ void TIMER1(void)
int i; int i;
TIMER1_VAL; /* Read value to ack IRQ */ TIMER1_VAL; /* Read value to ack IRQ */
/* Run through the list of tick tasks */ /* Run through the list of tick tasks (using main core) */
if (CURRENT_CORE == CPU)
{
for (i = 0;i < MAX_NUM_TICK_TASKS;i++) for (i = 0;i < MAX_NUM_TICK_TASKS;i++)
{ {
if (tick_funcs[i]) if (tick_funcs[i])
@ -507,17 +512,23 @@ void TIMER1(void)
current_tick++; current_tick++;
} }
}
#endif #endif
void tick_start(unsigned int interval_in_ms) void tick_start(unsigned int interval_in_ms)
{ {
#ifndef BOOTLOADER #ifndef BOOTLOADER
if(CURRENT_CORE == CPU)
{
TIMER1_CFG = 0x0; TIMER1_CFG = 0x0;
TIMER1_VAL; TIMER1_VAL;
/* enable timer */ /* enable timer */
TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1); TIMER1_CFG = 0xc0000000 | (interval_in_ms*1000 - 1);
/* unmask interrupt source */ /* unmask interrupt source */
CPU_INT_EN = TIMER1_MASK; CPU_INT_EN = TIMER1_MASK;
} else {
COP_INT_EN = TIMER1_MASK;
}
#else #else
/* We don't enable interrupts in the bootloader */ /* We don't enable interrupts in the bootloader */
(void)interval_in_ms; (void)interval_in_ms;
@ -645,6 +656,29 @@ void mutex_init(struct mutex *m)
m->thread = NULL; 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) void mutex_lock(struct mutex *m)
{ {
if (m->locked) if (m->locked)
@ -656,6 +690,7 @@ void mutex_lock(struct mutex *m)
/* ...and lock it */ /* ...and lock it */
m->locked = true; m->locked = true;
} }
#endif
void mutex_unlock(struct mutex *m) void mutex_unlock(struct mutex *m)
{ {

View file

@ -2905,7 +2905,8 @@ void audio_init(void)
queue_init(&mpeg_queue, true); queue_init(&mpeg_queue, true);
#endif /* !SIMULATOR */ #endif /* !SIMULATOR */
create_thread(mpeg_thread, mpeg_stack, 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); memset(trackdata, sizeof(trackdata), 0);

View file

@ -418,7 +418,8 @@ void pcm_rec_init(void)
queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send); queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send);
pcmrec_thread_p = pcmrec_thread_p =
create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), 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 */ } /* pcm_rec_init */
/** audio_* group **/ /** audio_* group **/

View file

@ -1245,7 +1245,8 @@ void powermgmt_init(void)
/* init history to 0 */ /* init history to 0 */
memset(power_history, 0x00, sizeof(power_history)); memset(power_history, 0x00, sizeof(power_history));
create_thread(power_thread, power_stack, sizeof(power_stack), 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 */ #endif /* SIMULATOR */

View file

@ -611,6 +611,8 @@ extern void TIMER2(void);
extern void ipod_mini_button_int(void); extern void ipod_mini_button_int(void);
void irq(void) void irq(void)
{
if(CURRENT_CORE == CPU)
{ {
if (CPU_INT_STAT & TIMER1_MASK) if (CPU_INT_STAT & TIMER1_MASK)
TIMER1(); TIMER1();
@ -618,6 +620,14 @@ void irq(void)
TIMER2(); TIMER2();
else if (CPU_HI_INT_STAT & GPIO_MASK) else if (CPU_HI_INT_STAT & GPIO_MASK)
ipod_mini_button_int(); 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) \ #elif (defined IRIVER_H10) || (defined IRIVER_H10_5GB) || defined(ELIO_TPJ1022) \
|| (defined SANSA_E200) || (defined SANSA_E200)
@ -625,16 +635,26 @@ void irq(void)
crt0.S not to find it while linking */ crt0.S not to find it while linking */
/* TODO: Even if it isn't in the target tree, this should be the default case */ /* TODO: Even if it isn't in the target tree, this should be the default case */
void irq(void) void irq(void)
{
if(CURRENT_CORE == CPU)
{ {
if (CPU_INT_STAT & TIMER1_MASK) if (CPU_INT_STAT & TIMER1_MASK)
TIMER1(); TIMER1();
else if (CPU_INT_STAT & TIMER2_MASK) else if (CPU_INT_STAT & TIMER2_MASK)
TIMER2(); TIMER2();
} else {
if (COP_INT_STAT & TIMER1_MASK)
TIMER1();
else if (COP_INT_STAT & TIMER2_MASK)
TIMER2();
}
} }
#else #else
extern void ipod_4g_button_int(void); extern void ipod_4g_button_int(void);
void irq(void) void irq(void)
{
if(CURRENT_CORE == CPU)
{ {
if (CPU_INT_STAT & TIMER1_MASK) if (CPU_INT_STAT & TIMER1_MASK)
TIMER1(); TIMER1();
@ -642,6 +662,14 @@ void irq(void)
TIMER2(); TIMER2();
else if (CPU_HI_INT_STAT & I2C_MASK) else if (CPU_HI_INT_STAT & I2C_MASK)
ipod_4g_button_int(); 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
#endif /* BOOTLOADER */ #endif /* BOOTLOADER */
@ -694,6 +722,8 @@ void set_cpu_frequency(long frequency)
{ {
unsigned long postmult; unsigned long postmult;
if (CURRENT_CORE == CPU)
{
if (frequency == CPUFREQ_NORMAL) if (frequency == CPUFREQ_NORMAL)
postmult = CPUFREQ_NORMAL_MULT; postmult = CPUFREQ_NORMAL_MULT;
else if (frequency == CPUFREQ_MAX) else if (frequency == CPUFREQ_MAX)
@ -730,8 +760,10 @@ void set_cpu_frequency(long frequency)
/* unmask interrupt source */ /* unmask interrupt source */
CPU_INT_EN |= TIMER1_MASK; CPU_INT_EN |= TIMER1_MASK;
COP_INT_EN |= TIMER1_MASK;
#endif #endif
} }
}
#elif !defined(BOOTLOADER) #elif !defined(BOOTLOADER)
void ipod_set_cpu_frequency(void) void ipod_set_cpu_frequency(void)
{ {
@ -754,6 +786,8 @@ void ipod_set_cpu_frequency(void)
void system_init(void) void system_init(void)
{ {
#ifndef BOOTLOADER #ifndef BOOTLOADER
if (CURRENT_CORE == CPU)
{
/* Remap the flash ROM from 0x00000000 to 0x20000000. */ /* Remap the flash ROM from 0x00000000 to 0x20000000. */
MMAP3_LOGICAL = 0x20000000 | 0x3a00; MMAP3_LOGICAL = 0x20000000 | 0x3a00;
MMAP3_PHYSICAL = 0x00000000 | 0x3f84; MMAP3_PHYSICAL = 0x00000000 | 0x3f84;
@ -770,8 +804,15 @@ void system_init(void)
outl(-1, 0x60001038); outl(-1, 0x60001038);
outl(-1, 0x60001028); outl(-1, 0x60001028);
outl(-1, 0x6000101c); outl(-1, 0x6000101c);
#ifndef HAVE_ADJUSTABLE_CPU_FREQ #if (!defined HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES == 1)
ipod_set_cpu_frequency(); ipod_set_cpu_frequency();
#endif
}
#if (!defined HAVE_ADJUSTABLE_CPU_FREQ) && (NUM_CORES > 1)
else
{
ipod_set_cpu_frequency();
}
#endif #endif
ipod_init_cache(); ipod_init_cache();
#endif #endif
@ -795,11 +836,19 @@ extern void TIMER1(void);
extern void TIMER2(void); extern void TIMER2(void);
void irq(void) void irq(void)
{
if(CURRENT_CORE == CPU)
{ {
if (CPU_INT_STAT & TIMER1_MASK) if (CPU_INT_STAT & TIMER1_MASK)
TIMER1(); TIMER1();
else if (CPU_INT_STAT & TIMER2_MASK) else if (CPU_INT_STAT & TIMER2_MASK)
TIMER2(); TIMER2();
} else {
if (COP_INT_STAT & TIMER1_MASK)
TIMER1();
else if (COP_INT_STAT & TIMER2_MASK)
TIMER2();
}
} }
#endif #endif
@ -848,6 +897,8 @@ void set_cpu_frequency(long frequency)
{ {
unsigned long postmult; unsigned long postmult;
if (CURRENT_CORE == CPU)
{
if (frequency == CPUFREQ_NORMAL) if (frequency == CPUFREQ_NORMAL)
postmult = CPUFREQ_NORMAL_MULT; postmult = CPUFREQ_NORMAL_MULT;
else if (frequency == CPUFREQ_MAX) else if (frequency == CPUFREQ_MAX)
@ -872,6 +923,7 @@ void set_cpu_frequency(long frequency)
/* Select PLL as clock source? */ /* Select PLL as clock source? */
outl(0xa8, 0xcf00500c); outl(0xa8, 0xcf00500c);
} }
}
#elif !defined(BOOTLOADER) #elif !defined(BOOTLOADER)
static void ipod_set_cpu_speed(void) static void ipod_set_cpu_speed(void)
{ {
@ -901,6 +953,8 @@ static void ipod_set_cpu_speed(void)
void system_init(void) void system_init(void)
{ {
#ifndef BOOTLOADER #ifndef BOOTLOADER
if (CURRENT_CORE == CPU)
{
/* Remap the flash ROM from 0x00000000 to 0x20000000. */ /* Remap the flash ROM from 0x00000000 to 0x20000000. */
MMAP3_LOGICAL = 0x20000000 | 0x3a00; MMAP3_LOGICAL = 0x20000000 | 0x3a00;
MMAP3_PHYSICAL = 0x00000000 | 0x3f84; MMAP3_PHYSICAL = 0x00000000 | 0x3f84;
@ -912,6 +966,7 @@ void system_init(void)
#ifndef HAVE_ADJUSTABLE_CPU_FREQ #ifndef HAVE_ADJUSTABLE_CPU_FREQ
ipod_set_cpu_speed(); ipod_set_cpu_speed();
#endif #endif
}
ipod_init_cache(); ipod_init_cache();
#endif #endif
} }

View file

@ -222,6 +222,19 @@ cop_init:
strhi r4, [r2], #4 strhi r4, [r2], #4
bhi 2b 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 ldr sp, =cop_stackend
/* Run cop_main() in apps/main.c */ /* Run cop_main() in apps/main.c */
@ -307,6 +320,10 @@ UIE:
.space 256*4 .space 256*4
irq_stack: irq_stack:
/* 256 words of COP IRQ stack */
.space 256*4
cop_irq_stack:
/* 256 words of FIQ stack */ /* 256 words of FIQ stack */
.space 256*4 .space 256*4
fiq_stack: fiq_stack:

View file

@ -687,7 +687,8 @@ int ata_init(void)
{ {
queue_init(&sd_queue, true); queue_init(&sd_queue, true);
create_thread(sd_thread, sd_stack, 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; initialized = true;
} }

View file

@ -64,6 +64,10 @@ int *cop_stackend = stackend;
#endif #endif
#endif #endif
#if (NUM_CORES > 1)
bool IDATA_ATTR kernel_running_on_cop = false;
#endif
/* Conserve IRAM /* Conserve IRAM
static void add_to_list(struct thread_entry **list, static void add_to_list(struct thread_entry **list,
struct thread_entry *thread) ICODE_ATTR; struct thread_entry *thread) ICODE_ATTR;
@ -316,10 +320,13 @@ static inline void sleep_core(void)
#elif CONFIG_CPU == SH7034 #elif CONFIG_CPU == SH7034
and_b(0x7F, &SBYCR); and_b(0x7F, &SBYCR);
asm volatile ("sleep"); asm volatile ("sleep");
#elif CONFIG_CPU == PP5020 #elif defined (CPU_PP)
/* This should sleep the CPU. It appears to wake by itself on /* This should sleep the CPU. It appears to wake by itself on
interrupts */ interrupts */
CPU_CTL = 0x80000000; if (CURRENT_CORE == CPU)
CPU_CTL = PROC_SLEEP;
else
COP_CTL = PROC_SLEEP;
#elif CONFIG_CPU == S3C2440 #elif CONFIG_CPU == S3C2440
CLKCON |= (1 << 2); /* set IDLE bit */ CLKCON |= (1 << 2); /* set IDLE bit */
for(i=0; i<10; i++); /* wait for IDLE */ 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. * Create a thread
* Return ID if context area could be allocated, else -1. * 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* struct thread_entry*
create_thread(void (*function)(void), void* stack, int stack_size, create_thread(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))
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))
{ {
unsigned int i; unsigned int i;
unsigned int stacklen; unsigned int stacklen;
@ -637,6 +633,29 @@ struct thread_entry*
struct regs *regs; struct regs *regs;
struct thread_entry *thread; 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++) for (n = 0; n < MAXTHREADS; n++)
{ {
if (cores[core].threads[n].name == NULL) if (cores[core].threads[n].name == NULL)
@ -644,8 +663,15 @@ struct thread_entry*
} }
if (n == MAXTHREADS) if (n == MAXTHREADS)
{
#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; return NULL;
}
/* Munge the stack to make it easy to spot stack overflows */ /* Munge the stack to make it easy to spot stack overflows */
stacklen = stack_size / sizeof(int); stacklen = stack_size / sizeof(int);
@ -677,6 +703,9 @@ struct thread_entry*
THREAD_CPU_INIT(core, thread); THREAD_CPU_INIT(core, thread);
return thread; return thread;
#if NUM_CORES == 1
#undef core
#endif
} }
#ifdef HAVE_SCHEDULER_BOOSTCTRL #ifdef HAVE_SCHEDULER_BOOSTCTRL
@ -751,6 +780,7 @@ void init_threads(void)
{ {
unsigned int core = CURRENT_CORE; unsigned int core = CURRENT_CORE;
if (core == CPU)
memset(cores, 0, sizeof cores); memset(cores, 0, sizeof cores);
cores[core].sleeping = NULL; cores[core].sleeping = NULL;
cores[core].running = NULL; cores[core].running = NULL;
@ -779,6 +809,10 @@ void init_threads(void)
#endif #endif
} }
cores[core].threads[0].context.start = 0; /* thread 0 already running */ 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) int thread_stack_usage(const struct thread_entry *thread)

View file

@ -428,7 +428,8 @@ void usb_init(void)
#ifndef BOOTLOADER #ifndef BOOTLOADER
queue_init(&usb_queue, true); queue_init(&usb_queue, true);
create_thread(usb_thread, usb_stack, sizeof(usb_stack), 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); tick_add_task(usb_tick);
#endif #endif

View file

@ -258,12 +258,6 @@ void remove_thread(int threadnum)
(void)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 */ /* assure an unused place to direct virtual pointers to */
#define VIRT_SIZE 0xFFFF /* more than enough for our string ID range */ #define VIRT_SIZE 0xFFFF /* more than enough for our string ID range */
unsigned char vp_dummy[VIRT_SIZE]; unsigned char vp_dummy[VIRT_SIZE];

View file

@ -75,12 +75,6 @@ int create_thread(void (*fp)(void), void* sp, int stk_size)
return 0; 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) void init_threads(void)
{ {
m = SDL_CreateMutex(); m = SDL_CreateMutex();