imx233:fuze+: major memory and usb rework
- now identity map dram uncached and have a cached and buffered virtual alias
- rework dma to handle virtual to physical pointers conversion
- fix lcd frame pointer
- implement usb detection properly
- implement bootloader usb properly
- allow the bootloader to disable MMC windowing (useful for recovery)

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30432 a1c6a512-1295-4272-9138-f99709370657
diff --git a/bootloader/imx233.c b/bootloader/imx233.c
index f6c5ad9..b160c79 100644
--- a/bootloader/imx233.c
+++ b/bootloader/imx233.c
@@ -39,6 +39,69 @@
 #include "fmradio_i2c.h"
 
 #include "usb.h"
+#include "usb-target.h"
+
+#include "clkctrl-imx233.h"
+
+#ifdef HAVE_BOOTLOADER_USB_MODE
+static void usb_mode(int connect_timeout)
+{
+    int button;
+    
+    usb_init();
+    usb_start_monitoring();
+
+    /* Wait for threads to connect or cable is pulled */
+    printf("USB: Connecting");
+
+    long end_tick = current_tick + connect_timeout;
+
+    while(1)
+    {
+        button = button_get_w_tmo(HZ/10);
+
+        if(button == SYS_USB_CONNECTED)
+            break; /* Hit */
+
+        if(TIME_AFTER(current_tick, end_tick))
+        {
+            /* Timed out waiting for the connect - will happen when connected
+             * to a charger through the USB port */
+            printf("USB: Timed out");
+            break;
+        }
+
+        if(!usb_plugged())
+            break; /* Cable pulled */
+    }
+
+    if(button == SYS_USB_CONNECTED)
+    {
+        /* Got the message - wait for disconnect */
+        printf("Bootloader USB mode");
+
+        usb_acknowledge(SYS_USB_CONNECTED_ACK);
+
+        while(1)
+        {
+            button = button_get_w_tmo(HZ/2);
+            if(button == SYS_USB_DISCONNECTED)
+                break;
+        }
+    }
+
+    /* Put drivers initialized for USB connection into a known state */
+    usb_close();
+
+    system_exception_wait();
+    power_off();
+}
+#else /* !HAVE_BOOTLOADER_USB_MODE */
+static void usb_mode(int connect_timeout)
+{
+    (void) connect_timeout;
+}
+#endif /* HAVE_BOOTLOADER_USB_MODE */
 
 void main(uint32_t arg) NORETURN_ATTR;
 void main(uint32_t arg)
@@ -51,6 +114,7 @@
     system_init();
     kernel_init();
 
+    power_init();
     enable_irq();
 
     lcd_init();
@@ -59,32 +123,32 @@
 
     backlight_init();
 
-    button_init_device();
+    button_init();
 
     //button_debug_screen();
-    printf("arg=%c%c%c%c", arg >> 24,
-        (arg >> 16) & 0xff, (arg >> 8) & 0xff, (arg & 0xff));
+    printf("arg=%x", arg);
+
+#ifdef SANSA_FUZEPLUS
+    extern void imx233_mmc_disable_window(void);
+    if(arg == 0xfee1dead)
+    {
+        printf("Disable MMC window.");
+        imx233_mmc_disable_window();
+    }
+#endif
 
     ret = storage_init();
     if(ret < 0)
         error(EATA, ret, true);
 
-    #ifdef HAVE_BOOTLOADER_USB_MODE
-    usb_init();
-    usb_core_enable_driver(USB_DRIVER_SERIAL, true);
-    usb_attach();
-    while(!(button_read_device() & BUTTON_POWER))
-        yield();
-    power_off();
-    #endif /* HAVE_BOOTLOADER_USB_MODE */
+    if(usb_plugged())
+        usb_mode(HZ * 2);
 
     while(!disk_init(IF_MV(0)))
-        panicf("disk_init failed!");
+        printf("disk_init failed!");
 
-    while((ret = disk_mount_all()) <= 0)
-    {
-        error(EDISK, ret, true);
-    }
+    if((ret = disk_mount_all()) <= 0)
+        error(EDISK, ret, false);
 
     if(button_read_device() & BUTTON_VOL_UP)
         printf("Booting from SD card required.");
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 57e6bb8..e1ce15a 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -937,7 +937,7 @@
 
 #endif /* CPU_PP */
 
-#if CONFIG_CPU == IMX31L
+#if CONFIG_CPU == IMX31L || CONFIG_CPU == IMX233
 #define NOCACHEBSS_ATTR     __attribute__((section(".ncbss"),nocommon))
 #define NOCACHEDATA_ATTR    __attribute__((section(".ncdata"),nocommon))
 #endif
diff --git a/firmware/export/config/sansafuzeplus.h b/firmware/export/config/sansafuzeplus.h
index 971ff01..13ad3af 100644
--- a/firmware/export/config/sansafuzeplus.h
+++ b/firmware/export/config/sansafuzeplus.h
@@ -172,7 +172,7 @@
 #define USB_VENDOR_ID 0x0781
 #define USB_PRODUCT_ID 0x74e1
 #define HAVE_USB_HID_MOUSE
-//#define HAVE_BOOTLOADER_USB_MODE
+#define HAVE_BOOTLOADER_USB_MODE
 
 /* The fuze+ actually interesting partition table does not use 512-byte sector
  * (usually 2048 logical sector size) */
diff --git a/firmware/export/imx233.h b/firmware/export/imx233.h
index d9ea06a..2a2097b 100644
--- a/firmware/export/imx233.h
+++ b/firmware/export/imx233.h
@@ -21,17 +21,41 @@
 #ifndef __IMX233_H__
 #define __IMX233_H__
 
+/*
+ * Chip Memory Map:
+ *   0x00000000 - 0x00007fff: on chip ram
+ *   0x40000000 - 0x5fffffff: dram (512Mb max)
+ *   0x80000000 - 0x80100000: memory mapped registers
+ * We use the following map:
+ *   0x60000000 - 0x7fffffff: dram (cached)
+ *   0x90000000 - 0xafffffff: dram (buffered)
+ *   everything else        : identity mapped (uncached)
+ *
+ * As a side note it's important to notice that uncached dram is identity mapped
+ */
+
 #define IRAM_ORIG           0
 #define IRAM_SIZE           0x8000
 #define DRAM_ORIG           0x40000000
 #define DRAM_SIZE           (MEMORYSIZE * 0x100000)
 
+#define UNCACHED_DRAM_ADDR  0x40000000
+#define CACHED_DRAM_ADDR    0x60000000
+#define BUFFERED_DRAM_ADDR  0x90000000
+#define CACHEALIGN_SIZE     32
+
+#define PHYSICAL_ADDR(a) \
+    ((typeof(a))((uintptr_t)(a) >= CACHED_DRAM_ADDR ? \
+        ((uintptr_t)(a) - CACHED_DRAM_ADDR + UNCACHED_DRAM_ADDR) \
+        :(uintptr_t)(a)))
+#define UNCACHED_ADDR(a) PHYSICAL_ADDR(a)
+
 #define TTB_BASE_ADDR   (DRAM_ORIG + DRAM_SIZE - TTB_SIZE)
 #define TTB_SIZE        0x4000
 #define TTB_BASE        ((unsigned long *)TTB_BASE_ADDR)
 #define FRAME_SIZE      (LCD_WIDTH * LCD_HEIGHT * LCD_DEPTH / 8)
-#define LCD_FRAME_ADDR  (DRAM_ORIG + DRAM_SIZE - TTB_SIZE - FRAME_SIZE)
-#define FRAME           ((unsigned short *)LCD_FRAME_ADDR)
+#define FRAME_PHYS_ADDR (DRAM_ORIG + DRAM_SIZE - TTB_SIZE - FRAME_SIZE)
+#define FRAME           ((void *)(FRAME_PHYS_ADDR - UNCACHED_DRAM_ADDR + BUFFERED_DRAM_ADDR))
 
 /* USBOTG */
 #define USB_QHARRAY_ATTR    __attribute__((section(".qharray"),nocommon,aligned(2048)))
@@ -52,5 +76,7 @@
 
 #define CACHEALIGN_BITS     4
 
+#define __XTRACT(reg, field)    ((reg & reg##__##field##_BM) >> reg##__##field##_BP)
+#define __XTRACT_EX(val, field)    (((val) & field##_BM) >> field##_BP)
 
 #endif /* __IMX233_H__ */
diff --git a/firmware/target/arm/imx233/boot.lds b/firmware/target/arm/imx233/boot.lds
index 8e4f201..fb6ffdc 100644
--- a/firmware/target/arm/imx233/boot.lds
+++ b/firmware/target/arm/imx233/boot.lds
@@ -9,7 +9,8 @@
 MEMORY
 {
     IRAM : ORIGIN = IRAM_ORIG, LENGTH = IRAM_SIZE
-    DRAM : ORIGIN = DRAM_ORIG, LENGTH = DRAM_SIZE - TTB_SIZE - FRAME_SIZE
+    DRAM : ORIGIN = CACHED_DRAM_ADDR, LENGTH = DRAM_SIZE - TTB_SIZE - FRAME_SIZE
+    UNCACHED_DRAM : ORIGIN = UNCACHED_DRAM_ADDR, LENGTH = DRAM_SIZE - TTB_SIZE - FRAME_SIZE
 }
 
 SECTIONS
@@ -57,10 +58,23 @@
         stackend = .;
     } > DRAM
 
+    /* treat .bss and .ncbss as a single section */
     .bss (NOLOAD) :
     {
         _edata = .;
         *(.bss*);
+    } > DRAM
+
+    /* align on cache size boundary to avoid mixing cached and noncached stuff */
+    .ncbss . - CACHED_DRAM_ADDR + UNCACHED_DRAM_ADDR (NOLOAD) :
+    {
+        . = ALIGN(CACHEALIGN_SIZE);
+        *(.ncbss*)
+        . = ALIGN(CACHEALIGN_SIZE);
+    } AT> DRAM
+
+    .bssendadr . - UNCACHED_DRAM_ADDR + CACHED_DRAM_ADDR (NOLOAD) :
+    {
         _end = .;
     } > DRAM
 }
diff --git a/firmware/target/arm/imx233/crt0.S b/firmware/target/arm/imx233/crt0.S
index a0f9ec2..ab0250f 100644
--- a/firmware/target/arm/imx233/crt0.S
+++ b/firmware/target/arm/imx233/crt0.S
@@ -33,6 +33,9 @@
     ldr     pc, =irq_handler
     ldr     pc, =fiq_handler
 
+/* When starting, we are running at 0x40000000 but the code
+ * assumes DRAM is somewhere else (for caching) so we first need to
+ * setup the MMU and then jump to the right location */
 .text
 .global start
 start:
@@ -46,6 +49,13 @@
     bic     r0, r1
     mcr     p15, 0, r0, c1, c0, 0
 
+    /* Enable MMU */
+    bl      memory_init
+
+    /* Jump to real location */
+    ldr     pc, =remap
+remap:
+
     /* Zero out IBSS */
     ldr     r2, =_iedata
     ldr     r3, =_iend
@@ -114,9 +124,6 @@
     msr     cpsr_c, #0xdb
     ldr     sp, =irq_stack
 
-    /* Enable MMU */
-    bl      memory_init
-
     /* Switch back to supervisor mode */
     msr     cpsr_c, #0xd3
 
diff --git a/firmware/target/arm/imx233/dma-imx233.c b/firmware/target/arm/imx233/dma-imx233.c
index 8a42bd1..eba4195 100644
--- a/firmware/target/arm/imx233/dma-imx233.c
+++ b/firmware/target/arm/imx233/dma-imx233.c
@@ -107,7 +107,8 @@
 }
 
 /* Commit and/or discard all DMA descriptors and buffers pointed by them,
- * handle circular lists */
+ * handle circular lists. At the same time, convert virtual pointers to
+ * real ones */
 static void imx233_dma_commit_and_discard(struct apb_dma_command_t *cmd)
 {
     /* We handle circular descriptors by using unused bits:
@@ -121,13 +122,15 @@
     {
         cur->cmd = (cur->cmd & ~HW_APB_CHx_CMD__UNUSED_BM) | HW_APB_CHx_CMD__UNUSED_MAGIC;
         int op = cur->cmd & HW_APB_CHx_CMD__COMMAND_BM;
-        int sz = (cur->cmd & HW_APB_CHx_CMD__XFER_COUNT_BM) >> HW_APB_CHx_CMD__XFER_COUNT_BP;
+        int sz = __XTRACT_EX(cur->cmd, HW_APB_CHx_CMD__XFER_COUNT);
         /* device > host: discard */
         if(op == HW_APB_CHx_CMD__COMMAND__WRITE)
             discard_dcache_range(cur->buffer, sz);
         /* host > device: commit and discard */
         else if(op == HW_APB_CHx_CMD__COMMAND__READ)
             commit_discard_dcache_range(cur->buffer, sz);
+        /* Virtual to physical buffer pointer conversion */
+        cur->buffer = PHYSICAL_ADDR(cur->buffer);
         /* chain ? */
         if(cur->cmd & HW_APB_CHx_CMD__CHAIN)
             cur = cur->next;
@@ -139,15 +142,21 @@
     while((cur->cmd & HW_APB_CHx_CMD__UNUSED_BM) != 0)
     {
         cur->cmd = cur->cmd & ~HW_APB_CHx_CMD__UNUSED_BM;
-        int sz = (cur->cmd & HW_APB_CHx_CMD__CMDWORDS_BM) >> HW_APB_CHx_CMD__CMDWORDS_BP;
-        /* commit descriptor (don't discard since we access it after) */
-        commit_dcache_range(cur,
-            sizeof(struct apb_dma_command_t) + sizeof(uint32_t) * sz);
+        int sz = __XTRACT_EX(cur->cmd, HW_APB_CHx_CMD__CMDWORDS) * sizeof(uint32_t);
+        /* commit descriptor and discard descriptor */
         /* chain ? */
         if(cur->cmd & HW_APB_CHx_CMD__CHAIN)
-            cur = cur->next;
+        {
+            struct apb_dma_command_t *next = cur->next;
+            cur->next = PHYSICAL_ADDR(cur->next);
+            commit_dcache_range(cur, sizeof(struct apb_dma_command_t) + sz);
+            cur = next;
+        }
         else
+        {
+            commit_dcache_range(cur, sizeof(struct apb_dma_command_t) + sz);
             break;
+        }
     }
 }
 
@@ -156,12 +165,12 @@
     imx233_dma_commit_and_discard(cmd);
     if(APB_IS_APBX_CHANNEL(chan))
     {
-        HW_APBX_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)cmd;
+        HW_APBX_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)PHYSICAL_ADDR(cmd);
         HW_APBX_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)) = 1;
     }
     else
     {
-        HW_APBH_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)cmd;
+        HW_APBH_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)PHYSICAL_ADDR(cmd);
         HW_APBH_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)) = 1;
     }
 }
diff --git a/firmware/target/arm/imx233/lcdif-imx233.c b/firmware/target/arm/imx233/lcdif-imx233.c
index 0b96cbf..9173b57 100644
--- a/firmware/target/arm/imx233/lcdif-imx233.c
+++ b/firmware/target/arm/imx233/lcdif-imx233.c
@@ -79,7 +79,7 @@
 
 unsigned imx233_lcdif_enable_irqs(unsigned irq_bm)
 {
-    unsigned old_msk = (HW_LCDIF_CTRL1 & HW_LCDIF_CTRL1__IRQ_EN_BM) >>HW_LCDIF_CTRL1__IRQ_EN_BP ;
+    unsigned old_msk = __XTRACT(HW_LCDIF_CTRL1, IRQ_EN);
     /* clear irq status */
     __REG_CLR(HW_LCDIF_CTRL1) = irq_bm << HW_LCDIF_CTRL1__IRQ_BP;
     /* disable irqs */
diff --git a/firmware/target/arm/imx233/mmc-imx233.c b/firmware/target/arm/imx233/mmc-imx233.c
index 889ba0c..d2e76e7 100644
--- a/firmware/target/arm/imx233/mmc-imx233.c
+++ b/firmware/target/arm/imx233/mmc-imx233.c
@@ -41,9 +41,15 @@
 /** When set, this values restrict the windows of the read and writes */
 static unsigned mmc_window_start = 0;
 static unsigned mmc_window_end = INT_MAX;
+static bool mmc_window_enable = true;
 
 static struct mutex mmc_mutex;
 
+void imx233_mmc_disable_window(void)
+{
+    mmc_window_enable = false;
+}
+
 int mmc_init(void)
 {
     mutex_init(&mmc_mutex);
@@ -123,34 +129,37 @@
     imx233_ssp_set_timings(MMC_SSP, 2, 0, 0xffff);
 
     #ifdef SANSA_FUZEPLUS
-    /**
-     * The Fuze+ uses a strange layout: is has a first MBR at sector 0 with four entries:
-     * 1) Actual user partition
-     * 2) Sigmatel boot partition
-     * 3)4) Other (certificate related ?) partitions
-     * The partition 1) has type 1 but it's actually a type 5 (logical partition) with
-     * a second partition table with usually one entry which is the FAT32 one.
-     * The first table uses 512-byte sector size and the second one usually uses
-     * 2048-byte logical sector size.
-     *
-     * We restrict mmc window to the user partition */
-    uint8_t mbr[512];
-    mmc_window_start = 0;
-    mmc_window_end = INT_MAX;
-    ret = mmc_read_sectors(IF_MD2(0,) 0, 1, mbr);
-    if(ret != 0)
-        return -100;
-    if(mbr[510] != 0x55 || mbr[511] != 0xAA)
-        return -101; /* invalid MBR */
-    /* sanity check that the first partition is greater than 2Gib */
-    uint8_t *ent = &mbr[446];
-    mmc_window_start = ent[8] | ent[9] << 8 | ent[10] << 16 | ent[11] << 24;
-    mmc_window_end = (ent[12] | ent[13] << 8 | ent[14] << 16 | ent[15] << 24) +
-        mmc_window_start;
-    if(ent[4] == 0x53)
-        return -102; /* sigmatel partition */
-    if((mmc_window_end - mmc_window_start) < 4 * 1024 * 1024)
-        return -103; /* partition too small */
+    if(mmc_window_enable)
+    {
+        /**
+         * The Fuze+ uses a strange layout: is has a first MBR at sector 0 with four entries:
+         * 1) Actual user partition
+         * 2) Sigmatel boot partition
+         * 3)4) Other (certificate related ?) partitions
+         * The partition 1) has type 1 but it's actually a type 5 (logical partition) with
+         * a second partition table with usually one entry which is the FAT32 one.
+         * The first table uses 512-byte sector size and the second one usually uses
+         * 2048-byte logical sector size.
+         *
+         * We restrict mmc window to the user partition */
+        uint8_t mbr[512];
+        mmc_window_start = 0;
+        mmc_window_end = INT_MAX;
+        ret = mmc_read_sectors(IF_MD2(0,) 0, 1, mbr);
+        if(ret != 0)
+            return -100;
+        if(mbr[510] != 0x55 || mbr[511] != 0xAA)
+            return -101; /* invalid MBR */
+        /* sanity check that the first partition is greater than 2Gib */
+        uint8_t *ent = &mbr[446];
+        mmc_window_start = ent[8] | ent[9] << 8 | ent[10] << 16 | ent[11] << 24;
+        mmc_window_end = (ent[12] | ent[13] << 8 | ent[14] << 16 | ent[15] << 24) +
+            mmc_window_start;
+        if(ent[4] == 0x53)
+            return -102; /* sigmatel partition */
+        if((mmc_window_end - mmc_window_start) < 4 * 1024 * 1024)
+            return -103; /* partition too small */
+    }
     #endif
 
     return 0;
@@ -221,3 +230,9 @@
     IF_MD((void) drive);
     return true;
 }
+
+bool mmc_removable(IF_MD(int drive))
+{
+    IF_MD((void) drive);
+    return false;
+}
diff --git a/firmware/target/arm/imx233/power-imx233.c b/firmware/target/arm/imx233/power-imx233.c
index f01a4ad..d9f390c 100644
--- a/firmware/target/arm/imx233/power-imx233.c
+++ b/firmware/target/arm/imx233/power-imx233.c
@@ -23,9 +23,33 @@
 #include "system.h"
 #include "power.h"
 #include "system-target.h"
+#include "usb-target.h"
+
+void INT_VDD5V(void)
+{
+    if(HW_POWER_CTRL & HW_POWER_CTRL__VBUSVALID_IRQ)
+    {
+        if(HW_POWER_STS & HW_POWER_STS__VBUSVALID)
+            usb_insert_int();
+        else
+            usb_remove_int();
+        /* reverse polarity */
+        __REG_TOG(HW_POWER_CTRL) = HW_POWER_CTRL__POLARITY_VBUSVALID;
+        /* enable int */
+        __REG_CLR(HW_POWER_CTRL) = HW_POWER_CTRL__VBUSVALID_IRQ;
+    }
+}
 
 void power_init(void)
 {
+    /* clear vbusvalid irq and set correct polarity */
+    __REG_CLR(HW_POWER_CTRL) = HW_POWER_CTRL__VBUSVALID_IRQ;
+    if(HW_POWER_STS & HW_POWER_STS__VBUSVALID)
+        __REG_CLR(HW_POWER_CTRL) = HW_POWER_CTRL__POLARITY_VBUSVALID;
+    else
+        __REG_SET(HW_POWER_CTRL) = HW_POWER_CTRL__POLARITY_VBUSVALID;
+    __REG_SET(HW_POWER_CTRL) = HW_POWER_CTRL__ENIRQ_VBUS_VALID;
+    imx233_enable_interrupt(INT_SRC_VDD5V, true);
 }
 
 void power_off(void)
diff --git a/firmware/target/arm/imx233/power-imx233.h b/firmware/target/arm/imx233/power-imx233.h
new file mode 100644
index 0000000..c37fdd6
--- /dev/null
+++ b/firmware/target/arm/imx233/power-imx233.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2011 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __POWER_IMX233__
+#define __POWER_IMX233__
+
+#include "system.h"
+#include "system-target.h"
+#include "cpu.h"
+
+#define HW_POWER_BASE           0x80044000
+
+#define HW_POWER_CTRL           (*(volatile uint32_t *)(HW_POWER_BASE + 0x0))
+#define HW_POWER_CTRL__ENIRQ_VBUS_VALID     (1 << 3)
+#define HW_POWER_CTRL__VBUSVALID_IRQ        (1 << 4)
+#define HW_POWER_CTRL__POLARITY_VBUSVALID   (1 << 5)
+
+#define HW_POWER_5VCTRL         (*(volatile uint32_t *)(HW_POWER_BASE + 0x10))
+#define HW_POWER_5VCTRL__VBUSVALID_5VDETECT (1 << 4)
+#define HW_POWER_5VCTRL__VBUSVALID_TRSH_BP  8
+#define HW_POWER_5VCTRL__VBUSVALID_TRSH_BM  (0x7 << 8)
+
+#define HW_POWER_MINPWR         (*(volatile uint32_t *)(HW_POWER_BASE + 0x20))
+
+#define HW_POWER_CHARGE         (*(volatile uint32_t *)(HW_POWER_BASE + 0x30))
+
+#define HW_POWER_VDDDCTRL       (*(volatile uint32_t *)(HW_POWER_BASE + 0x40))
+#define HW_POWER_VDDDCTRL__TRG_BP   0
+#define HW_POWER_VDDDCTRL__TRG_BM   0x1f
+#define HW_POWER_VDDDCTRL__TRG_STEP 25 /* mV */
+#define HW_POWER_VDDDCTRL__TRG_MIN  800 /* mV */
+
+#define HW_POWER_VDDACTRL       (*(volatile uint32_t *)(HW_POWER_BASE + 0x50))
+
+#define HW_POWER_VDDIOCTRL      (*(volatile uint32_t *)(HW_POWER_BASE + 0x60))
+
+#define HW_POWER_VDDMEMCTRL     (*(volatile uint32_t *)(HW_POWER_BASE + 0x70))
+
+#define HW_POWER_MISC           (*(volatile uint32_t *)(HW_POWER_BASE + 0x90))
+
+#define HW_POWER_STS            (*(volatile uint32_t *)(HW_POWER_BASE + 0xc0))
+#define HW_POWER_STS__VBUSVALID     (1 << 1)
+#define HW_POWER_STS__PSWITCH_BP    20
+#define HW_POWER_STS__PSWITCH_BM    (3 << 20)
+
+#define HW_POWER_BATTMONITOR    (*(volatile uint32_t *)(HW_POWER_BASE + 0xe0))
+
+#define HW_POWER_RESET          (*(volatile uint32_t *)(HW_POWER_BASE + 0x100))
+#define HW_POWER_RESET__UNLOCK  0x3E770000
+#define HW_POWER_RESET__PWD     0x1
+
+#endif /* __POWER_IMX233__ */
diff --git a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c
index 2e49e4d..539229e 100644
--- a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c
+++ b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c
@@ -509,7 +509,7 @@
     imx233_lcdif_set_data_format(false, false, false); /* RGB565, don't care, don't care */
     lcd_copy_buffer_rect((fb_data *)FRAME, &lcd_framebuffer[0][0],
                          LCD_WIDTH * LCD_HEIGHT, 1);
-    imx233_lcdif_dma_send(FRAME, LCD_WIDTH, LCD_HEIGHT);
+    imx233_lcdif_dma_send((void *)FRAME_PHYS_ADDR, LCD_WIDTH, LCD_HEIGHT);
 }
 
 void lcd_update_rect(int x, int y, int width, int height)
diff --git a/firmware/target/arm/imx233/sd-imx233.c b/firmware/target/arm/imx233/sd-imx233.c
index 16b7b91..630797b 100644
--- a/firmware/target/arm/imx233/sd-imx233.c
+++ b/firmware/target/arm/imx233/sd-imx233.c
@@ -227,3 +227,9 @@
     return imx233_ssp_sdmmc_detect(SD_SSP);
 }
 
+bool sd_removable(IF_MD(int drive))
+{
+    IF_MD((void) drive);
+    return true;
+}
+
diff --git a/firmware/target/arm/imx233/system-imx233.c b/firmware/target/arm/imx233/system-imx233.c
index c4a32dd..68f16bf 100644
--- a/firmware/target/arm/imx233/system-imx233.c
+++ b/firmware/target/arm/imx233/system-imx233.c
@@ -57,6 +57,7 @@
 default_interrupt(INT_GPIO0);
 default_interrupt(INT_GPIO1);
 default_interrupt(INT_GPIO2);
+default_interrupt(INT_VDD5V);
 
 typedef void (*isr_t)(void);
 
@@ -78,6 +79,7 @@
     [INT_SRC_GPIO0] = INT_GPIO0,
     [INT_SRC_GPIO1] = INT_GPIO1,
     [INT_SRC_GPIO2] = INT_GPIO2,
+    [INT_SRC_VDD5V] = INT_VDD5V,
 };
 
 static void UIRQ(void)
@@ -147,10 +149,8 @@
     map_section(0, 0, 0x1000, CACHE_NONE);
 
     /* map RAM and enable caching for it */
-    map_section(DRAM_ORIG, DRAM_ORIG, MEMORYSIZE, CACHE_ALL);
-    
-    /* enable buffered writing for the framebuffer */
-    map_section((int)FRAME, (int)FRAME, 1, BUFFERED);
+    map_section(DRAM_ORIG, CACHED_DRAM_ADDR, MEMORYSIZE, CACHE_ALL);
+    map_section(DRAM_ORIG, BUFFERED_DRAM_ADDR, MEMORYSIZE, BUFFERED);
 }
 
 void memory_init(void)
diff --git a/firmware/target/arm/imx233/system-target.h b/firmware/target/arm/imx233/system-target.h
index 399ab84..a5dc63d 100644
--- a/firmware/target/arm/imx233/system-target.h
+++ b/firmware/target/arm/imx233/system-target.h
@@ -26,44 +26,11 @@
 #include "panic.h"
 
 #include "clock-target.h" /* CPUFREQ_* are defined here */
+#include "power-imx233.h"
 
 #define HW_DIGCTL_BASE          0x8001C000
 #define HW_DIGCTL_MICROSECONDS  (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0xC0))
 
-#define HW_POWER_BASE           0x80044000
-
-#define HW_POWER_CTRL           (*(volatile uint32_t *)(HW_POWER_BASE + 0x0))
-
-#define HW_POWER_5VCTRL         (*(volatile uint32_t *)(HW_POWER_BASE + 0x10))
-
-#define HW_POWER_MINPWR         (*(volatile uint32_t *)(HW_POWER_BASE + 0x20))
-
-#define HW_POWER_CHARGE         (*(volatile uint32_t *)(HW_POWER_BASE + 0x30))
-
-#define HW_POWER_VDDDCTRL       (*(volatile uint32_t *)(HW_POWER_BASE + 0x40))
-#define HW_POWER_VDDDCTRL__TRG_BP   0
-#define HW_POWER_VDDDCTRL__TRG_BM   0x1f
-#define HW_POWER_VDDDCTRL__TRG_STEP 25 /* mV */
-#define HW_POWER_VDDDCTRL__TRG_MIN  800 /* mV */
-
-#define HW_POWER_VDDACTRL       (*(volatile uint32_t *)(HW_POWER_BASE + 0x50))
-
-#define HW_POWER_VDDIOCTRL      (*(volatile uint32_t *)(HW_POWER_BASE + 0x60))
-
-#define HW_POWER_VDDMEMCTRL     (*(volatile uint32_t *)(HW_POWER_BASE + 0x70))
-
-#define HW_POWER_MISC           (*(volatile uint32_t *)(HW_POWER_BASE + 0x90))
-
-#define HW_POWER_STS            (*(volatile uint32_t *)(HW_POWER_BASE + 0xc0))
-#define HW_POWER_STS__PSWITCH_BP    20
-#define HW_POWER_STS__PSWITCH_BM    (3 << 20)
-
-#define HW_POWER_BATTMONITOR    (*(volatile uint32_t *)(HW_POWER_BASE + 0xe0))
-
-#define HW_POWER_RESET          (*(volatile uint32_t *)(HW_POWER_BASE + 0x100))
-#define HW_POWER_RESET__UNLOCK  0x3E770000
-#define HW_POWER_RESET__PWD     0x1
-
 #define HW_ICOLL_BASE           0x80000000
 
 #define HW_ICOLL_VECTOR         (*(volatile uint32_t *)(HW_ICOLL_BASE + 0x0))
@@ -83,6 +50,7 @@
 #define HW_ICOLL_INTERRUPT__ENFIQ       0x10
 
 #define INT_SRC_SSP2_ERROR  2
+#define INT_SRC_VDD5V       3
 #define INT_SRC_USB_CTRL    11
 #define INT_SRC_SSP1_DMA    14
 #define INT_SRC_SSP1_ERROR  15
diff --git a/firmware/target/arm/imx233/usb-imx233.c b/firmware/target/arm/imx233/usb-imx233.c
index e3b540f..8e05da0 100644
--- a/firmware/target/arm/imx233/usb-imx233.c
+++ b/firmware/target/arm/imx233/usb-imx233.c
@@ -29,10 +29,20 @@
 #include "system.h"
 #include "system-target.h"
 
-int usb_status = USB_EXTRACTED;
+
+void usb_insert_int(void)
+{
+    usb_status_event(USB_POWERED);
+}
+
+void usb_remove_int(void)
+{
+    usb_status_event(USB_UNPOWERED);
+}
 
 void usb_drv_usb_detect_event()
 {
+    printf("usb_drv_usb_detect_event");
     usb_status_event(USB_INSERTED);
 }
 
@@ -58,16 +68,17 @@
 
 int usb_detect(void)
 {
-    return usb_status;
+    return usb_plugged() ? USB_INSERTED : USB_EXTRACTED;
 }
 
 bool usb_plugged(void)
 {
-    return true;
+    return !!(HW_POWER_STS & HW_POWER_STS__VBUSVALID);
 }
 
 void usb_enable(bool on)
 {
+    /* FIXME: power up/down usb phy and pll usb */
     if(on)
         usb_core_init();
     else
diff --git a/firmware/target/arm/imx233/usb-target.h b/firmware/target/arm/imx233/usb-target.h
new file mode 100644
index 0000000..8d6c0af
--- /dev/null
+++ b/firmware/target/arm/imx233/usb-target.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2011 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef USB_TARGET_H
+#define USB_TARGET_H
+
+#include "config.h"
+
+#ifdef HAVE_BOOTLOADER_USB_MODE
+#define USB_DRIVER_CLOSE
+#endif
+
+void usb_init_device(void);
+int usb_detect(void);
+void usb_insert_int(void);
+void usb_remove_int(void);
+bool usb_plugged(void);
+
+#endif /* USB_TARGET_H */