imx233: move the freescale partition handling to its own file

The freescale firmware partitions has a lots of quirks that
need to be dealt with, so do it the proper way.

Change-Id: I8a5bd3fb462a4df143bc6c931057f3ffedd4b3d3
diff --git a/bootloader/imx233.c b/bootloader/imx233.c
index 6d356b9..c1ab489 100644
--- a/bootloader/imx233.c
+++ b/bootloader/imx233.c
@@ -40,6 +40,8 @@
 #include "fmradio_i2c.h"
 #include "version.h"
 #include "powermgmt.h"
+#include "partitions-imx233.h"
+#include "adc-imx233.h"
 
 #include "usb.h"
 
@@ -84,6 +86,7 @@
         printf("Bootloader USB mode");
         /* Enable power management to charge */
         powermgmt_init();
+        adc_init();
 
         usb_acknowledge(SYS_USB_CONNECTED_ACK);
 
@@ -101,6 +104,14 @@
                 info.state == TOPOFF ? "topoff" :
                 info.state == CHARGING ? "charging" : "<unknown>");
             lcd_putsf(0, 8, "Battery: %d%%", battery_level());
+            lcd_putsf(0, 9, "Die temp: %d°C [%d, %d]",
+                adc_read(ADC_DIE_TEMP), IMX233_DIE_TEMP_HIGH,
+                IMX233_DIE_TEMP_LOW);
+            #ifdef ADC_BATT_TEMP
+            lcd_putsf(0, 10, "Batt temp: %d [%d, %d]",
+                adc_read(ADC_BATT_TEMP), IMX233_BATT_TEMP_HIGH,
+                IMX233_BATT_TEMP_LOW);
+            #endif
             lcd_update();
         }
     }
@@ -137,19 +148,15 @@
 
     button_init();
 
-    //button_debug_screen();
     printf("Boot version: %s", RBVERSION);
     printf("arg=%x addr=%x", arg, addr);
     printf("power up source: %x", __XTRACT(HW_POWER_STS, PWRUP_SOURCE));
 
-#ifdef SANSA_FUZEPLUS
-    extern void imx233_mmc_disable_window(void);
     if(arg == 0xfee1dead)
     {
-        printf("Disable MMC window.");
-        imx233_mmc_disable_window();
+        printf("Disable partitions window.");
+        imx233_partitions_enable_window(false);
     }
-#endif
 
     ret = storage_init();
     if(ret < 0)
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 61b4377..81f7d87 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -506,6 +506,7 @@
 target/arm/imx233/kernel-imx233.c
 target/arm/imx233/sd-imx233.c
 target/arm/imx233/mmc-imx233.c
+target/arm/imx233/partitions-imx233.c
 target/arm/imx233/ssp-imx233.c
 target/arm/imx233/dma-imx233.c
 target/arm/imx233/icoll-imx233.c
diff --git a/firmware/target/arm/imx233/mmc-imx233.c b/firmware/target/arm/imx233/mmc-imx233.c
index f4dab30..b2b18c8 100644
--- a/firmware/target/arm/imx233/mmc-imx233.c
+++ b/firmware/target/arm/imx233/mmc-imx233.c
@@ -25,6 +25,7 @@
 #include "storage.h"
 #include "ssp-imx233.h"
 #include "pinctrl-imx233.h"
+#include "partitions-imx233.h"
 
 /**
  * This code assumes a single eMMC internal flash
@@ -39,12 +40,13 @@
 #define MMC_RCA     1
 
 /** 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 unsigned mmc_window_start;
+static unsigned mmc_window_end;
 static bool mmc_window_enable = true;
 static long mmc_last_activity = -1;
 static bool mmc_is_active = false;
 static unsigned mmc_size = 0;
+static int mmc_first_drive = 0;
 
 static struct mutex mmc_mutex;
 
@@ -142,37 +144,19 @@
         mmc_size = *sec_count;
     }
 
+    mmc_window_start = 0;
+    mmc_window_end = INT_MAX;
     #ifdef SANSA_FUZEPLUS
-    if(mmc_window_enable)
+    if(imx233_partitions_is_window_enabled())
     {
-        /**
-         * 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 */
+        /* WARNING: mmc_first_drive is not set yet at this point */
         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(ret)
+            panicf("cannot read MBR: %d", ret);
+        ret = imx233_partitions_compute_window(mbr, &mmc_window_start, &mmc_window_end);
+        if(ret)
+            panicf("cannot compute partitions window: %d", ret);
         mmc_size = mmc_window_end - mmc_window_start;
     }
     #endif
@@ -182,7 +166,7 @@
 
 int mmc_num_drives(int first_drive)
 {
-    (void) first_drive;
+    mmc_first_drive = first_drive;
     return 1;
 }
 
diff --git a/firmware/target/arm/imx233/partitions-imx233.c b/firmware/target/arm/imx233/partitions-imx233.c
new file mode 100644
index 0000000..06c5a48
--- /dev/null
+++ b/firmware/target/arm/imx233/partitions-imx233.c
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2012 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.
+ *
+ ****************************************************************************/
+#include "partitions-imx233.h"
+
+static bool enable_window = true;
+
+void imx233_partitions_enable_window(bool enable)
+{
+    enable_window = enable;
+}
+
+bool imx233_partitions_is_window_enabled(void)
+{
+    return enable_window;
+}
+
+int imx233_partitions_compute_window(uint8_t mbr[512], unsigned *start, unsigned *end)
+{
+    /**
+     * Freescale 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 the window to the user partition
+     *
+     * WARNING HACK FIXME BUG
+     * Reverse engineering and experiments suggests that the OF ignores the lowest 2 bits
+     * of the LBAs in the partition table. There is at least one example
+     * (the Creative Zen X-Fi3) where this is important because the LBA of the user partition
+     * is not a multiple of 4. The behaviour of the size field is less clear but
+     * it seems that it is similarly truncated. */
+    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];
+    *start = ent[8] | ent[9] << 8 | ent[10] << 16 | ent[11] << 24;
+    /* ignore two lowest bits(see comment above) */
+    *start &= ~3;
+    *end = (ent[12] | ent[13] << 8 | ent[14] << 16 | ent[15] << 24);
+    *end &= ~3;
+    /* ignore two lowest bits(order is important, first truncate then add start) */
+    *end += *start;
+    
+    if(ent[4] == 0x53)
+        return -102; /* sigmatel partition */
+    if((*end - *start) < 4 * 1024 * 1024)
+        return -103; /* partition too small */
+    return 0;
+}
diff --git a/firmware/target/arm/imx233/partitions-imx233.h b/firmware/target/arm/imx233/partitions-imx233.h
new file mode 100644
index 0000000..4490aad
--- /dev/null
+++ b/firmware/target/arm/imx233/partitions-imx233.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2012 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 __PARTITIONS_IMX233__
+#define __PARTITIONS_IMX233__
+
+#include "system.h"
+#include "storage.h"
+
+/* Enable/Disable window computations for internal storage following the
+ * Freescale convention */
+void imx233_partitions_enable_window(bool enable);
+bool imx233_partitions_is_window_enabled(void);
+int imx233_partitions_compute_window(uint8_t mbr[512], unsigned *start, unsigned *end);
+
+#endif /* __PARTITIONS_IMX233__ */
\ No newline at end of file