diff --git a/apps/main.c b/apps/main.c index fdc5c0f..50c77f7 100644 --- a/apps/main.c +++ b/apps/main.c @@ -271,6 +271,9 @@ #if defined(CONFIG_CHARGING) && (CONFIG_ /* 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(); @@ -511,9 +514,14 @@ void cop_main(void) so it should not be assumed that the coprocessor be usable even on platforms which support it. - At present all we do is send the COP to sleep if anything wakes it. */ + A kernel thread runs on the coprocessor, which just waits for other + threads to be added */ + + system_init(); + kernel_init(); + while(1) { - COP_CTL = PROC_SLEEP; + sleep(HZ); } } #endif diff --git a/apps/playback.c b/apps/playback.c index 370c7e4..c7200f6 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -173,12 +173,12 @@ #endif -static struct mutex mutex_codecthread; -static struct event_queue codec_callback_queue; +static struct mutex mutex_codecthread IDATA_ATTR; +static struct event_queue codec_callback_queue IDATA_ATTR; -static volatile bool audio_codec_loaded; -static volatile bool playing; -static volatile bool paused; +static volatile bool audio_codec_loaded IDATA_ATTR; +static volatile bool playing IDATA_ATTR; +static volatile bool paused IDATA_ATTR; /* Is file buffer currently being refilled? */ static volatile bool filling IDATA_ATTR; @@ -268,7 +268,7 @@ static void audio_reset_buffer(void); /* Codec thread */ extern struct codec_api ci; -static struct event_queue codec_queue; +static struct event_queue codec_queue IDATA_ATTR; static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] IBSS_ATTR; static const char codec_thread_name[] = "codec"; @@ -280,14 +280,14 @@ #ifdef PLAYBACK_VOICE extern struct codec_api ci_voice; static volatile bool voice_thread_start; -static volatile bool voice_is_playing; -static volatile bool voice_codec_loaded; +static volatile bool voice_is_playing IDATA_ATTR; +static volatile bool voice_codec_loaded IDATA_ATTR; static void (*voice_getmore)(unsigned char** start, int* size); static char *voicebuf; static size_t voice_remaining; static struct thread_entry *voice_thread_p = NULL; -static struct event_queue voice_queue; +static struct event_queue voice_queue IDATA_ATTR; static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] IBSS_ATTR; static const char voice_thread_name[] = "voice codec"; diff --git a/firmware/export/config.h b/firmware/export/config.h index 091de05..e5d681c 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -234,14 +234,8 @@ #if (CONFIG_CPU == PP5002) || (CONFIG_CP #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 #else #define NUM_CORES 1 #define CURRENT_CORE 0 diff --git a/firmware/export/pp5002.h b/firmware/export/pp5002.h index 59056e1..998ab73 100644 --- a/firmware/export/pp5002.h +++ b/firmware/export/pp5002.h @@ -62,6 +62,9 @@ #define DEV_EN (*(volatile unsigned long #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 be997e9..8bc9f3d 100644 --- a/firmware/export/pp5020.h +++ b/firmware/export/pp5020.h @@ -139,6 +139,12 @@ #define CPU_INT_EN (*(volatile uns #define CPU_HI_INT_EN (*(volatile unsigned long*)(0x60004124)) #define CPU_INT_CLR (*(volatile unsigned long*)(0x60004028)) #define CPU_HI_INT_CLR (*(volatile unsigned long*)(0x60004128)) +#define COP_INT_STAT (*(volatile unsigned long*)(0x60004004)) /* Guessed */ +#define COP_HI_INT_STAT (*(volatile unsigned long*)(0x60004104)) /* From IPL*/ +#define COP_INT_EN (*(volatile unsigned long*)(0x60004034)) /* Guessed */ +#define COP_HI_INT_EN (*(volatile unsigned long*)(0x60004134)) /* From IPL*/ +#define COP_INT_CLR (*(volatile unsigned long*)(0x60004038)) /* Guessed */ +#define COP_HI_INT_CLR (*(volatile unsigned long*)(0x60004138)) /* From IPL*/ #define TIMER1_IRQ 0 #define TIMER2_IRQ 1 diff --git a/firmware/kernel.c b/firmware/kernel.c index 6415f71..395339e 100644 --- a/firmware/kernel.c +++ b/firmware/kernel.c @@ -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); } @@ -366,28 +369,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; @@ -508,6 +519,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, 0); + } +} + +#else void mutex_lock(struct mutex *m) { if (m->locked) @@ -519,6 +553,7 @@ void mutex_lock(struct mutex *m) /* ...and lock it */ m->locked = true; } +#endif void mutex_unlock(struct mutex *m) { diff --git a/firmware/system.c b/firmware/system.c index 6ba5dc6..0197a5e 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -1223,34 +1223,62 @@ 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) /* TODO: this should really be in the target tree, but moving it there caused crt0.S not to find it while linking */ 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 */ @@ -1303,43 +1331,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) @@ -1363,21 +1395,24 @@ #endif void system_init(void) { #ifndef BOOTLOADER - /* 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 (CURRENT_CORE == CPU) + { + /* 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(); + ipod_set_cpu_frequency(); #endif + } ipod_init_cache(); #endif } @@ -1401,10 +1436,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 @@ -1453,29 +1496,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) @@ -1506,13 +1552,16 @@ #endif void system_init(void) { #ifndef BOOTLOADER - ipod_hw_rev = (*((volatile unsigned long*)(0x01fffffc))); - outl(-1, 0xcf00101c); - outl(-1, 0xcf001028); - outl(-1, 0xcf001038); + if (CURRENT_CORE == CPU) + { + 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 3bf2805..7badc69 100644 --- a/firmware/target/arm/crt0-pp.S +++ b/firmware/target/arm/crt0-pp.S @@ -285,6 +285,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 bl cop_main @@ -368,6 +381,10 @@ #endif .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/thread.c b/firmware/thread.c index 1662740..4eada84 100644 --- a/firmware/thread.c +++ b/firmware/thread.c @@ -338,10 +338,13 @@ #ifdef CPU_COLDFIRE #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 == TCC730 /* Sleep mode is triggered by the SYS instr on CalmRisc16. * Unfortunately, the manual doesn't specify which arg to use. @@ -690,7 +693,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;