Index: apps/codecs.c
===================================================================
--- apps/codecs.c	(revision 12086)
+++ apps/codecs.c	(working copy)
@@ -63,6 +63,13 @@
 extern unsigned char codecbuf[];
 #endif
 
+#if (NUM_CORES > 1)
+void codec_yield(void) {}
+#define CODEC_YIELD codec_yield
+#else
+#define CODEC_YIELD yield
+#endif
+
 extern void* plugin_get_audio_buffer(int *buffer_size);
 
 struct codec_api ci_voice;
@@ -120,7 +127,7 @@
 
     /* kernel/ system */
     PREFIX(sleep),
-    yield,
+    CODEC_YIELD,
     &current_tick,
     default_event_handler,
     default_event_handler_ex,
Index: apps/settings.c
===================================================================
--- apps/settings.c	(revision 12086)
+++ apps/settings.c	(working copy)
@@ -416,9 +416,6 @@
 #endif
     /* disk */
 #ifndef HAVE_MMC
-#ifdef HAVE_ATA_POWER_OFF
-    {1, S_O(disk_poweroff), false, "disk poweroff", off_on },
-#endif
     {8, S_O(disk_spindown), 5, "disk spindown", NULL },
 #endif /* HAVE_MMC */
 
@@ -1192,9 +1189,6 @@
     dac_line_in(global_settings.line_in);
 #endif
     mpeg_id3_options(global_settings.id3_v1_first);
-#ifdef HAVE_ATA_POWER_OFF
-    ata_poweroff(global_settings.disk_poweroff);
-#endif
 
     set_poweroff_timeout(global_settings.poweroff);
 
Index: apps/lang/english.lang
===================================================================
--- apps/lang/english.lang	(revision 12086)
+++ apps/lang/english.lang	(working copy)
@@ -3850,16 +3850,16 @@
 </phrase>
 <phrase>
   id: LANG_POWEROFF
-  desc: disk poweroff flag
+  desc: DEPRECATED
   user:
   <source>
-    *: "Disk Poweroff"
+    *: ""
   </source>
   <dest>
-    *: "Disk Poweroff"
+    *: deprecated
   </dest>
   <voice>
-    *: "Disk Poweroff"
+    *: ""
   </voice>
 </phrase>
 <phrase>
Index: apps/gui/gwps-common.c
===================================================================
--- apps/gui/gwps-common.c	(revision 12086)
+++ apps/gui/gwps-common.c	(working copy)
@@ -179,13 +179,17 @@
 
         case 'P':
             /* progress bar image */
+        case 'S':
+            /* Progress slider */
         {
             int ret = 0;
             char *ptr = buf+2;
             char *pos = NULL;
             char imgname[MAX_PATH];
 
-            /* format: %P|filename.bmp| */
+            /* format: %P|filename.bmp|
+                    or %S|filename.bmp| */
+
             {
                 /* get filename */
                 pos = strchr(ptr, '|');
@@ -209,29 +213,26 @@
                 ret = read_bmp_file(imgname, &data->progressbar.bm,
                                     data->img_buf_free,
                                     FORMAT_ANY|FORMAT_TRANSPARENT);
-                        
+
                 if (ret > 0)
                 {
 #if LCD_DEPTH == 16
                      if (ret % 2) ret++; 
                      /* Always consume an even number of bytes */
 #endif
-
                      data->img_buf_ptr += ret;
                      data->img_buf_free -= ret;
 
                      if (data->progressbar.bm.width <= LCD_WIDTH) {
-                          data->progressbar.have_bitmap_pb=true;
+                          data->progressbar.pb_type = c=='P' ? BITMAP : SLIDER;
                           return true;
                      } else
                           return false;
                 }
-                
             }
         }
+        break;
 
-        break;
-        
         case 'x':
             /* Preload images so the %xd# tag can display it */
         {
@@ -1823,7 +1824,7 @@
                 if (!data->progress_end)
                     data->progress_end=display->width;
                 
-                if (gwps->data->progressbar.have_bitmap_pb)
+                if (gwps->data->progressbar.pb_type == BITMAP)
                     gui_bitmap_scrollbar_draw(display, data->progressbar.bm,
                                         data->progress_start, sb_y, 
                                         data->progress_end-data->progress_start,
@@ -1831,6 +1832,12 @@
                                         state->id3->length?state->id3->length:1, 0,
                                         state->id3->length?state->id3->elapsed + state->ff_rewind_count:0,
                                         HORIZONTAL);
+                else if (gwps->data->progressbar.pb_type == SLIDER)
+                    slider_progressbar_draw(display, data->progressbar.bm,
+                                            data->progress_start, sb_y,
+                                            data->progress_end-data->progress_start,
+                                            state->id3->length?state->id3->length:1,
+                                            state->id3->length?state->id3->elapsed + state->ff_rewind_count:0);
                 else
                     gui_scrollbar_draw(display, data->progress_start, sb_y, 
                                         data->progress_end-data->progress_start,
@@ -2596,3 +2603,26 @@
     gui_syncsplash(HZ, true, s);
 }
 
+#ifdef HAVE_LCD_BITMAP
+void slider_progressbar_draw(struct screen * screen, struct bitmap bm,
+                             int pb_x, int pb_y, int pb_width,
+                             int total_length, int progress)
+{
+    int slider_x = pb_x + (pb_width - bm.width) * progress / total_length;
+
+    screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+    screen->fillrect(pb_x, pb_y, pb_width, bm.height);
+
+    screen->set_drawmode(DRMODE_FG);
+#if LCD_DEPTH > 1
+    if(bm.format == FORMAT_MONO) {
+#endif
+        screen->mono_bitmap(bm.data, slider_x, pb_y, bm.width, bm.height);
+#if LCD_DEPTH > 1
+    } else {
+        screen->transparent_bitmap((fb_data *)bm.data, slider_x,
+                                    pb_y, bm.width, bm.height);
+    }
+#endif
+}
+#endif
Index: apps/gui/gwps-common.h
===================================================================
--- apps/gui/gwps-common.h	(revision 12086)
+++ apps/gui/gwps-common.h	(working copy)
@@ -23,6 +23,10 @@
 
 #include "gwps.h"
 
+void slider_progressbar_draw(struct screen * screen, struct bitmap bm,
+                             int pb_x, int pb_y, int pb_width,
+                             int total_length, int progress);
+
 void gui_wps_format_time(char* buf, int buf_size, long time);
 void fade(bool fade_in);
 void gui_wps_format(struct wps_data *data);
Index: apps/gui/gwps.c
===================================================================
--- apps/gui/gwps.c	(revision 12086)
+++ apps/gui/gwps.c	(working copy)
@@ -674,7 +674,7 @@
     }
     data->wps_sb_tag = false;
     data->show_sb_on_wps = false;
-    data->progressbar.have_bitmap_pb=false;
+    data->progressbar.pb_type = NORMAL;
 }
 #else
 #define wps_clear(a)
Index: apps/gui/gwps.h
===================================================================
--- apps/gui/gwps.h	(revision 12086)
+++ apps/gui/gwps.h	(working copy)
@@ -39,6 +39,11 @@
 #define WPS_ALIGN_CENTER 64
 #define WPS_ALIGN_LEFT 128
 
+/* progressbar types */
+#define NORMAL 0
+#define BITMAP 1
+#define SLIDER 2
+
 /* wps_data*/
 
 #ifdef HAVE_LCD_BITMAP
@@ -53,7 +58,7 @@
 
 struct prog_img{ /*progressbar image*/
     struct bitmap bm;
-    bool have_bitmap_pb;
+    short pb_type;
 };
 #endif
 
Index: apps/settings.h
===================================================================
--- apps/settings.h	(revision 12086)
+++ apps/settings.h	(working copy)
@@ -278,7 +278,6 @@
     int ff_rewind_min_step; /* FF/Rewind minimum step size */
     int ff_rewind_accel; /* FF/Rewind acceleration (in seconds per doubling) */
     int disk_spindown; /* time until disk spindown, in seconds (0=off) */
-    bool disk_poweroff; /* whether to cut disk power after spindown or not */
     int buffer_margin; /* MP3 buffer watermark margin, in seconds */
 
     int peak_meter_release;   /* units per read out */
Index: apps/settings_menu.c
===================================================================
--- apps/settings_menu.c	(revision 12086)
+++ apps/settings_menu.c	(working copy)
@@ -1104,14 +1104,6 @@
                    ata_spindown, 1, 3, 254, NULL );
 }
 
-#ifdef HAVE_ATA_POWER_OFF
-static bool poweroff(void)
-{
-    bool rc = set_bool(str(LANG_POWEROFF), &global_settings.disk_poweroff);
-    ata_poweroff(global_settings.disk_poweroff);
-    return rc;
-}
-#endif /* HAVE_ATA_POWEROFF */
 #endif /* !HAVE_MMC */
 
 #if CONFIG_CODEC == MAS3507D
@@ -2115,9 +2107,6 @@
 
     static const struct menu_item items[] = {
         { ID2P(LANG_SPINDOWN),    spindown        },
-#ifdef HAVE_ATA_POWER_OFF
-        { ID2P(LANG_POWEROFF),    poweroff        },
-#endif
 #ifdef HAVE_DIRCACHE
         { ID2P(LANG_DIRCACHE_ENABLE),  dircache },
 #endif
Index: apps/playback.c
===================================================================
--- apps/playback.c	(revision 12086)
+++ apps/playback.c	(working copy)
@@ -197,10 +197,10 @@
 /* TBD: Split out "audio" and "playback" (ie. calling) threads */
 
 /* Main state control */
-static volatile bool audio_codec_loaded;        /* Is codec loaded? (C/A-) */
-static volatile bool playing;                   /* Is audio playing? (A) */
-static volatile bool paused;                    /* Is audio paused? (A/C-) */
-static volatile bool filling IDATA_ATTR;        /* Is file buffer currently being refilled? (A/C-) */
+static volatile bool audio_codec_loaded IDATA_ATTR;/* Is codec loaded? (C/A-) */
+static volatile bool playing IDATA_ATTR;           /* Is audio playing? (A) */
+static volatile bool paused IDATA_ATTR;            /* Is audio paused? (A/C-) */
+static volatile bool filling IDATA_ATTR;           /* Is file buffer currently being refilled? (A/C-) */
 
 /* Ring buffer where tracks and codecs are loaded */
 static unsigned char *filebuf;                  /* Pointer to start of ring buffer (A/C-) */
@@ -273,7 +273,7 @@
 
 /* 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";
@@ -287,7 +287,7 @@
 extern struct codec_api ci_voice;
 
 static struct thread_entry *voice_thread_p = NULL;
-static struct event_queue voice_queue;
+static struct event_queue voice_queue IDATA_ATTR;
 static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
 IBSS_ATTR_VOICE_STACK;
 static const char voice_thread_name[] = "voice codec";
@@ -303,12 +303,12 @@
 
 static unsigned char *iram_buf[2] = { NULL, NULL }; /* Ptr to IRAM buffers for normal/voice codecs */
 static unsigned char *dram_buf[2] = { NULL, NULL }; /* Ptr to DRAM buffers for normal/voice codecs */
-static struct mutex mutex_codecthread;          /* Mutex to control which codec (normal/voice) is running */
+static struct mutex mutex_codecthread IDATA_ATTR;   /* Mutex to control which codec (normal/voice) is running */
 
 /* Voice state */
 static volatile bool voice_thread_start;    /* Set to trigger voice playback (A/V) */
-static volatile bool voice_is_playing;      /* Is voice currently playing? (V) */
-static volatile bool voice_codec_loaded;    /* Is voice codec loaded (V/A-) */
+static volatile bool voice_is_playing IDATA_ATTR;      /* Is voice currently playing? (V) */
+static volatile bool voice_codec_loaded IDATA_ATTR;    /* Is voice codec loaded (V/A-) */
 static char *voicebuf;
 static size_t voice_remaining;
 
@@ -3520,9 +3520,15 @@
     id3_voice.length = 1000000L;
 #endif
 
+#if (NUM_CORES > 1)
+    codec_thread_p = create_thread_on_core(COP, codec_thread, codec_stack, 
+                                   sizeof(codec_stack),
+                                   codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK));
+#else
     codec_thread_p = create_thread(codec_thread, codec_stack, 
                                    sizeof(codec_stack),
                                    codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK));
+#endif
 
     while (1)
     {
Index: apps/main.c
===================================================================
--- apps/main.c	(revision 12086)
+++ apps/main.c	(working copy)
@@ -295,6 +295,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();
 
@@ -548,10 +551,15 @@
    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. */
-    while(1) {
-        COP_CTL = PROC_SLEEP;
-    }
+   A kernel thread runs on the coprocessor, which just waits for other
+   threads to be added */
+
+   system_init();
+   kernel_init();
+
+   while(1) {
+       sleep(HZ);
+   }
 }
 #endif
 
Index: firmware/export/config-h10.h
===================================================================
--- firmware/export/config-h10.h	(revision 12086)
+++ firmware/export/config-h10.h	(working copy)
@@ -108,7 +108,7 @@
 #define ROM_START 0x00000000
 
 /* Define this to the CPU frequency */
-#define CPU_FREQ      75000000
+#define CPU_FREQ      45000000
 
 /* Type of LCD */
 #define CONFIG_LCD LCD_H10_20GB
@@ -149,7 +149,7 @@
 #define CONFIG_LED LED_VIRTUAL
 
 /* Define this if you have adjustable CPU frequency */
-/*#define HAVE_ADJUSTABLE_CPU_FREQ*/
+#define HAVE_ADJUSTABLE_CPU_FREQ
 
 #define BOOTFILE_EXT "h10"
 #define BOOTFILE "rockbox." BOOTFILE_EXT
Index: firmware/export/config.h
===================================================================
--- firmware/export/config.h	(revision 12086)
+++ firmware/export/config.h	(working copy)
@@ -246,14 +246,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
===================================================================
--- firmware/export/pp5002.h	(revision 12086)
+++ firmware/export/pp5002.h	(working copy)
@@ -68,6 +68,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/ata.h
===================================================================
--- firmware/export/ata.h	(revision 12086)
+++ firmware/export/ata.h	(working copy)
@@ -38,7 +38,6 @@
 
 extern void ata_enable(bool on);
 extern void ata_spindown(int seconds);
-extern void ata_poweroff(bool enable);
 extern void ata_sleep(void);
 extern void ata_sleepnow(void);
 extern bool ata_disk_is_active(void);
Index: firmware/export/system.h
===================================================================
--- firmware/export/system.h	(revision 12086)
+++ firmware/export/system.h	(working copy)
@@ -281,12 +281,12 @@
 
 #else
 
-#define CPUFREQ_DEFAULT_MULT 8
-#define CPUFREQ_DEFAULT 24000000
-#define CPUFREQ_NORMAL_MULT 10
-#define CPUFREQ_NORMAL 30000000
-#define CPUFREQ_MAX_MULT 25
-#define CPUFREQ_MAX 75000000
+#define CPUFREQ_DEFAULT_MULT 4
+#define CPUFREQ_DEFAULT 12000000
+#define CPUFREQ_NORMAL_MULT 15
+#define CPUFREQ_NORMAL 45000000
+#define CPUFREQ_MAX_MULT 35
+#define CPUFREQ_MAX 105000000
 
 #endif
 
Index: firmware/export/pp5020.h
===================================================================
--- firmware/export/pp5020.h	(revision 12086)
+++ firmware/export/pp5020.h	(working copy)
@@ -144,6 +144,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/kernel.c
===================================================================
--- firmware/kernel.c	(revision 12086)
+++ firmware/kernel.c	(working copy)
@@ -26,7 +26,7 @@
 #include "panic.h"
 
 #if !defined(CPU_PP) || !defined(BOOTLOADER) 
-long current_tick = 0;
+long current_tick IDATA_ATTR = 0;
 #endif
 
 static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
@@ -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);
 }
@@ -496,28 +499,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;
@@ -645,8 +656,31 @@
     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)
     {
         /* Wait until the lock is open... */
@@ -656,6 +690,7 @@
     /* ...and lock it */
     m->locked = true;
 }
+#endif
 
 void mutex_unlock(struct mutex *m)
 {
Index: firmware/system.c
===================================================================
--- firmware/system.c	(revision 12086)
+++ firmware/system.c	(working copy)
@@ -566,12 +566,22 @@
 
 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)
@@ -580,22 +590,40 @@
 /* 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 */
@@ -648,43 +676,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;
+    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)
@@ -708,21 +740,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)));
+    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);
+        /* disable all irqs */
+        outl(-1, 0x60001138);
+        outl(-1, 0x60001128);
+        outl(-1, 0x6000111c);
 
-    outl(-1, 0x60001038);
-    outl(-1, 0x60001028);
-    outl(-1, 0x6000101c);
+        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
 }
@@ -746,10 +781,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
@@ -798,29 +841,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;
+    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)
@@ -851,13 +897,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/target/arm/crt0-pp.S
===================================================================
--- firmware/target/arm/crt0-pp.S	(revision 12086)
+++ firmware/target/arm/crt0-pp.S	(working copy)
@@ -222,6 +222,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
     
     /* Run cop_main() in apps/main.c */
@@ -307,6 +320,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:
Index: firmware/thread.c
===================================================================
--- firmware/thread.c	(revision 12086)
+++ firmware/thread.c	(working copy)
@@ -304,10 +304,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 == S3C2440
         CLKCON |= (1 << 2); /* set IDLE bit */
         for(i=0; i<10; i++); /* wait for IDLE */
@@ -597,7 +600,7 @@
 
 /*---------------------------------------------------------------------------
  * Create thread on the current core.
- * Return ID if context area could be allocated, else -1.
+ * Return ID if context area could be allocated, else NULL.
  *---------------------------------------------------------------------------
  */
 struct thread_entry* 
@@ -610,7 +613,7 @@
 
 /*---------------------------------------------------------------------------
  * Create thread on a specific core.
- * Return ID if context area could be allocated, else -1.
+ * Return ID if context area could be allocated, else NULL.
  *---------------------------------------------------------------------------
  */
 struct thread_entry* 
@@ -735,7 +738,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/powermgmt.c
===================================================================
--- firmware/powermgmt.c	(revision 12086)
+++ firmware/powermgmt.c	(working copy)
@@ -30,7 +30,6 @@
 #include "ata.h"
 #include "power.h"
 #include "button.h"
-#include "ata.h"
 #include "audio.h"
 #include "mp3_playback.h"
 #include "usb.h"
@@ -638,9 +637,6 @@
         remote_backlight_set_timeout(2);
 #endif
         ata_spindown(3);
-#ifdef HAVE_ATA_POWER_OFF
-        ata_poweroff(true);
-#endif
         low_battery = true;
     } else if (low_battery && (battery_percent > 11)) {
         backlight_set_timeout(10);
Index: firmware/drivers/ata.c
===================================================================
--- firmware/drivers/ata.c	(revision 12086)
+++ firmware/drivers/ata.c	(working copy)
@@ -63,6 +63,10 @@
 
 #define READ_TIMEOUT 5*HZ
 
+#ifdef HAVE_ATA_POWER_OFF
+#define ATA_POWER_OFF_TIMEOUT 2*HZ
+#endif
+
 static struct mutex ata_mtx;
 int ata_device; /* device 0 (master) or 1 (slave) */
 
@@ -75,9 +79,6 @@
 static bool sleeping = true;
 static bool poweroff = false;
 static long sleep_timeout = 5*HZ;
-#ifdef HAVE_ATA_POWER_OFF
-static int poweroff_timeout = 2*HZ;
-#endif
 #ifdef HAVE_LBA48
 static bool lba48 = false; /* set for 48 bit addressing */
 #endif
@@ -561,16 +562,6 @@
     sleep_timeout = seconds * HZ;
 }
 
-#ifdef HAVE_ATA_POWER_OFF
-void ata_poweroff(bool enable)
-{
-    if (enable)
-        poweroff_timeout = 2*HZ;
-    else
-        poweroff_timeout = 0;
-}
-#endif
-
 bool ata_disk_is_active(void)
 {
     return !sleeping;
@@ -654,8 +645,8 @@
                 }
             }
 #ifdef HAVE_ATA_POWER_OFF
-            if ( !spinup && sleeping && poweroff_timeout && !poweroff &&
-                 TIME_AFTER( current_tick, last_sleep + poweroff_timeout ))
+            if ( !spinup && sleeping && ATA_POWER_OFF_TIMEOUT && !poweroff &&
+                 TIME_AFTER( current_tick, last_sleep + ATA_POWER_OFF_TIMEOUT ))
             {
                 mutex_lock(&ata_mtx);
                 ide_power_enable(false);
