Index: apps/main.c
===================================================================
RCS file: /cvsroot/rockbox/apps/main.c,v
retrieving revision 1.191
diff -u -r1.191 main.c
--- apps/main.c	19 Oct 2006 09:42:18 -0000	1.191
+++ apps/main.c	25 Oct 2006 05:00:11 -0000
@@ -274,6 +274,9 @@
     /* 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();
 
@@ -515,9 +518,14 @@
    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
Index: firmware/kernel.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/kernel.c,v
retrieving revision 1.60
diff -u -r1.60 kernel.c
--- firmware/kernel.c	19 Oct 2006 11:43:13 -0000	1.60
+++ firmware/kernel.c	25 Oct 2006 05:00:11 -0000
@@ -45,10 +45,13 @@
     /* 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);
 }
@@ -379,28 +382,36 @@
     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;
@@ -521,6 +532,29 @@
     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)
@@ -532,6 +566,7 @@
     /* ...and lock it */
     m->locked = true;
 }
+#endif
 
 void mutex_unlock(struct mutex *m)
 {
Index: firmware/system.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/system.c,v
retrieving revision 1.124
diff -u -r1.124 system.c
--- firmware/system.c	12 Oct 2006 20:22:15 -0000	1.124
+++ firmware/system.c	25 Oct 2006 05:00:11 -0000
@@ -1223,34 +1223,62 @@
 
 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 @@
 {
     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;
-
-    /* Enable PLL? */
-    outl(inl(0x70000020) | (1<<30), 0x70000020);
-
-    /* Select 24MHz crystal as clock source? */
-    outl((inl(0x60006020) & 0x0fffff0f) | 0x20000020, 0x60006020);
+    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);
+
+        /* 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.
-
-       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.
-    */
-
-    /* unmask interrupt source */
-    CPU_INT_EN |= TIMER1_MASK;
+        /* 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 "|=".
+
+           It's not needed on the PP5021 and PP5022 ipods.
+        */
+
+        /* 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 @@
 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 @@
 
 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 @@
 {
     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;
-
-    outl(0x02, 0xcf005008);
-    outl(0x55, 0xcf00500c);
-    outl(0x6000, 0xcf005010);
-
-    /* Clock frequency = (24/8)*postmult */
-    outl(8, 0xcf005018);
-    outl(postmult, 0xcf00501c);
+    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);
+
+        /* 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 @@
 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
 }
Index: firmware/thread.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/thread.c,v
retrieving revision 1.67
diff -u -r1.67 thread.c
--- firmware/thread.c	15 Oct 2006 11:57:52 -0000	1.67
+++ firmware/thread.c	25 Oct 2006 05:00:11 -0000
@@ -349,10 +349,13 @@
 #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.
@@ -717,7 +720,8 @@
 {
     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;
Index: firmware/export/config.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/config.h,v
retrieving revision 1.84
diff -u -r1.84 config.h
--- firmware/export/config.h	15 Oct 2006 11:57:52 -0000	1.84
+++ firmware/export/config.h	25 Oct 2006 05:00:11 -0000
@@ -235,14 +235,8 @@
 #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
Index: firmware/export/pp5002.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/pp5002.h,v
retrieving revision 1.5
diff -u -r1.5 pp5002.h
--- firmware/export/pp5002.h	3 Aug 2006 16:29:42 -0000	1.5
+++ firmware/export/pp5002.h	25 Oct 2006 05:00:11 -0000
@@ -62,6 +62,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))
Index: firmware/export/pp5020.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/pp5020.h,v
retrieving revision 1.10
diff -u -r1.10 pp5020.h
--- firmware/export/pp5020.h	20 Sep 2006 23:21:58 -0000	1.10
+++ firmware/export/pp5020.h	25 Oct 2006 05:00:11 -0000
@@ -139,6 +139,12 @@
 #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
Index: firmware/target/arm/crt0-pp.S
===================================================================
RCS file: /cvsroot/rockbox/firmware/target/arm/crt0-pp.S,v
retrieving revision 1.1
diff -u -r1.1 crt0-pp.S
--- firmware/target/arm/crt0-pp.S	31 Aug 2006 19:45:05 -0000	1.1
+++ firmware/target/arm/crt0-pp.S	25 Oct 2006 05:00:12 -0000
@@ -285,6 +285,19 @@
     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 @@
     .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:
