Enhanced OMAP3 boot ROM emulation
authorJuha Riihimäki <juhriihi@esdhcp039194.research.nokia.com>
Thu, 12 Mar 2009 13:12:54 +0000 (15:12 +0200)
committerRiku Voipio <riku.voipio@nokia.com>
Thu, 19 Mar 2009 14:24:20 +0000 (16:24 +0200)
Boot ROM emulation is no longer dependent on machine specifics (e.g. type of NAND device attached). Also a kind of stub ROM image is mapped at correct address at POR.

Makefile.target
hw/beagle.c
hw/omap.h
hw/omap3.c

index 355473c..a741a9e 100644 (file)
@@ -669,7 +669,7 @@ OBJS+= pflash_cfi01.o gumstix.o
 OBJS+= zaurus.o ide.o serial.o nand.o ecc.o spitz.o tosa.o tc6393xb.o
 OBJS+= omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
 OBJS+= omap2.o omap_dss.o soc_dma.o
-OBJS+= omap3.o omap3_mmc.o omap3_usb.o beagle.o twl4030.o
+OBJS+= omap3.o omap3_boot.o omap3_mmc.o omap3_usb.o beagle.o twl4030.o
 OBJS+= omap_sx1.o palm.o tsc210x.o
 OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
 OBJS+= tsc2005.o bt-hci-csr.o
index 519e583..ed4a927 100644 (file)
@@ -43,48 +43,6 @@ struct beagle_s {
     struct twl4030_s *twl4030;
 };
 
-static void beagle_nand_pread(struct nand_flash_s *nand,
-                              uint64_t addr,
-                              uint8_t *data,
-                              uint32_t len)
-{
-    uint16_t x;
-    uint32_t i;
-    
-    if ((len&1) || (addr&1)) {
-        fprintf(stderr, "%s: read byte length and address must be even (x16 device!)\n",
-                __FUNCTION__);
-        exit(-1);
-    }
-    /* send command: reset */
-    nand_setpins(nand, 1, 0, 0, 1, 0);
-    nand_setio(nand, 0xff);
-    while (len) {
-        /* send command: read page (cycle1) */
-        nand_setpins(nand, 1, 0, 0, 1, 0);
-        nand_setio(nand, 0);
-        /* send address */
-        nand_setpins(nand, 0, 1, 0, 1, 0);
-        nand_setio(nand, (uint32_t)((addr >> 1) & 0xff));
-        nand_setio(nand, (uint32_t)((addr >> 9) & 0x3));
-        nand_setio(nand, (uint32_t)((addr >> 11) & 0xff));
-        nand_setio(nand, (uint32_t)((addr >> 19) & 0xff));
-        nand_setio(nand, (uint32_t)((addr >> 27) & 0x1));
-        /* send command: read page (cycle2) */
-        nand_setpins(nand, 1, 0, 0, 1, 0);
-        nand_setio(nand, 0x30);
-        /* read page data */
-        nand_setpins(nand, 0, 0, 0, 1, 0);
-        for (i = (BEAGLE_NAND_PAGESIZE / 2) - (addr & 0x3ff); i && len; i--) {
-            x = nand_getio(nand);
-            *(data++) = (uint8_t)(x & 0xff);
-            *(data++) = (uint8_t)((x >> 8) & 0xff);
-            len -= 2;
-            addr += 2;
-        }
-    }
-}
-
 static void beagle_init(ram_addr_t ram_size, int vga_ram_size,
                 const char *boot_device,
                 const char *kernel_filename, const char *kernel_cmdline,
@@ -118,12 +76,7 @@ static void beagle_init(ram_addr_t ram_size, int vga_ram_size,
        s->lcd_panel = omap3_lcd_panel_init();
        omap3_lcd_panel_attach(s->cpu->dss, 0, s->lcd_panel);
     
-    if (!omap3_mmc_boot(s->cpu) 
-        && !omap3_nand_boot(s->cpu, s->nand, beagle_nand_pread)) {
-        fprintf(stderr, "%s: boot from MMC and NAND failed\n",
-                __FUNCTION__);
-        exit(-1);
-    }
+    omap3_boot_rom_emu(s->cpu);
 }
 
 QEMUMachine beagle_machine = {
index 8bd77a5..e186491 100644 (file)
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -1239,13 +1239,9 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
 struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
                 const char *core);
 void omap3_set_mem_type(struct omap_mpu_state_s *s, int bootfrom);
-int omap3_mmc_boot(struct omap_mpu_state_s *s);
-int omap3_nand_boot(struct omap_mpu_state_s *mpu,
-                    struct nand_flash_s *nand,
-                    void (*nand_pread_f)(struct nand_flash_s *nand,
-                                         uint64_t address,
-                                         uint8_t *data,
-                                         uint32_t len));
+
+/* omap3_boot.c */
+void omap3_boot_rom_emu(struct omap_mpu_state_s *s);
 
 # if TARGET_PHYS_ADDR_BITS == 32
 #  define OMAP_FMT_plx "0x%08x"
index c26d554..9abceaf 100644 (file)
@@ -3642,8 +3642,9 @@ static void omap3_scm_reset(struct omap3_scm_s *s)
        s->general[0x01] = 0x4000000;  /* CONTROL_DEVCONF_0 */
        s->general[0x1c] = 0x1;        /* 0x480022e0?? */
     s->general[0x20] = 0x30f;      /* CONTROL_STATUS:
-                                    * - device type = GP Device
-                                    * - sys_boot = NAND, USB, UART3, MMC1 */
+                                    * - device type  = GP Device
+                                    * - sys_boot:6   = oscillator bypass mode
+                                    * - sys_boot:0-5 = NAND, USB, UART3, MMC1*/
        s->general[0x75] = 0x7fc0;     /* CONTROL_PROG_IO0 */
        s->general[0x76] = 0xaa;       /* CONTROL_PROG_IO1 */
        s->general[0x7c] = 0x2700;     /* CONTROL_SDRC_SHARING */
@@ -4119,17 +4120,7 @@ static struct omap3_sms_s *omap3_sms_init(struct omap_mpu_state_s *mpu)
     return s;
 }
 
-#define OMAP3_BOOT_ROM_SIZE 0x1c000 /* 80 + 32 KB */
-static const uint8_t omap3_boot_rom[] = {
-    0x0e, 0xf0, 0xb0, 0xe1, /* movs pc, lr */
-    0x0e, 0xf0, 0xb0, 0xe1, /* movs pc, lr */
-    0x0e, 0xf0, 0xb0, 0xe1, /* movs pc, lr */
-    0x04, 0xf0, 0x5e, 0xe2, /* subs pc, lr, #4 */
-    0x08, 0xf0, 0x5e, 0xe2, /* subs pc, lr, #8 */
-    0x0e, 0xf0, 0xb0, 0xe1, /* movs pc, lr */
-    0x04, 0xf0, 0x5e, 0xe2, /* subs pc, lr, #4 */
-    0x04, 0xf0, 0x5e, 0xe2, /* subs pc, lr, #4 */
-};
+#define OMAP3_BOOT_ROM_SIZE 0x1c000 /* 80 + 32 kB */
 
 static const struct dma_irq_map omap3_dma_irq_map[] = {
     {0, OMAP_INT_3XXX_SDMA_IRQ0},
@@ -4179,8 +4170,6 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
                                  bootrom_base | IO_MEM_ROM);
     cpu_register_physical_memory(0, OMAP3_BOOT_ROM_SIZE,
                                  bootrom_base | IO_MEM_ROM);
-    cpu_physical_memory_write_rom(OMAP3_Q1_BASE, omap3_boot_rom,
-                                  sizeof(omap3_boot_rom));
 
     s->l4 = omap_l4_init(OMAP3_L4_BASE, 
                          sizeof(omap3_l4_agent_info) 
@@ -4376,497 +4365,3 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
                                     s->irq[0][OMAP_INT_3XXX_TLL_IRQ]);
     return s;
 }
-
-
-static inline uint32_t omap3_get_le32(const void *p)
-{
-    const uint8_t *q = (const uint8_t *)p;
-    uint32_t v;
-    v = q[3]; v <<= 8;
-    v |= q[2]; v <<= 8;
-    v |= q[1]; v <<= 8;
-    v |= q[0];
-    return v;
-}
-
-static inline uint32_t omap3_get_le16(const void *p)
-{
-    const uint8_t *q = (const uint8_t *)p;
-    uint32_t v;
-    v = q[1]; v <<= 8;
-    v |= q[0];
-    return v;
-}
-
-static inline void omap3_boot_setlsb(target_phys_addr_t addr, uint16_t lsb)
-{
-    uint8_t x[4];
-    
-    cpu_physical_memory_read(addr, x, 4);
-    x[0] = lsb & 0xff;
-    x[1] = (lsb >> 8) & 0xff;
-    cpu_physical_memory_write(addr, x, 4);
-}
-
-struct omap3_boot_s {
-    struct omap_mpu_state_s *mpu;
-    enum {
-        undefined = 0,
-        confighdr,
-        chdone,
-        imagehdr,
-        copy,
-        done
-    } state;
-    target_phys_addr_t addr;
-    uint32_t count;
-};
-
-static struct omap3_boot_s *omap3_boot_init(const uint8_t *data,
-                                            uint32_t data_len,
-                                            struct omap_mpu_state_s *mpu)
-{
-    struct omap3_boot_s *s = qemu_mallocz(sizeof(struct omap3_boot_s));
-    s->mpu = mpu;
-    s->state = imagehdr;
-    if (data_len >= 512) {
-        if (!strncasecmp((char *)(data + 0x14), "chsettings", 10)
-            || !strncasecmp((char *)(data + 0x14), "chram", 5)
-            || !strncasecmp((char *)(data + 0x14), "chflash", 7)
-            || !strncasecmp((char *)(data + 0x14), "chmmcsd", 7))
-            s->state = confighdr;
-    }
-    return s;
-}
-
-static void omap3_boot_chsettings(const uint8_t *chtoc)
-{
-    uint32_t flags, x;
-    
-    if (omap3_get_le32(chtoc) != 0xc0c0c0c1) {
-        fprintf(stderr, "%s: invalid section verification key\n", __FUNCTION__);
-        return;
-    }
-    if (!chtoc[4]) { /* section disabled? */
-        return;
-    }
-    if (omap3_get_le16(chtoc + 5) != 0x0001) {
-        fprintf(stderr, "%s: unsupported CH version (0x%04x)\n", __FUNCTION__,
-                omap3_get_le16(chtoc));
-        return;
-    }
-    flags = omap3_get_le32(chtoc + 8);
-    chtoc += 12;
-    if (flags & 1) {
-        cpu_physical_memory_write(0x48307270, chtoc + 0x00, 4); /* PRM_CLKSRC_CTRL */
-        cpu_physical_memory_write(0x48306d40, chtoc + 0x04, 4); /* PRM_CLKSEL */
-        cpu_physical_memory_write(0x48005140, chtoc + 0x08, 4); /* CM_CLKSEL1_EMU */
-        if (flags & (1 << 2)) { /* clock configuration */
-            cpu_physical_memory_write(0x48004a40, chtoc + 0x0c, 4); /* CM_CLKSEL_CORE */
-            cpu_physical_memory_write(0x48004c40, chtoc + 0x10, 4); /* CM_CLKSEL_WKUP */
-        }
-        if (flags & (1 << 5)) { /* DPLL3 CORE */
-            if (flags & (1 << 8)) { /* enable DPLL3 bypass */
-                cpu_physical_memory_read(0x48004d00, (uint8_t *)&x, 4);
-                x &= ~7; x |= 5; /* set DPLL3 bypass */
-                cpu_physical_memory_write(0x48004d00, (uint8_t *)&x, 4);
-            }
-            cpu_physical_memory_write(0x48004d00, chtoc + 0x14, 4); /* CM_CLKEN_PLL */
-            cpu_physical_memory_write(0x48004d30, chtoc + 0x18, 4); /* CM_AUTOIDLE_PLL */
-            cpu_physical_memory_write(0x48004d40, chtoc + 0x1c, 4); /* CM_CLKSEL1_PLL */
-        }
-        if (flags & (1 << 3)) { /* DPLL4 PER */
-            if (flags & (1 << 6)) { /* enable DPLL4 bypass */
-                cpu_physical_memory_read(0x48004d00, (uint8_t *)&x, 4);
-                x &= ~0x70000; x |= 0x10000; /* set DPLL4 in stop mode */
-                cpu_physical_memory_write(0x48004d00, (uint8_t *)&x, 4);
-            }
-            cpu_physical_memory_write(0x48004d00, chtoc + 0x20, 4); /* CM_CLKEN_PLL */
-            cpu_physical_memory_write(0x48004d30, chtoc + 0x24, 4); /* CM_AUTOIDLE_PLL */
-            cpu_physical_memory_write(0x48004d44, chtoc + 0x28, 4); /* CM_CLKSEL2_PLL */
-            cpu_physical_memory_write(0x48004d48, chtoc + 0x2c, 4); /* CM_CLKSEL3_PLL */
-        }
-        if (flags & (1 << 3)) { /* DPLL1 MPU */
-            if (flags & (1 << 7)) { /* enable DPLL1 bypass */
-                cpu_physical_memory_read(0x48004904, (uint8_t *)&x, 4);
-                x &= ~7; x |= 5; /* set DPLL1 bypass */
-                cpu_physical_memory_write(0x48004904, (uint8_t *)&x, 4);
-            }
-            cpu_physical_memory_write(0x48004904, chtoc + 0x30, 4); /* CM_CLKEN_PLL_MPU */
-            cpu_physical_memory_write(0x48004934, chtoc + 0x34, 4); /* CM_AUTOIDLE_PLL_MPU */
-            cpu_physical_memory_write(0x48004940, chtoc + 0x38, 4); /* CM_CLKSEL1_PLL_MPU */
-            cpu_physical_memory_write(0x48004944, chtoc + 0x3c, 4); /* CM_CLKSEL2_PLL_MPU */
-            cpu_physical_memory_write(0x48004948, chtoc + 0x40, 4); /* CM_CLKSTCTRL_MPU */
-        }
-        switch ((flags >> 24) & 0xff) {
-            case 0x01: x = 0; break; /* 12MHz */
-            case 0x02: x = 1; break; /* 13MHz */
-            case 0x03: x = 5; break; /* 16.8MHz */
-            case 0x04: x = 2; break; /* 19.2MHz */
-            case 0x05: x = 3; break; /* 26MHz */
-            case 0x06: x = 4; break; /* 38.4MHz */
-            default:
-                fprintf(stderr, "%s: unsupported SYS.CLK setting\n", __FUNCTION__);
-                x = 1;
-                break;
-        }
-        if (x != omap3_get_le32(chtoc + 0x04)) {
-            fprintf(stderr, "%s: mismatch in SYS.CLK id and PRM_CLKSEL value\n", __FUNCTION__);
-        }
-    }
-}
-
-static void omap3_boot_chram(const uint8_t *chtoc)
-{
-    if (omap3_get_le32(chtoc) != 0xc0c0c0c2) {
-        fprintf(stderr, "%s: invalid section verification key\n", __FUNCTION__);
-        return;
-    }
-    if (!chtoc[4]) { /* section disabled? */
-        return;
-    }
-    omap3_boot_setlsb(0x6d000040, omap3_get_le16(chtoc + 0x0a)); /* SDRC_CS_CFG */
-    omap3_boot_setlsb(0x6d000044, omap3_get_le16(chtoc + 0x0c)); /* SDRC_SHARING */
-    cpu_physical_memory_write(0x6d000060, chtoc + 0x10, 4);      /* SDRC_DLLA_CTRL */
-
-    cpu_physical_memory_write(0x6d000080, chtoc + 0x20, 4);      /* SDRC_MCFG_0 */
-    omap3_boot_setlsb(0x6d000084, omap3_get_le16(chtoc + 0x24)); /* SDRC_MR_0 */
-    omap3_boot_setlsb(0x6d000088, omap3_get_le16(chtoc + 0x26)); /* SDRC_EMR1_0? */
-    omap3_boot_setlsb(0x6d00008c, omap3_get_le16(chtoc + 0x28)); /* SDRC_EMR2_0 */
-    omap3_boot_setlsb(0x6d000090, omap3_get_le16(chtoc + 0x2a)); /* SDRC_EMR3_0? */
-    cpu_physical_memory_write(0x6d00009c, chtoc + 0x2c, 4);      /* SDRC_ACTIM_CTRLA_0 */
-    cpu_physical_memory_write(0x6d0000a0, chtoc + 0x30, 4);      /* SDRC_ACTIM_CTRLB_0 */
-    cpu_physical_memory_write(0x6d0000a4, chtoc + 0x34, 4);      /* SDRC_RFR_CTRL_0 */
-    
-    cpu_physical_memory_write(0x6d0000b0, chtoc + 0x20, 4);      /* SDRC_MCFG_1 */
-    omap3_boot_setlsb(0x6d0000b4, omap3_get_le16(chtoc + 0x24)); /* SDRC_MR_1 */
-    omap3_boot_setlsb(0x6d0000b8, omap3_get_le16(chtoc + 0x26)); /* SDRC_EMR1_1? */
-    omap3_boot_setlsb(0x6d0000bc, omap3_get_le16(chtoc + 0x28)); /* SDRC_EMR2_1 */
-    omap3_boot_setlsb(0x6d0000c0, omap3_get_le16(chtoc + 0x2a)); /* SDRC_EMR3_1? */
-    cpu_physical_memory_write(0x6d0000cc, chtoc + 0x2c, 4);      /* SDRC_ACTIM_CTRLA_1 */
-    cpu_physical_memory_write(0x6d0000d0, chtoc + 0x30, 4);      /* SDRC_ACTIM_CTRLB_1 */
-    cpu_physical_memory_write(0x6d0000d4, chtoc + 0x34, 4);      /* SDRC_RFR_CTRL_1 */
-}
-
-static void omap3_boot_chflash(const uint8_t *chtoc)
-{
-    if (omap3_get_le32(chtoc) != 0xc0c0c0c3) {
-        fprintf(stderr, "%s: invalid section verification key\n", __FUNCTION__);
-        return;
-    }
-    if (!chtoc[4]) { /* section disabled? */
-        return;
-    }
-    omap3_boot_setlsb(0x6e000010, omap3_get_le16(chtoc + 0x08)); /* GPMC_SYSCONFIG */
-    omap3_boot_setlsb(0x6e00001c, omap3_get_le16(chtoc + 0x0a)); /* GPMC_IRQENABLE */
-    omap3_boot_setlsb(0x6e000040, omap3_get_le16(chtoc + 0x0c)); /* GPMC_TIMEOUT_CONTROL */
-    omap3_boot_setlsb(0x6e000050, omap3_get_le16(chtoc + 0x0e)); /* GPMC_CONFIG */
-    cpu_physical_memory_write(0x6e000060, chtoc + 0x10, 4);      /* GPMC_CONFIG1_0 */
-    cpu_physical_memory_write(0x6e000064, chtoc + 0x14, 4);      /* GPMC_CONFIG2_0 */
-    cpu_physical_memory_write(0x6e000068, chtoc + 0x18, 4);      /* GPMC_CONFIG3_0 */
-    cpu_physical_memory_write(0x6e00006c, chtoc + 0x1c, 4);      /* GPMC_CONFIG4_0 */
-    cpu_physical_memory_write(0x6e000070, chtoc + 0x20, 4);      /* GPMC_CONFIG5_0 */
-    cpu_physical_memory_write(0x6e000074, chtoc + 0x24, 4);      /* GPMC_CONFIG6_0 */
-    cpu_physical_memory_write(0x6e000078, chtoc + 0x28, 4);      /* GPMC_CONFIG7_0 */
-    cpu_physical_memory_write(0x6e0001e0, chtoc + 0x2c, 4);      /* GPMC_PREFETCH_CONFIG1 */
-    omap3_boot_setlsb(0x6e0001e4, omap3_get_le16(chtoc + 0x30)); /* GPMC_PREFETCH_CONFIG2 */
-    omap3_boot_setlsb(0x6e0001ec, omap3_get_le16(chtoc + 0x32)); /* GPMC_PREFETCH_CONTROL */
-    /* TODO: ECC config registers. The TRM spec is not clear on these */
-}
-
-static void omap3_boot_chmmcsd(const uint8_t *chtoc)
-{
-    if (omap3_get_le32(chtoc) != 0xc0c0c0c4) {
-        fprintf(stderr, "%s: invalid section verification key\n", __FUNCTION__);
-        return;
-    }
-    if (!chtoc[4]) { /* section disabled? */
-        return;
-    }
-    /* TODO: MMCHS registers */
-}
-
-/* returns non-zero if more blocks are needed */
-static uint32_t omap3_boot_block(const uint8_t *data,
-                                 uint32_t data_len,
-                                 struct omap3_boot_s *s)
-{
-    const uint8_t *p = 0;
-    uint32_t i = 0;
-    
-    switch (s->state) {
-        case confighdr:
-            i = data_len;
-            for (p = data; i >= 32 && omap3_get_le32(p) != 0xffffffff; p += 32, i -= 32) {
-                if (!strcasecmp((char *)(p + 0x14), "chsettings"))
-                    omap3_boot_chsettings(p + omap3_get_le32(p));
-                else if (!strcasecmp((char *)(p + 0x14), "chram"))
-                    omap3_boot_chram(p + omap3_get_le32(p));
-                else if (!strcasecmp((char *)(p + 0x14), "chflash"))
-                    omap3_boot_chflash(p + omap3_get_le32(p));
-                else if (!strcasecmp((char *)(p + 0x14), "chmmcsd"))
-                    omap3_boot_chmmcsd(p + omap3_get_le32(p));
-                else
-                    fprintf(stderr, "%s: unknown CHTOC item \"%s\"\n",
-                            __FUNCTION__, (char *)(p + 0x14));
-            }
-            data += 512;
-            data_len -= 512;
-            s->state = chdone;
-            /* fallthrough */
-        case chdone:
-            s->state = imagehdr;
-            /* fallthrough */
-        case imagehdr:
-            if (!data_len)
-                return 1;
-            if (data_len < 8)
-                break;
-            s->count = omap3_get_le32(data);
-            s->addr = omap3_get_le32(data + 4);
-            if (!s->count || !s->addr || s->addr == 0xffffffff)
-                break;
-            s->mpu->env->regs[15] = s->addr;
-            data += 8;
-            data_len -= 8;
-            s->state = copy;
-            /* fallthrough */
-        case copy:
-            i = (s->count >= data_len) ? data_len : s->count;
-            cpu_physical_memory_write(s->addr, data, i);
-            s->addr += i;
-            s->count -= i;
-            if (!s->count)
-                s->state = done;
-            return s->count;
-        default:
-            break;
-    }
-    return 0;
-}
-
-/* returns ptr to matching dir entry / zero entry or 0 if unsuccessful */
-static const uint8_t *omap3_scan_fat_dir_sector(const uint8_t *s)
-{
-    int i;
-    
-    /* there are 0x10 items with 0x20 bytes per item */
-    for (i = 0x10; i--; s += 0x20) {
-        if (*s == 0xe5 || (s[0x0b] & 0x0f) == 0x0f) continue; /* erased/LFN */
-        if (!*s || !strncasecmp((void *)s, "mlo        ", 8+3)) return s;
-    }
-    return 0;
-}
-
-struct omap3_fat_drv_s {
-    BlockDriverState *bs;
-    uint8_t ptype; /* 12, 16, 32 */
-    uint64_t c0;   /* physical byte offset for data cluster 0 */
-    uint64_t fat;  /* physical byte offset for used FAT sector 0 */
-    uint32_t spc;  /* sectors per cluster */
-};
-
-/* returns cluster data in the buffer and next cluster chain number
-   or 0 if unsuccessful */
-static uint32_t omap3_read_fat_cluster(uint8_t *data,
-                                       struct omap3_fat_drv_s *drv,
-                                       uint32_t cl)
-{
-    uint8_t buf[ 4 ];
-    uint32_t len = drv->spc * 0x200; /* number of bytes to read */
-    
-    switch (drv->ptype) { /* check for EOF */
-        case 12: if (cl > 0xff0) return 0; break;
-        case 16: if (cl > 0xfff0) return 0; break;
-        case 32: if (cl > 0x0ffffff0) return 0; break;
-        default: return 0;
-    }
-    
-    if (bdrv_pread(drv->bs, 
-                   drv->c0 + ((drv->ptype == 32 ? cl - 2 : cl) * len),
-                   data, len) != len)
-        return 0;
-    
-    switch (drv->ptype) { /* determine next cluster # */
-        case 12:
-            fprintf(stderr, "%s: FAT12 parsing not implemented!\n",
-                    __FUNCTION__);
-            break;
-        case 16:
-            return (bdrv_pread(drv->bs, drv->fat + cl * 2, buf, 2) != 2)
-            ? 0 : omap3_get_le16(buf);
-        case 32:
-            return (bdrv_pread(drv->bs, drv->fat + cl * 4, buf, 4) != 4)
-            ? 0 : omap3_get_le32(buf) & 0x0fffffff;
-        default:
-            break;
-    }
-    return 0;
-}
-
-static int omap3_mmc_fat_boot(BlockDriverState *bs,
-                              uint8_t *sector,
-                              uint32_t pstart,
-                              struct omap_mpu_state_s *mpu)
-{
-    struct omap3_fat_drv_s drv;
-    struct omap3_boot_s *boot;
-    uint32_t i, j, cluster0, fatsize, bootsize, rootsize;
-    const uint8_t *p, *q;
-    uint8_t *cluster;
-    int result = 0;
-    
-    /* determine FAT type */
-    
-    drv.bs = bs;
-    fatsize = omap3_get_le16(sector + 0x16);
-    if (!fatsize) 
-        fatsize = omap3_get_le32(sector + 0x24);
-    bootsize = omap3_get_le16(sector + 0x0e);
-    cluster0 = bootsize + fatsize * sector[0x10];
-    rootsize = omap3_get_le16(sector + 0x11);
-    if (rootsize & 0x0f)
-        rootsize += 0x10;
-    rootsize >>= 4;
-    drv.spc = sector[0x0d];
-    i = omap3_get_le16(sector + 0x13);
-    if (!i)
-        i = omap3_get_le32(sector + 0x20);
-    i = (i - (cluster0 + rootsize)) / drv.spc;
-    drv.ptype = (i < 4085) ? 12 : (i < 65525) ? 16 : 32;
-    
-    /* search for boot loader file */
-    
-    drv.fat = (bootsize + pstart) * 0x200;
-    drv.c0 = (cluster0 + pstart) * 0x200;
-    if (drv.ptype == 32) {
-        i = omap3_get_le32(sector + 0x2c); /* first root cluster # */
-        j = omap3_get_le16(sector + 0x28);
-        if (j & 0x80)
-            drv.fat += (j & 0x0f) * fatsize * 0x200;
-        cluster = qemu_mallocz(drv.spc * 0x200);
-        for (p = 0; !p && (i = omap3_read_fat_cluster(cluster, &drv, i)); ) {
-            for (j = drv.spc, q=cluster; j-- & !p; q += 0x200)
-                p = omap3_scan_fat_dir_sector(q);
-            if (p) 
-                memcpy(sector, q - 0x200, 0x200); /* save the sector */
-        }
-        free(cluster);
-    } else { /* FAT12/16 */
-        for (i = rootsize, j = 0, p = 0; i-- && !p; j++) {
-            if (bdrv_pread(drv.bs, drv.c0 + j * 0x200, sector, 0x200) != 0x200)
-                break;
-            p = omap3_scan_fat_dir_sector(sector);
-        }
-    }
-    
-    if (p && *p) { /* did we indeed find the file? */
-        i = omap3_get_le16(p + 0x14);
-        i <<= 16;
-        i |= omap3_get_le16(p + 0x1a);
-        j = drv.spc * 0x200;
-        uint8 *data = qemu_mallocz(j);
-        if ((i = omap3_read_fat_cluster(data, &drv, i))) {
-            boot = omap3_boot_init(data, j, mpu);
-            boot->state = imagehdr; /* override CH detection */
-            while (omap3_boot_block(data, j, boot))
-                i = omap3_read_fat_cluster(data, &drv, i);
-            result = (boot->state == done);
-            free(boot);
-        } else
-            fprintf(stderr, "%s: unable to read MLO file contents from SD card\n",
-                    __FUNCTION__);
-        free(data);
-    } else
-        fprintf(stderr, "%s: MLO file not found in the root directory\n",
-                __FUNCTION__);
-
-    return result;
-}
-
-static int omap3_mmc_raw_boot(BlockDriverState *bs,
-                              uint8_t *sector,
-                              struct omap_mpu_state_s *mpu)
-{
-    struct omap3_boot_s *boot;
-    uint32_t i = 0;
-    int result = 0;
-    
-    if (bdrv_pread(bs, 0, sector, 0x200) == 0x200) {
-        boot = omap3_boot_init(sector, 0x200, mpu);
-        if (boot->state == confighdr) { /* CH must be present for raw boot */
-            while (omap3_boot_block(sector, 0x200, boot)) {
-                if (bdrv_pread(bs, ++i, sector, 0x200) != 0x200) {
-                    fprintf(stderr, "%s: error trying to read sector %u on boot device\n",
-                            __FUNCTION__, i);
-                    break;
-                }
-            }
-        }
-        result = (boot->state == done);
-        free(boot);
-    }
-    return result;
-}
-
-/* returns non-zero if successful, zero if unsuccessful */
-int omap3_mmc_boot(struct omap_mpu_state_s *s)
-{
-    BlockDriverState *bs;
-    int sdindex = drive_get_index(IF_SD, 0, 0);
-    uint8_t *sector, *p;
-    uint32_t pstart, i;
-    int result = 0;
-    
-    /* very simple implementation for GP device boot,
-       supports only two modes:
-       1. MBR partition table with an active FAT partition
-          and boot loader file (MLO) in its root directory, or
-       2. CH sector located on first sector, followed by boot loader image */
-    if (sdindex >= 0) {
-        bs = drives_table[sdindex].bdrv;
-        sector = qemu_mallocz(0x200);
-        if (bdrv_pread(bs, 0, sector, 0x200) == 0x200) {
-            for (i = 0, p = sector + 0x1be; i < 4; i++, p += 0x10) 
-                if (p[0] == 0x80) break;
-            if (sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa /* signature */
-                && i < 4 /* active partition exists */
-                && (p[4] == 1 || p[4] == 4 || p[4] == 6 || p[4] == 11
-                    || p[4] == 12 || p[4] == 14 || p[4] == 15) /* FAT */
-                && bdrv_pread(bs, (pstart = omap3_get_le32(p + 8)) * 0x200,
-                              sector, 0x200) == 0x200
-                && sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa)
-                result = omap3_mmc_fat_boot(bs, sector, pstart, s);
-            else
-                result = omap3_mmc_raw_boot(bs, sector, s);
-        }
-        free(sector);
-    }
-    return result;
-}
-
-/* returns non-zero if successful, zero if unsuccessful */
-int omap3_nand_boot(struct omap_mpu_state_s *mpu,
-                    struct nand_flash_s *nand,
-                    void (*nand_pread_f)(struct nand_flash_s *nand,
-                                         uint64_t address,
-                                         uint8_t *data,
-                                         uint32_t len))
-{
-    struct omap3_boot_s *boot;
-    uint8_t *data;
-    uint64_t addr = 0;
-    int result = 0;
-    
-    data = qemu_mallocz(0x1000);
-    nand_pread_f(nand, 0, data, 0x1000);
-    boot = omap3_boot_init(data, 0x1000, mpu);
-    while (omap3_boot_block(data, 0x1000, boot)) {
-        addr += 0x1000;
-        nand_pread_f(nand, addr, data, 0x1000);
-    }
-    result = (boot->state == done);
-    free(boot);
-    free(data);
-    return result;
-}