save/load vmstate support in omap3 hsusb host & clean-ups
[qemu] / hw / omap3.c
index 0160b0b..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;
@@ -577,6 +674,9 @@ static void omap3_l3pm_init(struct omap3_l3pm_s *s)
             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[] = {
@@ -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,10 +1438,17 @@ 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;
 }
 
@@ -1570,9 +1719,10 @@ 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)
@@ -1720,7 +1870,7 @@ static void omap3_prm_write(void *opaque, target_phys_addr_t addr,
         case 0x1264: s->gr.prm_sram_pcharge = value & 0xff; break;
         case 0x1270:
             s->gr.prm_clksrc_ctrl = value & 0xd8; /* set osc bypass mode */ 
-            omap3_prm_clksrc_ctrl_update(s, s->gr.prm_clksrc_ctrl);
+            omap3_prm_clksrc_ctrl_update(s);
             break;
         case 0x1280: OMAP_RO_REG(addr); break;
         case 0x1290: s->gr.prm_voltsetup1 = value; break;
@@ -1750,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,
@@ -1762,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));
@@ -1779,6 +2082,9 @@ 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;
 }
 
@@ -2249,6 +2555,14 @@ static inline void omap3_cm_iclken1_core_update(struct omap3_cm_s *s)
     s->cm_idlest1_core = ~v;
 }
 
+static inline void omap3_cm_l3l4iclk_update(struct omap3_cm_s *s)
+{
+    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)
 {
     s->cm_fclken_iva2 = 0x0;
@@ -2602,10 +2916,7 @@ static void omap3_cm_write(void *opaque,
         case 0xa40:
             s->cm_clksel_core = (value & 0xff) | 0x100;
             omap3_cm_gp10gp11_update(s);
-            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);
+            omap3_cm_l3l4iclk_update(s);
             break;
         case 0xa48:
             s->cm_clkstctrl_core = value & 0xf;
@@ -2728,11 +3039,266 @@ static void omap3_cm_write(void *opaque,
         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;
+        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;
+    
+    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);
+    
+    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,
@@ -2746,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));
@@ -2763,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;
 }
 
@@ -3037,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,
@@ -3057,8 +3679,9 @@ 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;
-
 }
 
 struct omap3_scm_s {
@@ -3072,6 +3695,41 @@ struct omap3_scm_s {
        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 { \
@@ -3379,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;
 }
 
@@ -3408,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;
@@ -3707,11 +4440,11 @@ 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;
 }
 
-#define OMAP3_BOOT_ROM_SIZE 0x1c000 /* 80 + 32 kB */
-
 static const struct dma_irq_map omap3_dma_irq_map[] = {
     {0, OMAP_INT_3XXX_SDMA_IRQ0},
     {0, OMAP_INT_3XXX_SDMA_IRQ1},
@@ -3726,13 +4459,15 @@ static int omap3_validate_addr(struct omap_mpu_state_s *s,
 }
 
 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, bootrom_base;
+    ram_addr_t sram_base, q2_base;
     qemu_irq *cpu_irq;
-    qemu_irq dma_irqs[4];
+    qemu_irq drqs[4];
     int i;
 
     s->mpu_model = omap3530;
@@ -3748,18 +4483,12 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
     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);
     sram_base = qemu_ram_alloc(s->sram_size);
     cpu_register_physical_memory(OMAP3_SRAM_BASE, s->sram_size,
                                  sram_base | IO_MEM_RAM);
-    bootrom_base = qemu_ram_alloc(OMAP3XXX_BOOTROM_SIZE);
-    cpu_register_physical_memory(OMAP3_Q1_BASE, OMAP3_BOOT_ROM_SIZE,
-                                 bootrom_base | IO_MEM_ROM);
-    cpu_register_physical_memory(0, OMAP3_BOOT_ROM_SIZE,
-                                 bootrom_base | IO_MEM_ROM);
 
     s->l4 = omap_l4_init(OMAP3_L4_BASE, 
                          sizeof(omap3_l4_agent_info) 
@@ -3773,14 +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);
 
@@ -3868,42 +4594,45 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
                                  omap_findclk(s, "omap3_uart1_fclk"),
                                  omap_findclk(s, "omap3_uart1_iclk"),
                                  s->drq[OMAP3XXX_DMA_UART1_TX],
-                                 s->drq[OMAP3XXX_DMA_UART1_RX], 0);
+                                 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_3XXX_UART2_IRQ],
                                  omap_findclk(s, "omap3_uart2_fclk"),
                                  omap_findclk(s, "omap3_uart2_iclk"),
                                  s->drq[OMAP3XXX_DMA_UART2_TX],
-                                 s->drq[OMAP3XXX_DMA_UART2_RX], 0);
+                                 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_3XXX_UART3_IRQ],
                                  omap_findclk(s, "omap3_uart2_fclk"),
                                  omap_findclk(s, "omap3_uart3_iclk"),
                                  s->drq[OMAP3XXX_DMA_UART3_TX],
-                                 s->drq[OMAP3XXX_DMA_UART3_RX], 0);
+                                 s->drq[OMAP3XXX_DMA_UART3_RX],
+                                 chr_uart3);
     
     s->dss = omap_dss_init(s, omap3_l4ta_init(s->l4, L4A_DSS), 
                     s->irq[0][OMAP_INT_3XXX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
                    NULL,NULL,NULL,NULL,NULL);
 
     s->gpif = omap3_gpif_init();
-    omap3_gpio_init(s, s->gpif ,omap3_l4ta_init(s->l4, L4A_GPIO1),
-                    &s->irq[0][OMAP_INT_3XXX_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_3XXX_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_3XXX_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_3XXX_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_3XXX_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_3XXX_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);
@@ -3953,5 +4682,31 @@ struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
                                     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"));
+    
     return s;
 }