save/load vmstate support in omap3 hsusb host & clean-ups
[qemu] / hw / omap3.c
index 4edc398..281a650 100644 (file)
 #include "audio/audio.h"
 #include "block.h"
 
+/*
+ * When the flag below is defined, the "less important" I/O regions
+ * will not be mapped -- this is needed because the current maximum
+ * number of I/O regions in qemu-system-arm (128) is easily reached
+ * when everything is mapped.
+ */
+#define OMAP3_REDUCE_IOREGIONS
+
 //#define OMAP3_DEBUG_
 
 #ifdef OMAP3_DEBUG_
@@ -153,6 +161,7 @@ static struct omap_l3_region_s omap3_l3_region[] = {
     [L3ID_IVA_PM       ] = {0x00014000, 0x0400, L3TYPE_PM},
 };
 
+#ifndef OMAP3_REDUCE_IOREGIONS
 static uint32_t omap3_l3ia_read(void *opaque, target_phys_addr_t addr)
 {
     struct omap3_l3_initiator_agent_s *s = (struct omap3_l3_initiator_agent_s *)opaque;
@@ -225,11 +234,37 @@ static void omap3_l3ia_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
+static void omap3_l3ia_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_l3_initiator_agent_s *s =
+        (struct omap3_l3_initiator_agent_s *)opaque;
+
+    qemu_put_be32(f, s->control);
+    qemu_put_be32(f, s->status);
+}
+
+static int omap3_l3ia_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap3_l3_initiator_agent_s *s =
+        (struct omap3_l3_initiator_agent_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->control = qemu_get_be32(f);
+    s->status = qemu_get_be32(f);
+    
+    return 0;
+}
+
 static void omap3_l3ia_init(struct omap3_l3_initiator_agent_s *s)
 {
     s->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
     s->control = 0x3e000000;
     s->status = 0;
+    
+    register_savevm("omap3_l3ia", (s->base >> 8) & 0xffff, 0,
+                    omap3_l3ia_save_state, omap3_l3ia_load_state, s);
 }
 
 static CPUReadMemoryFunc *omap3_l3ia_readfn[] = {
@@ -326,11 +361,37 @@ static void omap3_l3ta_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
+static void omap3_l3ta_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_target_agent_s *s =
+        (struct omap_target_agent_s *)opaque;
+    
+    qemu_put_be32(f, s->control);
+    qemu_put_be32(f, s->status);
+}
+
+static int omap3_l3ta_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_target_agent_s *s =
+        (struct omap_target_agent_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->control = qemu_get_be32(f);
+    s->status = qemu_get_be32(f);
+    
+    return 0;
+}
+
 static void omap3_l3ta_init(struct omap_target_agent_s *s)
 {
     s->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
     s->control = 0x03000000;
     s->status = 0;
+
+    register_savevm("omap3_l3ta", (s->base >> 8) & 0xffff, 0,
+                    omap3_l3ta_save_state, omap3_l3ta_load_state, s);
 }
 
 static CPUReadMemoryFunc *omap3_l3ta_readfn[] = {
@@ -519,6 +580,42 @@ static void omap3_l3pm_write32(void *opaque, target_phys_addr_t addr,
     omap3_l3pm_write16(opaque, addr + 2, (value >> 16) & 0xffff);
 }
 
+static void omap3_l3pm_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_l3pm_s *s = (struct omap3_l3pm_s *)opaque;
+    int i;
+    
+    qemu_put_be32(f, s->error_log);
+    qemu_put_byte(f, s->control);
+    for (i = 0; i < 8; i++) {
+        qemu_put_be16(f, s->req_info_permission[i]);
+        qemu_put_be16(f, s->read_permission[i]);
+        qemu_put_be16(f, s->write_permission[i]);
+        if (i < 7)
+            qemu_put_be32(f, s->addr_match[i]);
+    }
+}
+
+static int omap3_l3pm_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap3_l3pm_s *s = (struct omap3_l3pm_s *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->error_log = qemu_get_be32(f);
+    s->control = qemu_get_byte(f);
+    for (i = 0; i < 8; i++) {
+        s->req_info_permission[i] = qemu_get_be16(f);
+        s->read_permission[i] = qemu_get_be16(f);
+        s->write_permission[i] = qemu_get_be16(f);
+        if (i < 7)
+            s->addr_match[i] = qemu_get_be32(f);
+    }
+    return 0;
+}
+
 static void omap3_l3pm_init(struct omap3_l3pm_s *s)
 {
     int i;
@@ -572,11 +669,14 @@ static void omap3_l3pm_init(struct omap3_l3pm_s *s)
                 s->read_permission[i] = s->write_permission[i] = 0x140e;
             break;
         default:
-            fprintf(stderr, "%s: unknown PM region (0x%08x)\n",
+            fprintf(stderr, "%s: unknown PM region (0x%08llx)\n",
                     __FUNCTION__, s->base);
             exit(-1);
             break;
     }
+
+    register_savevm("omap3_l3pm", (s->base >> 8) & 0xffff, 0,
+                    omap3_l3pm_save_state, omap3_l3pm_load_state, s);
 }
 
 static CPUReadMemoryFunc *omap3_l3pm_readfn[] = {
@@ -593,21 +693,21 @@ static CPUWriteMemoryFunc *omap3_l3pm_writefn[] = {
 
 static uint32_t omap3_l3undef_read8(void *opaque, target_phys_addr_t addr)
 {
-    fprintf(stderr, "%s: unsupported register at %08x\n",
+    fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx "\n",
             __FUNCTION__, addr);
     return 0;
 }
 
 static uint32_t omap3_l3undef_read16(void *opaque, target_phys_addr_t addr)
 {
-    fprintf(stderr, "%s: unsupported register at %08x\n",
+    fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx "\n",
             __FUNCTION__, addr);
     return 0;
 }
 
 static uint32_t omap3_l3undef_read32(void *opaque, target_phys_addr_t addr)
 {
-    fprintf(stderr, "%s: unsupported register at %08x\n",
+    fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx "\n",
             __FUNCTION__, addr);
     return 0;
 }
@@ -615,21 +715,21 @@ static uint32_t omap3_l3undef_read32(void *opaque, target_phys_addr_t addr)
 static void omap3_l3undef_write8(void *opaque, target_phys_addr_t addr,
                                uint32_t value)
 {
-    fprintf(stderr, "%s: unsupported register at %08x, value %02x\n",
+    fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx ", value %02x\n",
             __FUNCTION__, addr, value);
 }
 
 static void omap3_l3undef_write16(void *opaque, target_phys_addr_t addr,
                                 uint32_t value)
 {
-    fprintf(stderr, "%s: unsupported register at %08x, value %04x\n",
+    fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx ", value %04x\n",
             __FUNCTION__, addr, value);
 }
 
 static void omap3_l3undef_write32(void *opaque, target_phys_addr_t addr,
                                 uint32_t value)
 {
-    fprintf(stderr, "%s: unsupported register at %08x, value %08x\n",
+    fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx ", value %08x\n",
             __FUNCTION__, addr, value);
 }
 
@@ -644,11 +744,15 @@ static CPUWriteMemoryFunc *omap3_l3undef_writefn[] = {
     omap3_l3undef_write16,
     omap3_l3undef_write32,
 };
+#endif
 
 static struct omap_l3_s *omap3_l3_init(target_phys_addr_t base,
                                        struct omap_l3_region_s *regions,
                                        int n)
 {
+#ifdef OMAP3_REDUCE_IOREGIONS
+    return NULL;
+#else
     int i, iomemtype = 0;
     
     struct omap_l3_s *bus = qemu_mallocz(sizeof(*bus) + n * sizeof(*bus->region));
@@ -699,6 +803,7 @@ static struct omap_l3_s *omap3_l3_init(target_phys_addr_t base,
     }
     
     return bus;
+#endif
 }
 
 typedef enum {
@@ -731,8 +836,10 @@ typedef enum {
     /* 48061000-48061FFF */ L4ID_I2C3_TA,
     /* 48062000-48062FFF */ L4ID_USBTLL,
     /* 48063000-48063FFF */ L4ID_USBTLL_TA,
-    /* 48064000-48064FFF */ L4ID_HSUSBHOST,
-    /* 48065000-48065FFF */ L4ID_HSUSBHOST_TA,
+    /* 48064000-480643FF */ L4ID_USBHOST,
+    /* 48064400-480647FF */ L4ID_USBHOST_OHCI,
+    /* 48064800-4806BFFF */ L4ID_USBHOST_EHCI,
+    /* 48065000-48065FFF */ L4ID_USBHOST_TA,
     /* 48066000-48069FFF */
     /* 4806A000-4806AFFF */ L4ID_UART1,
     /* 4806B000-4806BFFF */ L4ID_UART1_TA,
@@ -942,8 +1049,10 @@ static struct omap_l4_region_s omap3_l4_region[] = {
     [L4ID_I2C3_TA     ] = {0x00061000, 0x1000, L4TYPE_TA},
     [L4ID_USBTLL      ] = {0x00062000, 0x1000, L4TYPE_GENERIC},
     [L4ID_USBTLL_TA   ] = {0x00063000, 0x1000, L4TYPE_TA},
-    [L4ID_HSUSBHOST   ] = {0x00064000, 0x1000, L4TYPE_GENERIC},
-    [L4ID_HSUSBHOST_TA] = {0x00065000, 0x1000, L4TYPE_TA},
+    [L4ID_USBHOST     ] = {0x00064000, 0x0400, L4TYPE_GENERIC},
+    [L4ID_USBHOST_OHCI] = {0x00064400, 0x0400, L4TYPE_GENERIC},
+    [L4ID_USBHOST_EHCI] = {0x00064800, 0x0400, L4TYPE_GENERIC},
+    [L4ID_USBHOST_TA  ] = {0x00065000, 0x1000, L4TYPE_TA},
     [L4ID_UART1       ] = {0x0006a000, 0x1000, L4TYPE_GENERIC},
     [L4ID_UART1_TA    ] = {0x0006b000, 0x1000, L4TYPE_TA},
     [L4ID_UART2       ] = {0x0006c000, 0x1000, L4TYPE_GENERIC},
@@ -1121,7 +1230,12 @@ typedef enum {
     L4A_TAP,
     L4A_USBHS_OTG,
     L4A_USBHS_HOST,
-    L4A_USBHS_TLL
+    L4A_USBHS_TLL,
+    L4A_MCSPI1,
+    L4A_MCSPI2,
+    L4A_MCSPI3,
+    L4A_MCSPI4,
+    L4A_SDMA
 } omap3_l4_agent_info_id_t;
 
 struct omap3_l4_agent_info_s {
@@ -1135,7 +1249,7 @@ static const struct omap3_l4_agent_info_s omap3_l4_agent_info[] = {
     {L4A_DSS,        L4ID_DSI,       6},
     /* TODO: camera */
     {L4A_USBHS_OTG,  L4ID_HSUSBOTG,  2},
-    {L4A_USBHS_HOST, L4ID_HSUSBHOST, 2},
+    {L4A_USBHS_HOST, L4ID_USBHOST,   4},
     {L4A_USBHS_TLL,  L4ID_USBTLL,    2},
     {L4A_UART1,      L4ID_UART1,     2},
     {L4A_UART2,      L4ID_UART2,     2},
@@ -1146,16 +1260,16 @@ static const struct omap3_l4_agent_info_s omap3_l4_agent_info[] = {
     /* TODO: McBSP5 */
     {L4A_GPTIMER10,  L4ID_GPTIMER10, 2},
     {L4A_GPTIMER11,  L4ID_GPTIMER11, 2},
-    /* TODO: SPI1 */
-    /* TODO: SPI2 */
+    {L4A_MCSPI1,     L4ID_MCSPI1,    2},
+    {L4A_MCSPI2,     L4ID_MCSPI2,    2},
     {L4A_MMC1,       L4ID_MMCSDIO1,  2},
     {L4A_MMC2,       L4ID_MMCSDIO2,  2},
     {L4A_MMC3,       L4ID_MMCSDIO3,  2},
     /* TODO: HDQ/1-Wire */
     /* TODO: Mailbox */
-    /* TODO: SPI3 */
-    /* TODO: SPI4 */
-    /* TODO: SDMA */
+    {L4A_MCSPI3,     L4ID_MCSPI3,    2},
+    {L4A_MCSPI4,     L4ID_MCSPI4,    2},
+    {L4A_SDMA,       L4ID_SDMA,      2},
     {L4A_CM,         L4ID_CM_A,      3},
     {L4A_SCM,        L4ID_SCM,       2},
     {L4A_TAP,        L4ID_TAP,       2},
@@ -1185,6 +1299,7 @@ static const struct omap3_l4_agent_info_s omap3_l4_agent_info[] = {
     {L4A_GPIO6,      L4ID_GPIO6,     2},
 };
 
+#ifndef OMAP3_REDUCE_IOREGIONS
 static uint32_t omap3_l4ta_read(void *opaque, target_phys_addr_t addr)
 {
     struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
@@ -1245,6 +1360,29 @@ static void omap3_l4ta_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
+static void omap3_l4ta_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+    
+    qemu_put_be32(f, s->control);
+    qemu_put_be32(f, s->control_h);
+    qemu_put_be32(f, s->status);
+}
+
+static int omap3_l4ta_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->control = qemu_get_be32(f);
+    s->control_h = qemu_get_be32(f);
+    s->status = qemu_get_be32(f);
+    
+    return 0;
+}
+
 static CPUReadMemoryFunc *omap3_l4ta_readfn[] = {
     omap_badwidth_read32,
     omap_badwidth_read32,
@@ -1256,10 +1394,14 @@ static CPUWriteMemoryFunc *omap3_l4ta_writefn[] = {
     omap_badwidth_write32,
     omap3_l4ta_write,
 };
+#endif
 
 static struct omap_target_agent_s *omap3_l4ta_init(struct omap_l4_s *bus, int cs)
 {
-    int i, iomemtype;
+#ifndef OMAP3_REDUCE_IOREGIONS
+    int iomemtype;
+#endif
+    int i;
     struct omap_target_agent_s *ta = 0;
     const struct omap3_l4_agent_info_s *info = 0;
 
@@ -1296,25 +1438,37 @@ static struct omap_target_agent_s *omap3_l4ta_init(struct omap_l4_s *bus, int cs
         exit(-1);
     }
     
+#ifndef OMAP3_REDUCE_IOREGIONS
     iomemtype = l4_register_io_memory(0, omap3_l4ta_readfn,
                                       omap3_l4ta_writefn, ta);
     ta->base = omap_l4_attach(ta, i, iomemtype);
 
+    register_savevm("omap3_l4ta", ta->base >> 8, 0,
+                    omap3_l4ta_save_state, omap3_l4ta_load_state, ta);
+#else
+    ta->base = ta->bus->base + ta->start[i].offset;
+#endif
+
     return ta;
 }
 
 /* common PRM domain registers */
 struct omap3_prm_domain_s {
-    uint32_t rm_rstctrl;   /* 50 */
-    uint32_t rm_rstst;     /* 58 */
-    uint32_t pm_wken;      /* a0 */
-    uint32_t pm_mpugrpsel; /* a4 */
-    uint32_t pm_ivagrpsel; /* a8 */
-    uint32_t pm_wkst;      /* b0 */
-    uint32_t pm_wkdep;     /* c8 */
-    uint32_t pm_pwstctrl;  /* e0 */
-    uint32_t pm_pwstst;    /* e4 */
-    uint32_t pm_prepwstst; /* e8 */
+    uint32_t rm_rstctrl;     /* 50 */
+    uint32_t rm_rstst;       /* 58 */
+    uint32_t pm_wken;        /* a0 */
+    uint32_t pm_mpugrpsel;   /* a4 */
+    uint32_t pm_ivagrpsel;   /* a8 */
+    uint32_t pm_wkst;        /* b0 */
+    uint32_t pm_wkst3;       /* b8 */
+    uint32_t pm_wkdep;       /* c8 */
+    uint32_t pm_evgenctrl;   /* d4 */
+    uint32_t pm_evgenontim;  /* d8 */
+    uint32_t pm_evgenofftim; /* dc */
+    uint32_t pm_pwstctrl;    /* e0 */
+    uint32_t pm_pwstst;      /* e4 */
+    uint32_t pm_prepwstst;   /* e8 */
+    uint32_t pm_wken3;       /* f0 */
 };
 
 struct omap3_prm_s {
@@ -1334,169 +1488,150 @@ struct omap3_prm_s {
     struct omap3_prm_domain_s neon;
     struct omap3_prm_domain_s usbhost;
 
-    uint32_t iva2_prm_irqstatus;
-    uint32_t iva2_prm_irqenable;
+    uint32_t prm_irqstatus_iva2;
+    uint32_t prm_irqenable_iva2;
     
-    uint32_t mpu_pm_evgenctrl;
-    uint32_t mpu_pm_evgenontim;
-    uint32_t mpu_pm_evgenofftim;
-
-    uint32_t core_pm_wkst3;
-    uint32_t core_pm_wken3;
-    uint32_t core_pm_iva2grpsel3;
-    uint32_t core_pm_mpugrpsel3;
-
-    uint32_t prm_revision;
-    uint32_t prm_sysconfig;
-    uint32_t prm_irqstatus_mpu;
-    uint32_t prm_irqenable_mpu;
-
-    uint32_t prm_clksel;
-    uint32_t prm_clkout_ctrl;
-
-    uint32_t prm_vc_smps_sa;
-    uint32_t prm_vc_smps_vol_ra;
-    uint32_t prm_vc_smps_cmd_ra;
-    uint32_t prm_vc_cmd_val_0;
-    uint32_t prm_vc_cmd_val_1;
-    uint32_t prm_vc_hc_conf;
-    uint32_t prm_vc_i2c_cfg;
-    uint32_t prm_vc_bypass_val;
-    uint32_t prm_rstctrl;
-    uint32_t prm_rsttimer;
-    uint32_t prm_rstst;
-    uint32_t prm_voltctrl;
-    uint32_t prm_sram_pcharge;
-    uint32_t prm_clksrc_ctrl;
-    uint32_t prm_obs;
-    uint32_t prm_voltsetup1;
-    uint32_t prm_voltoffset;
-    uint32_t prm_clksetup;
-    uint32_t prm_polctrl;
-    uint32_t prm_voltsetup2;
+    uint32_t pm_iva2grpsel3_core;
+    uint32_t pm_mpugrpsel3_core;
+
+    struct {
+        uint32_t prm_revision;
+        uint32_t prm_sysconfig;
+        uint32_t prm_irqstatus_mpu;
+        uint32_t prm_irqenable_mpu;
+    } ocp;
+
+    struct {
+        uint32_t prm_clksel;
+        uint32_t prm_clkout_ctrl;
+    } ccr; /* clock_control_reg */
+
+    struct {
+        uint32_t prm_vc_smps_sa;
+        uint32_t prm_vc_smps_vol_ra;
+        uint32_t prm_vc_smps_cmd_ra;
+        uint32_t prm_vc_cmd_val_0;
+        uint32_t prm_vc_cmd_val_1;
+        uint32_t prm_vc_hc_conf;
+        uint32_t prm_vc_i2c_cfg;
+        uint32_t prm_vc_bypass_val;
+        uint32_t prm_rstctrl;
+        uint32_t prm_rsttimer;
+        uint32_t prm_rstst;
+        uint32_t prm_voltctrl;
+        uint32_t prm_sram_pcharge;
+        uint32_t prm_clksrc_ctrl;
+        uint32_t prm_obs;
+        uint32_t prm_voltsetup1;
+        uint32_t prm_voltoffset;
+        uint32_t prm_clksetup;
+        uint32_t prm_polctrl;
+        uint32_t prm_voltsetup2;
+    } gr; /* global_reg */
 };
 
 static void omap3_prm_int_update(struct omap3_prm_s *s)
 {
-    qemu_set_irq(s->mpu_irq, s->prm_irqstatus_mpu & s->prm_irqenable_mpu);
-    qemu_set_irq(s->iva_irq, s->iva2_prm_irqstatus & s->iva2_prm_irqenable);
+    qemu_set_irq(s->mpu_irq, s->ocp.prm_irqstatus_mpu & s->ocp.prm_irqenable_mpu);
+    qemu_set_irq(s->iva_irq, s->prm_irqstatus_iva2 & s->prm_irqenable_iva2);
 }
 
 static void omap3_prm_reset(struct omap3_prm_s *s)
 {
+    bzero(&s->iva2, sizeof(s->iva2));
     s->iva2.rm_rstctrl    = 0x7;
     s->iva2.rm_rstst      = 0x1;
     s->iva2.pm_wkdep      = 0xb3;
     s->iva2.pm_pwstctrl   = 0xff0f07;
     s->iva2.pm_pwstst     = 0xff7;
-    s->iva2.pm_prepwstst  = 0x0;
-    s->iva2_prm_irqstatus = 0x0;
-    s->iva2_prm_irqenable = 0x0;
-
-    s->prm_revision      = 0x10;
-    s->prm_sysconfig     = 0x1;
-    s->prm_irqstatus_mpu = 0x0;
-    s->prm_irqenable_mpu = 0x0;
+    s->prm_irqstatus_iva2 = 0x0;
+    s->prm_irqenable_iva2 = 0x0;
 
+    bzero(&s->ocp, sizeof(s->ocp));
+    s->ocp.prm_revision      = 0x10;
+    s->ocp.prm_sysconfig     = 0x1;
+    
+    bzero(&s->mpu, sizeof(s->mpu));
     s->mpu.rm_rstst       = 0x1;
     s->mpu.pm_wkdep       = 0xa5;
     s->mpu.pm_pwstctrl    = 0x30107;
     s->mpu.pm_pwstst      = 0xc7;
-    s->mpu.pm_pwstst      = 0x0;
-    s->mpu_pm_evgenctrl   = 0x12;
-    s->mpu_pm_evgenontim  = 0x0;
-    s->mpu_pm_evgenofftim = 0x0;
+    s->mpu.pm_evgenctrl   = 0x12;
 
+    bzero(&s->core, sizeof(s->core));
     s->core.rm_rstst       = 0x1;
     s->core.pm_wken        = 0xc33ffe18;
     s->core.pm_mpugrpsel   = 0xc33ffe18;
     s->core.pm_ivagrpsel   = 0xc33ffe18;
-    s->core.pm_wkst        = 0x0;
     s->core.pm_pwstctrl    = 0xf0307;
     s->core.pm_pwstst      = 0xf7;
-    s->core.pm_prepwstst   = 0x0;
-    s->core_pm_wkst3       = 0x0;
-    s->core_pm_wken3       = 0x4;
-    s->core_pm_iva2grpsel3 = 0x4;
-    s->core_pm_mpugrpsel3  = 0x4;
+    s->core.pm_wken3       = 0x4;
+    s->pm_iva2grpsel3_core = 0x4;
+    s->pm_mpugrpsel3_core  = 0x4;
 
+    bzero(&s->sgx, sizeof(s->sgx));
     s->sgx.rm_rstst     = 0x1;
     s->sgx.pm_wkdep     = 0x16;
     s->sgx.pm_pwstctrl  = 0x30107;
     s->sgx.pm_pwstst    = 0x3;
-    s->sgx.pm_prepwstst = 0x0;
 
+    bzero(&s->wkup, sizeof(s->wkup));
     s->wkup.pm_wken      = 0x3cb;
     s->wkup.pm_mpugrpsel = 0x3cb;
-    s->wkup.pm_ivagrpsel = 0x0;
-    s->wkup.pm_wkst      = 0x0;
     s->wkup.pm_pwstst    = 0x3; /* TODO: check on real hardware */
 
-    s->prm_clksel      = 0x4;
-    s->prm_clkout_ctrl = 0x80;
+    bzero(&s->ccr, sizeof(s->ccr));
+    s->ccr.prm_clksel      = 0x3; /* TRM says 0x4, but on HW this is 0x3 */
+    s->ccr.prm_clkout_ctrl = 0x80;
 
+    bzero(&s->dss, sizeof(s->dss));
     s->dss.rm_rstst     = 0x1;
     s->dss.pm_wken      = 0x1;
     s->dss.pm_wkdep     = 0x16;
     s->dss.pm_pwstctrl  = 0x30107;
     s->dss.pm_pwstst    = 0x3;
-    s->dss.pm_prepwstst = 0x0;
 
+    bzero(&s->cam, sizeof(s->cam));
     s->cam.rm_rstst     = 0x1;
     s->cam.pm_wkdep     = 0x16;
     s->cam.pm_pwstctrl  = 0x30107;
     s->cam.pm_pwstst    = 0x3;
-    s->cam.pm_prepwstst = 0x0;
 
+    bzero(&s->per, sizeof(s->per));
     s->per.rm_rstst     = 0x1;
     s->per.pm_wken      = 0x3efff;
     s->per.pm_mpugrpsel = 0x3efff;
     s->per.pm_ivagrpsel = 0x3efff;
-    s->per.pm_wkst      = 0x0;
     s->per.pm_wkdep     = 0x17;
     s->per.pm_pwstctrl  = 0x30107;
     s->per.pm_pwstst    = 0x7;
-    s->per.pm_prepwstst = 0x0;
 
+    bzero(&s->emu, sizeof(s->emu));
     s->emu.rm_rstst  = 0x1;
     s->emu.pm_pwstst = 0x13;
 
-    s->prm_vc_smps_sa     = 0x0;
-    s->prm_vc_smps_vol_ra = 0x0;
-    s->prm_vc_smps_cmd_ra = 0x0;
-    s->prm_vc_cmd_val_0   = 0x0;
-    s->prm_vc_cmd_val_1   = 0x0;
-    s->prm_vc_hc_conf     = 0x0;
-    s->prm_vc_i2c_cfg     = 0x18;
-    s->prm_vc_bypass_val  = 0x0;
-    s->prm_rstctrl        = 0x0;
-    s->prm_rsttimer       = 0x1006;
-    s->prm_rstst          = 0x1;
-    s->prm_voltctrl       = 0x0;
-    s->prm_sram_pcharge   = 0x50;
-    s->prm_clksrc_ctrl    = 0x43;
-    s->prm_obs            = 0x0;
-    s->prm_voltsetup1     = 0x0;
-    s->prm_voltoffset     = 0x0;
-    s->prm_clksetup       = 0x0;
-    s->prm_polctrl        = 0xa;
-    s->prm_voltsetup2     = 0x0;
+    bzero(&s->gr, sizeof(s->gr));
+    s->gr.prm_vc_i2c_cfg     = 0x18;
+    s->gr.prm_rsttimer       = 0x1006;
+    s->gr.prm_rstst          = 0x1;
+    s->gr.prm_sram_pcharge   = 0x50;
+    s->gr.prm_clksrc_ctrl    = 0x43;
+    s->gr.prm_polctrl        = 0xa;
 
+    bzero(&s->neon, sizeof(s->neon));
     s->neon.rm_rstst     = 0x1;
     s->neon.pm_wkdep     = 0x2;
     s->neon.pm_pwstctrl  = 0x7;
     s->neon.pm_pwstst    = 0x3;
-    s->neon.pm_prepwstst = 0x0;
 
+    bzero(&s->usbhost, sizeof(s->usbhost));
     s->usbhost.rm_rstst     = 0x1;
     s->usbhost.pm_wken      = 0x1;
     s->usbhost.pm_mpugrpsel = 0x1;
     s->usbhost.pm_ivagrpsel = 0x1;
-    s->usbhost.pm_wkst      = 0x0;
     s->usbhost.pm_wkdep     = 0x17;
     s->usbhost.pm_pwstctrl  = 0x30107;
     s->usbhost.pm_pwstst    = 0x3;
-    s->usbhost.pm_prepwstst = 0x0;
 
     omap3_prm_int_update(s);
 }
@@ -1532,51 +1667,51 @@ static uint32_t omap3_prm_read(void *opaque, target_phys_addr_t addr)
             case 0xa4: return d->pm_mpugrpsel;
             case 0xa8: return d->pm_ivagrpsel;
             case 0xb0: return d->pm_wkst;
+            case 0xb8: return d->pm_wkst3;
             case 0xc8: return d->pm_wkdep;
+            case 0xd4: return d->pm_evgenctrl;
+            case 0xd8: return d->pm_evgenontim;
+            case 0xdc: return d->pm_evgenofftim;
             case 0xe0: return d->pm_pwstctrl;
             case 0xe4: return d->pm_pwstst;
             case 0xe8: return d->pm_prepwstst;
+            case 0xf0: return d->pm_wken3;
             default: break;
         }
 
     /* okay, not a common domain register so let's take a closer look */
     switch (addr) {
-        case 0x00f8: return s->iva2_prm_irqstatus;
-        case 0x00fc: return s->iva2_prm_irqenable;
-        case 0x0804: return s->prm_revision;
-        case 0x0814: return s->prm_sysconfig;
-        case 0x0818: return s->prm_irqstatus_mpu;
-        case 0x081c: return s->prm_irqenable_mpu;
-        case 0x09d4: return s->mpu_pm_evgenctrl;
-        case 0x09d8: return s->mpu_pm_evgenontim;
-        case 0x09dc: return s->mpu_pm_evgenofftim;
-        case 0x0ab8: return s->core_pm_wkst3;
-        case 0x0af0: return s->core_pm_wken3;
-        case 0x0af4: return s->core_pm_iva2grpsel3;
-        case 0x0af8: return s->core_pm_mpugrpsel3;
-        case 0x0d40: return s->prm_clksel;
-        case 0x0d70: return s->prm_clkout_ctrl;
+        case 0x00f8: return s->prm_irqstatus_iva2;
+        case 0x00fc: return s->prm_irqenable_iva2;
+        case 0x0804: return s->ocp.prm_revision;
+        case 0x0814: return s->ocp.prm_sysconfig;
+        case 0x0818: return s->ocp.prm_irqstatus_mpu;
+        case 0x081c: return s->ocp.prm_irqenable_mpu;
+        case 0x0af4: return s->pm_iva2grpsel3_core;
+        case 0x0af8: return s->pm_mpugrpsel3_core;
+        case 0x0d40: return s->ccr.prm_clksel;
+        case 0x0d70: return s->ccr.prm_clkout_ctrl;
         case 0x0de4: return 0x3; /* TODO: check on real hardware */
-        case 0x1220: return s->prm_vc_smps_sa;
-        case 0x1224: return s->prm_vc_smps_vol_ra;
-        case 0x1228: return s->prm_vc_smps_cmd_ra;
-        case 0x122c: return s->prm_vc_cmd_val_0;
-        case 0x1230: return s->prm_vc_cmd_val_1;
-        case 0x1234: return s->prm_vc_hc_conf;
-        case 0x1238: return s->prm_vc_i2c_cfg;
-        case 0x123c: return s->prm_vc_bypass_val;
-        case 0x1250: return s->prm_rstctrl;
-        case 0x1254: return s->prm_rsttimer;
-        case 0x1258: return s->prm_rstst;
-        case 0x1260: return s->prm_voltctrl;
-        case 0x1264: return s->prm_sram_pcharge;       
-        case 0x1270: return s->prm_clksrc_ctrl;
-        case 0x1280: return s->prm_obs;
-        case 0x1290: return s->prm_voltsetup1;
-        case 0x1294: return s->prm_voltoffset;
-        case 0x1298: return s->prm_clksetup;
-        case 0x129c: return s->prm_polctrl;
-        case 0x12a0: return s->prm_voltsetup2;
+        case 0x1220: return s->gr.prm_vc_smps_sa;
+        case 0x1224: return s->gr.prm_vc_smps_vol_ra;
+        case 0x1228: return s->gr.prm_vc_smps_cmd_ra;
+        case 0x122c: return s->gr.prm_vc_cmd_val_0;
+        case 0x1230: return s->gr.prm_vc_cmd_val_1;
+        case 0x1234: return s->gr.prm_vc_hc_conf;
+        case 0x1238: return s->gr.prm_vc_i2c_cfg;
+        case 0x123c: return s->gr.prm_vc_bypass_val;
+        case 0x1250: return s->gr.prm_rstctrl;
+        case 0x1254: return s->gr.prm_rsttimer;
+        case 0x1258: return s->gr.prm_rstst;
+        case 0x1260: return s->gr.prm_voltctrl;
+        case 0x1264: return s->gr.prm_sram_pcharge;            
+        case 0x1270: return s->gr.prm_clksrc_ctrl;
+        case 0x1280: return s->gr.prm_obs;
+        case 0x1290: return s->gr.prm_voltsetup1;
+        case 0x1294: return s->gr.prm_voltoffset;
+        case 0x1298: return s->gr.prm_clksetup;
+        case 0x129c: return s->gr.prm_polctrl;
+        case 0x12a0: return s->gr.prm_voltsetup2;
         default: break;
     }
 
@@ -1584,15 +1719,38 @@ static uint32_t omap3_prm_read(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
-static inline void omap3_prm_clksrc_ctrl_update(struct omap3_prm_s *s,
-                                                uint32_t value)
+static inline void omap3_prm_clksrc_ctrl_update(struct omap3_prm_s *s)
 {
+    uint32_t value = s->gr.prm_clksrc_ctrl;
+    
     if ((value & 0xd0) == 0x40)
         omap_clk_setrate(omap_findclk(s->omap, "omap3_sys_clk"), 1, 1);
     else if ((value & 0xd0) == 0x80)
         omap_clk_setrate(omap_findclk(s->omap, "omap3_sys_clk"), 2, 1);
 }
 
+static void omap3_prm_clksel_update(struct omap3_prm_s *s)
+{
+    omap_clk newparent = 0;
+    
+    switch (s->ccr.prm_clksel & 7) {
+        case 0: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk12"); break;
+        case 1: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk13"); break;
+        case 2: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk192"); break;
+        case 3: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk26"); break;
+        case 4: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk384"); break;
+        case 5: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk168"); break;
+        default:
+            fprintf(stderr, "%s: invalid sys_clk input selection (%d) - ignored\n",
+                    __FUNCTION__, s->ccr.prm_clksel & 7);
+            break;
+    }
+    if (newparent) {
+        omap_clk_reparent(omap_findclk(s->omap, "omap3_sys_clk"), newparent);
+        omap_clk_reparent(omap_findclk(s->omap, "omap3_sys_clkout1"), newparent);
+    }
+}
+
 static void omap3_prm_write(void *opaque, target_phys_addr_t addr,
                             uint32_t value)
 {
@@ -1608,30 +1766,30 @@ static void omap3_prm_write(void *opaque, target_phys_addr_t addr,
         case 0x00e4: OMAP_RO_REG(addr); break;
         case 0x00e8: s->iva2.pm_prepwstst = value & 0xff7;
         case 0x00f8:
-            s->iva2_prm_irqstatus &= ~(value & 0x7);
+            s->prm_irqstatus_iva2 &= ~(value & 0x7);
             omap3_prm_int_update(s);
             break;
         case 0x00fc:
-            s->iva2_prm_irqenable = value & 0x7;
+            s->prm_irqenable_iva2 = value & 0x7;
             omap3_prm_int_update(s);
             break;
         /* OCP_System_Reg_PRM */
         case 0x0804: OMAP_RO_REG(addr); break;
-        case 0x0814: s->prm_sysconfig = value & 0x1; break;
+        case 0x0814: s->ocp.prm_sysconfig = value & 0x1; break;
         case 0x0818:
-            s->prm_irqstatus_mpu &= ~(value & 0x03c003fd);
+            s->ocp.prm_irqstatus_mpu &= ~(value & 0x03c003fd);
             omap3_prm_int_update(s);
             break;
         case 0x081c:
-            s->prm_irqenable_mpu = value & 0x03c003fd;
+            s->ocp.prm_irqenable_mpu = value & 0x03c003fd;
             omap3_prm_int_update(s);
             break;
         /* MPU_PRM */
         case 0x0958: s->mpu.rm_rstst &= ~(value & 0x080f); break;
         case 0x09c8: s->mpu.pm_wkdep = value & 0xa5; break;
-        case 0x09d4: s->mpu_pm_evgenctrl = value & 0x1f; break;
-        case 0x09d8: s->mpu_pm_evgenontim = value; break;
-        case 0x09dc: s->mpu_pm_evgenofftim = value; break;
+        case 0x09d4: s->mpu.pm_evgenctrl = value & 0x1f; break;
+        case 0x09d8: s->mpu.pm_evgenontim = value; break;
+        case 0x09dc: s->mpu.pm_evgenofftim = value; break;
         case 0x09e0: s->mpu.pm_pwstctrl = value & 0x3010f; break;
         case 0x09e4: OMAP_RO_REG(addr); break;
         case 0x09e8: s->mpu.pm_prepwstst = value & 0xc7; break;
@@ -1642,13 +1800,13 @@ static void omap3_prm_write(void *opaque, target_phys_addr_t addr,
         case 0x0aa4: s->core.pm_mpugrpsel = 0x80000008 | (value & 0x433ffe10); break;
         case 0x0aa8: s->core.pm_ivagrpsel = 0x80000008 | (value & 0x433ffe10); break;
         case 0x0ab0: s->core.pm_wkst = value & 0x433ffe10; break;
-        case 0x0ab8: s->core_pm_wkst3 &= ~(value & 0x4); break;
+        case 0x0ab8: s->core.pm_wkst3 &= ~(value & 0x4); break;
         case 0x0ae0: s->core.pm_pwstctrl = (value & 0x0f031f); break;
         case 0x0ae4: OMAP_RO_REG(addr); break;
         case 0x0ae8: s->core.pm_prepwstst = value & 0xf7; break;
-        case 0x0af0: s->core_pm_wken3 = value & 0x4; break;
-        case 0x0af4: s->core_pm_iva2grpsel3 = value & 0x4; break;
-        case 0x0af8: s->core_pm_mpugrpsel3 = value & 0x4; break;
+        case 0x0af0: s->core.pm_wken3 = value & 0x4; break;
+        case 0x0af4: s->pm_iva2grpsel3_core = value & 0x4; break;
+        case 0x0af8: s->pm_mpugrpsel3_core = value & 0x4; break;
         /* SGX_PRM */
         case 0x0b58: s->sgx.rm_rstst &= ~(value & 0xf); break;
         case 0x0bc8: s->sgx.pm_wkdep = value & 0x16; break;
@@ -1662,16 +1820,13 @@ static void omap3_prm_write(void *opaque, target_phys_addr_t addr,
         case 0x0cb0: s->wkup.pm_wkst &= ~(value & 0x0103cb); break;
         /* Clock_Control_Reg_PRM */
         case 0x0d40: 
-            s->prm_clksel = value & 0x7;
-            fprintf(stderr, "%s PRM_CLKSEL = 0x%x\n", __FUNCTION__,
-                    s->prm_clksel);
-            /* TODO: update clocks */
+            s->ccr.prm_clksel = value & 0x7;
+            omap3_prm_clksel_update(s);
             break;
         case 0x0d70:
-            s->prm_clkout_ctrl = value & 0x80;
-            fprintf(stderr, "%s PRM_CLKOUT_CTRL = 0x%x\n", __FUNCTION__,
-                    s->prm_clkout_ctrl);
-            /* TODO: update clocks */
+            s->ccr.prm_clkout_ctrl = value & 0x80;
+            omap_clk_onoff(omap_findclk(s->omap, "omap3_sys_clkout1"),
+                           s->ccr.prm_clkout_ctrl & 0x80);
             break;
         /* DSS_PRM */
         case 0x0e58: s->dss.rm_rstst &= ~(value & 0xf); break;
@@ -1700,30 +1855,29 @@ static void omap3_prm_write(void *opaque, target_phys_addr_t addr,
         case 0x1158: s->emu.rm_rstst &= ~(value & 7); break;
         case 0x11e4: OMAP_RO_REG(addr); break;
         /* Global_Reg_PRM */
-        case 0x1220: s->prm_vc_smps_sa = value & 0x7f007f; break;
-        case 0x1224: s->prm_vc_smps_vol_ra = value & 0xff00ff; break;
-        case 0x1228: s->prm_vc_smps_cmd_ra = value & 0xff00ff; break;
-        case 0x122c: s->prm_vc_cmd_val_0 = value; break;
-        case 0x1230: s->prm_vc_cmd_val_1 = value; break;
-        case 0x1234: s->prm_vc_hc_conf = value & 0x1f001f; break;
-        case 0x1238: s->prm_vc_i2c_cfg = value & 0x3f; break;
-        case 0x123c: s->prm_vc_bypass_val = value & 0x01ffff7f; break;
-        case 0x1250: s->prm_rstctrl = 0; break; /* TODO: resets */
-        case 0x1254: s->prm_rsttimer = value & 0x1fff; break;
-        case 0x1258: s->prm_rstst &= ~(value & 0x7fb); break;
-        case 0x1260: s->prm_voltctrl = value & 0x1f; break;
-        case 0x1264: s->prm_sram_pcharge = value & 0xff; break;
+        case 0x1220: s->gr.prm_vc_smps_sa = value & 0x7f007f; break;
+        case 0x1224: s->gr.prm_vc_smps_vol_ra = value & 0xff00ff; break;
+        case 0x1228: s->gr.prm_vc_smps_cmd_ra = value & 0xff00ff; break;
+        case 0x122c: s->gr.prm_vc_cmd_val_0 = value; break;
+        case 0x1230: s->gr.prm_vc_cmd_val_1 = value; break;
+        case 0x1234: s->gr.prm_vc_hc_conf = value & 0x1f001f; break;
+        case 0x1238: s->gr.prm_vc_i2c_cfg = value & 0x3f; break;
+        case 0x123c: s->gr.prm_vc_bypass_val = value & 0x01ffff7f; break;
+        case 0x1250: s->gr.prm_rstctrl = 0; break; /* TODO: resets */
+        case 0x1254: s->gr.prm_rsttimer = value & 0x1fff; break;
+        case 0x1258: s->gr.prm_rstst &= ~(value & 0x7fb); break;
+        case 0x1260: s->gr.prm_voltctrl = value & 0x1f; break;
+        case 0x1264: s->gr.prm_sram_pcharge = value & 0xff; break;
         case 0x1270:
-            s->prm_clksrc_ctrl = value & (0xd8);
-            omap3_prm_clksrc_ctrl_update(s, s->prm_clksrc_ctrl);
-            /* TODO: update SYSCLKSEL bits */
+            s->gr.prm_clksrc_ctrl = value & 0xd8; /* set osc bypass mode */ 
+            omap3_prm_clksrc_ctrl_update(s);
             break;
         case 0x1280: OMAP_RO_REG(addr); break;
-        case 0x1290: s->prm_voltsetup1 = value; break;
-        case 0x1294: s->prm_voltoffset = value & 0xffff; break;
-        case 0x1298: s->prm_clksetup = value & 0xffff; break;
-        case 0x129c: s->prm_polctrl = value & 0xf; break;
-        case 0x12a0: s->prm_voltsetup2 = value & 0xffff; break;
+        case 0x1290: s->gr.prm_voltsetup1 = value; break;
+        case 0x1294: s->gr.prm_voltoffset = value & 0xffff; break;
+        case 0x1298: s->gr.prm_clksetup = value & 0xffff; break;
+        case 0x129c: s->gr.prm_polctrl = value & 0xf; break;
+        case 0x12a0: s->gr.prm_voltsetup2 = value & 0xffff; break;
         /* NEON_PRM */
         case 0x1358: s->neon.rm_rstst &= ~(value & 0xf); break;
         case 0x13c8: s->neon.pm_wkdep = value & 0x2; break;
@@ -1746,6 +1900,159 @@ static void omap3_prm_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
+static void omap3_prm_save_domain_state(QEMUFile *f,
+                                        struct omap3_prm_domain_s *s)
+{
+    qemu_put_be32(f, s->rm_rstctrl);
+    qemu_put_be32(f, s->rm_rstst);
+    qemu_put_be32(f, s->pm_wken);
+    qemu_put_be32(f, s->pm_mpugrpsel);
+    qemu_put_be32(f, s->pm_ivagrpsel);
+    qemu_put_be32(f, s->pm_wkst);
+    qemu_put_be32(f, s->pm_wkst3);
+    qemu_put_be32(f, s->pm_wkdep);
+    qemu_put_be32(f, s->pm_evgenctrl);
+    qemu_put_be32(f, s->pm_evgenontim);
+    qemu_put_be32(f, s->pm_evgenofftim);
+    qemu_put_be32(f, s->pm_pwstctrl);
+    qemu_put_be32(f, s->pm_pwstst);
+    qemu_put_be32(f, s->pm_prepwstst);
+    qemu_put_be32(f, s->pm_wken3);
+}
+
+static void omap3_prm_load_domain_state(QEMUFile *f,
+                                        struct omap3_prm_domain_s *s)
+{
+    s->rm_rstctrl = qemu_get_be32(f);
+    s->rm_rstst = qemu_get_be32(f);
+    s->pm_wken = qemu_get_be32(f);
+    s->pm_mpugrpsel = qemu_get_be32(f);
+    s->pm_ivagrpsel = qemu_get_be32(f);
+    s->pm_wkst = qemu_get_be32(f);
+    s->pm_wkst3 = qemu_get_be32(f);
+    s->pm_wkdep = qemu_get_be32(f);
+    s->pm_evgenctrl = qemu_get_be32(f);
+    s->pm_evgenontim = qemu_get_be32(f);
+    s->pm_evgenofftim = qemu_get_be32(f);
+    s->pm_pwstctrl = qemu_get_be32(f);
+    s->pm_pwstst = qemu_get_be32(f);
+    s->pm_prepwstst = qemu_get_be32(f);
+    s->pm_wken3 = qemu_get_be32(f);
+}
+
+static void omap3_prm_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_prm_s *s = (struct omap3_prm_s *)opaque;
+    
+    omap3_prm_save_domain_state(f, &s->iva2);
+    omap3_prm_save_domain_state(f, &s->mpu);
+    omap3_prm_save_domain_state(f, &s->core);
+    omap3_prm_save_domain_state(f, &s->sgx);
+    omap3_prm_save_domain_state(f, &s->wkup);
+    omap3_prm_save_domain_state(f, &s->dss);
+    omap3_prm_save_domain_state(f, &s->cam);
+    omap3_prm_save_domain_state(f, &s->per);
+    omap3_prm_save_domain_state(f, &s->emu);
+    omap3_prm_save_domain_state(f, &s->neon);
+    omap3_prm_save_domain_state(f, &s->usbhost);
+    
+    qemu_put_be32(f, s->prm_irqstatus_iva2);
+    qemu_put_be32(f, s->prm_irqenable_iva2);
+    qemu_put_be32(f, s->pm_iva2grpsel3_core);
+    qemu_put_be32(f, s->pm_mpugrpsel3_core);
+    
+    qemu_put_be32(f, s->ocp.prm_revision);
+    qemu_put_be32(f, s->ocp.prm_sysconfig);
+    qemu_put_be32(f, s->ocp.prm_irqstatus_mpu);
+    qemu_put_be32(f, s->ocp.prm_irqenable_mpu);
+    
+    qemu_put_be32(f, s->ccr.prm_clksel);
+    qemu_put_be32(f, s->ccr.prm_clkout_ctrl);
+    
+    qemu_put_be32(f, s->gr.prm_vc_smps_sa);
+    qemu_put_be32(f, s->gr.prm_vc_smps_vol_ra);
+    qemu_put_be32(f, s->gr.prm_vc_smps_cmd_ra);
+    qemu_put_be32(f, s->gr.prm_vc_cmd_val_0);
+    qemu_put_be32(f, s->gr.prm_vc_cmd_val_1);
+    qemu_put_be32(f, s->gr.prm_vc_hc_conf);
+    qemu_put_be32(f, s->gr.prm_vc_i2c_cfg);
+    qemu_put_be32(f, s->gr.prm_vc_bypass_val);
+    qemu_put_be32(f, s->gr.prm_rstctrl);
+    qemu_put_be32(f, s->gr.prm_rsttimer);
+    qemu_put_be32(f, s->gr.prm_rstst);
+    qemu_put_be32(f, s->gr.prm_voltctrl);
+    qemu_put_be32(f, s->gr.prm_sram_pcharge);
+    qemu_put_be32(f, s->gr.prm_clksrc_ctrl);
+    qemu_put_be32(f, s->gr.prm_obs);
+    qemu_put_be32(f, s->gr.prm_voltsetup1);
+    qemu_put_be32(f, s->gr.prm_voltoffset);
+    qemu_put_be32(f, s->gr.prm_clksetup);
+    qemu_put_be32(f, s->gr.prm_polctrl);
+    qemu_put_be32(f, s->gr.prm_voltsetup2);
+}
+
+static int omap3_prm_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap3_prm_s *s = (struct omap3_prm_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    omap3_prm_load_domain_state(f, &s->iva2);
+    omap3_prm_load_domain_state(f, &s->mpu);
+    omap3_prm_load_domain_state(f, &s->core);
+    omap3_prm_load_domain_state(f, &s->sgx);
+    omap3_prm_load_domain_state(f, &s->wkup);
+    omap3_prm_load_domain_state(f, &s->dss);
+    omap3_prm_load_domain_state(f, &s->cam);
+    omap3_prm_load_domain_state(f, &s->per);
+    omap3_prm_load_domain_state(f, &s->emu);
+    omap3_prm_load_domain_state(f, &s->neon);
+    omap3_prm_load_domain_state(f, &s->usbhost);
+    
+    s->prm_irqstatus_iva2 = qemu_get_be32(f);
+    s->prm_irqenable_iva2 = qemu_get_be32(f);
+    s->pm_iva2grpsel3_core = qemu_get_be32(f);
+    s->pm_mpugrpsel3_core = qemu_get_be32(f);
+    
+    s->ocp.prm_revision = qemu_get_be32(f);
+    s->ocp.prm_sysconfig = qemu_get_be32(f);
+    s->ocp.prm_irqstatus_mpu = qemu_get_be32(f);
+    s->ocp.prm_irqenable_mpu = qemu_get_be32(f);
+    
+    s->ccr.prm_clksel = qemu_get_be32(f);
+    s->ccr.prm_clkout_ctrl = qemu_get_be32(f);
+    
+    s->gr.prm_vc_smps_sa = qemu_get_be32(f);
+    s->gr.prm_vc_smps_vol_ra = qemu_get_be32(f);
+    s->gr.prm_vc_smps_cmd_ra = qemu_get_be32(f);
+    s->gr.prm_vc_cmd_val_0 = qemu_get_be32(f);
+    s->gr.prm_vc_cmd_val_1 = qemu_get_be32(f);
+    s->gr.prm_vc_hc_conf = qemu_get_be32(f);
+    s->gr.prm_vc_i2c_cfg = qemu_get_be32(f);
+    s->gr.prm_vc_bypass_val = qemu_get_be32(f);
+    s->gr.prm_rstctrl = qemu_get_be32(f);
+    s->gr.prm_rsttimer = qemu_get_be32(f);
+    s->gr.prm_rstst = qemu_get_be32(f);
+    s->gr.prm_voltctrl = qemu_get_be32(f);
+    s->gr.prm_sram_pcharge = qemu_get_be32(f);
+    s->gr.prm_clksrc_ctrl = qemu_get_be32(f);
+    s->gr.prm_obs = qemu_get_be32(f);
+    s->gr.prm_voltsetup1 = qemu_get_be32(f);
+    s->gr.prm_voltoffset = qemu_get_be32(f);
+    s->gr.prm_clksetup = qemu_get_be32(f);
+    s->gr.prm_polctrl = qemu_get_be32(f);
+    s->gr.prm_voltsetup2 = qemu_get_be32(f);
+    
+    omap3_prm_int_update(s);
+    omap3_prm_clksrc_ctrl_update(s);
+    omap3_prm_clksel_update(s);
+    omap_clk_onoff(omap_findclk(s->omap, "omap3_sys_clkout1"),
+                   s->ccr.prm_clkout_ctrl & 0x80);
+    
+    return 0;
+}
+
 static CPUReadMemoryFunc *omap3_prm_readfn[] = {
     omap_badwidth_read32,
     omap_badwidth_read32,
@@ -1758,9 +2065,9 @@ static CPUWriteMemoryFunc *omap3_prm_writefn[] = {
     omap3_prm_write,
 };
 
-struct omap3_prm_s *omap3_prm_init(struct omap_target_agent_s *ta,
-                                   qemu_irq mpu_int, qemu_irq iva_int,
-                                   struct omap_mpu_state_s *mpu)
+static struct omap3_prm_s *omap3_prm_init(struct omap_target_agent_s *ta,
+                                          qemu_irq mpu_int, qemu_irq iva_int,
+                                          struct omap_mpu_state_s *mpu)
 {
     int iomemtype;
     struct omap3_prm_s *s = (struct omap3_prm_s *) qemu_mallocz(sizeof(*s));
@@ -1775,625 +2082,485 @@ struct omap3_prm_s *omap3_prm_init(struct omap_target_agent_s *ta,
     omap_l4_attach(ta, 0, iomemtype);
     omap_l4_attach(ta, 1, iomemtype);
 
+    register_savevm("omap3_prm", -1, 0,
+                    omap3_prm_save_state, omap3_prm_load_state, s);
+
     return s;
 }
 
-
-struct omap3_cm_s
-{
+struct omap3_cm_s {
     qemu_irq irq[3];
     struct omap_mpu_state_s *mpu;
 
-    /*IVA2_CM Register */
-    uint32_t cm_fclken_iva2;    /*0x4800 4000 */
-    uint32_t cm_clken_pll_iva2; /*0x4800 4004 */
-    uint32_t cm_idlest_iva2;    /*0x4800 4020 */
-    uint32_t cm_idlest_pll_iva2;        /*0x4800 4024 */
-    uint32_t cm_autoidle_pll_iva2;      /*0x4800 4034 */
-    uint32_t cm_clksel1_pll_iva2;       /*0x4800 4040 */
-    uint32_t cm_clksel2_pll_iva2;       /*0x4800 4044 */
-    uint32_t cm_clkstctrl_iva2; /*0x4800 4048 */
-    uint32_t cm_clkstst_iva2;   /*0x4800 404c */
-
-    /*OCP_System_Reg_CM */
-    uint32_t cm_revision;       /*0x4800 4800 */
-    uint32_t cm_sysconfig;      /*0x4800 4810 */
-
-    /*MPU_CM Register */
-    uint32_t cm_clken_pll_mpu;  /*0x4800 4904 */
-    uint32_t cm_idlest_mpu;     /*0x4800 4920 */
-    uint32_t cm_idlest_pll_mpu; /*0x4800 4924 */
-    uint32_t cm_autoidle_pll_mpu;       /*0x4800 4934 */
-    uint32_t cm_clksel1_pll_mpu;        /*0x4800 4940 */
-    uint32_t cm_clksel2_pll_mpu;        /*0x4800 4944 */
-    uint32_t cm_clkstctrl_mpu;  /*0x4800 4948 */
-    uint32_t cm_clkstst_mpu;    /*0x4800 494c */
-
-    /*CORE_CM Register */
-    uint32_t cm_fclken1_core;   /*0x4800 4a00 */
-    uint32_t cm_fclken3_core;   /*0x4800 4a08 */
-    uint32_t cm_iclken1_core;   /*0x4800 4a10 */
-    uint32_t cm_iclken2_core;   /*0x4800 4a14 */
-    uint32_t cm_iclken3_core;   /*0x4800 4a18 */
-    uint32_t cm_idlest1_core;   /*0x4800 4a20 */
-    uint32_t cm_idlest2_core;   /*0x4800 4a24 */
-    uint32_t cm_idlest3_core;   /*0x4800 4a28 */
-    uint32_t cm_autoidle1_core; /*0x4800 4a30 */
-    uint32_t cm_autoidle2_core; /*0x4800 4a34 */
-    uint32_t cm_autoidle3_core; /*0x4800 4a38 */
-    uint32_t cm_clksel_core;    /*0x4800 4a40 */
-    uint32_t cm_clkstctrl_core; /*0x4800 4a48 */
-    uint32_t cm_clkstst_core;   /*0x4800 4a4c */
-
-    /*SGX_CM Register */
-    uint32_t cm_fclken_sgx;     /*0x4800 4b00 */
-    uint32_t cm_iclken_sgx;     /*0x4800 4b10 */
-    uint32_t cm_idlest_sgx;     /*0x4800 4b20 */
-    uint32_t cm_clksel_sgx;     /*0x4800 4b40 */
-    uint32_t cm_sleepdep_sgx;   /*0x4800 4b44 */
-    uint32_t cm_clkstctrl_sgx;  /*0x4800 4b48 */
-    uint32_t cm_clkstst_sgx;    /*0x4800 4b4c */
-
-    /*WKUP_CM Register */
-    uint32_t cm_fclken_wkup;    /*0x4800 4c00 */
-    uint32_t cm_iclken_wkup;    /*0x4800 4c10 */
-    uint32_t cm_idlest_wkup;    /*0x4800 4c20 */
-    uint32_t cm_autoidle_wkup;  /*0x4800 4c30 */
-    uint32_t cm_clksel_wkup;    /*0x4800 4c40 */
-    uint32_t cm_c48;                  /*0x4800 4c48 */
-
-    /*Clock_Control_Reg_CM Register */
-    uint32_t cm_clken_pll;      /*0x4800 4d00 */
-    uint32_t cm_clken2_pll;     /*0x4800 4d04 */
-    uint32_t cm_idlest_ckgen;   /*0x4800 4d20 */
-    uint32_t cm_idlest2_ckgen;  /*0x4800 4d24 */
-    uint32_t cm_autoidle_pll;   /*0x4800 4d30 */
-    uint32_t cm_autoidle2_pll;  /*0x4800 4d34 */
-    uint32_t cm_clksel1_pll;    /*0x4800 4d40 */
-    uint32_t cm_clksel2_pll;    /*0x4800 4d44 */
-    uint32_t cm_clksel3_pll;    /*0x4800 4d48 */
-    uint32_t cm_clksel4_pll;    /*0x4800 4d4c */
-    uint32_t cm_clksel5_pll;    /*0x4800 4d50 */
-    uint32_t cm_clkout_ctrl;    /*0x4800 4d70 */
-
-    /*DSS_CM Register */
-    uint32_t cm_fclken_dss;     /*0x4800 4e00 */
-    uint32_t cm_iclken_dss;     /*0x4800 4e10 */
-    uint32_t cm_idlest_dss;     /*0x4800 4e20 */
-    uint32_t cm_autoidle_dss;   /*0x4800 4e30 */
-    uint32_t cm_clksel_dss;     /*0x4800 4e40 */
-    uint32_t cm_sleepdep_dss;   /*0x4800 4e44 */
-    uint32_t cm_clkstctrl_dss;  /*0x4800 4e48 */
-    uint32_t cm_clkstst_dss;    /*0x4800 4e4c */
-
-
-    /*CAM_CM Register */
-    uint32_t cm_fclken_cam;     /*0x4800 4f00 */
-    uint32_t cm_iclken_cam;     /*0x4800 4f10 */
-    uint32_t cm_idlest_cam;     /*0x4800 4f20 */
-    uint32_t cm_autoidle_cam;   /*0x4800 4f30 */
-    uint32_t cm_clksel_cam;     /*0x4800 4f40 */
-    uint32_t cm_sleepdep_cam;   /*0x4800 4f44 */
-    uint32_t cm_clkstctrl_cam;  /*0x4800 4f48 */
-    uint32_t cm_clkstst_cam;    /*0x4800 4f4c */
-
-    /*PER_CM Register */
-    uint32_t cm_fclken_per;     /*0x4800 5000 */
-    uint32_t cm_iclken_per;     /*0x4800 5010 */
-    uint32_t cm_idlest_per;     /*0x4800 5020 */
-    uint32_t cm_autoidle_per;   /*0x4800 5030 */
-    uint32_t cm_clksel_per;     /*0x4800 5040 */
-    uint32_t cm_sleepdep_per;   /*0x4800 5044 */
-    uint32_t cm_clkstctrl_per;  /*0x4800 5048 */
-    uint32_t cm_clkstst_per;    /*0x4800 504c */
-
-    /*EMU_CM Register */
-    uint32_t cm_clksel1_emu;    /*0x4800 5140 */
-    uint32_t cm_clkstctrl_emu;  /*0x4800 5148 */
-    uint32_t cm_clkstst_emu;    /*0x4800 514c */
-    uint32_t cm_clksel2_emu;    /*0x4800 5150 */
-    uint32_t cm_clksel3_emu;    /*0x4800 5154 */
-
-    /*Global_Reg_CM Register */
-    uint32_t cm_polctrl;        /*0x4800 529c */
-
-    /*NEON_CM Register */
-    uint32_t cm_idlest_neon;    /*0x4800 5320 */
-    uint32_t cm_clkstctrl_neon; /*0x4800 5348 */
-
-    /*USBHOST_CM Register */
-    uint32_t cm_fclken_usbhost; /*0x4800 5400 */
-    uint32_t cm_iclken_usbhost; /*0x4800 5410 */
-    uint32_t cm_idlest_usbhost; /*0x4800 5420 */
-    uint32_t cm_autoidle_usbhost;       /*0x4800 5430 */
-    uint32_t cm_sleepdep_usbhost;       /*0x4800 5444 */
-    uint32_t cm_clkstctrl_usbhost;      /*0x4800 5448 */
-    uint32_t cm_clkstst_usbhost;        /*0x4800 544c */
-
+    /* IVA2_CM: base + 0x0000 */
+    uint32_t cm_fclken_iva2;       /* 00 */
+    uint32_t cm_clken_pll_iva2;    /* 04 */
+    uint32_t cm_idlest_iva2;       /* 20 */
+    uint32_t cm_idlest_pll_iva2;   /* 24 */
+    uint32_t cm_autoidle_pll_iva2; /* 34 */
+    uint32_t cm_clksel1_pll_iva2;  /* 40 */
+    uint32_t cm_clksel2_pll_iva2;  /* 44 */
+    uint32_t cm_clkstctrl_iva2;    /* 48 */
+    uint32_t cm_clkstst_iva2;      /* 4c */
+
+    /* OCP_System_Reg_CM: base + 0x0800 */
+    uint32_t cm_revision;  /* 00 */
+    uint32_t cm_sysconfig; /* 10 */
+
+    /* MPU_CM: base + 0x0900 */
+    uint32_t cm_clken_pll_mpu;    /* 04 */
+    uint32_t cm_idlest_mpu;       /* 20 */
+    uint32_t cm_idlest_pll_mpu;   /* 24 */
+    uint32_t cm_autoidle_pll_mpu; /* 34 */
+    uint32_t cm_clksel1_pll_mpu;  /* 40 */
+    uint32_t cm_clksel2_pll_mpu;  /* 44 */
+    uint32_t cm_clkstctrl_mpu;    /* 48 */
+    uint32_t cm_clkstst_mpu;      /* 4c */
+
+    /* CORE_CM: base + 0x0a00 */
+    uint32_t cm_fclken1_core;   /* 0a00 */
+    uint32_t cm_fclken3_core;   /* 0a08 */
+    uint32_t cm_iclken1_core;   /* 0a10 */
+    uint32_t cm_iclken2_core;   /* 0a14 */
+    uint32_t cm_iclken3_core;   /* 0a18 */
+    uint32_t cm_idlest1_core;   /* 0a20 */
+    uint32_t cm_idlest2_core;   /* 0a24 */
+    uint32_t cm_idlest3_core;   /* 0a28 */
+    uint32_t cm_autoidle1_core; /* 0a30 */
+    uint32_t cm_autoidle2_core; /* 0a34 */
+    uint32_t cm_autoidle3_core; /* 0a38 */
+    uint32_t cm_clksel_core;    /* 0a40 */
+    uint32_t cm_clkstctrl_core; /* 0a48 */
+    uint32_t cm_clkstst_core;   /* 0a4c */
+
+    /* SGX_CM: base + 0x0b00 */
+    uint32_t cm_fclken_sgx;    /* 00 */
+    uint32_t cm_iclken_sgx;    /* 10 */
+    uint32_t cm_idlest_sgx;    /* 20 */
+    uint32_t cm_clksel_sgx;    /* 40 */
+    uint32_t cm_sleepdep_sgx;  /* 44 */
+    uint32_t cm_clkstctrl_sgx; /* 48 */
+    uint32_t cm_clkstst_sgx;   /* 4c */
+
+    /* WKUP_CM: base + 0x0c00 */
+    uint32_t cm_fclken_wkup;   /* 00 */
+    uint32_t cm_iclken_wkup;   /* 10 */
+    uint32_t cm_idlest_wkup;   /* 20 */
+    uint32_t cm_autoidle_wkup; /* 30 */
+    uint32_t cm_clksel_wkup;   /* 40 */
+    uint32_t cm_c48;           /* 48 */
+
+    /* Clock_Control_Reg_CM: base + 0x0d00 */
+    uint32_t cm_clken_pll;     /* 00 */
+    uint32_t cm_clken2_pll;    /* 04 */
+    uint32_t cm_idlest_ckgen;  /* 20 */
+    uint32_t cm_idlest2_ckgen; /* 24 */
+    uint32_t cm_autoidle_pll;  /* 30 */
+    uint32_t cm_autoidle2_pll; /* 34 */
+    uint32_t cm_clksel1_pll;   /* 40 */
+    uint32_t cm_clksel2_pll;   /* 44 */
+    uint32_t cm_clksel3_pll;   /* 48 */
+    uint32_t cm_clksel4_pll;   /* 4c */
+    uint32_t cm_clksel5_pll;   /* 50 */
+    uint32_t cm_clkout_ctrl;   /* 70 */
+
+    /* DSS_CM: base + 0x0e00 */
+    uint32_t cm_fclken_dss;    /* 00 */
+    uint32_t cm_iclken_dss;    /* 10 */
+    uint32_t cm_idlest_dss;    /* 20 */
+    uint32_t cm_autoidle_dss;  /* 30 */
+    uint32_t cm_clksel_dss;    /* 40 */
+    uint32_t cm_sleepdep_dss;  /* 44 */
+    uint32_t cm_clkstctrl_dss; /* 48 */
+    uint32_t cm_clkstst_dss;   /* 4c */
+
+   /* CAM_CM: base + 0x0f00 */
+    uint32_t cm_fclken_cam;    /* 00 */
+    uint32_t cm_iclken_cam;    /* 10 */
+    uint32_t cm_idlest_cam;    /* 20 */
+    uint32_t cm_autoidle_cam;  /* 30 */
+    uint32_t cm_clksel_cam;    /* 40 */
+    uint32_t cm_sleepdep_cam;  /* 44 */
+    uint32_t cm_clkstctrl_cam; /* 48 */
+    uint32_t cm_clkstst_cam;   /* 4c */
+
+    /* PER_CM: base + 0x1000 */
+    uint32_t cm_fclken_per;    /* 00 */
+    uint32_t cm_iclken_per;    /* 10 */
+    uint32_t cm_idlest_per;    /* 20 */
+    uint32_t cm_autoidle_per;  /* 30 */
+    uint32_t cm_clksel_per;    /* 40 */
+    uint32_t cm_sleepdep_per;  /* 44 */
+    uint32_t cm_clkstctrl_per; /* 48 */
+    uint32_t cm_clkstst_per;   /* 4c */
+
+    /* EMU_CM: base + 0x1100 */
+    uint32_t cm_clksel1_emu;   /* 40 */
+    uint32_t cm_clkstctrl_emu; /* 48 */
+    uint32_t cm_clkstst_emu;   /* 4c */
+    uint32_t cm_clksel2_emu;   /* 50 */
+    uint32_t cm_clksel3_emu;   /* 54 */
+
+    /* Global_Reg_CM: base + 0x1200 */
+    uint32_t cm_polctrl; /* 9c */
+
+    /* NEON_CM: base + 0x1300 */
+    uint32_t cm_idlest_neon;    /* 20 */
+    uint32_t cm_clkstctrl_neon; /* 48 */
+
+    /* USBHOST_CM: base + 0x1400 */
+    uint32_t cm_fclken_usbhost;    /* 00 */
+    uint32_t cm_iclken_usbhost;    /* 10 */
+    uint32_t cm_idlest_usbhost;    /* 20 */
+    uint32_t cm_autoidle_usbhost;  /* 30 */
+    uint32_t cm_sleepdep_usbhost;  /* 44 */
+    uint32_t cm_clkstctrl_usbhost; /* 48 */
+    uint32_t cm_clkstst_usbhost;   /* 4c */
 };
 
-/*
-static inline void omap3_cm_fclken_wkup_update(struct omap3_cm_s *s,
-                uint32_t value)
-{
-       
-       if (value & 0x28)
-       omap_clk_onoff(omap_findclk(s->mpu,"omap3_wkup_32k_fclk"), 1);
-    else
-       omap_clk_onoff(omap_findclk(s->mpu,"omap3_wkup_32k_fclk"), 0);
-
-    if (value &0x1)
-       omap_clk_onoff(omap_findclk(s->mpu,"omap3_gp1_fclk"), 1);
-    else
-       omap_clk_onoff(omap_findclk(s->mpu,"omap3_gp1_fclk"), 0);
-
-}
-static inline void omap3_cm_iclken_wkup_update(struct omap3_cm_s *s,
-                uint32_t value)
+static inline void omap3_cm_clksel_wkup_update(struct omap3_cm_s *s)
 {
-       
-       if (value & 0x3f)
-       omap_clk_onoff(omap_findclk(s->mpu,"omap3_wkup_l4_iclk"), 1);
-    else
-       omap_clk_onoff(omap_findclk(s->mpu,"omap3_wkup_l4_iclk"), 0);
-
-}
-*/
-static inline void omap3_cm_clksel_wkup_update(struct omap3_cm_s *s,
-                                               uint32_t value)
-{
-    omap_clk gp1_fclk = omap_findclk(s->mpu, "omap3_gp1_fclk");
-
-    if (value & 0x1)
-        omap_clk_reparent(gp1_fclk, omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(gp1_fclk, omap_findclk(s->mpu, "omap3_32k_fclk"));
-    /*Tell GPTIMER to generate new clk rate */
+    omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp1_fclk"),
+                      omap_findclk(s->mpu,
+                                   (s->cm_clksel_wkup & 1) /* CLKSEL_GPT1 */
+                                   ? "omap3_sys_clk"
+                                   : "omap3_32k_fclk"));
+    omap_clk_setrate(omap_findclk(s->mpu, "omap3_rm_iclk"),
+                     (s->cm_clksel_wkup >> 1) & 3, /* CLKSEL_RM */
+                     1);
+
+    /* Tell GPTIMER to generate new clk rate */
     omap_gp_timer_change_clk(s->mpu->gptimer[0]);
 
-    TRACE("omap3_gp1_fclk %lld",
+    TRACE("gptimer1 fclk=%lld",
           omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp1_fclk")));
 
-    /*TODO:CM_USIM_CLK CLKSEL_RM */
+    /* TODO: CM_USIM_CLK */
 }
 
-static inline void omap3_cm_mpu_update(struct omap3_cm_s *s)
+static inline void omap3_cm_iva2_update(struct omap3_cm_s *s)
 {
-    uint32_t m, n, divide, m2, cm_clken_pll_mpu;
-    uint32_t bypass = 1;
-
-    cm_clken_pll_mpu = s->cm_clken_pll_mpu;
-    omap_clk mpu_clk = omap_findclk(s->mpu, "omap3_mpu_clk");
+    uint32_t iva2_dpll_mul = ((s->cm_clksel1_pll_iva2 >> 8) & 0x7ff);
+    uint32_t iva2_dpll_div, iva2_dpll_clkout_div, iva2_clk_src;
+    omap_clk iva2_clk = omap_findclk(s->mpu, "omap3_iva2_clk");
 
-    if ((cm_clken_pll_mpu & 0x7) == 0x5)
-    {
-        bypass = 1;
-    }
-    else if ((cm_clken_pll_mpu & 0x7) == 0x7)
-    {
-        m = (s->cm_clksel1_pll_mpu & 0x7ff00) >> 8;
-        if ((m == 0) || (m == 1))
-            bypass = 1;
-        else
-            bypass = 0;
-    }
-    if (bypass == 1)
-    {
-        /*BYPASS Model */
-        divide = (s->cm_clksel1_pll_mpu & 0x380000) >> 19;
-        //OMAP3_DEBUG(("divide %d\n",divide));
-        omap_clk_reparent(mpu_clk, omap_findclk(s->mpu, "omap3_core_clk"));
-        omap_clk_setrate(mpu_clk, divide, 1);
+    omap_clk_onoff(iva2_clk, s->cm_fclken_iva2 & 1);
 
+    switch ((s->cm_clken_pll_iva2 & 0x7)) {
+        case 0x01: /* low power stop mode */
+        case 0x05: /* low power bypass mode */
+            s->cm_idlest_pll_iva2 &= ~1;
+            break;
+        case 0x07: /* locked */
+            if (iva2_dpll_mul < 2)
+                s->cm_idlest_pll_iva2 &= ~1;
+            else
+                s->cm_idlest_pll_iva2 |= 1;
+            break;
+        default:
+            break;
     }
-    else
-    {
-        n = (s->cm_clksel1_pll_mpu & 0x7F);
-        m2 = (s->cm_clksel2_pll_mpu & 0x1F);
-        //OMAP3_DEBUG(("M  %d N %d M2 %d \n",m,n,m2 ));
-        omap_clk_reparent(mpu_clk, omap_findclk(s->mpu, "omap3_sys_clk"));
-        omap_clk_setrate(mpu_clk, (n + 1) * m2, m);
-        //OMAP3_DEBUG(("mpu %d \n",omap_clk_getrate(mpu_clk)));
-
+    
+    if (s->cm_idlest_pll_iva2 & 1) {
+        iva2_dpll_div = s->cm_clksel1_pll_iva2 & 0x7f;
+        iva2_dpll_clkout_div = s->cm_clksel2_pll_iva2 & 0x1f;
+        omap_clk_reparent(iva2_clk, omap_findclk(s->mpu, "omap3_sys_clk"));
+        omap_clk_setrate(iva2_clk,
+                         (iva2_dpll_div + 1) * iva2_dpll_clkout_div,
+                         iva2_dpll_mul);
+    } else {
+        /* bypass mode */
+        iva2_clk_src = (s->cm_clksel1_pll_iva2 >> 19) & 0x07;
+        omap_clk_reparent(iva2_clk, omap_findclk(s->mpu, "omap3_core_clk"));
+        omap_clk_setrate(iva2_clk, iva2_clk_src, 1);
     }
-
 }
 
-static inline void omap3_cm_iva2_update(struct omap3_cm_s *s)
+static inline void omap3_cm_mpu_update(struct omap3_cm_s *s)
 {
-    uint32_t m, n, divide, m2, cm_clken_pll_iva2;
-    uint32_t bypass = 1;
-
-    cm_clken_pll_iva2 = s->cm_clken_pll_iva2;
-    omap_clk iva2_clk = omap_findclk(s->mpu, "omap3_iva2_clk");
-
-    if (((cm_clken_pll_iva2 & 0x7) == 0x5)
-        || ((cm_clken_pll_iva2 & 0x7) == 0x1))
-    {
-        bypass = 1;
-    }
-    else if ((cm_clken_pll_iva2 & 0x7) == 0x7)
-    {
-        m = (s->cm_clksel1_pll_iva2 & 0x7ff00) >> 8;
-        if ((m == 0) || (m == 1))
-            bypass = 1;
-        else
-            bypass = 0;
-    }
-    if (bypass == 1)
-    {
-        /*BYPASS Model */
-        divide = (s->cm_clksel1_pll_iva2 & 0x380000) >> 19;
-        //OMAP3_DEBUG(("divide %d\n",divide));
-        omap_clk_reparent(iva2_clk, omap_findclk(s->mpu, "omap3_core_clk"));
-        omap_clk_setrate(iva2_clk, divide, 1);
-
+    uint32_t mpu_dpll_mul = ((s->cm_clksel1_pll_mpu >> 8) & 0x7ff);
+    uint32_t mpu_dpll_div, mpu_dpll_clkout_div, mpu_clk_src;
+    omap_clk mpu_clk = omap_findclk(s->mpu, "omap3_mpu_clk");
+    
+    switch ((s->cm_clken_pll_mpu & 0x7)) {
+        case 0x05: /* low power bypass mode */
+            s->cm_idlest_pll_mpu &= ~1;
+            break;
+        case 0x07: /* locked */
+            if (mpu_dpll_mul < 2)
+                s->cm_idlest_pll_mpu &= ~1;
+            else
+                s->cm_idlest_pll_mpu |= 1;
+            break;
+        default:
+            break;
     }
-    else
-    {
-        n = (s->cm_clksel1_pll_iva2 & 0x7F);
-        m2 = (s->cm_clksel2_pll_iva2 & 0x1F);
-        //OMAP3_DEBUG(("M  %d N %d M2 %d \n",m,n,m2 ));
-        omap_clk_reparent(iva2_clk, omap_findclk(s->mpu, "omap3_sys_clk"));
-        omap_clk_setrate(iva2_clk, (n + 1) * m2, m);
-        //OMAP3_DEBUG(("iva2_clk %d \n",omap_clk_getrate(iva2_clk)));
-
+    
+    if (s->cm_idlest_pll_mpu & 1) {
+        mpu_dpll_div = s->cm_clksel1_pll_mpu & 0x7f;
+        mpu_dpll_clkout_div = s->cm_clksel2_pll_mpu & 0x1f;
+        omap_clk_reparent(mpu_clk, omap_findclk(s->mpu, "omap3_sys_clk"));
+        omap_clk_setrate(mpu_clk,
+                         (mpu_dpll_div + 1) * mpu_dpll_clkout_div,
+                         mpu_dpll_mul);
+    } else {
+        /* bypass mode */
+        mpu_clk_src = (s->cm_clksel1_pll_mpu >> 19) & 0x07;
+        omap_clk_reparent(mpu_clk, omap_findclk(s->mpu, "omap3_core_clk"));
+        omap_clk_setrate(mpu_clk, mpu_clk_src, 1);
     }
-
 }
 
 static inline void omap3_cm_dpll3_update(struct omap3_cm_s *s)
 {
-    uint32_t m, n, m2, m3, cm_clken_pll;
-    uint32_t bypass = 1;
+    uint32_t core_dpll_mul = ((s->cm_clksel1_pll >> 16) & 0x7ff);
+    uint32_t core_dpll_div, core_dpll_clkout_div, div_dpll3;
 
-    cm_clken_pll = s->cm_clken_pll;
-
-    /*dpll3 bypass mode. parent clock is always omap3_sys_clk */
-    if (((cm_clken_pll & 0x7) == 0x5) || ((cm_clken_pll & 0x7) == 0x6))
-    {
-        bypass = 1;
-    }
-    else if ((cm_clken_pll & 0x7) == 0x7)
-    {
-        m = (s->cm_clksel1_pll & 0x7ff0000) >> 16;
-        if ((m == 0) || (m == 1))
-            bypass = 1;
-        else
-            bypass = 0;
-    }
-    if (bypass == 1)
-    {
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_core_clk"), 1, 1);
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_core2_clk"), 1, 1);
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_emu_core_alwon_clk"), 1,
-                         1);
+    switch ((s->cm_clken_pll & 0x7)) {
+        case 0x05: /* low power bypass */
+        case 0x06: /* fast relock bypass */
+            s->cm_idlest_ckgen &= ~1;
+            break;
+        case 0x07: /* locked */
+            if (core_dpll_mul < 2)
+                s->cm_idlest_ckgen &= ~1;
+            else
+                s->cm_idlest_ckgen |= 1;
+            break;
+        default:
+            break;
     }
-    else
-    {
-        n = (s->cm_clksel1_pll & 0x3f00) >> 8;
-        m2 = (s->cm_clksel1_pll & 0xf8000000) >> 27;
-        m3 = (s->cm_clksel1_emu & 0x1f0000) >> 16;
-
-        if (s->cm_clksel2_emu&0x80000)
-        {
-               /*override control of DPLL3*/
-               m = (s->cm_clksel2_emu&0x7ff)>>8;
-               n =  s->cm_clksel2_emu&0x7f;
-               TRACE("DPLL3 override, m 0x%x n 0x%x",m,n);
-        }
 
-        //OMAP3_DEBUG(("dpll3 cm_clksel1_pll %x m  %d n %d m2 %d  m3 %d\n",s->cm_clksel1_pll,m,n,m2,m3 ));
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_core_clk"), (n + 1) * m2,
-                         m);
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_core2_clk"), (n + 1) * m2,
-                         m * 2);
+    if (s->cm_idlest_ckgen & 1) {
+        core_dpll_div = (s->cm_clksel1_pll >> 8) & 0x7f;
+        core_dpll_clkout_div = (s->cm_clksel1_pll >> 27) & 0x1f;
+        div_dpll3 = (s->cm_clksel1_emu >> 16) & 0x1f;
+        
+        if (s->cm_clksel2_emu & 0x80000) { /* OVERRIDE_ENABLE */
+               core_dpll_mul = (s->cm_clksel2_emu >> 8) & 0x7ff;
+               core_dpll_div = s->cm_clksel2_emu & 0x7f;
+        }
+        
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_core_clk"),
+                         (core_dpll_div + 1) * core_dpll_clkout_div,
+                         core_dpll_mul);
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_core2_clk"),
+                         (core_dpll_div + 1) * core_dpll_clkout_div,
+                         core_dpll_mul * 2);
         omap_clk_setrate(omap_findclk(s->mpu, "omap3_emu_core_alwon_clk"),
-                         (n + 1) * m3, m * 2);
-        TRACE("coreclk %lld",
-              omap_clk_getrate(omap_findclk(s->mpu, "omap3_core_clk")));
+                         (core_dpll_div + 1) * div_dpll3,
+                         core_dpll_mul * 2);
+    } else {
+        /* bypass mode */
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_core_clk"), 1, 1);
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_core2_clk"), 1, 1);
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_emu_core_alwon_clk"), 1, 1);
     }
-
-
 }
 
 static inline void omap3_cm_dpll4_update(struct omap3_cm_s *s)
 {
-    uint32_t m, n, m2, m3, m4, m5, m6, cm_clken_pll;
-    cm_clken_pll = s->cm_clken_pll;
-    uint32_t bypass = 1;
+    uint32_t per_dpll_mul = ((s->cm_clksel2_pll >> 8) & 0x7ff);
+    uint32_t per_dpll_div, div_96m, clksel_tv, clksel_dss1, clksel_cam, div_dpll4;
 
-    /*dpll3 bypass mode. parent clock is always omap3_sys_clk */
-    /*DPLL4 */
-    if ((cm_clken_pll & 0x70000) == 0x10000)
-    {
-        bypass = 1;
-    }
-    else if ((cm_clken_pll & 0x70000) == 0x70000)
-    {
-        m = (s->cm_clksel2_pll & 0x7ff00) >> 8;
-        if ((m == 0) || (m == 1))
-            bypass = 1;
-        else
-            bypass = 0;
+    switch (((s->cm_clken_pll >> 16) & 0x7)) {
+        case 0x01: /* lower power stop mode */
+            s->cm_idlest_ckgen &= ~2;
+            break;
+        case 0x07: /* locked */
+            if (per_dpll_mul < 2)
+                s->cm_idlest_ckgen &= ~2;
+            else
+                s->cm_idlest_ckgen |= 2;
+            break;
+        default:
+            break;
     }
-    if (bypass == 1)
-    {
+
+    if (s->cm_idlest_ckgen & 2) {
+        per_dpll_div = s->cm_clksel2_pll & 0x7f;
+        div_96m = s->cm_clksel3_pll & 0x1f;
+        clksel_tv = (s->cm_clksel_dss >> 8) & 0x1f;
+        clksel_dss1 = s->cm_clksel_dss & 0x1f;
+        clksel_cam = s->cm_clksel_cam & 0x1f;
+        div_dpll4 = (s->cm_clksel1_emu >> 24) & 0x1f;
+        
+        if (s->cm_clksel3_emu & 0x80000) { /* OVERRIDE_ENABLE */
+               per_dpll_mul = (s->cm_clksel3_emu >> 8) & 0x7ff;
+               per_dpll_div =  s->cm_clksel3_emu & 0x7f;
+        }
+        
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_96m_fclk"),
+                         (per_dpll_div + 1) * div_96m,
+                         per_dpll_mul * 2);
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_54m_fclk"),
+                         (per_dpll_div + 1) * clksel_tv,
+                         per_dpll_mul * 2);
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_dss1_alwon_fclk"),
+                         (per_dpll_div + 1) * clksel_dss1,
+                         per_dpll_mul * 2);
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_cam_mclk"),
+                         (per_dpll_div + 1) * clksel_cam,
+                         per_dpll_mul * 2);
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_per_alwon_clk"),
+                         (per_dpll_div + 1) * div_dpll4,
+                         per_dpll_mul * 2);
+    } else {
+        /* bypass mode */
         omap_clk_setrate(omap_findclk(s->mpu, "omap3_96m_fclk"), 1, 1);
         omap_clk_setrate(omap_findclk(s->mpu, "omap3_54m_fclk"), 1, 1);
         omap_clk_setrate(omap_findclk(s->mpu, "omap3_dss1_alwon_fclk"), 1, 1);
         omap_clk_setrate(omap_findclk(s->mpu, "omap3_cam_mclk"), 1, 1);
         omap_clk_setrate(omap_findclk(s->mpu, "omap3_per_alwon_clk"), 1, 1);
     }
-    else
-    {
-        n = (s->cm_clksel2_pll & 0x7f);
-        m2 = s->cm_clksel3_pll & 0x1f;
-        m3 = (s->cm_clksel_dss & 0x1f00) >> 8;
-        m4 = s->cm_clksel_dss & 0x1f;
-        m5 = s->cm_clksel_cam & 0x1f;
-        m6 = (s->cm_clksel1_emu & 0x1f000000) >> 24;
-
-        if (s->cm_clksel3_emu&0x80000)
-        {
-               /*override control of DPLL4*/
-               m = (s->cm_clksel3_emu&0x7ff)>>8;
-               n =  s->cm_clksel3_emu&0x7f;
-               TRACE("DPLL4 override, m 0x%x n 0x%x",m,n);
-        }
-
-
-        //OMAP3_DEBUG(("dpll4 m  %d n %d m2 %d  m3 %d m4 %d m5 %d m6 %d \n",m,n,m2,m3,m4,m5,m6 ));
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_96m_fclk"), (n + 1) * m2,
-                         m * 2);
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_54m_fclk"), (n + 1) * m3,
-                         m * 2);
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_dss1_alwon_fclk"),
-                         (n + 1) * m4, m * 2);
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_cam_mclk"), (n + 1) * m5,
-                         m * 2);
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_per_alwon_clk"),
-                         (n + 1) * m6, m * 2);
-
-        TRACE("omap3_96m_fclk %lld",
-              omap_clk_getrate(omap_findclk(s->mpu, "omap3_96m_fclk")));
-        TRACE("omap3_54m_fclk %lld",
-              omap_clk_getrate(omap_findclk(s->mpu, "omap3_54m_fclk")));
-        TRACE("omap3_dss1_alwon_fclk %lld",
-              omap_clk_getrate(omap_findclk(s->mpu, "omap3_dss1_alwon_fclk")));
-        TRACE("omap3_cam_mclk %lld",
-              omap_clk_getrate(omap_findclk(s->mpu, "omap3_cam_mclk")));
-        TRACE("omap3_per_alwon_clk %lld",
-              omap_clk_getrate(omap_findclk(s->mpu, "omap3_per_alwon_clk")));
-        TRACE("omap3_48m_fclk %lld",
-              omap_clk_getrate(omap_findclk(s->mpu, "omap3_48m_fclk")));
-        TRACE("omap3_12m_fclk %lld",
-              omap_clk_getrate(omap_findclk(s->mpu, "omap3_12m_fclk")));
-    }
 }
 
 static inline void omap3_cm_dpll5_update(struct omap3_cm_s *s)
 {
-        uint32_t m, n, m2, cm_idlest2_ckgen;
-    uint32_t bypass = 1;
+    uint32_t per2_dpll_mul = ((s->cm_clksel4_pll >> 8) & 0x7ff);
+    uint32_t per2_dpll_div, div_120m;
 
-    cm_idlest2_ckgen = s->cm_idlest2_ckgen;;
-
-    /*dpll5 bypass mode */
-    if ((cm_idlest2_ckgen & 0x1) == 0x0) 
-    {
-        bypass = 1;
+    switch ((s->cm_clken2_pll & 0x7)) {
+        case 0x01: /* low power stop mode */
+            s->cm_idlest2_ckgen &= ~1;
+            break;
+        case 0x07: /* locked */
+            if (per2_dpll_mul < 2)
+                s->cm_idlest2_ckgen &= ~1;
+            else
+                s->cm_idlest2_ckgen |= 1;
+            break;
+        default:
+            break;
     }
 
-    if (bypass == 1)
-    {
+    if (s->cm_idlest2_ckgen & 1) {
+        per2_dpll_div = s->cm_clksel4_pll & 0x7f;
+        div_120m = s->cm_clksel5_pll & 0x1f;
+        
+        omap_clk_setrate(omap_findclk(s->mpu, "omap3_120m_fclk"),
+                         (per2_dpll_div + 1) * div_120m,
+                         per2_dpll_mul);
+    } else {
+        /* bypass mode */
         omap_clk_setrate(omap_findclk(s->mpu, "omap3_120m_fclk"), 1, 1);
     }
-    else
-    {
-        m = (s->cm_clksel4_pll & 0x7ff00)>>8;
-        n = s->cm_clksel4_pll & 0x3f00;
-        m2 = s->cm_clksel5_pll & 0x1f;
-
-        TRACE("dpll5 m %d n %d m2 %d",m,n,m2);
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_120m_fclk"), (n + 1) * m2,
-                         m);
-        TRACE("omap3_120m_fclk %lld",
-              omap_clk_getrate(omap_findclk(s->mpu, "omap3_120m_fclk")));
-    }
 }
 
 static inline void omap3_cm_48m_update(struct omap3_cm_s *s)
 {
-    if (s->cm_clksel1_pll & 0x8)
-    {
-        /*parent is sysaltclk */
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_48m_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_altclk"));
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_12m_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_altclk"));
-        /*TODO:need to set rate ? */
-
-    }
-    else
-    {
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_12m_fclk"),
-                          omap_findclk(s->mpu, "omap3_96m_fclk"));
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_48m_fclk"),
-                          omap_findclk(s->mpu, "omap3_96m_fclk"));
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_48m_fclk"), 2, 1);
-        omap_clk_setrate(omap_findclk(s->mpu, "omap3_12m_fclk"), 8, 1);
-
-    }
-
+    omap_clk pclk = omap_findclk(s->mpu,
+                                 (s->cm_clksel1_pll & 0x8) /* SOURCE_48M */
+                                 ? "omap3_sys_altclk"
+                                 : "omap3_96m_fclk");
+    
+    omap_clk_reparent(omap_findclk(s->mpu, "omap3_48m_fclk"), pclk);
+    omap_clk_reparent(omap_findclk(s->mpu, "omap3_12m_fclk"), pclk);
 }
 
-static inline void omap3_cm_gp10_update(struct omap3_cm_s *s)
+static inline void omap3_cm_gp10gp11_update(struct omap3_cm_s *s)
 {
-    omap_clk gp10_fclk = omap_findclk(s->mpu, "omap3_gp10_fclk");
-
-    if (s->cm_clksel_core & 0x40)
-        omap_clk_reparent(gp10_fclk, omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(gp10_fclk, omap_findclk(s->mpu, "omap3_32k_fclk"));
+    omap_clk gp10 = omap_findclk(s->mpu, "omap3_gp10_fclk");
+    omap_clk gp11 = omap_findclk(s->mpu, "omap3_gp11_fclk");
+    omap_clk sys  = omap_findclk(s->mpu, "omap3_sys_clk");
+    omap_clk f32k = omap_findclk(s->mpu, "omap3_32k_fclk");
 
-    /*Tell GPTIMER10 to generate new clk rate */
+    omap_clk_reparent(gp10, (s->cm_clksel_core & 0x40) ? sys : f32k);
+    omap_clk_reparent(gp11, (s->cm_clksel_core & 0x80) ? sys : f32k);
     omap_gp_timer_change_clk(s->mpu->gptimer[9]);
-    TRACE("omap3_gp10_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp10_fclk")));
+    omap_gp_timer_change_clk(s->mpu->gptimer[10]);
+    
+    TRACE("gptimer10 fclk = %lld", omap_clk_getrate(gp10));
+    TRACE("gptimer11 fclk = %lld", omap_clk_getrate(gp11));
 }
 
-static inline void omap3_cm_gp11_update(struct omap3_cm_s *s)
+static inline void omap3_cm_per_gptimer_update(struct omap3_cm_s *s)
 {
-    omap_clk gp11_fclk = omap_findclk(s->mpu, "omap3_gp11_fclk");
-
-    if (s->cm_clksel_core & 0x80)
-        omap_clk_reparent(gp11_fclk, omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(gp11_fclk, omap_findclk(s->mpu, "omap3_32k_fclk"));
-    /*Tell GPTIMER11 to generate new clk rate */
-    omap_gp_timer_change_clk(s->mpu->gptimer[10]);
-    TRACE("omap3_gp11_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp11_fclk")));
+    omap_clk sys = omap_findclk(s->mpu, "omap3_sys_clk");
+    omap_clk f32k = omap_findclk(s->mpu, "omap3_32k_fclk");
+    uint32_t cm_clksel_per = s->cm_clksel_per;
+    uint32_t n;
+    char clkname[] = "omap3_gp#_fclk";
+
+    for (n = 1; n < 9; n++, cm_clksel_per >>= 1) {
+        clkname[8] = '1' + n; /* 2 - 9 */
+        omap_clk_reparent(omap_findclk(s->mpu, clkname),
+                          (cm_clksel_per & 1) ? sys : f32k);
+        omap_gp_timer_change_clk(s->mpu->gptimer[n]);
+        TRACE("gptimer%d fclk = %lld", n + 1,
+              omap_clk_getrate(omap_findclk(s->mpu, clkname)));
+    }
 }
 
-static inline void omap3_cm_l3clk_update(struct omap3_cm_s *s)
+static inline void omap3_cm_clkout2_update(struct omap3_cm_s *s)
 {
-    omap_clk l3_iclk = omap_findclk(s->mpu, "omap3_l3_iclk");
-    if ((s->cm_clksel_core & 0x3) == 0x1)
-        omap_clk_setrate(l3_iclk, 1, 1);
-    else if ((s->cm_clksel_core & 0x3) == 0x2)
-        omap_clk_setrate(l3_iclk, 2, 1);
+    omap_clk c = omap_findclk(s->mpu, "omap3_sys_clkout2");
+       
+    omap_clk_onoff(c, (s->cm_clkout_ctrl >> 7) & 1);
+    switch (s->cm_clkout_ctrl & 0x3) {
+        case 0:
+            omap_clk_reparent(c, omap_findclk(s->mpu, "omap3_core_clk"));
+            break;
+        case 1:
+            omap_clk_reparent(c, omap_findclk(s->mpu, "omap3_sys_clk"));
+            break;
+        case 2:
+            omap_clk_reparent(c, omap_findclk(s->mpu, "omap3_96m_fclk"));
+            break;
+        case 3:
+            omap_clk_reparent(c, omap_findclk(s->mpu, "omap3_54m_fclk"));
+            break;
+        default:
+            break;
+    }
+    omap_clk_setrate(c, 1 << ((s->cm_clkout_ctrl >> 3) & 7), 1);
 }
 
-static inline void omap3_cm_l4clk_update(struct omap3_cm_s *s)
+static inline void omap3_cm_fclken1_core_update(struct omap3_cm_s *s)
 {
-    omap_clk l4_iclk = omap_findclk(s->mpu, "omap3_l4_iclk");
-    if ((s->cm_clksel_core & 0xc) == 0x4)
-        omap_clk_setrate(l4_iclk, 1, 1);
-    else if ((s->cm_clksel_core & 0xc) == 0x8)
-        omap_clk_setrate(l4_iclk, 2, 1);
+    uint32_t v = s->cm_fclken1_core;
+    
+    /* TODO: EN_MCBSP1,5 */
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_gp10_fclk"),  (v >> 11) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_gp11_fclk"),  (v >> 12) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_uart1_fclk"), (v >> 13) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_uart2_fclk"), (v >> 14) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c1_fclk"),  (v >> 15) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c2_fclk"),  (v >> 16) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c3_fclk"),  (v >> 17) & 1);
+    /* TODO: EN_HDQ, EN_SPI1-4 */
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc1_fclk"),  (v >> 24) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc2_fclk"),  (v >> 25) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc3_fclk"),  (v >> 30) & 1);
 }
 
-static inline void omap3_cm_per_gptimer_update(struct omap3_cm_s *s)
+static inline void omap3_cm_iclken1_core_update(struct omap3_cm_s *s)
 {
-    uint32_t cm_clksel_per = s->cm_clksel_per;
-
-    if (cm_clksel_per & 0x1)
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp2_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp2_fclk"),
-                          omap_findclk(s->mpu, "omap3_32k_fclk"));
-    omap_gp_timer_change_clk(s->mpu->gptimer[1]);
-
-    if (cm_clksel_per & 0x2)
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp3_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp3_fclk"),
-                          omap_findclk(s->mpu, "omap3_32k_fclk"));
-    omap_gp_timer_change_clk(s->mpu->gptimer[2]);
-
-    if (cm_clksel_per & 0x4)
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp4_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp4_fclk"),
-                          omap_findclk(s->mpu, "omap3_32k_fclk"));
-    omap_gp_timer_change_clk(s->mpu->gptimer[3]);
-
-    if (cm_clksel_per & 0x8)
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp5_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp5_fclk"),
-                          omap_findclk(s->mpu, "omap3_32k_fclk"));
-    omap_gp_timer_change_clk(s->mpu->gptimer[4]);
-
-    if (cm_clksel_per & 0x10)
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp6_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp6_fclk"),
-                          omap_findclk(s->mpu, "omap3_32k_fclk"));
-    omap_gp_timer_change_clk(s->mpu->gptimer[5]);
+    uint32_t v = s->cm_iclken1_core;
     
-    if (cm_clksel_per & 0x20)
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp7_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp7_fclk"),
-                          omap_findclk(s->mpu, "omap3_32k_fclk"));
-    omap_gp_timer_change_clk(s->mpu->gptimer[6]);
-
-
-    if (cm_clksel_per & 0x40)
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp8_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp8_fclk"),
-                          omap_findclk(s->mpu, "omap3_32k_fclk"));
-    omap_gp_timer_change_clk(s->mpu->gptimer[7]);
-    
-    if (cm_clksel_per & 0x80)
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp9_fclk"),
-                          omap_findclk(s->mpu, "omap3_sys_clk"));
-    else
-        omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp9_fclk"),
-                          omap_findclk(s->mpu, "omap3_32k_fclk"));
-    omap_gp_timer_change_clk(s->mpu->gptimer[8]);
-
-    /*TODO:Tell GPTIMER to generate new clk rate */
-    TRACE("omap3_gp2_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp2_fclk")));
-    TRACE("omap3_gp3_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp3_fclk")));
-       TRACE("omap3_gp4_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp4_fclk")));
-    TRACE("omap3_gp5_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp5_fclk")));
-    TRACE("omap3_gp6_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp6_fclk")));
-    TRACE("omap3_gp7_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp7_fclk")));
-    TRACE("omap3_gp8_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp8_fclk")));
-    TRACE("omap3_gp9_fclk %lld",
-          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp9_fclk")));
+    /* TODO: EN_SDRC, EN_HSOTGUSB, EN_OMAPCTRL, EN_MAILBOXES, EN_MCBSP1,5 */
+    /* TODO: EN_GPT10, EN_GPT11 */
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_uart1_iclk"), (v >> 13) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_uart2_iclk"), (v >> 14) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c1_iclk"),  (v >> 15) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c2_iclk"),  (v >> 16) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c3_iclk"),  (v >> 17) & 1);
+    /* TODO: EN_HDQ, EN_SPI1-4 */
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc1_iclk"),  (v >> 24) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc2_iclk"),  (v >> 25) & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc3_iclk"),  (v >> 30) & 1);
+    /* set USB OTG idle if iclk is enabled and SDMA always in standby */
+    v &= ~0x24;
+    v |= (v & 0x10) << 1;
+    s->cm_idlest1_core = ~v;
 }
 
-static inline void omap3_cm_clkout2_update(struct omap3_cm_s *s)
+static inline void omap3_cm_l3l4iclk_update(struct omap3_cm_s *s)
 {
-       uint32 divor;
-       
-       if (!s->cm_clkout_ctrl&0x80)
-               return;
-
-       switch (s->cm_clkout_ctrl&0x3)
-       {
-               case 0x0:
-                       omap_clk_reparent(omap_findclk(s->mpu, "omap3_sys_clkout2"),
-                          omap_findclk(s->mpu, "omap3_core_clk"));
-                       break;
-               case 0x1:
-                       omap_clk_reparent(omap_findclk(s->mpu, "omap3_sys_clkout2"),
-                          omap_findclk(s->mpu, "omap3_sys_clk"));
-                       break;
-               case 0x2:
-                       omap_clk_reparent(omap_findclk(s->mpu, "omap3_sys_clkout2"),
-                          omap_findclk(s->mpu, "omap3_96m_fclk"));
-                       break;
-               case 0x3:
-                       omap_clk_reparent(omap_findclk(s->mpu, "omap3_sys_clkout2"),
-                          omap_findclk(s->mpu, "omap3_54m_fclk"));
-                       break;
-       }
-
-       divor = (s->cm_clkout_ctrl&0x31)>>3;
-       divor = 1<<divor;
-       omap_clk_setrate(omap_findclk(s->mpu, "omap3_sys_clkout2"), divor, 1);
-       
+    omap_clk_setrate(omap_findclk(s->mpu, "omap3_l3_iclk"),
+                     s->cm_clksel_core & 0x3, 1);
+    omap_clk_setrate(omap_findclk(s->mpu, "omap3_l4_iclk"),
+                     (s->cm_clksel_core >> 2) & 0x3, 1);
 }
 
 static void omap3_cm_reset(struct omap3_cm_s *s)
@@ -2401,7 +2568,7 @@ static void omap3_cm_reset(struct omap3_cm_s *s)
     s->cm_fclken_iva2 = 0x0;
     s->cm_clken_pll_iva2 = 0x11;
     s->cm_idlest_iva2 = 0x1;
-    s->cm_idlest_pll_iva2 = 0x0;
+    s->cm_idlest_pll_iva2 = 0;
     s->cm_autoidle_pll_iva2 = 0x0;
     s->cm_clksel1_pll_iva2 = 0x80000;
     s->cm_clksel2_pll_iva2 = 0x1;
@@ -2413,7 +2580,7 @@ static void omap3_cm_reset(struct omap3_cm_s *s)
 
     s->cm_clken_pll_mpu = 0x15;
     s->cm_idlest_mpu = 0x1;
-    s->cm_idlest_pll_mpu = 0x0;
+    s->cm_idlest_pll_mpu = 0;
     s->cm_autoidle_pll_mpu = 0x0;
     s->cm_clksel1_pll_mpu = 0x80000;
     s->cm_clksel2_pll_mpu = 0x1;
@@ -2454,8 +2621,8 @@ static void omap3_cm_reset(struct omap3_cm_s *s)
 
     s->cm_clken_pll = 0x110015;
     s->cm_clken2_pll = 0x11;
-    s->cm_idlest_ckgen = 0x0;
-    s->cm_idlest2_ckgen = 0x0;
+    s->cm_idlest_ckgen = 0x3f3c; /* FIXME: provide real clock statuses */
+    s->cm_idlest2_ckgen = 0xa; /* FIXME: provide real clock statuses */
     s->cm_autoidle_pll = 0x0;
     s->cm_autoidle2_pll = 0x0;
     s->cm_clksel1_pll = 0x8000040;
@@ -2518,608 +2685,620 @@ static void omap3_cm_reset(struct omap3_cm_s *s)
 static uint32_t omap3_cm_read(void *opaque, target_phys_addr_t addr)
 {
     struct omap3_cm_s *s = (struct omap3_cm_s *) opaque;
-    uint32_t ret;
-    uint32_t bypass = 0, m;
-
-    TRACE("%04x", addr);
-    switch (addr)
-    {
-    case 0x0:
-       return s->cm_fclken_iva2;
-    case 0x04:
-        return s->cm_clken_pll_iva2;
-    case 0x20:
-       return s->cm_idlest_iva2;
-    case 0x24:
-        if (((s->cm_clken_pll_iva2 & 0x7) == 0x5)
-            || ((s->cm_clken_pll_iva2 & 0x7) == 0x1))
-        {
-            bypass = 1;
-        }
-        else if ((s->cm_clken_pll_iva2 & 0x7) == 0x7)
-        {
-            m = (s->cm_clksel1_pll_iva2 & 0x7ff00) >> 8;
-            if ((m == 0) || (m == 1))
-                bypass = 1;
-            else
-                bypass = 0;
-        }
-        if (bypass)
-            return 0;
-        else
-            return 1;
-    case 0x34:
-       return s->cm_autoidle_pll_iva2;
-    case 0x40:
-        return s->cm_clksel1_pll_iva2;
-    case 0x44:
-        return s->cm_clksel2_pll_iva2;
-    case 0x48:
-       return s->cm_clkstctrl_iva2;
-    case 0x4c:
-       return s->cm_clkstst_iva2;
-
-   case 0x800:
-               return s->cm_revision;
-       case 0x810:
-               return s->cm_sysconfig;
-
-       
-    case 0x904:                /*CM_CLKEN_PLL_MPU */
-        return s->cm_clken_pll_mpu;
-   case 0x920:
-               return s->cm_idlest_mpu & 0x0;  /*MPU is active*/
-    case 0x924:
-        if ((s->cm_clken_pll_mpu & 0x7) == 0x5)
-        {
-            bypass = 1;
-        }
-        else if ((s->cm_clken_pll_mpu & 0x7) == 0x7)
-        {
-            m = (s->cm_clksel1_pll_mpu & 0x7ff00) >> 8;
-            if ((m == 0) || (m == 1))
-                bypass = 1;
-            else
-                bypass = 0;
-        }
-        if (bypass)
-            return 0;
-        else
-            return 1;
-    case 0x934:
-       return s->cm_autoidle_pll_mpu;
-    case 0x940:
-        return s->cm_clksel1_pll_mpu;
-    case 0x944:
-        return s->cm_clksel2_pll_mpu;
-     case 0x948:
-       return s->cm_clkstctrl_mpu;
-     case 0x94c:
-       return s->cm_clkstst_mpu;
-
-
-       
-    case 0xa00:
-        return s->cm_fclken1_core;
-    case 0xa08:
-       return s->cm_fclken3_core;
-    case 0xa10:
-        return s->cm_iclken1_core;
-    case 0xa14:
-        return s->cm_iclken2_core;
-    case 0xa20:
-       return s->cm_idlest1_core;
-    case 0xa24:
-       return s->cm_idlest2_core;
-    case 0xa28:
-       return s->cm_idlest3_core;
-    case 0xa30:
-       return s->cm_autoidle1_core;
-    case 0xa34:
-       return s->cm_autoidle2_core;
-    case 0xa38:
-       return s->cm_autoidle3_core;
-    case 0xa40:                /*CM_CLKSEL_CORE */
-        return s->cm_clksel_core;
-    case 0xa48:
-        return s->cm_clkstctrl_core;
-     case 0xa4c:
-       return s->cm_clkstst_core;
-
-   case 0xb00:
-               return s->cm_fclken_sgx;
-       case 0xb10:
-               return s->cm_iclken_sgx;
-       case 0xb20:
-               return s->cm_idlest_sgx&0x0;
-   case 0xb40:                /*CM_CLKSEL_SGX */
-        return s->cm_clksel_sgx;
-   case 0xb48:
-               return s->cm_clkstctrl_sgx;
-       case 0xb4c:
-               return s->cm_clkstst_sgx;
-
-               
-    case 0xc00:                /*CM_FCLKEN_WKUP */
-        return s->cm_fclken_wkup;
-    case 0xc10:                /*CM_ICLKEN_WKUP */
-        return s->cm_iclken_wkup;
-    case 0xc20:                /*CM_IDLEST_WKUP */
-        /*TODO: Check whether the timer can be accessed. */
-        return 0x0;
-    case 0xc30:
-       return s->cm_idlest_wkup;
-    case 0xc40:
-        return s->cm_clksel_wkup;
-    case 0xc48:
-       return s->cm_c48;
-
-       
-    case 0xd00:                /*CM_CLKEN_PLL */
-        return s->cm_clken_pll;
-    case 0xd04:
-       return s->cm_clken2_pll;
-    case 0xd20:
-        /*FIXME: all clock is active. we do not care it. */
-        ret = 0x3ffff;
-
-       /*DPLL3*/
-       bypass = 0;
-       if (((s->cm_clken_pll & 0x7) == 0x5) || ((s->cm_clken_pll & 0x7) == 0x6))
-               bypass = 1;
-        else if ((s->cm_clken_pll & 0x7) == 0x7) {
-            m = (s->cm_clksel1_pll & 0x7ff0000) >> 16;
-            if ((m == 0) || (m == 1))
-                bypass = 1;
-            else
-                bypass = 0;
-        }
-        if (bypass)
-            ret &= 0xfffe;
-        
-        /*DPLL4*/
-           bypass = 0;
-           if ((s->cm_clken_pll & 0x70000) == 0x10000)
-            bypass = 1;
-        else if ((s->cm_clken_pll & 0x70000) == 0x70000) {
-            m = (s->cm_clksel2_pll & 0x7ff00) >> 8;
-            if ((m == 0) || (m == 1))
-                bypass = 1;
-            else
-                bypass = 0;
-        }
-        if (bypass)
-            ret &= 0xfffd;
-       return ret;
-       
-    case 0xd24:
-       return s->cm_idlest2_ckgen;
-    case 0xd30:
-       return s->cm_autoidle_pll;
-    case 0xd34:
-       return s->cm_autoidle2_pll;
-    case 0xd40:                /*CM_CLKSEL1_PLL */
-        return s->cm_clksel1_pll;
-    case 0xd44:
-        return s->cm_clksel2_pll;
-    case 0xd48:                /*CM_CLKSEL3_PLL */
-        return s->cm_clksel3_pll;
-    case 0xd4c:
-        return s->cm_clksel4_pll;
-    case 0xd50:                /*CM_CLKSEL5_PLL */
-        return s->cm_clksel5_pll;
-    case 0xd70:
-        return s->cm_clkout_ctrl;
-
-        
-    case 0xe00:
-       return s->cm_fclken_dss;
-       case 0xe10:
-       return s->cm_iclken_dss;
-    case 0xe20:
-       return s->cm_idlest_dss;
-    case 0xe30:
-       return s->cm_autoidle_dss;
-    case 0xe40:
-        return s->cm_clksel_dss;
-    case 0xe44:
-        return s->cm_sleepdep_dss;
-    case 0xe48:
-        return s->cm_clkstctrl_dss;
-    case 0xe4c:
-        return s->cm_clkstst_dss;
-
-        
-    case 0xf00:
-       return s->cm_fclken_cam;
-    case 0xf10:
-       return s->cm_iclken_cam;
-    case 0xf20:
-       return s->cm_idlest_cam&0x0;
-    case 0xf30:
-       return s->cm_autoidle_cam;
-    case 0xf40:
-        return s->cm_clksel_cam;
-    case 0xf44:
-       return s->cm_sleepdep_cam;
-    case 0xf48:
-       return s->cm_clkstctrl_cam;
-    case 0xf4c:
-       return s->cm_clkstst_cam;
-
-       
-    case 0x1000:
-        return s->cm_fclken_per;
-    case 0x1010:
-        return s->cm_iclken_per;
-    case 0x1020:
-       return s->cm_idlest_per ;
-    case 0x1030:
-       return s->cm_autoidle_per;
-    case 0x1040:
-        return s->cm_clksel_per;
-    case 0x1044:
-       return s->cm_sleepdep_per;
-    case 0x1048:
-       return s->cm_clkstctrl_per;
-    case 0x104c:
-               return s->cm_clkstst_per;
-
-       
-    case 0x1140:               /*CM_CLKSEL1_EMU */
-        return s->cm_clksel1_emu;
-    case 0x1148:
-        return s->cm_clkstctrl_emu;
-    case 0x114c:
-       return s->cm_clkstst_emu&0x0;
-    case 0x1150:
-       return s->cm_clksel2_emu;
-    case 0x1154:
-       return s->cm_clksel3_emu;
-
-   case 0x129c:
-               return s->cm_polctrl;
-
-       case 0x1320:
-               return s->cm_idlest_neon&0x0;
-       case 0x1348:
-               return s->cm_clkstctrl_neon;
-
-       case 0x1400:
-               return s->cm_fclken_usbhost;
-       case 0x1410:
-               return s->cm_iclken_usbhost;
-       case 0x1420:
-               return s->cm_idlest_usbhost&0x0;
-    case 0x1430:
-       return s->cm_autoidle_usbhost;
-    case 0x1444:
-       return s->cm_sleepdep_usbhost;
-    case 0x1448:
-       return s->cm_clkstctrl_usbhost;
-    case 0x144c:
-       return s->cm_clkstst_usbhost;
 
-    default:
-        printf("omap3_cm_read addr %x pc %x \n", addr, cpu_single_env->regs[15] );
-        exit(-1);
+    switch (addr) {
+        /* IVA2_CM */
+        case 0x0000: return s->cm_fclken_iva2;
+        case 0x0004: return s->cm_clken_pll_iva2;
+        case 0x0020: return s->cm_idlest_iva2;
+        case 0x0024: return s->cm_idlest_pll_iva2;
+        case 0x0034: return s->cm_autoidle_pll_iva2;
+        case 0x0040: return s->cm_clksel1_pll_iva2;
+        case 0x0044: return s->cm_clksel2_pll_iva2;
+        case 0x0048: return s->cm_clkstctrl_iva2;
+        case 0x004c: return s->cm_clkstst_iva2;
+        /* OCP_System_Reg_CM */
+        case 0x0800: return s->cm_revision;
+        case 0x0810: return s->cm_sysconfig;
+        /* MPU_CM */
+        case 0x0904: return s->cm_clken_pll_mpu;
+        case 0x0920: return s->cm_idlest_mpu & 0x0; /*MPU is active*/
+        case 0x0924: return s->cm_idlest_pll_mpu;
+        case 0x0934: return s->cm_autoidle_pll_mpu;
+        case 0x0940: return s->cm_clksel1_pll_mpu;
+        case 0x0944: return s->cm_clksel2_pll_mpu;
+        case 0x0948: return s->cm_clkstctrl_mpu;
+        case 0x094c: return s->cm_clkstst_mpu;
+        /* CORE_CM */
+        case 0x0a00: return s->cm_fclken1_core;
+        case 0x0a08: return s->cm_fclken3_core;
+        case 0x0a10: return s->cm_iclken1_core;
+        case 0x0a14: return s->cm_iclken2_core;
+        case 0x0a20: return s->cm_idlest1_core;
+        case 0x0a24: return s->cm_idlest2_core;
+        case 0x0a28: return s->cm_idlest3_core;
+        case 0x0a30: return s->cm_autoidle1_core;
+        case 0x0a34: return s->cm_autoidle2_core;
+        case 0x0a38: return s->cm_autoidle3_core;
+        case 0x0a40: return s->cm_clksel_core;
+        case 0x0a48: return s->cm_clkstctrl_core;
+        case 0x0a4c: return s->cm_clkstst_core;
+        /* SGX_CM */
+        case 0x0b00: return s->cm_fclken_sgx;
+        case 0x0b10: return s->cm_iclken_sgx;
+        case 0x0b20: return s->cm_idlest_sgx & 0x0;
+        case 0x0b40: return s->cm_clksel_sgx;
+        case 0x0b48: return s->cm_clkstctrl_sgx;
+        case 0x0b4c: return s->cm_clkstst_sgx;
+        /* WKUP_CM */
+        case 0x0c00: return s->cm_fclken_wkup;
+        case 0x0c10: return s->cm_iclken_wkup;
+        case 0x0c20: return 0; /* TODO: Check if the timer can be accessed. */
+        case 0x0c30: return s->cm_idlest_wkup;
+        case 0x0c40: return s->cm_clksel_wkup;
+        case 0x0c48: return s->cm_c48;
+        /* Clock_Control_Reg_CM */
+        case 0x0d00: return s->cm_clken_pll;
+        case 0x0d04: return s->cm_clken2_pll;
+        case 0x0d20: return s->cm_idlest_ckgen;
+        case 0x0d24: return s->cm_idlest2_ckgen;
+        case 0x0d30: return s->cm_autoidle_pll;
+        case 0x0d34: return s->cm_autoidle2_pll;
+        case 0x0d40: return s->cm_clksel1_pll;
+        case 0x0d44: return s->cm_clksel2_pll;
+        case 0x0d48: return s->cm_clksel3_pll;
+        case 0x0d4c: return s->cm_clksel4_pll;
+        case 0x0d50: return s->cm_clksel5_pll;
+        case 0x0d70: return s->cm_clkout_ctrl;
+        /* DSS_CM */
+        case 0x0e00: return s->cm_fclken_dss;
+        case 0x0e10: return s->cm_iclken_dss;
+        case 0x0e20: return s->cm_idlest_dss;
+        case 0x0e30: return s->cm_autoidle_dss;
+        case 0x0e40: return s->cm_clksel_dss;
+        case 0x0e44: return s->cm_sleepdep_dss;
+        case 0x0e48: return s->cm_clkstctrl_dss;
+        case 0x0e4c: return s->cm_clkstst_dss;
+        /* CAM_CM */
+        case 0x0f00: return s->cm_fclken_cam;
+        case 0x0f10: return s->cm_iclken_cam;
+        case 0x0f20: return s->cm_idlest_cam & 0x0;
+        case 0x0f30: return s->cm_autoidle_cam;
+        case 0x0f40: return s->cm_clksel_cam;
+        case 0x0f44: return s->cm_sleepdep_cam;
+        case 0x0f48: return s->cm_clkstctrl_cam;
+        case 0x0f4c: return s->cm_clkstst_cam;
+        /* PER_CM */
+        case 0x1000: return s->cm_fclken_per;
+        case 0x1010: return s->cm_iclken_per;
+        case 0x1020: return s->cm_idlest_per ;
+        case 0x1030: return s->cm_autoidle_per;
+        case 0x1040: return s->cm_clksel_per;
+        case 0x1044: return s->cm_sleepdep_per;
+        case 0x1048: return s->cm_clkstctrl_per;
+        case 0x104c: return s->cm_clkstst_per;
+        /* EMU_CM */
+        case 0x1140: return s->cm_clksel1_emu;
+        case 0x1148: return s->cm_clkstctrl_emu;
+        case 0x114c: return s->cm_clkstst_emu & 0x0;
+        case 0x1150: return s->cm_clksel2_emu;
+        case 0x1154: return s->cm_clksel3_emu;
+        /* Global_Reg_CM */
+        case 0x129c: return s->cm_polctrl;
+        /* NEON_CM */
+        case 0x1320: return s->cm_idlest_neon & 0x0;
+        case 0x1348: return s->cm_clkstctrl_neon;
+        /* USBHOST_CM */
+        case 0x1400: return s->cm_fclken_usbhost;
+        case 0x1410: return s->cm_iclken_usbhost;
+        case 0x1420: return s->cm_idlest_usbhost & 0x0;
+        case 0x1430: return s->cm_autoidle_usbhost;
+        case 0x1444: return s->cm_sleepdep_usbhost;
+        case 0x1448: return s->cm_clkstctrl_usbhost;
+        case 0x144c: return s->cm_clkstst_usbhost;
+        /* unknown */
+        default: break;
     }
+    OMAP_BAD_REG(addr);
+    return 0;
 }
 
-
-static void omap3_cm_write(void *opaque, target_phys_addr_t addr,
+static void omap3_cm_write(void *opaque,
+                           target_phys_addr_t addr,
                            uint32_t value)
 {
-    struct omap3_cm_s *s = (struct omap3_cm_s *) opaque;
-
-    TRACE("%04x = %08x", addr, value);
-    switch (addr)
-    {
-    case 0x20:
-    case 0x24:
-    case 0x4c:
-    case 0x800:
-    case 0x920:
-    case 0x924:
-    case 0x94c:
-    case 0xa20:
-    case 0xa24:
-    case 0xa28:
-    case 0xa4c:
-    case 0xb20:
-    case 0xb4c:
-    case 0xc20:                /*CM_IDLEST_WKUP */
-    case 0xd20:
-    case 0xd24:
-    case 0xe20:
-    case 0xe4c:
-    case 0xf20:
-    case 0xf4c:
-    case 0x1020:
-    case 0x104c:
-    case 0x114c:
-    case 0x1320:
-    case 0x1420:
-    case 0x144c:
-        OMAP_RO_REG(addr);
-        exit(-1);
-        break;
-        
-    case 0x0:
-       s->cm_fclken_iva2 = value & 0x1;
-       break;
-    case 0x4:                  /*CM_CLKEN_PLL_IVA2 */
-        s->cm_clken_pll_iva2 = value & 0x7ff;
-        omap3_cm_iva2_update(s);
-        break;
-    case 0x34:
-       s->cm_autoidle_pll_iva2 = value & 0x7;
-       break;
-    case 0x40:
-        s->cm_clksel1_pll_iva2 = value & 0x3fff7f;
-        //printf("value %x s->cm_clksel1_pll_iva2 %x \n",value,s->cm_clksel1_pll_iva2);
-        omap3_cm_iva2_update(s);
-        break;
-    case 0x44:
-        s->cm_clksel2_pll_iva2 = value & 0x1f;
-        omap3_cm_iva2_update(s);
-        break;
-    case 0x48:
-       s->cm_clkstctrl_iva2 = value& 0x3;
-       break;
-
-    case 0x810:
-       s->cm_sysconfig = value & 0x1;
-       break;
-
-        
-    case 0x904:                /*CM_CLKEN_PLL_MPU */
-        s->cm_clken_pll_mpu = value & 0x7ff;
-        omap3_cm_mpu_update(s);
-        break;
-    case 0x934:
-       s->cm_autoidle_pll_mpu = value & 0x7;
-       break;
-    case 0x940:
-        //printf("s->cm_clksel1_pll_mpu  %x\n",s->cm_clksel1_pll_mpu );
-        s->cm_clksel1_pll_mpu = value & 0x3fff7f;
-        omap3_cm_mpu_update(s);
-        break;
-    case 0x944:
-        s->cm_clksel2_pll_mpu = value & 0x1f;
-        omap3_cm_mpu_update(s);
-        break;
-    case 0x948:
-       s->cm_clkstctrl_mpu = value & 0x3;
-       break;
-
-       
-    case 0xa00:
-        s->cm_fclken1_core = value & 0x43fffe00;
-         break;
-    case 0xa08:
-        s->cm_fclken3_core = value & 0x7;
-        break;
-    case 0xa10:
-        s->cm_iclken1_core = value & 0x637ffed2;
-        s->cm_idlest1_core = ~s->cm_iclken1_core;
-        /* TODO: replace code below with real implementation */
-        s->cm_idlest1_core &= ~0x20; /* HS OTG USB idle */
-        s->cm_idlest1_core |= 4; /* SDMA in standby */
-        break;
-    case 0xa14:
-        s->cm_iclken2_core = value & 0x1f;
-        break;
-    case 0xa18:
-       s->cm_iclken3_core = value & 0x4;
-        s->cm_idlest3_core = 0xd & ~(s->cm_iclken3_core & 4);
-       break;
-    case 0xa30:
-       s->cm_autoidle1_core = value & 0x7ffffed0;
-       break;
-    case 0xa34:
-       s->cm_autoidle2_core = value & 0x1f;
-       break;
-    case 0xa38:
-       s->cm_autoidle3_core = value & 0x2;
-       break;
-    case 0xa40:                /*CM_CLKSEL_CORE */
-        s->cm_clksel_core = (value & 0xff);
-        s->cm_clksel_core |= 0x100;
-        omap3_cm_gp10_update(s);
-        omap3_cm_gp11_update(s);
-        omap3_cm_l3clk_update(s);
-        omap3_cm_l4clk_update(s);
-        break;
-    case 0xa48:
-       s->cm_clkstctrl_core = value & 0xf;
-       break;
+    struct omap3_cm_s *s = (struct omap3_cm_s *)opaque;
 
-    case 0xb00:
-       s->cm_fclken_sgx = value &0x2;
-       break;
-    case 0xb10:
-       s->cm_iclken_sgx = value & 0x1;
-       break;
-    case 0xb40:                /*CM_CLKSEL_SGX */
-        /*TODO: SGX Clock!! */
-        s->cm_clksel_sgx = value;
-        break;
-    case 0xb44:
-       s->cm_sleepdep_sgx = value &0x2;
-       break;
-    case 0xb48:
-       s->cm_clkstctrl_sgx = value & 0x3;
-       break;
+    switch (addr) {
+        case 0x0020:
+        case 0x0024:
+        case 0x004c:
+        case 0x0800:
+        case 0x0920:
+        case 0x0924:
+        case 0x094c:
+        case 0x0a20:
+        case 0x0a24:
+        case 0x0a28:
+        case 0x0a4c:
+        case 0x0b20:
+        case 0x0b4c:
+        case 0x0c20:
+        case 0x0d20:
+        case 0x0d24:
+        case 0x0e20:
+        case 0x0e4c:
+        case 0x0f20:
+        case 0x0f4c:
+        case 0x1020:
+        case 0x104c:
+        case 0x114c:
+        case 0x1320:
+        case 0x1420:
+        case 0x144c:
+            OMAP_RO_REGV(addr, value);
+            break;
+        /* IVA2_CM */
+        case 0x0000:
+            s->cm_fclken_iva2 = value & 0x1;
+            omap3_cm_iva2_update(s);
+            break;
+        case 0x0004: 
+            s->cm_clken_pll_iva2 = value & 0x7ff;
+            omap3_cm_iva2_update(s);
+            break;
+        case 0x0034:
+            s->cm_autoidle_pll_iva2 = value & 0x7;
+            break;
+        case 0x0040:
+            s->cm_clksel1_pll_iva2 = value & 0x3fff7f;
+            omap3_cm_iva2_update(s);
+            break;
+        case 0x0044:
+            s->cm_clksel2_pll_iva2 = value & 0x1f;
+            omap3_cm_iva2_update(s);
+            break;
+        case 0x0048:
+            s->cm_clkstctrl_iva2 = value & 0x3;
+            break;
+        /* OCP_System_Reg_CM */
+        case 0x0810:
+            s->cm_sysconfig = value & 0x1;
+            break;
+        /* MPU_CM */
+        case 0x0904:
+            s->cm_clken_pll_mpu = value & 0x7ff;
+            omap3_cm_mpu_update(s);
+            break;
+        case 0x0934:
+            s->cm_autoidle_pll_mpu = value & 0x7;
+            break;
+        case 0x0940:
+            s->cm_clksel1_pll_mpu = value & 0x3fff7f;
+            omap3_cm_mpu_update(s);
+            break;
+        case 0x0944:
+            s->cm_clksel2_pll_mpu = value & 0x1f;
+            omap3_cm_mpu_update(s);
+            break;
+        case 0x0948:
+            s->cm_clkstctrl_mpu = value & 0x3;
+            break;
+        /* CORE_CM */
+        case 0xa00:
+            s->cm_fclken1_core = value & 0x43fffe00;
+            omap3_cm_fclken1_core_update(s);
+            break;
+        case 0xa08:
+            s->cm_fclken3_core = value & 0x7;
+            /* TODO: EN_USBTLL, EN_TS */
+            break;
+        case 0xa10:
+            s->cm_iclken1_core = value & 0x637ffed2;
+            omap3_cm_iclken1_core_update(s);
+            break;
+        case 0xa14:
+            s->cm_iclken2_core = value & 0x1f;
+            break;
+        case 0xa18:
+            s->cm_iclken3_core = value & 0x4;
+            s->cm_idlest3_core = 0xd & ~(s->cm_iclken3_core & 4);
+            break;
+        case 0xa30:
+            s->cm_autoidle1_core = value & 0x7ffffed0;
+            break;
+        case 0xa34:
+            s->cm_autoidle2_core = value & 0x1f;
+            break;
+        case 0xa38:
+            s->cm_autoidle3_core = value & 0x2;
+            break;
+        case 0xa40:
+            s->cm_clksel_core = (value & 0xff) | 0x100;
+            omap3_cm_gp10gp11_update(s);
+            omap3_cm_l3l4iclk_update(s);
+            break;
+        case 0xa48:
+            s->cm_clkstctrl_core = value & 0xf;
+            break;
+        /* SGX_CM */
+        case 0xb00: s->cm_fclken_sgx = value & 0x2; break;
+        case 0xb10: s->cm_iclken_sgx = value & 0x1; break;
+        case 0xb40: s->cm_clksel_sgx = value; break; /* TODO: SGX clock */
+        case 0xb44: s->cm_sleepdep_sgx = value &0x2; break;
+        case 0xb48: s->cm_clkstctrl_sgx = value & 0x3; break;
+        /* WKUP_CM */
+        case 0xc00:
+            s->cm_fclken_wkup = value & 0x2e9;
+            omap_clk_onoff(omap_findclk(s->mpu, "omap3_gp1_fclk"),
+                           s->cm_fclken_wkup & 1);
+            /* TODO: EN_GPIO1 */
+            /* TODO: EN_WDT2 */
+            break;
+        case 0xc10:
+            s->cm_iclken_wkup = value & 0x23f;
+            omap_clk_onoff(omap_findclk(s->mpu, "omap3_wkup_l4_iclk"),
+                           s->cm_iclken_wkup ? 1 : 0);
+            break;
+        case 0xc30: s->cm_autoidle_wkup = value & 0x23f; break;
+        case 0xc40:
+            s->cm_clksel_wkup = value & 0x7f;
+            omap3_cm_clksel_wkup_update(s);
+            break;
+        /* Clock_Control_Reg_CM */
+        case 0xd00:
+            s->cm_clken_pll = value & 0xffff17ff;
+            omap3_cm_dpll3_update(s);
+            omap3_cm_dpll4_update(s);
+            break;
+        case 0xd04:
+            s->cm_clken2_pll = value & 0x7ff;
+            omap3_cm_dpll5_update(s);
+            break;
+        case 0xd30: s->cm_autoidle_pll = value & 0x3f; break;
+        case 0xd34: s->cm_autoidle2_pll = value & 0x7; break;
+        case 0xd40:
+            s->cm_clksel1_pll = value & 0xffffbffc;
+            omap3_cm_dpll3_update(s);
+            omap3_cm_48m_update(s);
+            /* TODO: 96m and 54m update */
+            break;
+        case 0xd44:
+            s->cm_clksel2_pll = value & 0x7ff7f;
+            omap3_cm_dpll4_update(s);
+            break;
+        case 0xd48:
+            s->cm_clksel3_pll = value & 0x1f;
+            omap3_cm_dpll4_update(s);
+            break;
+        case 0xd4c:
+            s->cm_clksel4_pll = value & 0x7ff7f;
+            omap3_cm_dpll5_update(s);
+            break;
+        case 0xd50:
+            s->cm_clksel5_pll = value & 0x1f;
+            omap3_cm_dpll5_update(s);
+            break;
+        case 0xd70:
+            s->cm_clkout_ctrl = value & 0xbb;
+            omap3_cm_clkout2_update(s);
+            break;
+        /* DSS_CM */
+        case 0xe00: s->cm_fclken_dss = value & 0x7; break;
+        case 0xe10: s->cm_iclken_dss = value & 0x1; break;
+        case 0xe30: s->cm_autoidle_dss = value & 0x1; break;
+        case 0xe40:
+            s->cm_clksel_dss = value & 0x1f1f;
+            omap3_cm_dpll4_update(s);
+            break;
+        case 0xe44: s->cm_sleepdep_dss = value & 0x7; break;
+        case 0xe48: s->cm_clkstctrl_dss = value & 0x3; break;
+        /* CAM_CM */
+        case 0xf00: s->cm_fclken_cam = value & 0x3; break;
+        case 0xf10: s->cm_iclken_cam = value & 0x1; break;
+        case 0xf30: s->cm_autoidle_cam = value & 0x1; break;
+        case 0xf40:
+            s->cm_clksel_cam = value & 0x1f;
+            omap3_cm_dpll4_update(s);
+            break;
+        case 0xf44: s->cm_sleepdep_cam = value & 0x2; break;
+        case 0xf48: s->cm_clkstctrl_cam = value & 0x3; break;
+        /* PER_CM */
+        case 0x1000: s->cm_fclken_per = value & 0x3ffff; break;
+        case 0x1010: s->cm_iclken_per = value & 0x3ffff; break;
+        case 0x1030: s->cm_autoidle_per = value &0x3ffff; break;
+        case 0x1040:
+            s->cm_clksel_per = value & 0xff;
+            omap3_cm_per_gptimer_update(s);
+            break;
+        case 0x1044: s->cm_sleepdep_per = value & 0x6; break;
+        case 0x1048: s->cm_clkstctrl_per = value &0x7; break;
+        /* EMU_CM */
+        case 0x1140:
+            s->cm_clksel1_emu = value & 0x1f1f3fff;
+            omap3_cm_dpll3_update(s);
+            omap3_cm_dpll4_update(s);
+            break;
+        case 0x1148: s->cm_clkstctrl_emu = value & 0x3; break;
+        case 0x1150:
+            s->cm_clksel2_emu = value & 0xfff7f;
+            omap3_cm_dpll3_update(s);
+            break;
+        case 0x1154:
+            s->cm_clksel3_emu = value & 0xfff7f;
+            omap3_cm_dpll4_update(s);
+            break;
+        /* Global_Reg_CM */
+        case 0x129c: s->cm_polctrl = value & 0x1; break;
+        /* NEON_CM */
+        case 0x1348: s->cm_clkstctrl_neon = value & 0x3; break;
+        /* USBHOST_CM */
+        case 0x1400: s->cm_fclken_usbhost = value & 0x3; break;
+        case 0x1410: s->cm_iclken_usbhost = value & 0x1; break;
+        case 0x1430: s->cm_autoidle_usbhost = value & 0x1; break;
+        case 0x1444: s->cm_sleepdep_usbhost = value & 0x6; break;
+        case 0x1448: s->cm_clkstctrl_usbhost = value & 0x3; break;
+        /* unknown */
+        default:
+            OMAP_BAD_REGV(addr, value);
+            break;
+    }
+}
 
+static void omap3_cm_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_cm_s *s = (struct omap3_cm_s *)opaque;
     
-    case 0xc00:                /*CM_FCLKEN_WKUP */
-        s->cm_fclken_wkup = value & 0x2e9;
-        break;
-    case 0xc10:                /*CM_ICLKEN_WKUP */
-        s->cm_iclken_wkup = value & 0x2ff;
-        break;
-    case 0xc30:
-       s->cm_autoidle_wkup = value & 0x23f;
-       break;
-    case 0xc40:                /*CM_CLKSEL_WKUP */
-        s->cm_clksel_wkup = value & 0x7f;
-        omap3_cm_clksel_wkup_update(s, s->cm_clksel_wkup);
-        break;
-
-        
-    case 0xd00:                /*CM_CLKEN_PLL */
-        s->cm_clken_pll = value & 0xffff17ff;
-        omap3_cm_dpll3_update(s);
-        omap3_cm_dpll4_update(s);
-        break;
-    case 0xd04:
-       s->cm_clken2_pll = value & 0x7ff;
-       break;
-    case 0xd30:
-       s->cm_autoidle_pll = value & 0x3f;
-       break;
-    case 0xd34:
-       s->cm_autoidle2_pll = value & 0x7;
-       break;
-    case 0xd40:                /*CM_CLKSEL1_PLL */
-        //OMAP3_DEBUG(("WD40 value %x \n",value));
-        s->cm_clksel1_pll = value & 0xffffbffc;
-        //OMAP3_DEBUG(("WD40 value %x \n",value));
-        omap3_cm_dpll3_update(s);
-        omap3_cm_48m_update(s);
-        break;
-    case 0xd44:
-        s->cm_clksel2_pll = value & 0x7ff7f;
-        omap3_cm_dpll4_update(s);
-        break;
-    case 0xd48:                /*CM_CLKSEL3_PLL */
-        s->cm_clksel3_pll = value & 0x1f;
-        omap3_cm_dpll4_update(s);
-        break;
-    case 0xd4c:                /*CM_CLKSEL4_PLL */  
-       s->cm_clksel4_pll = value & 0x7ff7f;
-        omap3_cm_dpll5_update(s);
-        break;
-     case 0xd50:                /*CM_CLKSEL5_PLL */
-        s->cm_clksel5_pll = value & 0x1f;
-        omap3_cm_dpll5_update(s);
-        break;
-    case 0xd70:
-       s->cm_clkout_ctrl = value & 0xbb;
-       omap3_cm_clkout2_update(s);
-       break;
-        
-    case 0xe00:
-       s->cm_fclken_dss = value & 0x7;
-       break;
-       case 0xe10:
-       s->cm_iclken_dss = value & 0x1;
-       break;
-    case 0xe30:
-       s->cm_autoidle_dss = value & 0x1;
-       break;
-    case 0xe40:
-        s->cm_clksel_dss = value & 0x1f1f;
-        omap3_cm_dpll4_update(s);
-        break;
-   case 0xe44:
-               s->cm_sleepdep_dss = value & 0x7;
-       break;
-   case 0xe48:
-               s->cm_clkstctrl_dss = value & 0x3;
-       break;
-        
-    case 0xf00:
-       s->cm_fclken_cam = value & 0x3;
-       break;
-    case 0xf10:
-       s->cm_iclken_cam = value & 0x1;
-       break;
-    case 0xf30:
-       s->cm_autoidle_cam = value & 0x1;
-       break;
-    case 0xf40:
-        s->cm_clksel_cam = value & 0x1f;
-        omap3_cm_dpll4_update(s);
-        break;
-    case 0xf44:
-       s->cm_sleepdep_cam = value & 0x2;
-       break;
-    case 0xf48:
-       s->cm_clkstctrl_cam = value & 0x3;
-       break;
-   
-    case 0x1000:
-        s->cm_fclken_per = value & 0x3ffff;
-        break;
-    case 0x1010:
-        s->cm_iclken_per = value & 0x3ffff;
-        break;
+    qemu_put_be32(f, s->cm_fclken_iva2);
+    qemu_put_be32(f, s->cm_clken_pll_iva2);
+    qemu_put_be32(f, s->cm_idlest_iva2);
+    qemu_put_be32(f, s->cm_idlest_pll_iva2);
+    qemu_put_be32(f, s->cm_autoidle_pll_iva2);
+    qemu_put_be32(f, s->cm_clksel1_pll_iva2);
+    qemu_put_be32(f, s->cm_clksel2_pll_iva2);
+    qemu_put_be32(f, s->cm_clkstctrl_iva2);
+    qemu_put_be32(f, s->cm_clkstst_iva2);
     
-    case 0x1030:
-       s->cm_autoidle_per = value &0x3ffff;
-       break;
-    case 0x1040:
-        s->cm_clksel_per = value & 0xff;
-        omap3_cm_per_gptimer_update(s);
-        break;
-    case 0x1044:
-       s->cm_sleepdep_per = value & 0x6;
-       break;
-    case 0x1048:
-        s->cm_clkstctrl_per = value &0x7;
-        break;
-        
-    case 0x1140:               /*CM_CLKSEL1_EMU */
-        s->cm_clksel1_emu = value & 0x1f1f3fff;
-        //printf("cm_clksel1_emu %x\n",s->cm_clksel1_emu);
-        omap3_cm_dpll3_update(s);
-        omap3_cm_dpll4_update(s);
-        break;
-    case 0x1148:
-       s->cm_clkstctrl_emu = value & 0x3;
-       break;
-        case 0x1150:
-                s->cm_clksel2_emu = value & 0xfff7f;
-                omap3_cm_dpll3_update(s);
-        break;
-    case 0x1154:
-        s->cm_clksel3_emu = value & 0xfff7f;
-                omap3_cm_dpll4_update(s);
-        break;
-
-    case 0x129c:
-        s->cm_polctrl = value & 0x1;
-        break;
-
-   case 0x1348:
-               s->cm_clkstctrl_neon = value & 0x3;
-               break;
-
-       case 0x1400:
-               s->cm_fclken_usbhost = value & 0x3;
-               break;
-       case 0x1410:
-               s->cm_iclken_usbhost = value & 0x1;
-               break;
-    case 0x1430:
-       s->cm_autoidle_usbhost = value & 0x1;
-       break;
-    case 0x1444:
-       s->cm_sleepdep_usbhost = value & 0x6;
-       break;
-    case 0x1448:
-       s->cm_clkstctrl_usbhost = value & 0x3;
-       break;
-   
-    default:
-        printf("omap3_cm_write addr %x value %x pc %x\n", addr, value,cpu_single_env->regs[15] );
-        exit(-1);
-    }
+    qemu_put_be32(f, s->cm_revision);
+    qemu_put_be32(f, s->cm_sysconfig);
+    
+    qemu_put_be32(f, s->cm_clken_pll_mpu);
+    qemu_put_be32(f, s->cm_idlest_mpu);
+    qemu_put_be32(f, s->cm_idlest_pll_mpu);
+    qemu_put_be32(f, s->cm_autoidle_pll_mpu);
+    qemu_put_be32(f, s->cm_clksel1_pll_mpu);
+    qemu_put_be32(f, s->cm_clksel2_pll_mpu);
+    qemu_put_be32(f, s->cm_clkstctrl_mpu);
+    qemu_put_be32(f, s->cm_clkstst_mpu);
+    
+    qemu_put_be32(f, s->cm_fclken1_core);
+    qemu_put_be32(f, s->cm_fclken3_core);
+    qemu_put_be32(f, s->cm_iclken1_core);
+    qemu_put_be32(f, s->cm_iclken2_core);
+    qemu_put_be32(f, s->cm_iclken3_core);
+    qemu_put_be32(f, s->cm_idlest1_core);
+    qemu_put_be32(f, s->cm_idlest2_core);
+    qemu_put_be32(f, s->cm_idlest3_core);
+    qemu_put_be32(f, s->cm_autoidle1_core);
+    qemu_put_be32(f, s->cm_autoidle2_core);
+    qemu_put_be32(f, s->cm_autoidle3_core);
+    qemu_put_be32(f, s->cm_clksel_core);
+    qemu_put_be32(f, s->cm_clkstctrl_core);
+    qemu_put_be32(f, s->cm_clkstst_core);
+    
+    qemu_put_be32(f, s->cm_fclken_sgx);
+    qemu_put_be32(f, s->cm_iclken_sgx);
+    qemu_put_be32(f, s->cm_idlest_sgx);
+    qemu_put_be32(f, s->cm_clksel_sgx);
+    qemu_put_be32(f, s->cm_sleepdep_sgx);
+    qemu_put_be32(f, s->cm_clkstctrl_sgx);
+    qemu_put_be32(f, s->cm_clkstst_sgx);
+    
+    qemu_put_be32(f, s->cm_fclken_wkup);
+    qemu_put_be32(f, s->cm_iclken_wkup);
+    qemu_put_be32(f, s->cm_idlest_wkup);
+    qemu_put_be32(f, s->cm_autoidle_wkup);
+    qemu_put_be32(f, s->cm_clksel_wkup);
+    qemu_put_be32(f, s->cm_c48);
+    
+    qemu_put_be32(f, s->cm_clken_pll);
+    qemu_put_be32(f, s->cm_clken2_pll);
+    qemu_put_be32(f, s->cm_idlest_ckgen);
+    qemu_put_be32(f, s->cm_idlest2_ckgen);
+    qemu_put_be32(f, s->cm_autoidle_pll);
+    qemu_put_be32(f, s->cm_autoidle2_pll);
+    qemu_put_be32(f, s->cm_clksel1_pll);
+    qemu_put_be32(f, s->cm_clksel2_pll);
+    qemu_put_be32(f, s->cm_clksel3_pll);
+    qemu_put_be32(f, s->cm_clksel4_pll);
+    qemu_put_be32(f, s->cm_clksel5_pll);
+    qemu_put_be32(f, s->cm_clkout_ctrl);
+    
+    qemu_put_be32(f, s->cm_fclken_dss);
+    qemu_put_be32(f, s->cm_iclken_dss);
+    qemu_put_be32(f, s->cm_idlest_dss);
+    qemu_put_be32(f, s->cm_autoidle_dss);
+    qemu_put_be32(f, s->cm_clksel_dss);
+    qemu_put_be32(f, s->cm_sleepdep_dss);
+    qemu_put_be32(f, s->cm_clkstctrl_dss);
+    qemu_put_be32(f, s->cm_clkstst_dss);
+    
+    qemu_put_be32(f, s->cm_fclken_cam);
+    qemu_put_be32(f, s->cm_iclken_cam);
+    qemu_put_be32(f, s->cm_idlest_cam);
+    qemu_put_be32(f, s->cm_autoidle_cam);
+    qemu_put_be32(f, s->cm_clksel_cam);
+    qemu_put_be32(f, s->cm_sleepdep_cam);
+    qemu_put_be32(f, s->cm_clkstctrl_cam);
+    qemu_put_be32(f, s->cm_clkstst_cam);
+
+    qemu_put_be32(f, s->cm_fclken_per);
+    qemu_put_be32(f, s->cm_iclken_per);
+    qemu_put_be32(f, s->cm_idlest_per);
+    qemu_put_be32(f, s->cm_autoidle_per);
+    qemu_put_be32(f, s->cm_clksel_per);
+    qemu_put_be32(f, s->cm_sleepdep_per);
+    qemu_put_be32(f, s->cm_clkstctrl_per);
+    qemu_put_be32(f, s->cm_clkstst_per);
+    
+    qemu_put_be32(f, s->cm_clksel1_emu);
+    qemu_put_be32(f, s->cm_clkstctrl_emu);
+    qemu_put_be32(f, s->cm_clkstst_emu);
+    qemu_put_be32(f, s->cm_clksel2_emu);
+    qemu_put_be32(f, s->cm_clksel3_emu);
+    
+    qemu_put_be32(f, s->cm_polctrl);
+
+    qemu_put_be32(f, s->cm_idlest_neon);
+    qemu_put_be32(f, s->cm_clkstctrl_neon);
+
+    qemu_put_be32(f, s->cm_fclken_usbhost);
+    qemu_put_be32(f, s->cm_iclken_usbhost);
+    qemu_put_be32(f, s->cm_idlest_usbhost);
+    qemu_put_be32(f, s->cm_autoidle_usbhost);
+    qemu_put_be32(f, s->cm_sleepdep_usbhost);
+    qemu_put_be32(f, s->cm_clkstctrl_usbhost);
+    qemu_put_be32(f, s->cm_clkstst_usbhost);
 }
 
-
+static int omap3_cm_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap3_cm_s *s = (struct omap3_cm_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->cm_fclken_iva2 = qemu_get_be32(f);
+    s->cm_clken_pll_iva2 = qemu_get_be32(f);
+    s->cm_idlest_iva2 = qemu_get_be32(f);
+    s->cm_idlest_pll_iva2 = qemu_get_be32(f);
+    s->cm_autoidle_pll_iva2 = qemu_get_be32(f);
+    s->cm_clksel1_pll_iva2 = qemu_get_be32(f);
+    s->cm_clksel2_pll_iva2 = qemu_get_be32(f);
+    s->cm_clkstctrl_iva2 = qemu_get_be32(f);
+    s->cm_clkstst_iva2 = qemu_get_be32(f);
+    
+    s->cm_revision = qemu_get_be32(f);
+    s->cm_sysconfig = qemu_get_be32(f);
+    
+    s->cm_clken_pll_mpu = qemu_get_be32(f);
+    s->cm_idlest_mpu = qemu_get_be32(f);
+    s->cm_idlest_pll_mpu = qemu_get_be32(f);
+    s->cm_autoidle_pll_mpu = qemu_get_be32(f);
+    s->cm_clksel1_pll_mpu = qemu_get_be32(f);
+    s->cm_clksel2_pll_mpu = qemu_get_be32(f);
+    s->cm_clkstctrl_mpu = qemu_get_be32(f);
+    s->cm_clkstst_mpu = qemu_get_be32(f);
+    
+    s->cm_fclken1_core = qemu_get_be32(f);
+    s->cm_fclken3_core = qemu_get_be32(f);
+    s->cm_iclken1_core = qemu_get_be32(f);
+    s->cm_iclken2_core = qemu_get_be32(f);
+    s->cm_iclken3_core = qemu_get_be32(f);
+    s->cm_idlest1_core = qemu_get_be32(f);
+    s->cm_idlest2_core = qemu_get_be32(f);
+    s->cm_idlest3_core = qemu_get_be32(f);
+    s->cm_autoidle1_core = qemu_get_be32(f);
+    s->cm_autoidle2_core = qemu_get_be32(f);
+    s->cm_autoidle3_core = qemu_get_be32(f);
+    s->cm_clksel_core = qemu_get_be32(f);
+    s->cm_clkstctrl_core = qemu_get_be32(f);
+    s->cm_clkstst_core = qemu_get_be32(f);
+    
+    s->cm_fclken_sgx = qemu_get_be32(f);
+    s->cm_iclken_sgx = qemu_get_be32(f);
+    s->cm_idlest_sgx = qemu_get_be32(f);
+    s->cm_clksel_sgx = qemu_get_be32(f);
+    s->cm_sleepdep_sgx = qemu_get_be32(f);
+    s->cm_clkstctrl_sgx = qemu_get_be32(f);
+    s->cm_clkstst_sgx = qemu_get_be32(f);
+    
+    s->cm_fclken_wkup = qemu_get_be32(f);
+    s->cm_iclken_wkup = qemu_get_be32(f);
+    s->cm_idlest_wkup = qemu_get_be32(f);
+    s->cm_autoidle_wkup = qemu_get_be32(f);
+    s->cm_clksel_wkup = qemu_get_be32(f);
+    s->cm_c48 = qemu_get_be32(f);
+    
+    s->cm_clken_pll = qemu_get_be32(f);
+    s->cm_clken2_pll = qemu_get_be32(f);
+    s->cm_idlest_ckgen = qemu_get_be32(f);
+    s->cm_idlest2_ckgen = qemu_get_be32(f);
+    s->cm_autoidle_pll = qemu_get_be32(f);
+    s->cm_autoidle2_pll = qemu_get_be32(f);
+    s->cm_clksel1_pll = qemu_get_be32(f);
+    s->cm_clksel2_pll = qemu_get_be32(f);
+    s->cm_clksel3_pll = qemu_get_be32(f);
+    s->cm_clksel4_pll = qemu_get_be32(f);
+    s->cm_clksel5_pll = qemu_get_be32(f);
+    s->cm_clkout_ctrl = qemu_get_be32(f);
+    
+    s->cm_fclken_dss = qemu_get_be32(f);
+    s->cm_iclken_dss = qemu_get_be32(f);
+    s->cm_idlest_dss = qemu_get_be32(f);
+    s->cm_autoidle_dss = qemu_get_be32(f);
+    s->cm_clksel_dss = qemu_get_be32(f);
+    s->cm_sleepdep_dss = qemu_get_be32(f);
+    s->cm_clkstctrl_dss = qemu_get_be32(f);
+    s->cm_clkstst_dss = qemu_get_be32(f);
+    
+    s->cm_fclken_cam = qemu_get_be32(f);
+    s->cm_iclken_cam = qemu_get_be32(f);
+    s->cm_idlest_cam = qemu_get_be32(f);
+    s->cm_autoidle_cam = qemu_get_be32(f);
+    s->cm_clksel_cam = qemu_get_be32(f);
+    s->cm_sleepdep_cam = qemu_get_be32(f);
+    s->cm_clkstctrl_cam = qemu_get_be32(f);
+    s->cm_clkstst_cam = qemu_get_be32(f);
+    
+    s->cm_fclken_per = qemu_get_be32(f);
+    s->cm_iclken_per = qemu_get_be32(f);
+    s->cm_idlest_per = qemu_get_be32(f);
+    s->cm_autoidle_per = qemu_get_be32(f);
+    s->cm_clksel_per = qemu_get_be32(f);
+    s->cm_sleepdep_per = qemu_get_be32(f);
+    s->cm_clkstctrl_per = qemu_get_be32(f);
+    s->cm_clkstst_per = qemu_get_be32(f);
+    
+    s->cm_clksel1_emu = qemu_get_be32(f);
+    s->cm_clkstctrl_emu = qemu_get_be32(f);
+    s->cm_clkstst_emu = qemu_get_be32(f);
+    s->cm_clksel2_emu = qemu_get_be32(f);
+    s->cm_clksel3_emu = qemu_get_be32(f);
+    
+    s->cm_polctrl = qemu_get_be32(f);
+    
+    s->cm_idlest_neon = qemu_get_be32(f);
+    s->cm_clkstctrl_neon = qemu_get_be32(f);
+    
+    s->cm_fclken_usbhost = qemu_get_be32(f);
+    s->cm_iclken_usbhost = qemu_get_be32(f);
+    s->cm_idlest_usbhost = qemu_get_be32(f);
+    s->cm_autoidle_usbhost = qemu_get_be32(f);
+    s->cm_sleepdep_usbhost = qemu_get_be32(f);
+    s->cm_clkstctrl_usbhost = qemu_get_be32(f);
+    s->cm_clkstst_usbhost = qemu_get_be32(f);
+
+    omap3_cm_iva2_update(s);
+    omap3_cm_mpu_update(s);
+    omap3_cm_fclken1_core_update(s);
+    omap3_cm_iclken1_core_update(s);
+    omap3_cm_gp10gp11_update(s);
+    omap3_cm_l3l4iclk_update(s);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_gp1_fclk"),
+                   s->cm_fclken_wkup & 1);
+    omap_clk_onoff(omap_findclk(s->mpu, "omap3_wkup_l4_iclk"),
+                   s->cm_iclken_wkup ? 1 : 0);
+    omap3_cm_clksel_wkup_update(s);
+    omap3_cm_dpll3_update(s);
+    omap3_cm_dpll4_update(s);
+    omap3_cm_dpll5_update(s);
+    omap3_cm_48m_update(s);
+    omap3_cm_clkout2_update(s);
+    omap3_cm_per_gptimer_update(s);
+    
+    return 0;
+}
 
 static CPUReadMemoryFunc *omap3_cm_readfn[] = {
     omap_badwidth_read32,
@@ -3133,9 +3312,10 @@ static CPUWriteMemoryFunc *omap3_cm_writefn[] = {
     omap3_cm_write,
 };
 
-struct omap3_cm_s *omap3_cm_init(struct omap_target_agent_s *ta,
-                                 qemu_irq mpu_int, qemu_irq dsp_int,
-                                 qemu_irq iva_int, struct omap_mpu_state_s *mpu)
+static struct omap3_cm_s *omap3_cm_init(struct omap_target_agent_s *ta,
+                                        qemu_irq mpu_int, qemu_irq dsp_int,
+                                        qemu_irq iva_int,
+                                        struct omap_mpu_state_s *mpu)
 {
     int iomemtype;
     struct omap3_cm_s *s = (struct omap3_cm_s *) qemu_mallocz(sizeof(*s));
@@ -3150,6 +3330,8 @@ struct omap3_cm_s *omap3_cm_init(struct omap_target_agent_s *ta,
     omap_l4_attach(ta, 0, iomemtype);
     omap_l4_attach(ta, 1, iomemtype);
 
+    register_savevm("omap3_cm", -1, 0,
+                    omap3_cm_save_state, omap3_cm_load_state, s);
     return s;
 }
 
@@ -3192,13 +3374,11 @@ struct omap3_wdt_s
 static inline void omap3_wdt_timer_update(struct omap3_wdt_s *wdt_timer)
 {
     int64_t expires;
-    if (wdt_timer->active)
-    {
+    if (wdt_timer->active) {
         expires = muldiv64(0xffffffffll - wdt_timer->wcrr,
                            ticks_per_sec, wdt_timer->rate);
         qemu_mod_timer(wdt_timer->timer, wdt_timer->time + expires);
-    }
-    else
+    } else
         qemu_del_timer(wdt_timer->timer);
 }
 
@@ -3211,8 +3391,7 @@ static inline uint32_t omap3_wdt_timer_read(struct omap3_wdt_s *timer)
 {
     uint64_t distance;
 
-    if (timer->active)
-    {
+    if (timer->active) {
         distance = qemu_get_clock(vm_clock) - timer->time;
         distance = muldiv64(distance, timer->rate, ticks_per_sec);
 
@@ -3220,8 +3399,7 @@ static inline uint32_t omap3_wdt_timer_read(struct omap3_wdt_s *timer)
             return 0xffffffff;
         else
             return timer->wcrr + distance;
-    }
-    else
+    } else
         return timer->wcrr;
 }
 
@@ -3242,29 +3420,31 @@ static void omap3_wdt_reset(struct omap3_wdt_s *s, int wdt_index)
     s->wier = 0x0;
     s->wclr = 0x20;
     s->wcrr = 0x0;
-    switch (wdt_index)
-    {
-    case OMAP3_MPU_WDT:
-    case OMAP3_IVA2_WDT:
-        s->wldr = 0xfffb0000;
-        break;
-    case OMAP3_SEC_WDT:
-        s->wldr = 0xffa60000;
-        break;
+    switch (wdt_index) {
+        case OMAP3_MPU_WDT:
+        case OMAP3_IVA2_WDT:
+            s->wldr = 0xfffb0000;
+            break;
+        case OMAP3_SEC_WDT:
+            s->wldr = 0xffa60000;
+            break;
+        default:
+            break;
     }
     s->wtgr = 0x0;
     s->wwps = 0x0;
     s->wspr = 0x0;
 
-    switch (wdt_index)
-    {
-    case OMAP3_SEC_WDT:
-    case OMAP3_MPU_WDT:
-        s->active = 1;
-        break;
-    case OMAP3_IVA2_WDT:
-        s->active = 0;
-        break;
+    switch (wdt_index) {
+        case OMAP3_SEC_WDT:
+        case OMAP3_MPU_WDT:
+            s->active = 1;
+            break;
+        case OMAP3_IVA2_WDT:
+            s->active = 0;
+            break;
+        default:
+            break;
     }
     s->pre = s->wclr & (1 << 5);
     s->ptv = (s->wclr & 0x1c) >> 2;
@@ -3280,36 +3460,24 @@ static uint32_t omap3_wdt_read32(void *opaque, target_phys_addr_t addr,
 {
     struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
 
-    //uint32_t ret;
-    //printf("omap3_wdt_read32 addr %x \n",addr);
-    switch (addr)
-    {
-    case 0x10:                 /*WD_SYSCONFIG */
-        return s->wd_sysconfig;
-    case 0x14:                 /*WD_SYSSTATUS */
-        return s->wd_sysstatus;
-    case 0x18:
-         /*WISR*/ return s->wisr & 0x1;
-    case 0x1c:
-         /*WIER*/ return s->wier & 0x1;
-    case 0x24:
-         /*WCLR*/ return s->wclr & 0x3c;
-    case 0x28:
-         /*WCRR*/ s->wcrr = omap3_wdt_timer_read(s);
-        s->time = qemu_get_clock(vm_clock);
-        return s->wcrr;
-    case 0x2c:
-         /*WLDR*/ return s->wldr;
-    case 0x30:
-         /*WTGR*/ return s->wtgr;
-    case 0x34:
-         /*WWPS*/ return s->wwps;
-    case 0x48:
-         /*WSPR*/ return s->wspr;
-    default:
-        printf("omap3_wdt_read32 addr %x \n", addr);
-        exit(-1);
+    switch (addr) {
+        case 0x10: return s->wd_sysconfig;
+        case 0x14: return s->wd_sysstatus;
+        case 0x18: return s->wisr & 0x1;
+        case 0x1c: return s->wier & 0x1;
+        case 0x24: return s->wclr & 0x3c;
+        case 0x28: /* WCRR */
+            s->wcrr = omap3_wdt_timer_read(s);
+            s->time = qemu_get_clock(vm_clock);
+            return s->wcrr;
+        case 0x2c: return s->wldr;
+        case 0x30: return s->wtgr;
+        case 0x34: return s->wwps;
+        case 0x48: return s->wspr;
+        default: break;
     }
+    OMAP_BAD_REG(addr);
+    return 0;
 }
 
 static uint32_t omap3_mpu_wdt_read16(void *opaque, target_phys_addr_t addr)
@@ -3319,12 +3487,10 @@ static uint32_t omap3_mpu_wdt_read16(void *opaque, target_phys_addr_t addr)
 
     if (addr & 2)
         return s->readh;
-    else
-    {
-        ret = omap3_wdt_read32(opaque, addr, OMAP3_MPU_WDT);
-        s->readh = ret >> 16;
-        return ret & 0xffff;
-    }
+
+    ret = omap3_wdt_read32(opaque, addr, OMAP3_MPU_WDT);
+    s->readh = ret >> 16;
+    return ret & 0xffff;
 }
 
 static uint32_t omap3_mpu_wdt_read32(void *opaque, target_phys_addr_t addr)
@@ -3337,37 +3503,33 @@ static void omap3_wdt_write32(void *opaque, target_phys_addr_t addr,
 {
     struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
 
-    //printf("omap3_wdt_write32 addr %x value %x \n",addr,value);
-    switch (addr)
-    {
-    case 0x14:                 /*WD_SYSSTATUS */
-    case 0x34:
-         /*WWPS*/ OMAP_RO_REG(addr);
-        exit(-1);
+    switch (addr) {
+    case 0x14: /* WD_SYSSTATUS */
+    case 0x34: /* WWPS */
+        OMAP_RO_REGV(addr, value);
         break;
-    case 0x10:                 /*WD_SYSCONFIG */
+    case 0x10: /*WD_SYSCONFIG */
         s->wd_sysconfig = value & 0x33f;
         break;
-    case 0x18:
-         /*WISR*/ s->wisr = value & 0x1;
+    case 0x18: /* WISR */
+         s->wisr = value & 0x1;
         break;
-    case 0x1c:
-         /*WIER*/ s->wier = value & 0x1;
+    case 0x1c: /* WIER */
+        s->wier = value & 0x1;
         break;
-    case 0x24:
-         /*WCLR*/ s->wclr = value & 0x3c;
+    case 0x24: /* WCLR */
+        s->wclr = value & 0x3c;
         break;
-    case 0x28:
-         /*WCRR*/ s->wcrr = value;
+    case 0x28: /* WCRR */
+        s->wcrr = value;
         s->time = qemu_get_clock(vm_clock);
         omap3_wdt_timer_update(s);
         break;
-    case 0x2c:
-         /*WLDR*/ s->wldr = value;      /*It will take effect after next overflow */
+    case 0x2c: /* WLDR */
+        s->wldr = value; /* It will take effect after next overflow */
         break;
-    case 0x30:
-         /*WTGR*/ if (value != s->wtgr)
-        {
+    case 0x30: /* WTGR */
+        if (value != s->wtgr) {
             s->wcrr = s->wldr;
             s->pre = s->wclr & (1 << 5);
             s->ptv = (s->wclr & 0x1c) >> 2;
@@ -3377,16 +3539,13 @@ static void omap3_wdt_write32(void *opaque, target_phys_addr_t addr,
         }
         s->wtgr = value;
         break;
-    case 0x48:
-         /*WSPR*/
-            if (((value & 0xffff) == 0x5555) && ((s->wspr & 0xffff) == 0xaaaa))
-        {
+    case 0x48: /* WSPR */
+        if (((value & 0xffff) == 0x5555) && ((s->wspr & 0xffff) == 0xaaaa)) {
             s->active = 0;
             s->wcrr = omap3_wdt_timer_read(s);
             omap3_wdt_timer_update(s);
         }
-        if (((value & 0xffff) == 0x4444) && ((s->wspr & 0xffff) == 0xbbbb))
-        {
+        if (((value & 0xffff) == 0x4444) && ((s->wspr & 0xffff) == 0xbbbb)) {
             s->active = 1;
             s->time = qemu_get_clock(vm_clock);
             omap3_wdt_timer_update(s);
@@ -3394,8 +3553,8 @@ static void omap3_wdt_write32(void *opaque, target_phys_addr_t addr,
         s->wspr = value;
         break;
     default:
-        printf("omap3_wdt_write32 addr %x \n", addr);
-        exit(-1);
+        OMAP_BAD_REGV(addr, value);
+        break;
     }
 }
 
@@ -3447,6 +3606,59 @@ static void omap3_mpu_wdt_timer_tick(void *opaque)
     omap3_wdt_timer_update(wdt_timer);
 }
 
+static void omap3_mpu_wdt_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_wdt_s *s = (struct omap3_wdt_s *)opaque;
+
+    qemu_put_timer(f, s->timer);
+    qemu_put_sbe32(f, s->active);
+    qemu_put_be64(f, s->rate);
+    qemu_put_be64(f, s->time);
+    qemu_put_be32(f, s->wd_sysconfig);
+    qemu_put_be32(f, s->wd_sysstatus);
+    qemu_put_be32(f, s->wisr);
+    qemu_put_be32(f, s->wier);
+    qemu_put_be32(f, s->wclr);
+    qemu_put_be32(f, s->wcrr);
+    qemu_put_be32(f, s->wldr);
+    qemu_put_be32(f, s->wtgr);
+    qemu_put_be32(f, s->wwps);
+    qemu_put_be32(f, s->wspr);
+    qemu_put_be32(f, s->pre);
+    qemu_put_be32(f, s->ptv);
+    qemu_put_be16(f, s->writeh);
+    qemu_put_be16(f, s->readh);
+}
+
+static int omap3_mpu_wdt_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap3_wdt_s *s = (struct omap3_wdt_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    qemu_get_timer(f, s->timer);
+    s->active = qemu_get_sbe32(f);
+    s->rate = qemu_get_be64(f);
+    s->time = qemu_get_be64(f);
+    s->wd_sysconfig = qemu_get_be32(f);
+    s->wd_sysstatus = qemu_get_be32(f);
+    s->wisr = qemu_get_be32(f);
+    s->wier = qemu_get_be32(f);
+    s->wclr = qemu_get_be32(f);
+    s->wcrr = qemu_get_be32(f);
+    s->wldr = qemu_get_be32(f);
+    s->wtgr = qemu_get_be32(f);
+    s->wwps = qemu_get_be32(f);
+    s->wspr = qemu_get_be32(f);
+    s->pre = qemu_get_be32(f);
+    s->ptv = qemu_get_be32(f);
+    s->writeh = qemu_get_be16(f);
+    s->readh = qemu_get_be16(f);
+    
+    return 0;
+}
+
 static struct omap3_wdt_s *omap3_mpu_wdt_init(struct omap_target_agent_s *ta,
                                               qemu_irq irq, omap_clk fclk,
                                               omap_clk iclk,
@@ -3467,23 +3679,57 @@ static struct omap3_wdt_s *omap3_mpu_wdt_init(struct omap_target_agent_s *ta,
                                       omap3_mpu_wdt_writefn, s);
     omap_l4_attach(ta, 0, iomemtype);
 
+    register_savevm("omap3_mpu_wdt", -1, 0,
+                    omap3_mpu_wdt_save_state, omap3_mpu_wdt_load_state, s);
     return s;
-
 }
 
-/*dummy system control module*/
-struct omap3_scm_s
-{
+struct omap3_scm_s {
     struct omap_mpu_state_s *mpu;
 
-       uint8 interface[48];           /*0x4800 2000*/
-       uint8 padconfs[576];         /*0x4800 2030*/
-       uint32 general[228];            /*0x4800 2270*/
-       uint8 mem_wkup[1024];     /*0x4800 2600*/
+       uint8 interface[48];     /*0x4800 2000*/
+       uint8 padconfs[576];     /*0x4800 2030*/
+       uint32 general[228];     /*0x4800 2270*/
+       uint8 mem_wkup[1024];    /*0x4800 2600*/
        uint8 padconfs_wkup[84]; /*0x4800 2a00*/
-       uint32 general_wkup[8];    /*0x4800 2a60*/
+       uint32 general_wkup[8];  /*0x4800 2a60*/
 };
 
+static void omap3_scm_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_scm_s *s = (struct omap3_scm_s *)opaque;
+    int i;
+
+    qemu_put_buffer(f, s->interface, sizeof(s->interface));
+    qemu_put_buffer(f, s->padconfs, sizeof(s->padconfs));
+    for (i = 0; i < sizeof(s->general)/sizeof(uint32); i++)
+        qemu_put_be32(f, s->general[i]);
+    qemu_put_buffer(f, s->mem_wkup, sizeof(s->mem_wkup));
+    qemu_put_buffer(f, s->padconfs_wkup, sizeof(s->padconfs_wkup));
+    for (i = 0; i < sizeof(s->general_wkup)/sizeof(uint32); i++)
+        qemu_put_be32(f, s->general_wkup[i]);
+}
+
+static int omap3_scm_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap3_scm_s *s = (struct omap3_scm_s *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    qemu_get_buffer(f, s->interface, sizeof(s->interface));
+    qemu_get_buffer(f, s->padconfs, sizeof(s->padconfs));
+    for (i = 0; i < sizeof(s->general)/sizeof(uint32); i++)
+        s->general[i] = qemu_get_be32(f);
+    qemu_get_buffer(f, s->mem_wkup, sizeof(s->mem_wkup));
+    qemu_get_buffer(f, s->padconfs_wkup, sizeof(s->padconfs_wkup));
+    for (i = 0; i < sizeof(s->general_wkup)/sizeof(uint32); i++)
+        s->general_wkup[i] = qemu_get_be32(f);
+
+    return 0;
+}
+
 #define PADCONFS_VALUE(wakeup0,wakeup1,offmode0,offmode1, \
                                                inputenable0,inputenable1,pupd0,pupd1,muxmode0,muxmode1,offset) \
        do { \
@@ -3494,7 +3740,7 @@ struct omap3_scm_s
 
 static void omap3_scm_reset(struct omap3_scm_s *s)
 {
-        uint32 * padconfs;
+    uint32 * padconfs;
     padconfs = (uint32 *)(s->padconfs);
     PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x0);
     PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x4);
@@ -3639,44 +3885,46 @@ static void omap3_scm_reset(struct omap3_scm_s *s)
     PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x230);
     PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x234);
 
-
        padconfs = (uint32 *)(s->general);
-       s->general[1] = 0x4000000;  /*0x4800 2274*/
-       s->general[0x1c] = 0x1;  /*0x4800 22e0*/
-       s->general[0x75] = 0x7fc0;  /*0x4800 2444*/
-       s->general[0x76] = 0xaa;  /*0x4800 2448*/
-       s->general[0x7c] = 0x2700;  /*0x4800 2460*/
-       s->general[0x7d] = 0x300000;  /*0x4800 2464*/
-       s->general[0x7e] = 0x300000;  /*0x4800 2468*/
-       s->general[0x81] = 0xffff;  /*0x4800 2474*/
-       s->general[0x82] = 0xffff;  /*0x4800 2478*/
-       s->general[0x83] = 0xffff;  /*0x4800 247c*/
-       s->general[0x84] = 0x6;  /*0x4800 2480*/
-       s->general[0x85] = 0xffffffff;  /*0x4800 2484*/
-       s->general[0x86] = 0xffff;  /*0x4800 2488*/
-       s->general[0x87] = 0xffff;  /*0x4800 248c*/
-       s->general[0x88] = 0x1;  /*0x4800 2490*/
-       s->general[0x8b] = 0xffffffff;  /*0x4800 249c*/
-       s->general[0x8c] = 0xffff;  /*0x4800 24a0*/
-       s->general[0x8e] = 0xffff;  /*0x4800 24a8*/
-       s->general[0x8f] = 0xffff;  /*0x4800 24ac*/
-       s->general[0x91] = 0xffff;  /*0x4800 24b4*/
-       s->general[0x92] = 0xffff;  /*0x4800 24b8*/
-       s->general[0xac] = 0x109;  /*0x4800 2520*/
-       s->general[0xb2] = 0xffff;  /*0x4800 2538*/
-       s->general[0xb3] = 0xffff;  /*0x4800 253c*/
-       s->general[0xb4] = 0xffff;  /*0x4800 2540*/
-       PADCONFS_VALUE(0,0,0,0,1,1,3,3,4,4,0x368);
-    PADCONFS_VALUE(0,0,0,0,1,1,3,3,4,4,0x36c);
-    PADCONFS_VALUE(0,0,0,0,1,1,3,3,4,4,0x370);
-    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x374);
-    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x378);
-    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x37c);
-    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x380);
-    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x384);
-    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x388);
-
-    
+    memset(s->general, 0, sizeof(s->general));
+       s->general[0x01] = 0x4000000;  /* CONTROL_DEVCONF_0 */
+       s->general[0x1c] = 0x1;        /* 0x480022e0?? */
+    s->general[0x20] = 0x30f;      /* CONTROL_STATUS:
+                                    * - 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 */
+       s->general[0x7d] = 0x300000;   /* CONTROL_SDRC_MCFG0 */
+       s->general[0x7e] = 0x300000;   /* CONTROL_SDRC_MCFG1 */
+       s->general[0x81] = 0xffff;     /* CONTROL_MODEM_GPMC_DT_FW_REQ_INFO */
+       s->general[0x82] = 0xffff;     /* CONTROL_MODEM_GPMC_DT_FW_RD */
+       s->general[0x83] = 0xffff;     /* CONTROL_MODEM_GPMC_DT_FW_WR */
+       s->general[0x84] = 0x6;        /* CONTROL_MODEM_GPMC_BOOT_CODE */
+       s->general[0x85] = 0xffffffff; /* CONTROL_MODEM_SMS_RG_ATT1 */
+       s->general[0x86] = 0xffff;     /* CONTROL_MODEM_SMS_RG_RDPERM1 */
+       s->general[0x87] = 0xffff;     /* CONTROL_MODEM_SMS_RG_WRPERM1 */
+       s->general[0x88] = 0x1;        /* CONTROL_MODEM_D2D_FW_DEBUG_MODE */
+       s->general[0x8b] = 0xffffffff; /* CONTROL_DPF_OCM_RAM_FW_REQINFO */
+       s->general[0x8c] = 0xffff;     /* CONTROL_DPF_OCM_RAM_FW_WR */
+       s->general[0x8e] = 0xffff;     /* CONTROL_DPF_REGION4_GPMC_FW_REQINFO */
+       s->general[0x8f] = 0xffff;     /* CONTROL_DPF_REGION4_GPMC_FW_WR */
+       s->general[0x91] = 0xffff;     /* CONTROL_DPF_REGION1_IVA2_FW_REQINFO */
+       s->general[0x92] = 0xffff;     /* CONTROL_DPF_REGION1_IVA2_FW_WR */
+       s->general[0xac] = 0x109;      /* CONTROL_PBIAS_LITE */
+       s->general[0xb2] = 0xffff;     /* CONTROL_DPF_MAD2D_FW_ADDR_MATCH */
+       s->general[0xb3] = 0xffff;     /* CONTROL_DPF_MAD2D_FW_REQINFO */
+       s->general[0xb4] = 0xffff;     /* CONTROL_DPF_MAD2D_FW_WR */
+       PADCONFS_VALUE(0,0,0,0,1,1,3,3,4,4,0x368); /* PADCONF_ETK_CLK */
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,4,4,0x36c); /* PADCONF_ETK_D0 */
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,4,4,0x370); /* PADCONF_ETK_D2 */
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x374); /* PADCONF_ETK_D4 */
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x378); /* PADCONF_ETK_D6 */
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x37c); /* PADCONF_ETK_D8 */
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x380); /* PADCONF_ETK_D10 */
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x384); /* PADCONF_ETK_D12 */
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x388); /* PADCONF_ETK_D14 */
 
        padconfs = (uint32 *)(s->padconfs_wkup);
        PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x0);
@@ -3691,9 +3939,7 @@ static void omap3_scm_reset(struct omap3_scm_s *s)
        PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x24);
        PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x2c);
 
-
-       s->general_wkup[0] = 0x66ff; /*0x4800 2A60*/
-           
+       s->general_wkup[0] = 0x66ff; /* 0x48002A60?? */
 }
 
 static uint32_t omap3_scm_read8(void *opaque, target_phys_addr_t addr)
@@ -3702,24 +3948,15 @@ static uint32_t omap3_scm_read8(void *opaque, target_phys_addr_t addr)
     uint8_t* temp;
        
     switch (addr) {
-    case 0x00 ... 0x2f:
-        return s->interface[addr];
-    case 0x30 ... 0x26f:
-        return s->padconfs[addr-0x30];
-    case 0x270 ... 0x5ff:
-        temp = (uint8_t *)s->general;
-        return temp[addr-0x270];
-    case 0x600 ... 0x9ff:
-        return s->mem_wkup[addr-0x600];
-    case 0xa00 ... 0xa5f:
-        return s->padconfs_wkup[addr-0xa00];
-    case 0xa60 ... 0xa7f:
-        temp = (uint8_t *)s->general_wkup;
-        return temp[addr-0xa60];
-    default:
-        break;
+        case 0x000 ... 0x02f: return s->interface[addr];
+        case 0x030 ... 0x26f: return s->padconfs[addr - 0x30];
+        case 0x270 ... 0x5ff: temp = (uint8_t *)s->general; return temp[addr - 0x270];
+        case 0x600 ... 0x9ff: return s->mem_wkup[addr - 0x600];
+        case 0xa00 ... 0xa5f: return s->padconfs_wkup[addr - 0xa00];
+        case 0xa60 ... 0xa7f: temp = (uint8_t *)s->general_wkup; return temp[addr - 0xa60];
+        default: break;
     }
-    printf("omap3_scm_read8 addr %x pc %x  \n", addr,cpu_single_env->regs[15] );
+    OMAP_BAD_REG(addr);
     return 0;
 }
 
@@ -3747,34 +3984,14 @@ static void omap3_scm_write8(void *opaque, target_phys_addr_t addr,
     struct omap3_scm_s *s = (struct omap3_scm_s *) opaque;
     uint8_t* temp;
 
-    switch (addr)
-    {
-    case 0x00 ... 0x2f:
-        s->interface[addr] = value;
-        break;
-    case 0x30 ... 0x26f:
-        s->padconfs[addr-0x30] = value;
-        break;
-    case 0x270 ... 0x5ff:
-        temp = (uint8_t *)s->general;
-        temp[addr-0x270] = value;
-        break;
-    case 0x600 ... 0x9ff:
-        s->mem_wkup[addr-0x600] = value;
-        break;
-    case 0xa00 ... 0xa5f:
-        s->padconfs_wkup[addr-0xa00] = value;
-        break;
-    case 0xa60 ... 0xa7f:
-        temp = (uint8_t *)s->general_wkup;
-        temp[addr-0xa60] = value;
-        break;
-    default:
-        /*we do not care scm write*/
-        printf("omap3_scm_write8 addr %x pc %x \n \n", addr,
-               cpu_single_env->regs[15] - 0x80008000 + 0x80e80000);
-        exit(1);
-        //break;
+    switch (addr) {
+        case 0x000 ... 0x02f: s->interface[addr] = value; break;
+        case 0x030 ... 0x26f: s->padconfs[addr-0x30] = value; break;
+        case 0x270 ... 0x5ff: temp = (uint8_t *)s->general; temp[addr-0x270] = value; break;
+        case 0x600 ... 0x9ff: s->mem_wkup[addr-0x600] = value; break;
+        case 0xa00 ... 0xa5f: s->padconfs_wkup[addr-0xa00] = value; break;
+        case 0xa60 ... 0xa7f: temp = (uint8_t *)s->general_wkup; temp[addr-0xa60] = value; break;
+        default: OMAP_BAD_REGV(addr, value); break;
     }
 }
 
@@ -3820,6 +4037,8 @@ static struct omap3_scm_s *omap3_scm_init(struct omap_target_agent_s *ta,
                                       omap3_scm_writefn, s);
     omap_l4_attach(ta, 0, iomemtype);
     
+    register_savevm("omap3_scm", -1, 0,
+                    omap3_scm_save_state, omap3_scm_load_state, s);
     return s;
 }
 
@@ -3849,6 +4068,79 @@ struct omap3_sms_s
     uint32 sms_rot_physical_ba[12];
 };
 
+static void omap3_sms_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_sms_s *s = (struct omap3_sms_s *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->sms_sysconfig);
+    qemu_put_be32(f, s->sms_sysstatus);
+    for (i = 0; i < 8; i++) {
+        qemu_put_be32(f, s->sms_rg_att[i]);
+        qemu_put_be32(f, s->sms_rg_rdperm[i]);
+        qemu_put_be32(f, s->sms_rg_wrperm[i]);
+        if (i < 7) {
+            qemu_put_be32(f, s->sms_rg_start[i]);
+            qemu_put_be32(f, s->sms_rg_end[i]);
+        }
+    }
+    qemu_put_be32(f, s->sms_security_control);
+    qemu_put_be32(f, s->sms_class_arbiter0);
+    qemu_put_be32(f, s->sms_class_arbiter1);
+    qemu_put_be32(f, s->sms_class_arbiter2);
+    qemu_put_be32(f, s->sms_interclass_arbiter);
+    qemu_put_be32(f, s->sms_class_rotation[0]);
+    qemu_put_be32(f, s->sms_class_rotation[1]);
+    qemu_put_be32(f, s->sms_class_rotation[2]);
+    qemu_put_be32(f, s->sms_err_addr);
+    qemu_put_be32(f, s->sms_err_type);
+    qemu_put_be32(f, s->sms_pow_ctrl);
+    for (i = 0; i< 12; i++) {
+        qemu_put_be32(f, s->sms_rot_control[i]);
+        qemu_put_be32(f, s->sms_rot_size[i]);
+        qemu_put_be32(f, s->sms_rot_physical_ba[i]);
+    }
+}
+
+static int omap3_sms_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap3_sms_s *s = (struct omap3_sms_s *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->sms_sysconfig = qemu_get_be32(f);
+    s->sms_sysstatus = qemu_get_be32(f);
+    for (i = 0; i < 8; i++) {
+        s->sms_rg_att[i] = qemu_get_be32(f);
+        s->sms_rg_rdperm[i] = qemu_get_be32(f);
+        s->sms_rg_wrperm[i] = qemu_get_be32(f);
+        if (i < 7) {
+            s->sms_rg_start[i] = qemu_get_be32(f);
+            s->sms_rg_end[i] = qemu_get_be32(f);
+        }
+    }
+    s->sms_security_control = qemu_get_be32(f);
+    s->sms_class_arbiter0 = qemu_get_be32(f);
+    s->sms_class_arbiter1 = qemu_get_be32(f);
+    s->sms_class_arbiter2 = qemu_get_be32(f);
+    s->sms_interclass_arbiter = qemu_get_be32(f);
+    s->sms_class_rotation[0] = qemu_get_be32(f);
+    s->sms_class_rotation[1] = qemu_get_be32(f);
+    s->sms_class_rotation[2] = qemu_get_be32(f);
+    s->sms_err_addr = qemu_get_be32(f);
+    s->sms_err_type = qemu_get_be32(f);
+    s->sms_pow_ctrl = qemu_get_be32(f);
+    for (i = 0; i< 12; i++) {
+        s->sms_rot_control[i] = qemu_get_be32(f);
+        s->sms_rot_size[i] = qemu_get_be32(f);
+        s->sms_rot_physical_ba[i] = qemu_get_be32(f);
+    }
+    
+    return 0;
+}
+
 static uint32_t omap3_sms_read32(void *opaque, target_phys_addr_t addr)
 {
     struct omap3_sms_s *s = (struct omap3_sms_s *) opaque;
@@ -3964,9 +4256,10 @@ static uint32_t omap3_sms_read32(void *opaque, target_phys_addr_t addr)
                return s->sms_rot_size[(addr-0x188)/0x10];
 
     default:
-        printf("omap3_sms_read32 addr %x \n", addr);
-        exit(-1);
+        break;
     }
+    OMAP_BAD_REG(addr);
+    return 0;
 }
 
 static void omap3_sms_write32(void *opaque, target_phys_addr_t addr,
@@ -4104,8 +4397,8 @@ static void omap3_sms_write32(void *opaque, target_phys_addr_t addr,
                s->sms_rot_size[(addr-0x188)/0x10] = value;   
                break;
        default:
-        printf("omap3_sms_write32 addr %x\n", addr);
-        exit(-1);
+        OMAP_BAD_REGV(addr, value);
+        break;
     }
 }
 
@@ -4147,14 +4440,16 @@ static struct omap3_sms_s *omap3_sms_init(struct omap_mpu_state_s *mpu)
                                        omap3_sms_writefn, s);
     cpu_register_physical_memory(0x6c000000, 0x10000, iomemtype);
 
+    register_savevm("omap3_sms", -1, 0,
+                    omap3_sms_save_state, omap3_sms_load_state, s);
     return s;
 }
 
 static const struct dma_irq_map omap3_dma_irq_map[] = {
-    {0, OMAP_INT_35XX_SDMA_IRQ0},
-    {0, OMAP_INT_35XX_SDMA_IRQ1},
-    {0, OMAP_INT_35XX_SDMA_IRQ2},
-    {0, OMAP_INT_35XX_SDMA_IRQ3},
+    {0, OMAP_INT_3XXX_SDMA_IRQ0},
+    {0, OMAP_INT_3XXX_SDMA_IRQ1},
+    {0, OMAP_INT_3XXX_SDMA_IRQ2},
+    {0, OMAP_INT_3XXX_SDMA_IRQ3},
 };
 
 static int omap3_validate_addr(struct omap_mpu_state_s *s,
@@ -4163,52 +4458,17 @@ static int omap3_validate_addr(struct omap_mpu_state_s *s,
     return 1;
 }
 
-/*
-  set the kind of memory connected to GPMC that we are trying to boot form.
-  Uses SYS BOOT settings.
-*/
-void omap3_set_mem_type(struct omap_mpu_state_s *s,int bootfrom)
-{
-    s->omap3_scm->general[32] &= ~0x3f;
-       switch (bootfrom) {
-               case 0x0: /*GPMC_NOR*/
-                       s->omap3_scm->general[32] |= 7;
-                       break;
-               case 0x1: /*GPMC_NAND*/
-                       s->omap3_scm->general[32] |= 1;
-                       break;
-               case 0x2:
-                       s->omap3_scm->general[32] |= 8;
-                       break;
-               case 0x3:
-                       s->omap3_scm->general[32] |= 0;
-                       break;
-               case 0x4:
-                       s->omap3_scm->general[32] |= 17;
-                       break;
-               case 0x5:
-                       s->omap3_scm->general[32] |= 3;
-                       break;
-       }
-}
-
-void omap3_set_device_type(struct omap_mpu_state_s *s,int device_type)
-{
-    s->omap3_scm->general[32] &= ~(0x7 << 8);
-       s->omap3_scm->general[32] |= (device_type & 0x7) << 8;
-}
-
 struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
-                                           const char *core)
+                                           CharDriverState *chr_uart1,
+                                           CharDriverState *chr_uart2,
+                                           CharDriverState *chr_uart3)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
         qemu_mallocz(sizeof(struct omap_mpu_state_s));
     ram_addr_t sram_base, q2_base;
     qemu_irq *cpu_irq;
-    qemu_irq dma_irqs[4];
+    qemu_irq drqs[4];
     int i;
-    int sdindex;
-    //omap_clk gpio_clks[4];
 
     s->mpu_model = omap3530;
     s->env = cpu_init("cortex-a8-r2");
@@ -4217,25 +4477,18 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
         exit(1);
     }
     s->sdram_size = sdram_size;
-    s->sram_size = OMAP3530_SRAM_SIZE;
-
-    sdindex = drive_get_index(IF_SD, 0, 0);
-    if (sdindex == -1) {
-        fprintf(stderr, "qemu: missing SecureDigital device\n");
-        exit(1);
-    }
+    s->sram_size = OMAP3XXX_SRAM_SIZE;
 
     /* Clocks */
     omap_clk_init(s);
 
     /* Memory-mapped stuff */
-
     q2_base = qemu_ram_alloc(s->sdram_size);
     cpu_register_physical_memory(OMAP3_Q2_BASE, s->sdram_size,
-                                 (q2_base | IO_MEM_RAM));
+                                 q2_base | IO_MEM_RAM);
     sram_base = qemu_ram_alloc(s->sram_size);
     cpu_register_physical_memory(OMAP3_SRAM_BASE, s->sram_size,
-                                 (sram_base | IO_MEM_RAM));
+                                 sram_base | IO_MEM_RAM);
 
     s->l4 = omap_l4_init(OMAP3_L4_BASE, 
                          sizeof(omap3_l4_agent_info) 
@@ -4249,15 +4502,11 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
                                omap_findclk(s, "omap3_mpu_intc_iclk"));
 
     for (i = 0; i < 4; i++)
-        dma_irqs[i] =
-            s->irq[omap3_dma_irq_map[i].ih][omap3_dma_irq_map[i].intr];
-    s->dma = omap_dma4_init(0x48056000, dma_irqs, s, 256, 32,
-                            omap_findclk(s, "omap3_sdma_fclk"),
-                            omap_findclk(s, "omap3_sdma_iclk"));
+        drqs[i] = s->irq[omap3_dma_irq_map[i].ih][omap3_dma_irq_map[i].intr];
+    s->dma = omap3_dma4_init(omap3_l4ta_init(s->l4, L4A_SDMA), s, drqs, 32,
+                             omap_findclk(s, "omap3_sdma_fclk"),
+                             omap_findclk(s, "omap3_sdma_iclk"));
     s->port->addr_valid = omap3_validate_addr;
-
-
-    /* Register SDRAM and SRAM ports for fast DMA transfers.  */
     soc_dma_port_add_mem_ram(s->dma, q2_base, OMAP2_Q2_BASE, s->sdram_size);
     soc_dma_port_add_mem_ram(s->dma, sram_base, OMAP2_SRAM_BASE, s->sram_size);
 
@@ -4265,7 +4514,7 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
     s->omap3_cm = omap3_cm_init(omap3_l4ta_init(s->l4, L4A_CM), NULL, NULL, NULL, s);
 
     s->omap3_prm = omap3_prm_init(omap3_l4ta_init(s->l4, L4A_PRM),
-                                  s->irq[0][OMAP_INT_35XX_PRCM_MPU_IRQ],
+                                  s->irq[0][OMAP_INT_3XXX_PRCM_MPU_IRQ],
                                   NULL, s);
 
     s->omap3_mpu_wdt = omap3_mpu_wdt_init(omap3_l4ta_init(s->l4, L4A_WDTIMER2),
@@ -4283,51 +4532,51 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
     s->omap3_sms = omap3_sms_init(s);
 
     s->gptimer[0] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER1),
-                                       s->irq[0][OMAP_INT_35XX_GPT1_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT1_IRQ],
                                        omap_findclk(s, "omap3_gp1_fclk"),
                                        omap_findclk(s, "omap3_wkup_l4_iclk"));
     s->gptimer[1] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER2),
-                                       s->irq[0][OMAP_INT_35XX_GPT2_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT2_IRQ],
                                        omap_findclk(s, "omap3_gp2_fclk"),
                                        omap_findclk(s, "omap3_per_l4_iclk"));
     s->gptimer[2] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER3),
-                                       s->irq[0][OMAP_INT_35XX_GPT3_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT3_IRQ],
                                        omap_findclk(s, "omap3_gp3_fclk"),
                                        omap_findclk(s, "omap3_per_l4_iclk"));
     s->gptimer[3] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER4),
-                                       s->irq[0][OMAP_INT_35XX_GPT4_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT4_IRQ],
                                        omap_findclk(s, "omap3_gp4_fclk"),
                                        omap_findclk(s, "omap3_per_l4_iclk"));
     s->gptimer[4] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER5),
-                                       s->irq[0][OMAP_INT_35XX_GPT5_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT5_IRQ],
                                        omap_findclk(s, "omap3_gp5_fclk"),
                                        omap_findclk(s, "omap3_per_l4_iclk"));
     s->gptimer[5] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER6),
-                                       s->irq[0][OMAP_INT_35XX_GPT6_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT6_IRQ],
                                        omap_findclk(s, "omap3_gp6_fclk"),
                                        omap_findclk(s, "omap3_per_l4_iclk"));
     s->gptimer[6] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER7),
-                                       s->irq[0][OMAP_INT_35XX_GPT7_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT7_IRQ],
                                        omap_findclk(s, "omap3_gp7_fclk"),
                                        omap_findclk(s, "omap3_per_l4_iclk"));
     s->gptimer[7] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER8),
-                                       s->irq[0][OMAP_INT_35XX_GPT8_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT8_IRQ],
                                        omap_findclk(s, "omap3_gp8_fclk"),
                                        omap_findclk(s, "omap3_per_l4_iclk"));
     s->gptimer[8] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER9),
-                                       s->irq[0][OMAP_INT_35XX_GPT9_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT9_IRQ],
                                        omap_findclk(s, "omap3_gp9_fclk"),
                                        omap_findclk(s, "omap3_per_l4_iclk"));
     s->gptimer[9] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER10),
-                                       s->irq[0][OMAP_INT_35XX_GPT10_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT10_IRQ],
                                        omap_findclk(s, "omap3_gp10_fclk"),
                                        omap_findclk(s, "omap3_core_l4_iclk"));
     s->gptimer[10] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER11),
-                                       s->irq[0][OMAP_INT_35XX_GPT11_IRQ],
+                                       s->irq[0][OMAP_INT_3XXX_GPT11_IRQ],
                                        omap_findclk(s, "omap3_gp12_fclk"),
                                        omap_findclk(s, "omap3_core_l4_iclk"));
     s->gptimer[11] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER12),
-                                        s->irq[0][OMAP_INT_35XX_GPT12_IRQ],
+                                        s->irq[0][OMAP_INT_3XXX_GPT12_IRQ],
                                         omap_findclk(s, "omap3_gp12_fclk"),
                                         omap_findclk(s, "omap3_wkup_l4_iclk"));
     
@@ -4337,101 +4586,90 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
 
     s->sdrc = omap_sdrc_init(0x6d000000);
     
-    s->gpmc = omap_gpmc_init(s, 0x6e000000, s->irq[0][OMAP_INT_35XX_GPMC_IRQ]);
+    s->gpmc = omap_gpmc_init(s, 0x6e000000, s->irq[0][OMAP_INT_3XXX_GPMC_IRQ]);
     
 
     s->uart[0] = omap2_uart_init(omap3_l4ta_init(s->l4, L4A_UART1),
-                                 s->irq[0][OMAP_INT_35XX_UART1_IRQ],
+                                 s->irq[0][OMAP_INT_3XXX_UART1_IRQ],
                                  omap_findclk(s, "omap3_uart1_fclk"),
                                  omap_findclk(s, "omap3_uart1_iclk"),
-                                 s->drq[OMAP35XX_DMA_UART1_TX],
-                                 s->drq[OMAP35XX_DMA_UART1_RX], serial_hds[0]);
+                                 s->drq[OMAP3XXX_DMA_UART1_TX],
+                                 s->drq[OMAP3XXX_DMA_UART1_RX],
+                                 chr_uart1);
     s->uart[1] = omap2_uart_init(omap3_l4ta_init(s->l4, L4A_UART2),
-                                 s->irq[0][OMAP_INT_35XX_UART2_IRQ],
+                                 s->irq[0][OMAP_INT_3XXX_UART2_IRQ],
                                  omap_findclk(s, "omap3_uart2_fclk"),
                                  omap_findclk(s, "omap3_uart2_iclk"),
-                                 s->drq[OMAP35XX_DMA_UART2_TX],
-                                 s->drq[OMAP35XX_DMA_UART2_RX],
-                                 serial_hds[0] ? serial_hds[1] : 0);
+                                 s->drq[OMAP3XXX_DMA_UART2_TX],
+                                 s->drq[OMAP3XXX_DMA_UART2_RX],
+                                 chr_uart2);
     s->uart[2] = omap2_uart_init(omap3_l4ta_init(s->l4, L4A_UART3),
-                                 s->irq[0][OMAP_INT_35XX_UART3_IRQ],
+                                 s->irq[0][OMAP_INT_3XXX_UART3_IRQ],
                                  omap_findclk(s, "omap3_uart2_fclk"),
                                  omap_findclk(s, "omap3_uart3_iclk"),
-                                 s->drq[OMAP35XX_DMA_UART3_TX],
-                                 s->drq[OMAP35XX_DMA_UART3_RX],
-                                 serial_hds[0]
-                                 && serial_hds[1] ? serial_hds[2] : 0);
+                                 s->drq[OMAP3XXX_DMA_UART3_TX],
+                                 s->drq[OMAP3XXX_DMA_UART3_RX],
+                                 chr_uart3);
     
-    /*attach serial[0] to uart 2 for beagle board */
-    omap_uart_attach(s->uart[2], serial_hds[0]);
-
     s->dss = omap_dss_init(s, omap3_l4ta_init(s->l4, L4A_DSS), 
-                    s->irq[0][OMAP_INT_35XX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
+                    s->irq[0][OMAP_INT_3XXX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
                    NULL,NULL,NULL,NULL,NULL);
 
-    //gpio_clks[0] = NULL;
-    //gpio_clks[1] = NULL;
-    //gpio_clks[2] = NULL;
-    //gpio_clks[3] = NULL;
-
     s->gpif = omap3_gpif_init();
-    omap3_gpio_init(s, s->gpif ,omap3_l4ta_init(s->l4, L4A_GPIO1),
-                    &s->irq[0][OMAP_INT_35XX_GPIO1_MPU_IRQ], 
+    omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO1),
+                    s->irq[0][OMAP_INT_3XXX_GPIO1_MPU_IRQ], 
                     NULL,NULL,0);
-    omap3_gpio_init(s, s->gpif ,omap3_l4ta_init(s->l4, L4A_GPIO2),
-                    &s->irq[0][OMAP_INT_35XX_GPIO2_MPU_IRQ], 
+    omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO2),
+                    s->irq[0][OMAP_INT_3XXX_GPIO2_MPU_IRQ], 
                     NULL,NULL,1);
-    omap3_gpio_init(s, s->gpif ,omap3_l4ta_init(s->l4, L4A_GPIO3),
-                    &s->irq[0][OMAP_INT_35XX_GPIO3_MPU_IRQ], 
+    omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO3),
+                    s->irq[0][OMAP_INT_3XXX_GPIO3_MPU_IRQ], 
                     NULL,NULL,2);
-    omap3_gpio_init(s, s->gpif ,omap3_l4ta_init(s->l4, L4A_GPIO4),
-                    &s->irq[0][OMAP_INT_35XX_GPIO4_MPU_IRQ], 
+    omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO4),
+                    s->irq[0][OMAP_INT_3XXX_GPIO4_MPU_IRQ], 
                     NULL,NULL,3);
-    omap3_gpio_init(s, s->gpif ,omap3_l4ta_init(s->l4, L4A_GPIO5),
-                    &s->irq[0][OMAP_INT_35XX_GPIO5_MPU_IRQ], 
+    omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO5),
+                    s->irq[0][OMAP_INT_3XXX_GPIO5_MPU_IRQ], 
                     NULL,NULL,4);
-    omap3_gpio_init(s, s->gpif ,omap3_l4ta_init(s->l4, L4A_GPIO6),
-                    &s->irq[0][OMAP_INT_35XX_GPIO6_MPU_IRQ], 
+    omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO6),
+                    s->irq[0][OMAP_INT_3XXX_GPIO6_MPU_IRQ], 
                     NULL,NULL,5);
 
     omap_tap_init(omap3_l4ta_init(s->l4, L4A_TAP), s);
 
     s->omap3_mmc[0] = omap3_mmc_init(omap3_l4ta_init(s->l4, L4A_MMC1),
-                                     drives_table[sdindex].bdrv,
-                                     s->irq[0][OMAP_INT_35XX_MMC1_IRQ],
-                                     &s->drq[OMAP35XX_DMA_MMC1_TX],
+                                     s->irq[0][OMAP_INT_3XXX_MMC1_IRQ],
+                                     &s->drq[OMAP3XXX_DMA_MMC1_TX],
                                      omap_findclk(s, "omap3_mmc1_fclk"),
                                      omap_findclk(s, "omap3_mmc1_iclk"));
 
     s->omap3_mmc[1] = omap3_mmc_init(omap3_l4ta_init(s->l4, L4A_MMC2),
-                                     NULL,
-                                     s->irq[0][OMAP_INT_35XX_MMC2_IRQ],
-                                     &s->drq[OMAP35XX_DMA_MMC2_TX],
+                                     s->irq[0][OMAP_INT_3XXX_MMC2_IRQ],
+                                     &s->drq[OMAP3XXX_DMA_MMC2_TX],
                                      omap_findclk(s, "omap3_mmc2_fclk"),
                                      omap_findclk(s, "omap3_mmc2_iclk"));
 
     s->omap3_mmc[2] = omap3_mmc_init(omap3_l4ta_init(s->l4, L4A_MMC3),
-                                     NULL,
-                                     s->irq[0][OMAP_INT_35XX_MMC3_IRQ],
-                                     &s->drq[OMAP35XX_DMA_MMC3_TX],
+                                     s->irq[0][OMAP_INT_3XXX_MMC3_IRQ],
+                                     &s->drq[OMAP3XXX_DMA_MMC3_TX],
                                      omap_findclk(s, "omap3_mmc3_fclk"),
                                      omap_findclk(s, "omap3_mmc3_iclk"));
 
     s->i2c[0] = omap3_i2c_init(omap3_l4ta_init(s->l4, L4A_I2C1),
-                               s->irq[0][OMAP_INT_35XX_I2C1_IRQ],
-                               &s->drq[OMAP35XX_DMA_I2C1_TX],
+                               s->irq[0][OMAP_INT_3XXX_I2C1_IRQ],
+                               &s->drq[OMAP3XXX_DMA_I2C1_TX],
                                omap_findclk(s, "omap3_i2c1_fclk"),
                                omap_findclk(s, "omap3_i2c1_iclk"),
                                8);
     s->i2c[1] = omap3_i2c_init(omap3_l4ta_init(s->l4, L4A_I2C2),
-                               s->irq[0][OMAP_INT_35XX_I2C2_IRQ],
-                               &s->drq[OMAP35XX_DMA_I2C2_TX],
+                               s->irq[0][OMAP_INT_3XXX_I2C2_IRQ],
+                               &s->drq[OMAP3XXX_DMA_I2C2_TX],
                                omap_findclk(s, "omap3_i2c2_fclk"),
                                omap_findclk(s, "omap3_i2c2_iclk"),
                                8);
     s->i2c[2] = omap3_i2c_init(omap3_l4ta_init(s->l4, L4A_I2C3),
-                               s->irq[0][OMAP_INT_35XX_I2C3_IRQ],
-                               &s->drq[OMAP35XX_DMA_I2C3_TX],
+                               s->irq[0][OMAP_INT_3XXX_I2C3_IRQ],
+                               &s->drq[OMAP3XXX_DMA_I2C3_TX],
                                omap_findclk(s, "omap3_i2c3_fclk"),
                                omap_findclk(s, "omap3_i2c3_iclk"),
                                64);
@@ -4439,473 +4677,36 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
     s->omap3_usb = omap3_hsusb_init(omap3_l4ta_init(s->l4, L4A_USBHS_OTG),
                                     omap3_l4ta_init(s->l4, L4A_USBHS_HOST),
                                     omap3_l4ta_init(s->l4, L4A_USBHS_TLL),
-                                    s->irq[0][OMAP_INT_35XX_HSUSB_MC],
-                                    s->irq[0][OMAP_INT_35XX_HSUSB_DMA],
-                                    s->irq[0][OMAP_INT_35XX_OHCI_IRQ],
-                                    s->irq[0][OMAP_INT_35XX_EHCI_IRQ],
-                                    s->irq[0][OMAP_INT_35XX_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];
+                                    s->irq[0][OMAP_INT_3XXX_HSUSB_MC],
+                                    s->irq[0][OMAP_INT_3XXX_HSUSB_DMA],
+                                    s->irq[0][OMAP_INT_3XXX_OHCI_IRQ],
+                                    s->irq[0][OMAP_INT_3XXX_EHCI_IRQ],
+                                    s->irq[0][OMAP_INT_3XXX_TLL_IRQ]);
+
+    s->mcspi[0] = omap_mcspi_init(omap3_l4ta_init(s->l4, L4A_MCSPI1), s, 4,
+                                  s->irq[0][OMAP_INT_3XXX_MCSPI1_IRQ],
+                                  &s->drq[OMAP3XXX_DMA_SPI1_TX0],
+                                  omap_findclk(s, "omap3_spi1_fclk"),
+                                  omap_findclk(s, "omap3_spi1_iclk"));
+    s->mcspi[1] = omap_mcspi_init(omap3_l4ta_init(s->l4, L4A_MCSPI2), s, 2,
+                                  s->irq[0][OMAP_INT_3XXX_MCSPI2_IRQ],
+                                  &s->drq[OMAP3XXX_DMA_SPI2_TX0],
+                                  omap_findclk(s, "omap3_spi2_fclk"),
+                                  omap_findclk(s, "omap3_spi2_iclk"));
+    drqs[0] = s->drq[OMAP3XXX_DMA_SPI3_TX0];
+    drqs[1] = s->drq[OMAP3XXX_DMA_SPI3_RX0];
+    drqs[2] = s->drq[OMAP3XXX_DMA_SPI3_TX1];
+    drqs[3] = s->drq[OMAP3XXX_DMA_SPI3_RX1];
+    s->mcspi[2] = omap_mcspi_init(omap3_l4ta_init(s->l4, L4A_MCSPI3), s, 2,
+                                  s->irq[0][OMAP_INT_3XXX_MCSPI3_IRQ],
+                                  drqs,
+                                  omap_findclk(s, "omap3_spi3_fclk"),
+                                  omap_findclk(s, "omap3_spi3_iclk"));
+    s->mcspi[3] = omap_mcspi_init(omap3_l4ta_init(s->l4, L4A_MCSPI4), s, 1,
+                                  s->irq[0][OMAP_INT_3XXX_MCSPI4_IRQ],
+                                  &s->drq[OMAP3XXX_DMA_SPI4_TX0],
+                                  omap_findclk(s, "omap3_spi4_fclk"),
+                                  omap_findclk(s, "omap3_spi4_iclk"));
     
-    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 < 8)
-                break;
-            s->count = omap3_get_le32(data);
-            s->addr = omap3_get_le32(data + 4);
-            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);
-            free(boot);
-            result = 1;
-        } 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;
-    
-    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;
-                }
-            }
-        }
-        free(boot);
-    }
-    return 0;
-}
-
-/* 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;
-}
-