From 82f9056988331572e01231d70fadc64b7ab76c6f Mon Sep 17 00:00:00 2001 From: Daniel Ankers Date: Sun, 4 Mar 2007 20:06:41 +0000 Subject: 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 --- firmware/backlight.c | 3 +- firmware/common/dircache.c | 3 +- firmware/drivers/ata.c | 3 +- firmware/drivers/ata_mmc.c | 3 +- firmware/drivers/lcd-16bit.c | 3 +- firmware/drivers/lcd-1bit-vert.c | 3 +- firmware/drivers/lcd-2bit-horz.c | 3 +- firmware/drivers/lcd-2bit-vert.c | 3 +- firmware/drivers/lcd-player.c | 3 +- firmware/drivers/lcd-remote-1bit-v.c | 3 +- firmware/drivers/lcd-remote-2bit-vi.c | 3 +- firmware/export/config.h | 39 ++-- firmware/export/pp5002.h | 3 + firmware/export/pp5020.h | 9 + firmware/export/thread.h | 9 +- firmware/kernel.c | 67 ++++-- firmware/mpeg.c | 3 +- firmware/pcm_record.c | 3 +- firmware/powermgmt.c | 3 +- firmware/system.c | 237 +++++++++++++--------- firmware/target/arm/crt0-pp.S | 17 ++ firmware/target/arm/sandisk/sansa-e200/ata-e200.c | 3 +- firmware/thread.c | 78 +++++-- firmware/usb.c | 3 +- 24 files changed, 340 insertions(+), 167 deletions(-) (limited to 'firmware') 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; - - /* 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); - - outl(-1, 0x60001038); - outl(-1, 0x60001028); - outl(-1, 0x6000101c); -#ifndef HAVE_ADJUSTABLE_CPU_FREQ - ipod_set_cpu_frequency(); + 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))); + + /* disable all irqs */ + outl(-1, 0x60001138); + outl(-1, 0x60001128); + outl(-1, 0x6000111c); + + 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; - - ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc))); - outl(-1, 0xcf00101c); - outl(-1, 0xcf001028); - outl(-1, 0xcf001038); + 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); #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 -- cgit v1.2.3