Merge commit 'origin/upstream' into juha-devel
authorJuha Riihimäki <juhriihi@esdhcp035153.research.nokia.com>
Thu, 2 Apr 2009 09:11:11 +0000 (12:11 +0300)
committerJuha Riihimäki <juhriihi@esdhcp035153.research.nokia.com>
Thu, 2 Apr 2009 09:11:11 +0000 (12:11 +0300)
85 files changed:
Makefile
Makefile.target
audio/coreaudio.c
block-vmstate.c [new file with mode: 0644]
block.c
block.h
cocoa.m
configure
cpu-all.h
debian/README.Debian [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/cputransp-methods [new file with mode: 0644]
debian/overrides/qemu [new file with mode: 0644]
debian/qemu-user.1 [new file with mode: 0644]
debian/qemu.dirs [new file with mode: 0644]
debian/qemu.doc-base [new file with mode: 0644]
debian/qemu.docs [new file with mode: 0644]
debian/qemu.install [new file with mode: 0644]
debian/qemu.links [new file with mode: 0644]
debian/qemu.manpages [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/tundev.c [new file with mode: 0644]
debian/watch [new file with mode: 0644]
elf.h
exec.c
hw/beagle.c [new file with mode: 0644]
hw/boards.h
hw/devices.h
hw/flash.h
hw/gumstix.c
hw/i2c.h
hw/integratorcp.c
hw/mainstone.c
hw/nand.c
hw/nseries.c
hw/omap.h
hw/omap1.c
hw/omap2.c
hw/omap3.c [new file with mode: 0644]
hw/omap3_boot.c [new file with mode: 0644]
hw/omap3_lcd_panel_template.h [new file with mode: 0644]
hw/omap3_mmc.c [new file with mode: 0644]
hw/omap3_usb.c [new file with mode: 0644]
hw/omap_clk.c
hw/omap_dma.c
hw/omap_dss.c
hw/omap_i2c.c
hw/omap_spi.c [new file with mode: 0644]
hw/onenand.c
hw/realview.c
hw/sd.c
hw/smc91c111.c
hw/soc_dma.c
hw/soc_dma.h
hw/tsc2005.c
hw/tusb6010.c
hw/twl4030.c [new file with mode: 0644]
hw/usb-hid.c
hw/usb-hub.c
hw/usb-musb.c
hw/usb-ohci.c
hw/versatilepb.c
linux-user/elfload.c
linux-user/i386/syscall.h
linux-user/linuxload.c
linux-user/main.c
linux-user/mmap.c
linux-user/path.c
linux-user/qemu.h
linux-user/signal.c
linux-user/strace.c
linux-user/strace.list
linux-user/syscall.c
linux-user/syscall_defs.h
linux-user/x86_64/syscall.h
target-arm/cpu.h
target-arm/helper.c
target-arm/machine.c
target-arm/op_helper.c
target-arm/translate.c
tcg/i386/tcg-target.c
tcg/x86_64/tcg-target.c

index 2bee52c..ce78d78 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -52,7 +52,7 @@ recurse-all: $(SUBDIR_RULES)
 BLOCK_OBJS=cutils.o qemu-malloc.o
 BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
 BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
-BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o
+BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o block-vmstate.o
 BLOCK_OBJS+=nbd.o block.o aio.o
 
 ifdef CONFIG_WIN32
@@ -211,7 +211,7 @@ qemu-img$(EXESUF) qemu-nbd$(EXESUF): LIBS += -lz
 clean:
 # avoid old build problems by removing potentially incorrect old files
        rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
-       rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
+       rm -f *.o *.d *.a $(TOOLS) tags TAGS cscope.* *.pod *~ */*~
        rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d
        $(MAKE) -C tests clean
        for d in $(TARGET_DIRS); do \
@@ -275,6 +275,8 @@ test speed: all
 
 TAGS:
        etags *.[ch] tests/*.[ch]
+tags:
+       find . -name "*.[ch]" -print | xargs ctags
 
 cscope:
        rm -f ./cscope.*
index 046427d..35250b7 100644 (file)
@@ -235,8 +235,10 @@ endif
 VPATH+=:$(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
 CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
 
+#sbox hack
 ifdef CONFIG_STATIC
-LDFLAGS+=-static
+LDFLAGS+=-static -L/scratchbox/tools/lib
+LIBS+=-lsb -ldl
 endif
 
 ifeq ($(ARCH),i386)
@@ -666,7 +668,8 @@ OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
 OBJS+= pflash_cfi01.o gumstix.o
 OBJS+= zaurus.o ide.o serial.o nand.o ecc.o spitz.o tosa.o tc6393xb.o
 OBJS+= omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
-OBJS+= omap2.o omap_dss.o soc_dma.o
+OBJS+= omap2.o omap_dss.o soc_dma.o omap_spi.o
+OBJS+= omap3.o omap3_boot.o omap3_mmc.o omap3_usb.o beagle.o twl4030.o
 OBJS+= omap_sx1.o palm.o tsc210x.o
 OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
 OBJS+= tsc2005.o bt-hci-csr.o
index 9671429..c865775 100644 (file)
@@ -47,6 +47,9 @@ typedef struct coreaudioVoiceOut {
     pthread_mutex_t mutex;
     int isAtexit;
     AudioDeviceID outputDeviceID;
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
+    AudioDeviceIOProcID ioProcID;
+#endif
     UInt32 audioDevicePropertyBufferFrameSize;
     AudioStreamBasicDescription outputStreamBasicDescription;
     int live;
@@ -56,7 +59,7 @@ typedef struct coreaudioVoiceOut {
 
 static void coreaudio_logstatus (OSStatus status)
 {
-    char *str = "BUG";
+    const char *str = "BUG";
 
     switch(status) {
     case kAudioHardwareNoError:
@@ -104,7 +107,7 @@ static void coreaudio_logstatus (OSStatus status)
         break;
 
     default:
-        AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
+        AUD_log (AUDIO_CAP, "Reason: status code %d\n", status);
         return;
     }
 
@@ -362,7 +365,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
         &core->audioDevicePropertyBufferFrameSize);
     if (status != kAudioHardwareNoError) {
         coreaudio_logerr2 (status, typ,
-                           "Could not set device buffer frame size %ld\n",
+                           "Could not set device buffer frame size %d\n",
                            core->audioDevicePropertyBufferFrameSize);
         return -1;
     }
@@ -418,7 +421,14 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
     }
 
     /* set Callback */
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
+    status = AudioDeviceCreateIOProcID(core->outputDeviceID,
+                                       audioDeviceIOProc,
+                                       hw,
+                                       &core->ioProcID);
+#else
     status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
+#endif
     if (status != kAudioHardwareNoError) {
         coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
         core->outputDeviceID = kAudioDeviceUnknown;
@@ -430,7 +440,11 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
         status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
         if (status != kAudioHardwareNoError) {
             coreaudio_logerr2 (status, typ, "Could not start playback\n");
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
+            AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioProcID);
+#else
             AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
+#endif
             core->outputDeviceID = kAudioDeviceUnknown;
             return -1;
         }
@@ -455,8 +469,13 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
         }
 
         /* remove callback */
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
+        status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
+                                            core->ioProcID);
+#else
         status = AudioDeviceRemoveIOProc(core->outputDeviceID,
                                          audioDeviceIOProc);
+#endif
         if (status != kAudioHardwareNoError) {
             coreaudio_logerr (status, "Could not remove IOProc\n");
         }
diff --git a/block-vmstate.c b/block-vmstate.c
new file mode 100644 (file)
index 0000000..1852eff
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Block driver for vmstate format
+ *
+ * Copyright (c) 2009 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "block_int.h"
+
+#define VMSTATE_MAGIC 0x564D53544154451ALL
+#define VMSTATE_VERSION 1
+
+typedef struct VMStateHeader {
+    uint64_t magic;
+    uint32_t version;
+    uint64_t state_offset;
+    uint64_t state_size;
+} VMStateHeader;
+
+typedef struct BDRVVmState {
+    int fd;
+    uint64_t state_offset;
+    uint64_t state_size;
+    uint64_t write_offset;
+} BDRVVMState;
+
+static int vmstate_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const VMStateHeader *header = (const VMStateHeader *)buf;
+    if (buf_size >= sizeof(VMStateHeader) &&
+        be64_to_cpu(header->magic) == VMSTATE_MAGIC &&
+        be32_to_cpu(header->version) == VMSTATE_VERSION)
+        return 100;
+    return 0;
+}
+
+static int vmstate_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVVMState *s = bs->opaque;
+    VMStateHeader header;
+    
+    s->fd = open(filename, O_RDWR | O_BINARY);
+    if (s->fd < 0)
+        return -errno;
+    if (read(s->fd, &header, sizeof(header)) == sizeof(header) &&
+        be64_to_cpu(header.magic) == VMSTATE_MAGIC &&
+        be32_to_cpu(header.version) == VMSTATE_VERSION) {
+        s->state_offset = be64_to_cpu(header.state_offset);
+        s->state_size = be64_to_cpu(header.state_size);
+        
+        s->write_offset = s->state_offset;
+        return 0;
+    }
+    close(s->fd);
+    return -EIO;
+}
+
+static void vmstate_flush(BlockDriverState *bs)
+{
+}
+
+static void vmstate_close(BlockDriverState *bs)
+{
+    BDRVVMState *s = bs->opaque;
+    
+    vmstate_flush(bs);
+    close(s->fd);
+}
+
+static int vmstate_create(const char *filename, int64_t total_size,
+                          const char *backing_file, int flags)
+{
+    VMStateHeader header;
+    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (fd < 0)
+        return -EIO;
+    memset(&header, 0, sizeof(header));
+    header.magic = cpu_to_be64(VMSTATE_MAGIC);
+    header.version = cpu_to_be32(VMSTATE_VERSION);
+    header.state_offset = cpu_to_be64(sizeof(header));
+    write(fd, &header, sizeof(header));
+    close(fd);
+    return 0;
+}
+
+static int vmstate_refresh_header(BDRVVMState *s)
+{
+    VMStateHeader header;
+    
+    if (!lseek(s->fd, 0, SEEK_SET) &&
+        read(s->fd, &header, sizeof(header)) == sizeof(header)) {
+        header.state_size = cpu_to_be64(s->state_size);
+        if (!lseek(s->fd, 0, SEEK_SET) &&
+            write(s->fd, &header, sizeof(header)) == sizeof(header))
+            return 0;
+    }
+    return -EIO;
+}
+
+static int vmstate_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVVMState *s = bs->opaque;
+    
+    bdi->cluster_size = 0;//VMSTATE_BLOCK_SIZE;
+    bdi->vm_state_offset = s->state_offset;
+    return 0;
+}
+
+static int vmstate_read(BlockDriverState *bs, int64_t sector_num,
+                        uint8_t *buf, int nb_sectors)
+{
+    BDRVVMState *s = bs->opaque;
+    
+    if (lseek(s->fd, sector_num * 512, SEEK_SET) != sector_num * 512)
+        return -EIO;
+    return read(s->fd, buf, nb_sectors * 512);
+}
+
+static int vmstate_write(BlockDriverState *bs, int64_t sector_num,
+                         const uint8_t *buf, int nb_sectors)
+{
+    BDRVVMState *s = bs->opaque;
+    
+    if (lseek(s->fd, sector_num * 512, SEEK_SET) != sector_num * 512)
+        return -EIO;
+    return write(s->fd, buf, nb_sectors * 512);
+}
+
+static int vmstate_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
+{
+    BDRVVMState *s = bs->opaque;
+
+    return s->state_size ? 0 : -ENOENT;
+}
+
+static int vmstate_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+    BDRVVMState *s = bs->opaque;
+    
+    if (s->state_size) {
+        s->state_size = 0;
+        vmstate_refresh_header(s);
+        if (!lseek(s->fd, 0, SEEK_SET))
+            return ftruncate(s->fd, sizeof(VMStateHeader));
+    }
+    return -ENOENT;
+}
+
+static int vmstate_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+{
+    BDRVVMState *s = bs->opaque;
+    
+    if (s->state_size)
+        vmstate_snapshot_delete(bs, NULL);
+    s->state_size = sn_info->vm_state_size;
+    s->write_offset = s->state_offset;
+    return vmstate_refresh_header(s);
+}
+
+static int vmstate_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+{
+    BDRVVMState *s = bs->opaque;
+    QEMUSnapshotInfo *sn_info;
+    
+    sn_info = qemu_mallocz(sizeof(QEMUSnapshotInfo));
+    if (s->state_size) {
+        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), "vmstate");
+        pstrcpy(sn_info->name, sizeof(sn_info->name), "vmstate");
+        sn_info->vm_state_size = s->state_size;
+    }
+    *psn_tab = sn_info;
+    return s->state_size ? 1 : 0;
+}
+
+static int64_t vmstate_getlength(BlockDriverState *bs)
+{
+    return 1LL << 63; /* big enough? */
+}
+
+BlockDriver bdrv_vmstate = {
+    .format_name = "vmstate",
+    .instance_size = sizeof(BDRVVMState),
+    .bdrv_probe = vmstate_probe,
+    .bdrv_open = vmstate_open,
+    .bdrv_read = vmstate_read,
+    .bdrv_write = vmstate_write,
+    .bdrv_close = vmstate_close,
+    .bdrv_create = vmstate_create,
+    .bdrv_flush = vmstate_flush,
+    .bdrv_getlength = vmstate_getlength,
+    .bdrv_snapshot_create = vmstate_snapshot_create,
+    .bdrv_snapshot_goto = vmstate_snapshot_goto,
+    .bdrv_snapshot_delete = vmstate_snapshot_delete,
+    .bdrv_snapshot_list = vmstate_snapshot_list,
+    .bdrv_get_info = vmstate_get_info
+};
\ No newline at end of file
diff --git a/block.c b/block.c
index 4da3bcb..b70f28f 100644 (file)
--- a/block.c
+++ b/block.c
@@ -1519,6 +1519,7 @@ void bdrv_init(void)
     bdrv_register(&bdrv_qcow2);
     bdrv_register(&bdrv_parallels);
     bdrv_register(&bdrv_nbd);
+    bdrv_register(&bdrv_vmstate);
 }
 
 void aio_pool_init(AIOPool *pool, int aiocb_size,
diff --git a/block.h b/block.h
index 6701d34..6e443ad 100644 (file)
--- a/block.h
+++ b/block.h
@@ -20,6 +20,7 @@ extern BlockDriver bdrv_vvfat;
 extern BlockDriver bdrv_qcow2;
 extern BlockDriver bdrv_parallels;
 extern BlockDriver bdrv_nbd;
+extern BlockDriver bdrv_vmstate;
 
 typedef struct BlockDriverInfo {
     /* in bytes, 0 if irrelevant */
diff --git a/cocoa.m b/cocoa.m
index 55ff2b4..0662df3 100644 (file)
--- a/cocoa.m
+++ b/cocoa.m
@@ -58,6 +58,7 @@ int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
 NSWindow *normalWindow;
 id cocoaView;
 static DisplayChangeListener *dcl;
+static int last_vm_running;
 
 int gArgc;
 char **gArgv;
@@ -229,7 +230,7 @@ int keymap[] =
 */
 };
 
-int cocoa_keycode_to_qemu(int keycode)
+static int cocoa_keycode_to_qemu(int keycode)
 {
     if((sizeof(keymap)/sizeof(int)) <= keycode)
     {
@@ -269,6 +270,7 @@ int cocoa_keycode_to_qemu(int keycode)
 - (float) cdx;
 - (float) cdy;
 - (QEMUScreen) gscreen;
+- (void) updateCaption;
 @end
 
 @implementation QemuCocoaView
@@ -298,6 +300,11 @@ int cocoa_keycode_to_qemu(int keycode)
     [super dealloc];
 }
 
+- (BOOL) isOpaque
+{
+    return YES;
+}
+
 - (void) drawRect:(NSRect) rect
 {
     COCOA_DEBUG("QemuCocoaView: drawRect\n");
@@ -337,7 +344,7 @@ int cocoa_keycode_to_qemu(int keycode)
         } else {
             // selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
             const NSRect *rectList;
-            int rectCount;
+            NSInteger rectCount;
             int i;
             CGImageRef clipImageRef;
             CGRect clipRect;
@@ -401,10 +408,9 @@ int cocoa_keycode_to_qemu(int keycode)
         [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
         [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO];
     } else {
-        if (qemu_name)
-            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
-        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:YES];
+        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:NO];
     }
+    [self updateCaption];
     screen.width = w;
     screen.height = h;
        [normalWindow center];
@@ -568,12 +574,12 @@ int cocoa_keycode_to_qemu(int keycode)
             if (isAbsoluteEnabled) {
                 if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
                     if (isTabletEnabled) { // if we leave the window, deactivate the tablet
-                        [NSCursor unhide];
+                        if (cursor_hide) [NSCursor unhide];
                         isTabletEnabled = FALSE;
                     }
                 } else {
                     if (!isTabletEnabled) { // if we enter the window, activate the tablet
-                        [NSCursor hide];
+                        if (cursor_hide) [NSCursor hide];
                         isTabletEnabled = TRUE;
                     }
                 }
@@ -646,31 +652,34 @@ int cocoa_keycode_to_qemu(int keycode)
 - (void) grabMouse
 {
     COCOA_DEBUG("QemuCocoaView: grabMouse\n");
-
-    if (!isFullscreen) {
-        if (qemu_name)
-            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
-        else
-            [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
-    }
-    [NSCursor hide];
+    if (cursor_hide) [NSCursor hide];
     CGAssociateMouseAndMouseCursorPosition(FALSE);
     isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
+    [self updateCaption];
 }
 
 - (void) ungrabMouse
 {
     COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
 
-    if (!isFullscreen) {
-        if (qemu_name)
-            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
-        else
-            [normalWindow setTitle:@"QEMU"];
-    }
-    [NSCursor unhide];
+    if (cursor_hide) [NSCursor unhide];
     CGAssociateMouseAndMouseCursorPosition(TRUE);
     isMouseGrabed = FALSE;
+    [self updateCaption];
+}
+
+- (void) updateCaption
+{
+    //if (!isFullScreen)...
+    NSMutableString *caption = [NSMutableString stringWithCapacity:10];
+    [caption appendFormat:@"QEMU"];
+    if (qemu_name)
+        [caption appendFormat:@" (%s)", qemu_name];
+    if (!vm_running)
+        [caption appendString:@" [Stopped]"];
+    else if (isMouseGrabed)
+        [caption appendString:@" - Press Ctrl-Alt to release mouse"];
+    [normalWindow setTitle:caption];
 }
 
 - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
@@ -726,7 +735,7 @@ int cocoa_keycode_to_qemu(int keycode)
         [normalWindow setContentView:cocoaView];
         [normalWindow makeKeyAndOrderFront:self];
                [normalWindow center];
-
+        [cocoaView updateCaption];
     }
     return self;
 }
@@ -783,7 +792,7 @@ int cocoa_keycode_to_qemu(int keycode)
     if(returnCode == NSCancelButton) {
         exit(0);
     } else if(returnCode == NSOKButton) {
-        char *bin = "qemu";
+        const char *bin = "qemu";
         char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding];
 
         char **argv = (char**)malloc( sizeof(char*)*3 );
@@ -922,7 +931,7 @@ static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
             w * [cocoaView cdx],
             h * [cocoaView cdy]);
     }
-    [cocoaView displayRect:rect];
+    [cocoaView setNeedsDisplayInRect:rect];
 }
 
 static void cocoa_resize(DisplayState *ds)
@@ -936,6 +945,11 @@ static void cocoa_refresh(DisplayState *ds)
 {
     COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
 
+    if (last_vm_running != vm_running) {
+        last_vm_running = vm_running;
+        [cocoaView updateCaption];
+    }
+    
     if (kbd_mouse_is_absolute()) {
         if (![cocoaView isAbsoluteEnabled]) {
             if ([cocoaView isMouseGrabed]) {
index 5c62c59..63e7ad9 100755 (executable)
--- a/configure
+++ b/configure
@@ -176,6 +176,7 @@ softmmu="yes"
 linux_user="no"
 darwin_user="no"
 bsd_user="no"
+guest_base="no"
 build_docs="no"
 uname_release=""
 curses="yes"
@@ -437,6 +438,8 @@ for opt do
   ;;
   --enable-bsd-user) bsd_user="yes"
   ;;
+  --enable-guest-base) guest_base="yes"
+  ;;
   --enable-uname-release=*) uname_release="$optarg"
   ;;
   --sparc_cpu=*)
@@ -570,6 +573,8 @@ echo "  --enable-darwin-user     enable all darwin usermode emulation targets"
 echo "  --disable-darwin-user    disable all darwin usermode emulation targets"
 echo "  --enable-bsd-user        enable all BSD usermode emulation targets"
 echo "  --disable-bsd-user       disable all BSD usermode emulation targets"
+echo "  --enable-guest-base      enable GUEST_BASE support for usermode"
+echo "                           emulation targets"
 echo "  --fmod-lib               path to FMOD library"
 echo "  --fmod-inc               path to FMOD includes"
 echo "  --oss-lib                path to OSS library"
@@ -1106,6 +1111,32 @@ EOF
   fi
 fi
 
+##########################################
+# Check for xxxat() functions when we are building linux-user
+# emulator.  This is done because older glibc versions don't
+# have syscall stubs for these implemented.  In that case we
+# don't provide them even if kernel supports them.
+#
+atfile=no
+if [ "$linux_user" = "yes" ] ; then
+  cat > $TMPC << EOF
+#define _ATFILE_SOURCE
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main(void)
+{ 
+       /* try to unlink nonexisting file */
+       return (unlinkat(AT_FDCWD, "nonexistent_file", 0));
+}
+EOF
+  if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+    atfile=yes
+  fi
+fi
+
 # Check if tools are available to build documentation.
 if [ -x "`which texi2html 2>/dev/null`" ] && \
    [ -x "`which pod2man 2>/dev/null`" ]; then
@@ -1150,43 +1181,44 @@ else
   binsuffix="/bin"
 fi
 
-echo "Install prefix    $prefix"
-echo "BIOS directory    $prefix$datasuffix"
-echo "binary directory  $prefix$binsuffix"
+echo "Install prefix     $prefix"
+echo "BIOS directory     $prefix$datasuffix"
+echo "binary directory   $prefix$binsuffix"
 if test "$mingw32" = "no" ; then
-echo "Manual directory  $prefix$mansuffix"
-echo "ELF interp prefix $interp_prefix"
-fi
-echo "Source path       $source_path"
-echo "C compiler        $cc"
-echo "Host C compiler   $host_cc"
-echo "ARCH_CFLAGS       $ARCH_CFLAGS"
-echo "make              $make"
-echo "install           $install"
-echo "host CPU          $cpu"
-echo "host big endian   $bigendian"
-echo "target list       $target_list"
-echo "gprof enabled     $gprof"
-echo "sparse enabled    $sparse"
-echo "profiler          $profiler"
-echo "static build      $static"
-echo "-Werror enabled   $werror"
+echo "Manual directory   $prefix$mansuffix"
+echo "ELF interp prefix  $interp_prefix"
+fi
+echo "Source path        $source_path"
+echo "C compiler         $cc"
+echo "Host C compiler    $host_cc"
+echo "ARCH_CFLAGS        $ARCH_CFLAGS"
+echo "make               $make"
+echo "install            $install"
+echo "host CPU           $cpu"
+echo "host big endian    $bigendian"
+echo "target list        $target_list"
+echo "gprof enabled      $gprof"
+echo "sparse enabled     $sparse"
+echo "profiler           $profiler"
+echo "static build       $static"
+echo "-Werror enabled    $werror"
 if test "$darwin" = "yes" ; then
-    echo "Cocoa support     $cocoa"
+    echo "Cocoa support      $cocoa"
 fi
-echo "SDL support       $sdl"
+echo "SDL support        $sdl"
 if test "$sdl" != "no" ; then
-    echo "SDL static link   $sdl_static"
-fi
-echo "curses support    $curses"
-echo "mingw32 support   $mingw32"
-echo "Audio drivers     $audio_drv_list"
-echo "Extra audio cards $audio_card_list"
-echo "Mixer emulation   $mixemu"
-echo "VNC TLS support   $vnc_tls"
+    echo "SDL static link    $sdl_static"
+fi
+echo "curses support     $curses"
+echo "atfile support     $atfile"
+echo "mingw32 support    $mingw32"
+echo "Audio drivers      $audio_drv_list"
+echo "Extra audio cards  $audio_card_list"
+echo "Mixer emulation    $mixemu"
+echo "VNC TLS support    $vnc_tls"
 if test "$vnc_tls" = "yes" ; then
-    echo "    TLS CFLAGS    $vnc_tls_cflags"
-    echo "    TLS LIBS      $vnc_tls_libs"
+    echo "    TLS CFLAGS     $vnc_tls_cflags"
+    echo "    TLS LIBS       $vnc_tls_libs"
 fi
 echo "VNC SASL support  $vnc_sasl"
 if test "$vnc_sasl" = "yes" ; then
@@ -1194,19 +1226,20 @@ if test "$vnc_sasl" = "yes" ; then
     echo "    SASL LIBS      $vnc_sasl_libs"
 fi
 if test -n "$sparc_cpu"; then
-    echo "Target Sparc Arch $sparc_cpu"
+    echo "Target Sparc Arch  $sparc_cpu"
 fi
-echo "kqemu support     $kqemu"
-echo "brlapi support    $brlapi"
-echo "Documentation     $build_docs"
+echo "kqemu support      $kqemu"
+echo "brlapi support     $brlapi"
+echo "Documentation      $build_docs"
 [ ! -z "$uname_release" ] && \
-echo "uname -r          $uname_release"
-echo "NPTL support      $nptl"
-echo "vde support       $vde"
-echo "AIO support       $aio"
-echo "Install blobs     $blobs"
-echo "KVM support       $kvm"
-echo "fdt support       $fdt"
+echo "uname -r           $uname_release"
+echo "NPTL support       $nptl"
+echo "vde support        $vde"
+echo "AIO support        $aio"
+echo "Install blobs      $blobs"
+echo "KVM support        $kvm"
+echo "fdt support        $fdt"
+echo "GUEST_BASE support $guest_base"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1485,6 +1518,9 @@ if test "$curses" = "yes" ; then
   echo "CONFIG_CURSES=yes" >> $config_mak
   echo "CURSES_LIBS=-lcurses" >> $config_mak
 fi
+if test "$atfile" = "yes" ; then
+  echo "#define CONFIG_ATFILE 1" >> $config_h
+fi
 if test "$brlapi" = "yes" ; then
   echo "CONFIG_BRLAPI=yes" >> $config_mak
   echo "#define CONFIG_BRLAPI 1" >> $config_h
@@ -1848,6 +1884,9 @@ if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then
   echo "TARGET_HAS_ELFLOAD32=yes" >> $config_mak
   echo "#define TARGET_HAS_ELFLOAD32 1" >> $config_h
 fi
+if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then
+  echo "#define CONFIG_USE_GUEST_BASE 1" >> $config_h
+fi
 if test "$target_bsd_user" = "yes" ; then
   echo "CONFIG_BSD_USER=yes" >> $config_mak
   echo "#define CONFIG_BSD_USER 1" >> $config_h
index 366f47e..04f436b 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -629,8 +629,12 @@ static inline void stfq_be_p(void *ptr, float64 v)
 /* On some host systems the guest address space is reserved on the host.
  * This allows the guest address space to be offset to a convenient location.
  */
-//#define GUEST_BASE 0x20000000
+#if defined(CONFIG_USE_GUEST_BASE)
+extern unsigned long guest_base;
+#define GUEST_BASE guest_base
+#else
 #define GUEST_BASE 0
+#endif
 
 /* All direct uses of g2h and h2g need to go away for usermode softmmu.  */
 #define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
@@ -739,6 +743,8 @@ extern unsigned long qemu_host_page_mask;
 #define PAGE_RESERVED  0x0020
 
 void page_dump(FILE *f);
+void walk_memory_regions(void *,
+    int (*fn)(void *, unsigned long, unsigned long, unsigned long));
 int page_get_flags(target_ulong address);
 void page_set_flags(target_ulong start, target_ulong end, int flags);
 int page_check_range(target_ulong start, target_ulong len, int flags);
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644 (file)
index 0000000..de0b0ab
--- /dev/null
@@ -0,0 +1,25 @@
+qemu for Debian
+---------------
+
+The qemu debian package does not include the video.x file, which is 
+needed by qemu-system-ppc for some systems. The file is available from
+the mac-on-linux project, and the sources are available on:
+  http://mac-on-linux.svn.sourceforge.net/viewvc/mac-on-linux/mac-drivers/video_driver/Makefile?revision=HEAD&view=markup
+
+They are not buildable on a Debian system though, hence video.x is not
+present in the package. The qemu-system-ppc binary is still useful for
+emulating a PReP platform, which does not need video.x.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sun, 16 Mar 2008 19:17:39 +0100
+
+
+The qemu debian package includes a simple script called qemu-make-debian-root
+under /usr/sbin, which uses debootstrap to create an image suitable for qemu
+with a fresh Debian installation inside.
+
+If you just want a test system, not wanting to go through any installation
+process, that might be just ideal. Take a look at the manual page
+qemu-make-debian-root (8) for further usage instructions.
+
+ -- Guilherme de S. Pastore <gpastore@colband.com.br>, Sun May 15 09:49:11 2005
+
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..1552399
--- /dev/null
@@ -0,0 +1,1175 @@
+qemu (0.10.0-0maemo4) unstable; urgency=low
+
+  * Riku voipio
+     - fix conditional sb1-qemu build
+     - split system qemu to a different package, so sb2-qemu has less
+       dependencies
+     - basic usb-musb support for omap3
+     - smc91x networking support
+  * Jussi Hakala:
+     - fix sbox-call
+     - make sb1 packaging more scratchboxy
+  * Juha Riihimäki
+     - SPI support
+     - lots of fixes and cleanups
+     - qemu snapshotting support
+
+ -- Riku Voipio <riku.voipio@iki.fi>  Thu, 26 Mar 2009 14:46:21 +0200
+
+qemu (0.10.0-0maemo3) unstable; urgency=low
+
+  * debian/
+    make building sb1-qemu conditional
+  * MW:
+    linux-user: removed unnecessary MAX_SOCK_ADDR checks for socket syscalls
+  * Riku:
+    Convert musb fifo to 8bit to allow 8/16/32bit access
+    Make USB devices self-powered
+    add some USB registers
+    fix omap3_usb interrupt raising
+  * Juha
+    let beagleboard understand the -m switch
+    arm core emulation performance improvement
+    omap3 prcm and clocks clean-up
+    omap3 bootrom emulations
+
+ -- Riku Voipio <riku.voipio@iki.fi>  Thu, 19 Mar 2009 16:33:06 +0200
+
+qemu (0.10.0-0maemo2) unstable; urgency=low
+
+  * Add guest-base support
+  * merge upstream
+  * more omap3 fixes
+
+ -- Riku Voipio <riku.voipio@iki.fi>  Mon, 09 Mar 2009 14:53:44 +0200
+
+qemu (0.10.0-0maemo1) unstable; urgency=low
+
+  * New upstream version
+  * merge maemo patches 
+
+ -- Riku Voipio <riku.voipio@iki.fi>  Thu, 05 Mar 2009 11:50:07 +0200
+
+qemu (0.9.1+svn20090113-0maemo1) unstable; urgency=low
+
+  * maemo patched version
+
+ -- Riku Voipio <riku.voipio@iki.fi>  Wed, 28 Jan 2009 11:18:41 +0200
+
+qemu (0.9.1+svn20090104-1) experimental; urgency=low
+
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+  * Disable security/CVE-2008-0928-fedora.patch, it still breaks qcow 
+    format.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sun, 04 Jan 2009 16:31:40 +0100
+
+qemu (0.9.1+svn20081223-1) experimental; urgency=low
+
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+    - Fix CVE-2008-2382
+  * Update patches/48_signal_terminate.patch.
+  * debian/rules: remove upstream flags from CFLAGS.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Tue, 23 Dec 2008 14:51:25 +0100
+
+qemu (0.9.1+svn20081214-1) experimental; urgency=low
+
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+    - Fix jmp im on x86_64 when executing 32-bit code. Fix grub
+      installation (Closes: bug#467148).
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sun, 14 Dec 2008 23:26:04 +0100
+
+qemu (0.9.1+svn20081207-1) experimental; urgency=low
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+    - Do not depend on gcc-3.4 anymore (Closes: bug#440425, bug#463066).
+    - Fix broken display introduced by CVE-2007-1320 (Closes: bug#422578).
+  * debian/control: remove build-dependency on gcc-3.4.
+  * debian/rules: remove code for dyngen targets.
+  * Split 90_security.patch into
+    - security/CVE-2007-5730.patch
+    - security/leftover.patch
+  * Replace 91_security.patch by security/CVE-2008-0928-fedora.patch taken
+    from fedora repository and enable it (Closes: #469649).
+
+  [ Riku Voipio ]
+  * 2 patches gone, 19 to go:
+    - 10_signal_jobs.patch: drop, merged upstream
+    - 11_signal_sigaction.patch: drop, merged upstream
+    - series: update
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sun, 07 Dec 2008 19:40:09 +0100
+
+qemu (0.9.1+svn20081128-1) experimental; urgency=low
+
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+    - Include documentation for network downscript option (Closes: 
+      bug#506994). 
+    - Drop 00_bios.patch and pass --disable-blobs instead.
+    - Update 12_signal_powerpc_support.patch.
+  
+  [ Riku Voipio ]
+  * Drop 31_syscalls.patch as it makes no sense using host uselib to 
+    load target code into qemu's host memoryspace.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sat, 29 Nov 2008 09:04:41 +0100
+
+qemu (0.9.1+svn20081112-1) experimental; urgency=low
+
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+    - does not need a disk image anymore (Closes: bug#260935).
+    - 53_openbios_size.patch: drop (merged upstream).
+    - 90_security: update.
+  * debian/control: depend on openbios-sparc (>= 1.0~alpha2+20081109)
+    (Closes: bug#502411, bug#502414).
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sun, 09 Nov 2008 14:42:37 +0100
+
+qemu (0.9.1+svn20081101-1) experimental; urgency=low
+
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+    - fix a heap overflow in Cirrus emulation (CVE-2008-4539).
+    - 50_linuxbios_isa_bios_ram.patch: update.
+    - 90_security.patch: update.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sat, 01 Nov 2008 09:26:45 +0100
+
+qemu (0.9.1+svn20081023-1) experimental; urgency=low
+
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+    - 12_signal_powerpc_support.patch: update.
+    - 50_linuxbios_isa_bios_ram.patch: update.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Thu, 23 Oct 2008 21:34:26 +0200
+
+qemu (0.9.1+svn20081016-1) experimental; urgency=low
+
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+  * patches/31_syscalls.patch: remove parts merged upstream.
+  * debian/qemu-make-debian-root:
+    - Fix bug introduced when fixing bug#496394 (Closes: bug#502325).
+
+ -- Aurelien Jarno <aurel32@debian.org>  Mon, 13 Oct 2008 23:11:15 +0200
+
+qemu (0.9.1+svn20081012-1) experimental; urgency=low
+
+  [ Riku Voipio ]
+  * Add a bunch of patches from scratchbox
+    - 44_socklen_t_check work better with badbehavin net apps
+    - 48_signal_terminate make qemu binary terminate on signals as expected
+    - 49_null_checks don't bother some syscalls when null/zero is passed
+
+  [ Aurelien Jarno ]
+  * New upstream snapshot.
+    - alpha is now a TCG target.
+    - comma has been added to sendkey (closes: bug#414342).
+  * patches/31_syscalls.patch: remove parts merged upstream.
+  * patches/39_syscall_fadvise64.patch: remove (merged upstream).
+  * patches/90_security.patch: remove parts merged upstream.
+  * debian/control: build-depends on libbluetooth-dev.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sun, 12 Oct 2008 18:46:54 +0200
+
+qemu (0.9.1+svn20080905-1) experimental; urgency=low
+
+  * New upstream snapshot.
+    - SH4 is now a TCG target.
+  * debian/watch: update URL location.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Tue, 02 Sep 2008 01:43:24 +0200
+
+qemu (0.9.1+svn20080826-1) experimental; urgency=low
+
+  * New upstream snapshot.
+  * debian/qemu-make-debian-root:
+    - Use mktemp instead of $$ to create temporary directories (Closes: 
+      bug#496394).
+  * Ship a libqemu-dev package (Closes: bug#451618).
+
+ -- Aurelien Jarno <aurel32@debian.org>  Tue, 26 Aug 2008 09:55:36 +0200
+
+qemu (0.9.1+svn20080822-1) experimental; urgency=low
+
+  * New upstream snapshot.
+    - Focus to monitor to ask password (Closes: bug#473240).
+    - TCG SPARC host support (Closes: bug#450817).
+    - Check KQEMU availability before allocating memory (Closes: bug#414566).
+    - Fix dead keys (Closes: bug#489594).
+    - Fix ES1370 emulation (Closes: bug#494462).
+    - New USB UHCI implemnation (Closes: bug#457651).
+    - Add debian/patches/00_bios.patch.
+    - Remove debian/patches/02_snapshot_use_tmpdir.patch (merged).
+    - Remove debian/patches/04_do_not_print_rtc_freq_if_ok.patch (merged).
+    - Remove patches/05_non-fatal_if_linux_hd_missing.patch (merged).
+    - Update debian/patches/07_i386_exec_name.patch
+    - Update debian/patches/12_signal_powerpc_support.patch 
+    - Remove debian/patches/33_syscall_ppc_clone.patch (merged differently).
+    - Remove debian/patches/41_arm_fpa_sigfpe.patch (merged).
+    - Remove debian/patches/42_arm_tls.patch (merged differently).
+    - Update debian/patches/55_unmux_socketcall.patch.
+    - Remove debian/patches/63_sparc_build.patch (useless).
+    - Update debian/patches/65_kfreebsd.patch.
+    - Update debian/patches/66_tls_ld.patch.
+    - Remove debian/patches/70_manpage.patch (merged).
+    - Remove debian/patches/71_doc.patch  (merged).
+    - Remove debian/patches/80_ui_curses.patch (merged).
+    - Remove debian/patches/81_mips32r2_fpu.patch (merged).
+    - Remove debian/patches/82_mips_abs.patch (merged).
+    - Remove debian/patches/83_usb-serial.patch (merged).
+    - Remove debian/patches/84_rtl8139.patch (merged).
+    - Remove debian/patches/85_vvfat.patch (merged).
+    - Remove debian/patches/86_df.patch (merged).
+    - Remove debian/patches/87_eoi.patch (merged).
+    - Remove debian/patches/88_dma.patch (merged).
+    - Remove debian/patches/89_braille.patch (merged).
+    - Remove debian/patches/92_no_shutdown.patch (merged).
+    - Remove debian/patches/93_tmpfs.patch (merged).
+    - Remove debian/patches/94_security.patch (merged).
+  * debian/README.source: new file.
+  * debian/patches/*: convert to patchlevel 1 (Closes: bug#484963).
+  * debian/control:
+    - Add build-depends on libesd0-dev.
+    - Add build-depends on libpulse-dev.
+    - Add build-depends on libvdeplug2-dev.
+    - Add build-depends on etherboot.
+    - Update list of supported targets (Closes: bug#488339).
+    - Suggests kqemu-source.
+    - Bump Standards-Version to 3.8.0.
+  * debian/links:
+    - Add missing manpage symlinks.
+  * debian/rules:
+    - Enable audio drivers depending on the system.
+    - Enable DYNGEN targets depending on the system.
+    - Install PXE bios from etherboot (Closes: bug#412010).
+    - Don't ignore make clean errors.
+    - Don't build DYNGEN targets on kfreebsd-amd64 (Closes: bug#494353).
+  * debian/patches/22_net_tuntap_stall.patch: remove (outdated).
+
+ -- Aurelien Jarno <aurel32@debian.org>  Fri, 22 Aug 2008 01:00:54 +0200
+
+qemu (0.9.1-5) unstable; urgency=high
+
+  [ Guillem Jover ]
+  * Add Homepage field.
+  * Add Vcs-Browser and Vcs-Svn fields.
+  * Remove packaging repository information from debian/copyright.
+  * Add former package co-maintainers to debian/copyright.
+  * Serialize patch and configure steps in debian/rules to support parallel
+    builds, as we are patching configure.
+  * Remove myself from Uploaders.
+
+  [ Aurelien Jarno ]
+  * debian/patches/70_manpage.patch: remove curses documentation, it is already
+    in debian/patches/80_ui_curses.patch (Closes: bug#477369).
+  * debian/patches/94_security.patch: add format= to drive options
+    (CVE-2008-2004).
+
+ -- Aurelien Jarno <aurel32@debian.org>  Mon, 28 Apr 2008 21:54:12 +0200
+
+qemu (0.9.1-4) unstable; urgency=high
+
+  * debian/patches/52_ne2000_return.patch: drop, the patch is wrong.  
+  * Backports from upstream:
+    - Typo in curses_keys.h
+    - Documentation for the -curses option
+    - Fix broken absoluteness check for cabs.d.*.
+    - USB-to-serial device.
+    - rtl8139: fix endianness on big endian targets
+    - restore rw support for vvfat
+    - x86-64: recompute DF after eflags has been modified when emulating 
+      SYSCALL
+    - ignore reads to the EOI register
+    - IDE: Improve DMA transfers by increasing the buffer size
+    - Braille device support
+    - Add -no-shutdown option (Closes: #326406)
+    - Ask to use "mount -o remount" instead of "umount" and "mount" 
+      /dev/shm (Closes: #476539).
+  * debian/qemu.doc-base: fix section. 
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sun, 20 Apr 2008 23:29:42 +0200
+
+qemu (0.9.1-3) unstable; urgency=low
+
+  [ Aurelien Jarno ]
+  * debian/patches/42_arm_tls.patch: fix to get qemu-system-arm working
+    again. (Closes: #471722).
+  * debian/patches/56_dhcp.patch: fix DHCP server to correctly support 
+    MS-Windows guests. (Closes: #471452).
+
+ -- Aurelien Jarno <aurel32@debian.org>  Wed, 19 Mar 2008 18:58:29 +0100
+
+qemu (0.9.1-2) unstable; urgency=low
+
+  [ Aurelien Jarno ]
+  * debian/patches/80_ui_curses.patch: pull new patch from upstream CVS
+    (Closes: #442274).
+  * debian/patches/65_kfreebsd.patch: link with -lfreebsd. (Closes: 
+    #465932).
+  * debian/patches/81_mips32r2_fpu.patch: patch pulled from upstream
+    to fix FPU issue on MIPS32R2.
+  * debian/patches/42_arm_tls.patch: reenable, mistakenly disabled in the
+    previous upload. (Closes: #469743).
+  * debian/rules: fix parallel building. (Closes: #469981). 
+  * debian/patches/07_i386_exec_name.patch: install the i386 emulator as
+    qemu-system-i386, and change qemu into a link pointing to the i386
+    version.
+  * debian/README.Debian: add notes about qemu-system-ppc and video.x
+    (Closes: #388735).
+  * debian/patches/70_manpage.patch: describe the -curses option.
+    (Closes: #433658).
+  * debian/patches/71_doc.patch: fix the monitor change option. (Closes: 
+    #467106).
+  * debian/patches/35_syscall_sockaddr.patch: fix sockaddr (Closes: 
+    #469351).
+  * debian/patches/43_arm_cpustate.patch: disable (Closes: #444171).
+
+ -- Aurelien Jarno <aurel32@debian.org>  Mon, 17 Mar 2008 01:29:03 +0100
+
+qemu (0.9.1-1) unstable; urgency=low
+
+  [ Aurelien Jarno ]
+  * New upstream version. (Closes: #459801)
+    - Supports s390 host. (Closes: #441119)
+    - Fix PCI bar allocation. (Closes: #413315)
+    - Fix typo in keys name. (Closes: #426181)
+    - Fix segfault of qemu-i386 (Closes: #446868).
+    - debian/control: bump depends on openbios-sparc to
+      >= 1.0~alpha2+20080106.
+    - debian/patches/02_snapshot_use_tmpdir.patch: Refreshed.
+    - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+    - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+    - debian/patches/06_exit_segfault.patch: Likewise.
+    - debian/patches/10_signal_jobs.patch: Likewise.
+    - debian/patches/11_signal_sigaction.patch: Likewise.
+    - debian/patches/12_signal_powerpc_support.patch: Likewise.
+    - debian/patches/21_net_soopts.patch: Likewise.
+    - debian/patches/30_syscall_ipc.patch: Likewise.
+    - debian/patches/31_syscalls.patch: Likewise.
+    - debian/patches/32_syscall_sysctl.patch: Likewise.
+    - debian/patches/33_syscall_ppc_clone.patch: Likewise.
+    - debian/patches/35_syscall_sockaddr.patch: Likewise.
+    - debian/patches/41_arm_fpa_sigfpe.patch: Likewise.
+    - debian/patches/42_arm_tls.patch: Likewise.
+    - debian/patches/50_linuxbios_isa_bios_ram.patch: Likewise
+    - debian/patches/51_linuxbios_piix_ram_size.patch: Likewise
+    - debian/patches/61_safe_64bit_int.patch: Removed, merged upstream.
+    - debian/patches/63_sparc_build.patch: Refreshed.
+    - debian/patches/80_ui_curses.patch: Likewise.
+  * debian/patches/90_security.patch: fix 64-bit overflow. (Closes:
+    #425634)
+  * debian/qemu-make-debian-root: add a -s option to create sparse
+    image. (Closes: #322325)
+  * debian/control: bump depends on bochsbios to >= 2.3.5-1. Use
+    BIOS-qemu-latest instead of BIOS-bochs-latest. (Closes: #402289,
+    #442822)
+  * debian/rules: build the non-dyngen part with default gcc.
+  * debian/rules: support DEB_BUILD_OPTIONS="parallel=n".
+  * debian/patches/70_manpage.patch: describe the arguments of the
+    -usbdevice option in the manpage. (Closes: #443801)
+  * debian/control: now using Standards-Version 3.7.3 (no changes needed).
+  * debian/control: build-depends on libgnutls-dev to enable TLS support
+    in VNC.
+  * debian/patches/01_nostrip.patch: don't strip binaries during make
+    install. (Closes: #437866)
+  * debian/patches/53_openbios_size.patch: increase maximum prom size to
+    support latest openbios.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Mon, 28 Jan 2008 21:24:14 +0100
+
+qemu (0.9.0+20070816-1) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * New upstream snapshot.
+    - Fix hang on ARM during Etch installation. (Closes: #430164)
+    - Fix data corruption with qcow 2. (Closes: #440296)
+    - Fix errors with raw images > 4 GiB. (Closes: #425634)
+    - debian/patches/01_typo_qemu-img.patch: Removed, merged upstream.
+    - debian/patches/03_machines_list_no_error.patch: Likewise.
+    - debian/patches/36_syscall_prctl.patch: Likewise.
+    - debian/patches/37_syscall_mount.patch: Likewise.
+    - debian/patches/38_syscall_semctl.patch: Likewise.
+    - debian/patches/40_sparc_fp_to_int.patch: Likewise.
+    - debian/patches/44_arm_eabi_built_on_64bit_arches.patch: Likewise.
+    - debian/patches/62_linux_boot_nasm.patch: Likewise.
+    - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Synced.
+    - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+    - debian/patches/31_syscalls.patch: Likewise.
+    - debian/patches/35_syscall_sockaddr.patch: Likewise.
+    - debian/patches/42_arm_tls.patch: Likewise.
+    - debian/patches/43_arm_cpustate.patch: Likewise.
+    - debian/patches/51_linuxbios_piix_ram_size.patch: Likewise.
+    - debian/patches/55_unmux_socketcall.patch: Likewise.
+    - debian/patches/60_ppc_ld.patch: Likewise.
+    - debian/patches/65_kfreebsd.patch: Likewise.
+    - debian/patches/80_ui_curses.patch: Likewise.
+    - debian/patches/90_security.patch: Likewise.
+  * Remove Elrond and Guilherme de S. Pastore from Uploaders, with their
+    permission, and add Aurelien Jarno and Riku Voipio.
+  * Remove Tag field, this is better maintained outside of the package.
+  * Add openbios-sparc64 to qemu_bios_files in debian/rules.
+
+  [ Aurelien Jarno ]
+  * Fix FTBFS on amd64. (Closes: #434296)
+    - Drop debian/patches/34_syscalls_types.patch
+  * debian/control:
+    - Suggest samba. (Closes: #430368)
+  * Add OpenBIOS for sparc. (Closes: #407076)
+    - debian/control: depends on openbios-sparc.
+    - debian/links: provide symlinks in /usr/share/qemu.
+
+ -- Guillem Jover <guillem@debian.org>  Tue, 04 Sep 2007 04:04:47 +0300
+
+qemu (0.9.0-2) unstable; urgency=high
+
+  [ Guillem Jover ]
+  * Fix several security issues. (Closes: #424070)
+    Thanks to Tavis Ormandy <taviso@google.com>.
+    - Cirrus LGD-54XX "bitblt" heap overflow. CVE-2007-1320
+    - NE2000 "mtu" heap overflow.
+    - QEMU "net socket" heap overflow.
+    - QEMU NE2000 "receive" integer signedness error. CVE-2007-1321
+    - Infinite loop in the emulated SB16 device.
+    - Unprivileged "aam" instruction does not correctly handle the
+      undocumented divisor operand. CVE-2007-1322
+    - Unprivileged "icebp" instruction will halt emulation. CVE-2007-1322
+    - debian/patches/90_security.patch: New file.
+  * Enable adlib audio emulation. (Closes: #419170)
+  * Fix structure padding for target_eabi_flock64 when built for a 64 bit
+    architecture. (Closes: #414799)
+    Thanks to Stuart Anderson <anderson@netsweng.com>.
+    - debian/patches/44_arm_eabi_built_on_64bit_arches.patch: New file.
+  * Fix qemu to be able to use LinuxBios. (Closes: #412212)
+    Thanks to Ed Swierk <eswierk@cs.stanford.edu>.
+    - debian/patches/50_linuxbios_isa_bios_ram.patch: New file.
+    - 51_linuxbios_piix_ram_size.patch: Likewise.
+  * Fix segfault when booting a Linux kernel w/o a disk image, by exiting but
+    clarifying the message, as to use '/dev/null'. (Closes: #409817, #411780)
+    Thanks to Robert Millan <rmh@aybabtu.com>.
+    - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Updated.
+  * Fix segfault by using addrlen instead of target_addrlen in
+    do_getpeername()/do_getsockname(). (Closes: #411910)
+    Thanks to Stuart Anderson <anderson@netsweng.com>.
+    - debian/patches/35_syscall_sockaddr.patch: Updated.
+  * Fix semctl() for 32 bit targets on 64 bit hosts. (Closes: #414809)
+    Thanks to Stuart Anderson <anderson@netsweng.com>.
+    - debian/patches/38_syscall_semctl.patch: New file.
+  * Remove Elrond from Uploaders with consent, always welcome to join
+    back anytime.
+
+ -- Guillem Jover <guillem@debian.org>  Wed, 16 May 2007 08:08:31 +0300
+
+qemu (0.9.0-1) experimental; urgency=low
+
+  [ Guillem Jover ]
+  * New upstream release. (Closes: #409989)
+    - Support for relative paths in backing files for disk images.
+      (Closes: #390446)
+    - debian/patches/01_doc_typos.patch: Removed, merged upstream.
+    - debian/patches/38_syscall_arm_statfs64.patch: Likewise.
+    - debian/patches/51_serial_small_divider.patch: Likewise.
+    - debian/patches/67_ppc_ftbfs.patch: Likewise.
+    - debian/patches/21_net_soopts.patch: Synced.
+    - debian/patches/30_syscall_ipc.patch: Likewise.
+    - debian/patches/31_syscalls.patch: Likewise.
+    - debian/patches/35_syscall_sockaddr.patch: Likewise.
+    - debian/patches/39_syscall_fadvise64.patch: Likewise.
+    - debian/patches/42_arm_tls.patch: Likewise.
+    - debian/patches/55_unmux_socketcall.patch: Likewise.
+    - debian/patches/80_ui_curses.patch: Likewise.
+  * Update the copyright information.
+  * The ACPI initialization code has been moved to bochsbios.
+    - debian/patches/acpi-dsdt.hex: Removed.
+    - debian/rules: Do not install acpi-dsdt.hex.
+  * Add more files to the list of roms removed from the tarball needed to
+    be touched so that upstream 'make install' does not fail.
+  * Added armeb and armel to Architecture fields and libgpmg1-dev
+    Build-Depends.
+  * Recommend vde2 instead of the transitional vde package. (Closes: #407251)
+  * Fix typo in qemu-img output. (Closes: #408542)
+    - debian/patches/01_typo_qemu-img.patch: New file.
+    Thanks to Adam Buchbinder <adam.buchbinder@gmail.com>.
+  * Symlink qemu-user(1) to qemu-m68k(1).
+  * Reduce redundancy in qemu-user(1) synopsis.
+  * Fix rounding in sparc floating point to integer conversions.
+    - debian/patches/40_sparc_fp_to_int.patch: New file.
+    Thanks to Aurelien Jarno <aurelien@aurel32.net>.
+
+ -- Guillem Jover <guillem@debian.org>  Thu,  8 Feb 2007 01:01:29 +0200
+
+qemu (0.8.2-5) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * Added a missing part to the ARM NPTL support patch, initially lost.
+    - debian/patches/42_arm_tls.patch: Updated.
+
+ -- Guillem Jover <guillem@debian.org>  Tue, 16 Jan 2007 11:44:00 +0200
+
+qemu (0.8.2-4) unstable; urgency=medium
+
+  [ Guillem Jover ]
+  * Disable using iasl for now until it's ported to big-endian systems and
+    include a locally built acpi-dsdt.hex file.
+
+ -- Guillem Jover <guillem@debian.org>  Sun,  3 Dec 2006 21:10:23 +0200
+
+qemu (0.8.2-3) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * Hopefully really fix powerpc FTBFS.
+
+ -- Guillem Jover <guillem@debian.org>  Sun,  5 Nov 2006 17:09:53 +0200
+
+qemu (0.8.2-2) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * Update Tag field to match new debtags vocabulary.
+  * Clean properly. (Closes: #390166)
+    - Remove the acpi generated files and the docs.
+    - Revert the docs regeneration forcing logic.
+    Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+  * On install use DESTDIR instead of specifying all paths. (Closes: #396139)
+    Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+  * Port to GNU/kFreeBSD. (Closes: #327622)
+    - Disable ALSA on non-linux systems.
+    - Add a Build-Depends on libfreebsd-dev on kfreebsd systems.
+    - Add kfreebsd-i386 and kfreebsd-amd64 to the Architecture field.
+    - debian/patches/65_kfreebsd.patch: New file.
+    Thanks Petr Salinger <Petr.Salinger@seznam.cz>.
+  * In qemu-make-debian-root do not explicitely install in aptitude and
+    libsigc++-1.2-5c102, they are pulled now by default. And do not remove
+    aptitude afterwards. (Closes: #392481)
+    Thanks to Ted Percival <ted@midg3t.net>.
+  * Add experimental ncurses ui support. (Closes: #369462)
+    - debian/patches/80_ui_curses.patch: New file.
+    Thanks to Andrzej Zaborowski <balrog@zabor.org>.
+  * Add SO_PEERCRED and SO_SNDTIMEO support, and fix accept syscall when
+    being passed NULL pointers.
+    - debian/patches/21_net_sockopts.patch: Renamed to ...
+    - debian/patches/21_net_soopts.patch: ... here. Modify.
+    Thanks to Pablo Virolainen.
+  * Add a fadvise64 syscall stub.
+    - debian/patches/39_syscall_fadvise64.patch: New file.
+    Thanks to Pablo Virolainen.
+  * Add EABI unmuxed socket syscalls.
+    - debian/patches/55_unmux_socketcall.patch: New file.
+    Thanks to Riku Voipio.
+  * Add TLS sections to the ARM and x86 linker scripts so that qemu user
+    emulators can be linked statically.
+    - debian/patches/66_tls_ld.patch: New file.
+  * Move the documentation of the binary blob removals from the original
+    upstream tarball from README.Debian to debian/copyright.
+  * Reword the emphasis on "FAST!" from the package description.
+  * Fix FTBFS on powerpc by adding the missing fp_status variable to the
+    int32_to_float32 function calls.
+    - debian/patches/67_ppc_ftbfs.patch: New file.
+
+ -- Guillem Jover <guillem@debian.org>  Sun,  5 Nov 2006 08:48:27 +0200
+
+qemu (0.8.2-1) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * New upstream release. (Closes: #379461, #385029, #388810)
+    - Add ACPI BIOS emulation support. (Closes: #372533)
+    - Fix mouse invisible wall when using Windows XP. (Closes: #384666)
+    - debian/patches/01_doc_typos.patch: Sync.
+    - debian/patches/03_machines_list_no_error.patch: Likewise.
+    - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+    - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+    - debian/patches/06_exit_segfault.patch: Likewise.
+    - debian/patches/12_signal_powerpc_support.patch: Likewise.
+    - debian/patches/21_net_sockopt.patch: Likewise.
+    - debian/patches/22_net_tuntap_stall.patch: Likewise.
+    - debian/patches/30_syscall_ipc.patch: Likewise.
+    - debian/patches/31_syscalls.patch: Likewise.
+    - debian/patches/32_syscall_sysctl.patch: Likewise.
+    - debian/patches/33_syscall_ppc_clone.patch: Likewise.
+    - debian/patches/35_syscall_sockaddr.patch: Likewise.
+    - debian/patches/36_syscall_prctl.patch: Likewise.
+    - debian/patches/37_syscall_mount.patch: Likewise.
+    - debian/patches/41_arm_fpa_sigfpe.patch: Likewise.
+    - debian/patches/42_arm_tls.patch: Likewise.
+    - debian/patches/61_safe_64bit_int.patch: Likewise.
+    - debian/patches/63_sparc_build.patch: Likewise.
+    - debian/patches/50_missing_keycodes.patch: Removed, integrated upstream.
+  * Switch to quilt:
+    - debian/control: Add quilt (>= 0.40) to Build-Depends.
+    - debian/patches/series: New file.
+    - debian/patch.mk: Removed.
+    - debian/rules: Include '/usr/share/quilt/quilt.make' instead of
+      'debian/patch.mk'.
+  * Build the ACPI Source Language files with iasl.
+  * Add a Tag field to the binary package, using data from debtags.
+  * Add 2006 to the debian/copyright years.
+  * Add a Recommends on vde. (Closes: #386780)
+  * Fix spelling error in package description (peripherials -> peripherals).
+    (Closes: #388700)
+    Thanks to Rakesh 'arky' Ambati <rakesh_ambati@yahoo.com>.
+  * Fix ne2000_can_receive return code to 0 when the command is STOP.
+    (Closes: #386209)
+    - debian/patches/52_ne2000_return.patch: New file.
+    Thanks to Samuel Thibault <samuel.thibault@ens-lyon.org>.
+  * Document the binary blob removals from the original upstream tarball in
+    README.Debian. (Closes: #388740)
+
+ -- Guillem Jover <guillem@debian.org>  Mon, 25 Sep 2006 04:16:25 +0300
+
+qemu (0.8.1-1) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * New upstream release. (Closes: #366955, #366637)
+    - debian/patches/01_doc_typos.patch: Sync.
+    - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+    - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+    - debian/patches/12_signal_powerpc_support.patch: Likewise.
+    - debian/patches/21_net_sockopt.patch: Likewise.
+    - debian/patches/22_net_tuntap_stall.patch: Likewise.
+    - debian/patches/30_syscall_ipc.patch: Likewise.
+    - debian/patches/31_syscalls.patch: Likewise.
+    - debian/patches/32_syscall_sysctl.patch: Likewise.
+    - debian/patches/33_syscall_ppc_clone.patch: Likewise.
+    - debian/patches/35_syscall_sockaddr.patch: Likewise.
+    - debian/patches/36_syscall_prctl.patch: Likewise.
+    - debian/patches/37_syscall_mount.patch: Likewise.
+    - debian/patches/41_arm_fpa_sigfpe.patch: Likewise.
+    - debian/patches/42_arm_tls.patch: Likewise.
+    - debian/patches/43_arm_cpustate.patch: Likewise.
+    - debian/patches/50_missing_keycodes.patch: Likewise.
+    - debian/patches/51_serial_small_divider.patch: Likewise.
+    - debian/patches/61_safe_64bit_int.patch: Likewise.
+    - debian/patches/63_sparc_build.patch: Likewise.
+    - debian/patches/40_arm_nwfpe_cpsr.patch: Removed, integrated upstream.
+  * Make the patch system apply the patch on the first run.
+    - debian/patches/64_ppc_asm_constraints.patch: Add DPATCHLEVEL.
+  * Document how to use the images created with qemu-make-debian-root in the
+    man page. Thanks to Jacobo <jacobo221@hotmail.com>. (Closes: #343450)
+  * Add support for the -snapshot option to use the TMPDIR evironment
+    variable. (Closes: #353880)
+    - debian/patches/02_snapshot_use_tmpdir.patch: New file.
+  * Do not exit with an error when using '-M ?'. (Closes: #365209)
+    - debian/patches/03_machines_list_no_error.patch: New file.
+  * Added symlink for system-mipsel emulator man page.
+  * Build and clean the pc-bios directory.
+  * Avoid segfaulting by using _exit(2) instead of exit(3) in qemu user
+    emulators. (Closes: #338289)
+    - debian/patches/06_exit_segfault.patch: New file.
+  * Enable ALSA audio support and add libasound2-dev to the Build-Depends.
+  * Now using Standards-Version 3.7.2 (no changes needed).
+
+ -- Guillem Jover <guillem@debian.org>  Sun, 28 May 2006 20:51:10 +0300
+
+qemu (0.8.0-3) unstable; urgency=low
+
+  [ Josh Triplett ]
+  * Fix FTBFS on PowerPC caused by asm constraint problem. (Closes: #361727)
+    - debian/patches/64_ppc_asm_constraints.patch.
+
+  [ Guillem Jover ]
+  * Clamp addrlen from host to target when using AF_UNIX. This fixes
+    socket problems when using EABI.
+    - debian/patches/35_syscall_sockaddr.patch: New file.
+  * Fix floating point comparison on ARM NWFPE, due to glue code missmatch.
+    (Closes: #356287)
+    - debian/patches/40_arm_nwfpe_cpsr.patch: New file.
+    - debian/patches/40_fpu_arm_sigfpe.patch: Rename to ...
+    - debian/patches/41_arm_fpa_sigfpe.patch: ... this. Resync.
+    Thanks to Ulrich Hecht.
+  * Fix POSIX threads creation on ARM hanging when initializing the cpu
+    structure being it cyclic.
+    - debian/patches/43_arm_cpustate.patch: New file.
+  * Add TLS support for ARM. Stolen from Scratchbox.
+    - debian/patches/42_arm_tls.patch: New file.
+  * Fix sysctl endian problem.
+    - debian/patches/32_syscall_sysctl.patch: Update.
+    Thanks to Timo Savola <tsavola@movial.fi>.
+  * Remove now default '--enable-slirp' build option. (Closes: #356284)
+    Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+  * Remove unused sharedir to 'make install'. (Closes: #356418)
+    Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+  * Fix package not cleaning properly. (Closes: #356279)
+    Thanks to Anderson Lizardo <anderson.lizardo@gmail.com> for the initial
+    patch.
+  * Add needed syscalls to make debootstrap work. (Closes: #356291)
+    - debian/patches/36_syscall_prctl.patch: New file.
+    - debian/patches/37_syscall_mount.patch: Likewise.
+    - debian/patches/38_syscall_arm_statfs64.patch: Likewise.
+    Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+  * Remove obsolete Build-Dependency xlibs-dev.
+
+ -- Guillem Jover <guillem@debian.org>  Thu, 13 Apr 2006 11:53:00 +0300
+
+qemu (0.8.0-2) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * Switch away from cdbs to plain debhelper.
+  * Upgrade to debhelper compat level 5.
+  * Allow overriding CC compiler variable. (Closes: #345772)
+  * Do not redefine 64 bit types on 64 bit arches.
+    - debian/patches/61_safe_64bit_int.patch: New file.
+  * Allow linux_boot.bin to be built on any arch by switching to nasm,
+    and Build-Depending on it.
+    - debian/patches/62_linux_boot_nasm.patch: New file.
+  * The serial hw driver uses a small divider that gets zeroed when shifting
+    bits to the right. (Closes: #276276, #348098)
+    - debian/patches/51_serial_small_divider.patch: New file.
+    Thanks to Samuel Thibault <samuel.thibault@ens-lyon.org>.
+  * Escaped hyphens in qemu-user manpage, use italics for filenames and
+    parameters and bold for options.
+  * Partial build failure fix for Sparc. (Bugs: #317145, #336970)
+    Thanks to Jurij Smakov <jurij@wooyd.org>.
+
+ -- Guillem Jover <guillem@debian.org>  Mon, 20 Feb 2006 09:17:46 +0200
+
+qemu (0.8.0-1) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * New upstream release. (Closes: #344339)
+    - Added support for Virtual FAT. (Closes: #313123)
+    - Emulate repeated keystrokes when holding a key. (Closes: #298864)
+    - debian/patches/01_doc_typos.patch: Sync.
+    - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+    - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+    - debian/patches/12_signal_powerpc_support.patch: Likewise.
+    - debian/patches/21_net_sockopt.patch: Likewise.
+    - debian/patches/22_net_tuntap_stall.patch: Likewise.
+    - debian/patches/30_syscall_ipc.patch: Likewise.
+    - debian/patches/31_syscalls.patch: Likewise.
+    - debian/patches/32_syscall_sysctl.patch: Likewise.
+    - debian/patches/33_syscall_ppc_clone.patch: Likewise.
+    - debian/patches/40_fpu_arm_sigfpe.patch: Likewise.
+    - debian/patches/50_missing_keycodes.patch: Likewise.
+  * Added mips and mipsel to the lintian overrides for the user emulators
+    being shlib-with-non-pic-code.
+  * Added symlinks for mips, mipsel and system-arm emulator manpages.
+
+ -- Guillem Jover <guillem@debian.org>  Fri, 30 Dec 2005 05:44:53 +0200
+
+qemu (0.7.2-2) unstable; urgency=low
+
+  [ Josh Triplett ]
+  * Add support for signal handling on PowerPC. (Closes: #335509)
+    - debian/patches/12_signal_powerpc_support.patch: New file.
+
+  [ Guillem Jover ]
+  * Add Josh Triplett <josh@psas.pdx.edu> to Uploaders and packaging team.
+  * Fix PowerPC build failure by reintroducing the ppc linker script and
+    adding the missing _SDA_BASE_ and _SDA2_BASE_ symbols. (Closes: #336983)
+  * Remove invalid patch making X11 fail at runtime.
+    - debian/patches/20_net_socket.patch: Remove.
+    - debian/patches/32_syscall_sysctl.patch: Sync.
+    Thanks to Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>.
+  * Avoid the patch system to try until it applies.
+    - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Added patch level.
+    - debian/patches/12_signal_powerpc_support.patch: Likewise.
+
+ -- Guillem Jover <guillem@debian.org>  Wed, 21 Dec 2005 22:11:34 +0200
+
+qemu (0.7.2-1) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * New upstream release. (Closes: #321232, #327168)
+    - debian/patches/12_signal_silent.patch: Integrated upstream, remove.
+    - debian/patches/50_ppc_ldscript.patch: Likewise.
+    - debian/patches/33_syscall_truncate64.patch: Likewise.
+    - debian/patches/01_doc_typos.patch: Resync with upstream.
+    - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+    - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+    - debian/patches/10_signal_jobs.patch: Likewise.
+    - debian/patches/11_signal_sigaction.patch: Likewise.
+    - debian/patches/20_net_socket.patch: Likewise.
+    - debian/patches/21_net_sockopt.patch: Likewise.
+    - debian/patches/22_net_tuntap_stall.patch: Likewise.
+    - debian/patches/30_syscall_ipc.patch: Likewise.
+    - debian/patches/31_syscalls.patch: Likewise.
+    - debian/patches/32_syscall_sysctl.patch: Likewise.
+    - debian/patches/40_fpu_arm_sigfpe.patch: Likewise.
+  * Repackaged upstream source to deal with binaries w/o sources.
+    - pc-bios/video.x: New file removed.
+  * Create a new qemu-user(1) manpage and link all user emulator manpages
+    to it. (Closes: #335163)
+  * Add missing '-' and '=' keycodes for sendkey command.
+    - debian/patches/50_missing_keycodes.patch: New file. (Closes: #334071)
+    Thanks to Robert Millan <rmh@aybabtu.com>.
+  * Add manpage link for qemu-system-mips.
+  * Make sysctl byte-swap the name values.
+    - debian/patches/32_syscall_sysctl.patch: Merge patch. (Closes: #334458)
+    Thanks to Josh Triplett <josh@psas.pdx.edu>.
+  * Change documentation menu section to "Apps/Emulators". (Closes: #335062)
+    Thanks to Frans Pop <aragorn@tiscali.nl>.
+  * On PowerPC, do not zero registers r7-r31 in do_fork and zero register r3.
+    Fixing segfaults on programs using the clone syscall.
+    - debian/patches/33_syscall_ppc_clone.patch: New file. (Closes: #335159)
+    Thanks to Josh Triplett <josh@psas.pdx.edu>
+    and Paul Brook <paul@codesourcery.com>.
+  * Tighten vgabios and bochsbios versioned Depends.
+  * Add video.x to the list of roms to touch to make qemu Makefile happy.
+  * Add lintian overrides for the user emulators being shlib-with-non-pic-code.
+  * Wrap lines in debian/control fields (knowingly breaking policy).
+
+  [ Guilherme de S. Pastore ]
+  * debian/control:
+    - Updated my e-mail address.
+  * debian/copyright:
+    - Dropped André from team members list, not a single contribution ever.
+
+ -- Guillem Jover <guillem@debian.org>  Mon, 31 Oct 2005 05:01:45 +0200
+
+qemu (0.7.0-4) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * Rebuild source with locally deborked dpkg-source. (Closes: #321019)
+  * Added the location of the Subversion repo used for the packages and
+    fixed the upstream URL in debian/copyright.
+  * Lower case title header in qemu-make-debian-root man page.
+  * Use dd instead of cat to generate the qemu debian root image.
+    (Closes: #315952)
+
+ -- Guillem Jover <guillem@debian.org>  Wed,  3 Aug 2005 05:53:30 +0300
+
+qemu (0.7.0-3) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * Update watch file to version 3, use perlre and new upstream site.
+  * Now using Standards-Version 3.6.2 (no changes needed).
+  * Fix TUN/TAP network interface stalling the connection. (Closes: #290569)
+    Thanks to Vitaly Belostotsky <byly.useless@tochka.ru>.
+  * Link against librt, needed by the new clock_gettime syscall.
+    - debian/patches/31_syscalls.patch: Update. (Closes: #315388)
+    Thanks to Timo Savola <tsavola@movial.fi> for noticing.
+  * Force Build-Dependency on binutils >= 2.16-1 needed by the amd64 and
+    powerpc linker scripts. (Closes: #262655)
+  * Force usage of gcc-3.4. (Closes: #319527)
+  * Add missing Build-Dependency on zlib1g-dev.
+    Thanks to Reinhard Tartler <siretart@tauware.de>.
+  * Include <linux/types.h> in syscall.c to avoid the broken headers in 
+    linux-kernel-headers 2.6.12.
+    - debian/patches/34_syscalls_types.patch: New file.
+    Thanks to Octavian Cerna <tavy@ylabs.com>.
+  * Fix powerpc linker script.
+    - debian/patches/50_ppc_ldscript.patch: New file.
+    Thanks to Octavian Cerna <tavy@ylabs.com>.
+
+ -- Guillem Jover <guillem@debian.org>  Mon,  1 Aug 2005 02:48:09 +0300
+
+qemu (0.7.0-2) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * Add alpha, sparc, arm and s390 to Architectures (and to the
+    libgpmg1-dev Build-Depends).
+
+  * Forward SIGSTOP and SIGCONT sent to QEMU to the emulated application.
+    - debian/patches/10_signal_jobs.patch: New file.
+    Thanks to Ulrich Hecht.
+  * Return EINVAL on emulated sigaction when given invalid signal
+    parameters SIGKILL and SIGSTOP.
+    - debian/patches/11_signal_sigaction.patch: New fle.
+    Thanks to Valtteri Rahkonen.
+  * Do not print messsages for uncaught signal, thus fixing the case
+    were some applications want to kill their siblings.
+    - debian/patches/12_signal_silent.patch: New file.
+    Thanks to Valtteri Rahkonen
+
+  * Fix Unix sockets by handling correctly AF_UNIX socket address
+    structure length.
+    - debian/patches/20_net_socket.patch: New file.
+    Thanks to Timo Savola.
+  * Implement SO_LINGER, SO_RCVTIMEO, SO_SNDTIMEO, SO_PEERNAME and
+    SO_PEERCRED getsockoptions.
+    - debian/patches/21_net_sockopt.patch: New file.
+    Thanks to Valtteri Rahkonen.
+
+  * Implement SysV IPC message and semaphore syscalls.
+    - debian/patches/30_syscall_ipc.patch: New file.
+    Thanks to Valtteri Rahkonen.
+  * Implement acct, umount2, uselib, swapon, syslog, ftruncate64,
+    mincore, madvise, readahead and clock_gettime syscalls.
+    - debian/patches/31_syscalls.patch: New file.
+    Thanks to Ulrich Hecht.
+  * Implement sysctl CTL_KERN/KERN_VERSION
+    - debian/patches/32_syscall_sysctl.patch: New file.
+    Thanks to Timo Savola.
+  * Implement truncate64 syscall.
+    - debian/patches/33_syscall_truncate64.patch: New file.
+    Thanks to Valtteri Rahkonen.
+
+  * Implement ARM floating point exeption emulation.
+    - debian/patches/40_fpu_arm_sigfpe.patch: New file.
+    Thanks to Ulrich Hecht.
+
+ -- Guillem Jover <guillem@debian.org>  Sun, 19 Jun 2005 15:05:37 +0300
+
+qemu (0.7.0-1) experimental; urgency=low
+
+  [ Guillem Jover ]
+  * New upstream release. (Closes: #308459, #308494)
+  * Do not require a disk image when booting a Linux kernel. (Closes: #260935)
+    Thanks to Jonas Smedegaard <dr@jones.dk>.
+
+  [ Guilherme de S. Pastore ]
+  * Rewrote README.Debian for more clarity
+  * Add support for amd64 as a host architecture. (Closes: #262655)
+    - Add build-depend on libgpmg1-dev on amd64.
+  * Fixed qemu-make-debian-root so that it shows the name by which
+    it was called on the usage notice, not "%s". (Closes: #303507)
+    Thanks to Micah Anderson <micah@riseup.net>.
+
+  [ Elrond ]
+  * Clean up more files, so they don't end up in the final .diff.gz
+  * Switch to external proll and openhackware:
+    - Instead of patching qemu's Makefile, trick it by giving it empty
+      files to install and remove them straight after install.
+    - Don't ship the roms in debian/roms any more!
+    - Instead add more symlinks.
+    - Update Depends: apropiately.
+
+ -- Guillem Jover <guillem@debian.org>  Fri, 27 May 2005 02:06:20 +0300
+
+qemu (0.6.1+20050407-1) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * New upstream snapshot.
+    - Fix -user-net. (Closes: #295019)
+    - Fix win2k and winxp image booting. (Closes: #285170, #292707)
+    - Fix installation of outdated documentation. (Closes: #286931)
+    - Provide qemu-img instead of qemu-mkcow. (Closes: #290713)
+    - Remove debian/patches/05_fix_openpic_timer_test.patch, integrated
+      upstream.
+    - Remove debian/patches/02_selectable_sdl_keyboard.patch, superseded
+      by new keyboard implementation. (Closes: #284510, #299432)
+    - Remove debian/patches/01_mkcow_section_and_hyphens.patch.
+    - Conditionalize qemu -g option for some architectures. (Closes: #298988)
+  * Added new copyright year to debian/copyright.
+  * Added initial qemu-make-debian-root man page. (Closes: #286932)
+  * Fixed typos in qemu documentation. (Closes: #301933)
+    Thanks to A Costa <agcosta@gis.net>.
+  * Added Elrond <elrond@samba-tng.org> to Uploaders and packaging team.
+  * Use the default target list:
+    - Do not build qemu-fast anymore as it is deprecated upstream anyway.
+    (Closes: #278602, #281510)
+    - New targets armeb and system-x86_64.
+  * Updated ROM images under debian/roms/:
+    - OpenHackWare 0.4.
+    - Proll 18 with qemu specific patches.
+  * Remove uudecoded files from pc-bios/ on clean.
+  * Fix qemu-make-debian-root to behave correctly even if the needed
+    Recommends are not installed.
+
+  [ Guilherme de S. Pastore ]
+  * Create a doc-base entry for the package (Closes: #290669)
+  * debian/control:
+    - Add debootstrap to the 'Recommends: ' line, as needed by
+      qemu-make-debian-root (Closes: #302848)
+    - Moved sharutils from dependency to recommendation, as it is only
+      needed by qemu-make-debian-root
+  * debian/docs:
+    - Do not include README.distrib in the binary package (Closes: #302853)
+
+  [ Elrond ]
+  * Replace "libgpmg1-dev | not+linux-gnu" by "libgpmg1-dev [i386 powerpc]"
+    in Build-Depends. qemu should not need to build-depend on it anyway, the
+    real problem is described in Bug#267174. When it is solved, we can
+    remove our dependency. Until then please remember to add any arch, which
+    we will build on and that has gpm. This change hopefully calms:
+    <http://qa.debian.org/debcheck.php?dist=unstable&package=qemu>
+  * Add versions to the dependencies on bochsbios and vgabios
+    (Closes: #288997):
+    - vgabios: Use the current version from testing/unstable (0.4c+20041014-1),
+      according to Frans Pop <aragorn@tiscali.nl>, this fixed those
+      "blank screen" problems.
+    - bochsbios: Use the current version from unstable (2.1.1+20041109-3), as
+      Guillem Jover fixed the networking in that version.
+
+ -- Guillem Jover <guillem@debian.org>  Thu,  7 Apr 2005 01:26:01 +0300
+
+qemu (0.6.1-1) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * New upstream release. (Closes: #281626)
+    - Booting from drive b is not supported anymore. (Closes: #275679)
+    - Fix ne2k network interface that was not working in some situations.
+      (Closes: #281862)
+    - Remove debian/patches/06_build_gcc3.4.patch, fixed upstream.
+    - Remove debian/patches/04_lfs.patch, fixed upstream.
+    - Remove debian/patches/02_fix_powerpc_FTBFS.patch, fixed upstream.
+    - Remove debian/patches/00_escape_manpage_hyphens.patch, not needed.
+    - Sync debian/patches/03_use_external_bios.patch.
+  * Include uuencoded source for proll 18, some build fixes and its binary
+    proll.bin on debian/roms/.
+  * Suggests sudo to be used by the qemu-ifup script.
+    Thanks to Elrond <elrond@samba-tng.org>.
+  * Make sudo in qemu-ifup explain what the password is for. (Closes: #281380)
+  * Add an option to select the method to convert keyevent to keycode
+    in the SDL keyboard handling code. Added support for Right Shift in the
+    generic handler. (Closes: #282658)
+    Thanks to Elrond <elrond@samba-tng.org>.
+  * Do not set RTC frequency to 1024 or warn about this if it has already
+    the correct value. (Closes: #281403)
+  * Enabled sparc-softmmu support.
+
+ -- Guillem Jover <guillem@debian.org>  Sat, 27 Nov 2004 23:23:49 +0100
+
+qemu (0.6.0.dfsg.2-1) unstable; urgency=low
+
+  [ Guillem Jover ]
+  * Repackaged upstream source to remove external included files.
+    - pc-bios/ppc-rom.bin: Removed.
+    - pc-bios/OpenHackWare_0.3.tar.bz2: Likewise.
+    - pc-bios/vgabios.bin: Likewise.
+    - pc-bios/vgabios-cirrus.bin: Likewise.
+    - pc-bios/vgabios-cvs-2004-06-17.tgz: Likewise.
+  * Include uuencoded source for OpenHackWare 0.3.1 and its binary
+    ppc-rom.bin on debian/roms/. Add a Build-Depends on sharutils.
+  * Update tundev.c. Pass -tun-dev to qemu without the equal sign.
+    Thanks to Isaac Clerencia <isaac@sindominio.net>.
+  * Fix README.Debian to point to the renamed qemu-make-debian-root.
+  * Add Depends on sharutils needed by qemu-make-debian-root.
+    (Closes: #272130)
+  * Use and depend on vgabios package, which is in sync with bochsbios
+    that checks for rom bios checksums. (Closes: #281202)
+  * Enable LFS globally, thus fixing problems with qemu-mkcow when using
+    an existing large image.
+    (Closes: #279925)
+  * Fix openpic timer write test, catched from a warning about a constant
+    value larger than the type it was casted to.
+  * Fix build failure with gcc 3.4. Patch stolen from Gentoo BTS.
+
+ -- Guillem Jover <guillem@debian.org>  Mon, 15 Nov 2004 10:46:54 +0100
+
+qemu (0.6.0.dfsg.1-1) unstable; urgency=high
+
+  [ Guillem Jover ]
+  * Repackaged upstream source to deal with binaries w/o sources.
+    (Closes: #268780)
+    - pc-bios/bios.bin: Removed binary without source. Now using
+      bochsbios package.
+    - pc-bios/vgabios.bin: Rebuilt from vgabios cvs 2004-06-17 snapshot,
+      source included.
+    - pc-bios/vgabios-cirrus.bin: Likewise.
+    - pc-bios/ppc-rom.bin: Rebuilt on voltaire, source included.
+    - pc-bios/linux_boot.bin: Rebuilt from source.
+  * Move make-debian-root.sh to /usr/sbin/qemu-make-debian-root.
+    (Closes: #268705)
+
+ -- Guillem Jover <guillem@debian.org>  Mon, 13 Sep 2004 01:28:54 +0200
+
+qemu (0.6.0-2) unstable; urgency=high
+
+  [ Guilherme de S. Pastore ]
+  * Fixed dangling symlinks under /usr/share/man/man1. (Closes: #264764)
+
+  [ Guillem Jover ]
+  * Fix FTBFS on powerpc.
+    - debian/patches/02_fix_powerpc_FTBFS.patch: New file.
+
+ -- Guillem Jover <guillem@debian.org>  Wed, 18 Aug 2004 15:50:43 +0200
+
+qemu (0.6.0-1) unstable; urgency=medium
+
+  * New maintainers. (Closes: #258900)
+  * New upstream release. (Closes: #258732)
+    - Installs ppc BIOS ROM file. (Closes: #257492)
+    - Builds with -fno-strict-aliasing. (Closes: #257123)
+
+  [ Guilherme de S. Pastore ]
+  * debian/rules:
+    - Cleaned up.
+    - Ported to use CDBS.
+  * 00_escape_manpage_hyphens.patch:
+    - Correct a little typo and escape hyphens in upstream manpage.
+  * 01_mkcow_section_and_hyphens.patch:
+    - Fix section mismatch and escape hyphens in the qemu-mkcow manpage.
+  * Added simple /etc/qemu-ifup helper script. (Closes: #245281)
+    Thanks to Martin Michlmayr <tbm@cyrius.com>.
+  * Cleaned debian/watch.
+  * UTF-8'ed debian/changelog.
+  * Updated Standards-Version to 3.6.1.1.
+  * Removed outdated and unnecessary debian/qemu-i386.sgml.
+    - Removed build dependency on docbook-to-man.
+  * Removed "x86" part from the description (hey, qemu is not x86-only
+    in any way). Deserves a complete rewrite, shall be done soon.
+
+  [ Guillem Jover ]
+  * Lower-case package short description.
+  * Added missing CPU emulations to the description.
+  * Cleaned and updated debian/copyright.
+  * Removed manually added libx11-6 dependency.
+  * Only Build-Depends on libgpmg1-dev on GNU/Linux systems.
+  * Cosmetic unification to debian/changelog.
+  * debian/rules:
+    - Remove generated files.
+    - Give exec perms to qemu-ifup.
+
+ -- Guillem Jover <guillem@debian.org>  Sun,  8 Aug 2004 17:24:08 +0200
+
+qemu (0.5.5-2) unstable; urgency=low
+
+  * Re-enable SDL disabled while I was bugchasing. (Closes: #255014)
+  * Yes, this is really 0.5.5. (Closes: #254655)
+  * Enable slirp networking. (Closes: #253573)
+  * Add Build-Depends on libgpmg1-dev (found by Bastian Blank, probably breaks
+    Hurd but that's a problem for another day).
+
+ -- Paul Russell <prussell@debian.org>  Thu, 24 Jun 2004 06:26:42 +0200
+
+qemu (0.5.5-1) unstable; urgency=low
+
+  * New upstream release. (Closes: #237556, #237556)
+  * Applied patch to add options to make_debian_root.sh. (Closes: #238787)
+  * Applied patch for other archs: hmmm... (Closes: #251420)
+  * Do umount -d in make_debian_root.sh. (Closes: #251775)
+
+ -- Paul Russell <prussell@debian.org>  Tue,  1 Jun 2004 03:50:05 +0200
+
+qemu (0.5.4-1) unstable; urgency=low
+
+  * New upstream release. (Closes: #246634)
+  * qemu-mkcow included in upstream.
+  * Added tundev program source in doc, to see if people find it useful.
+
+ -- Paul Russell <prussell@debian.org>  Mon,  3 May 2004 08:14:49 +0200
+
+qemu (0.5.3-1) unstable; urgency=low
+
+  * New upstream release. (Closes: #237556)
+  * Use aalib-config --static-libs. (Closes: #243325)
+  * Document Control-Shift to release mouse pointer. (Closes: #238074)
+
+ -- Paul Russell <prussell@debian.org>  Tue, 13 Apr 2004 02:58:49 +0200
+
+qemu (0.5.2-4) unstable; urgency=low
+
+  * Fix PPC install (Michel Daenzer patch). (Closes: #238431)
+  * Simplify deps (might be wrong, but it's neater). (Closes: #238430)
+
+ -- Paul Russell <prussell@debian.org>  Wed, 17 Mar 2004 01:35:47 +0100
+
+qemu (0.5.2-3) unstable; urgency=low
+
+  * Make compile on woody. (Closes: #238163)
+  * Include qemu-doc.html. (Closes: #238076)
+  * Wrote qemu-i386 man page. (Closes: #238077)
+
+ -- Paul Russell <prussell@debian.org>  Mon, 15 Mar 2004 23:56:25 +0100
+
+qemu (0.5.2-2) unstable; urgency=low
+
+  * Fix build problem so bios.bin etc. can be found. (Closes: #237553)
+
+ -- Paul Russell <prussell@debian.org>  Fri, 12 Mar 2004 05:43:00 +0100
+
+qemu (0.5.2-1) unstable; urgency=low
+
+  * Initial Release. (Closes: #187407)
+
+ -- Paul Russell <prussell@debian.org>  Wed,  3 Mar 2004 02:18:54 +0100
+
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7ed6ff8
--- /dev/null
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..49163b6
--- /dev/null
@@ -0,0 +1,34 @@
+Source: qemu
+Section: misc
+Priority: optional
+Maintainer: Maemo Integration <integration@maemo.org>
+Build-Depends: debhelper (>= 5), quilt (>= 0.40), binutils (>= 2.16), nasm,
+ libx11-dev, libsdl1.2-dev (>> 1.2.1), libncurses5-dev, zlib1g-dev,
+ texi2html, sharutils, libgnutls-dev, libesd0-dev, etherboot,
+ libpulse-dev,
+ libfreebsd-dev [kfreebsd-i386 kfreebsd-amd64], 
+ libasound2-dev [!kfreebsd-i386 !kfreebsd-amd64],
+ libbluetooth-dev [!kfreebsd-i386 !kfreebsd-amd64],
+ libgpmg1-dev [amd64 arm armel hppa i386 powerpc sparc ppc64],
+Standards-Version: 3.8.0
+
+Package: sb2-qemu-arm
+Architecture: amd64 i386 powerpc
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Qemu for scratchbox2
+ Qemu packaging for sb2. This should become eventually temporary
+ when mainstream qemu merges any remaining patches.
+
+Package: scratchbox-devkit-qemu
+Architecture: i386
+Depends: ${shlibs:Depends}, ${misc:Depends}, scratchbox-core (>= 1.0.12)
+Description: Qemu scratchbox devkit
+ The qemu for the scratchbox1 lovers.
+
+Package: sb-system-qemu
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Recommends: sbrsh
+Description: System qemu for scratchbox
+ This package includes system qemu to be used with scratchbox and sbrsh
+ for cpu transparency.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..35348bd
--- /dev/null
@@ -0,0 +1,53 @@
+This package was debianized by Paul Russell <prussell@debian.org> on
+Wed,  3 Mar 2004 02:18:54 +0100.
+
+Then maintained as part of the team by:
+
+    Guilherme de S. Pastore <gpastore@debian.org>
+    Elrond <elrond@samba-tng.org>
+    Guillem Jover <guillem@debian.org>
+
+Now maintained as a team by:
+
+    Aurelien Jarno <aurel32@debian.org>
+    Josh Triplett <josh@psas.pdx.edu>
+    Riku Voipio <riku@debian.org>
+
+The upstream source was downloaded from:
+
+    <http://www.qemu.org/download.html>
+
+    All the binary blobs without sources contained in the pc-bios/ directory
+    in the original upstream tarball have been removed starting from Debian
+    package version 0.6.0.dfsg.1-1. Those roms which are free can be found
+    in split packages of their own, represented accordingly in the dependecy
+    relationships.
+
+Upstream Author:
+
+    Fabrice Bellard <fabrice.bellard@free.fr>
+
+Copyright:
+
+    Copyright (C) 2003, 2004, 2005, 2006, 2007  Fabrice Bellard
+
+License:
+
+    QEMU as a whole is released under the GNU General Public License.
+    On Debian systems, the complete text of the GNU General Public License
+    can be found in the file /usr/share/common-licenses/GPL.
+
+    Parts of QEMU have specific licenses which are compatible with the
+    GNU General Public License. Hence each source file contains its own
+    licensing information.
+
+    In particular, the QEMU virtual CPU core library (libqemu.a) is
+    released under the GNU Lesser General Public License. On Debian systems,
+    the complete text of the GNU Lesser General Public License can be found
+    in the file /usr/share/common-licenses/LGPL.
+
+    Many hardware device emulation sources are released under the BSD license.
+    On Debian systems, the complete text of the BSD license be found in the
+    file /usr/share/common-licenses/BSD.
+
+
diff --git a/debian/cputransp-methods b/debian/cputransp-methods
new file mode 100644 (file)
index 0000000..164f458
--- /dev/null
@@ -0,0 +1,7 @@
+qemu-arm-sb
+qemu-armeb-sb
+qemu-i386-sb
+qemu-mips-sb
+qemu-mipsel-sb
+qemu-ppc-sb
+qemu-sparc-sb
diff --git a/debian/overrides/qemu b/debian/overrides/qemu
new file mode 100644 (file)
index 0000000..5e81b13
--- /dev/null
@@ -0,0 +1,7 @@
+qemu: shlib-with-non-pic-code usr/bin/qemu-ppc
+qemu: shlib-with-non-pic-code usr/bin/qemu-sparc
+qemu: shlib-with-non-pic-code usr/bin/qemu-i386
+qemu: shlib-with-non-pic-code usr/bin/qemu-arm
+qemu: shlib-with-non-pic-code usr/bin/qemu-armeb
+qemu: shlib-with-non-pic-code usr/bin/qemu-mips
+qemu: shlib-with-non-pic-code usr/bin/qemu-mipsel
diff --git a/debian/qemu-user.1 b/debian/qemu-user.1
new file mode 100644 (file)
index 0000000..c9e1e9e
--- /dev/null
@@ -0,0 +1,38 @@
+.\" $Id: qemu-user.1 325 2008-08-09 21:39:16Z aurel32 $
+.TH qemu\-user 1 2007-02-08 "0.9.0" Debian
+.SH NAME
+qemu\-user \- QEMU User Emulator
+.SH SYNOPSIS
+.B qemu\-user
+.RI [ options ]
+.I program
+.RI [ program-arguments... ]
+.SH DESCRIPTION
+The
+.B qemu\-user
+emulator can run binaries for other architectures but with the same operating
+system as the current one.
+.SH OPTIONS
+.TP
+.BR \-h
+Print this help.
+.TP
+.BR \-g
+Wait gdb connection to port 1234.
+.TP
+.BR \-L " \fI<path>\fP"
+Set the elf interpreter prefix (default=\fI/usr/gnemul/qemu\-arm\fP).
+.TP
+.BR \-s " \fI<size>\fP"
+Set the stack size in bytes (default=\fI524288\fP).
+.TP
+.BR \-d " \fI<options>\fP"
+Activate log (logfile=\fI/tmp/qemu.log\fP)
+.TP
+.BR \-p " \fI<pagesize>\fP"
+Set the host page size to 'pagesize'.
+.SH SEE ALSO
+.BR qemu (1),
+.BR qemu\-img (1).
+.SH AUTHOR
+This manual page was written by Guillem Jover <guillem@debian.org>.
diff --git a/debian/qemu.dirs b/debian/qemu.dirs
new file mode 100644 (file)
index 0000000..58660d4
--- /dev/null
@@ -0,0 +1 @@
+usr/share/qemu/
diff --git a/debian/qemu.doc-base b/debian/qemu.doc-base
new file mode 100644 (file)
index 0000000..d3b0f8a
--- /dev/null
@@ -0,0 +1,12 @@
+Document: qemu-doc
+Title: QEMU User Manual
+Author: Fabrice Bellard
+Abstract: The QEMU user manual intends to make the user understand what
+ qemu is/does, and to guide them through the first steps of getting
+ the emulator to work, documenting parameters and commands, among other
+ useful things.
+Section: Emulators
+
+Format: HTML
+Index: /usr/share/doc/qemu/qemu-doc.html
+Files: /usr/share/doc/qemu/qemu-doc.html
diff --git a/debian/qemu.docs b/debian/qemu.docs
new file mode 100644 (file)
index 0000000..d227b95
--- /dev/null
@@ -0,0 +1,4 @@
+README
+TODO
+qemu-doc.html
+debian/tundev.c
diff --git a/debian/qemu.install b/debian/qemu.install
new file mode 100644 (file)
index 0000000..f3da625
--- /dev/null
@@ -0,0 +1,3 @@
+debian/qemu-ifup etc/
+debian/qemu-make-debian-root usr/sbin/
+debian/overrides/qemu usr/share/lintian/overrides/
diff --git a/debian/qemu.links b/debian/qemu.links
new file mode 100644 (file)
index 0000000..8f0732b
--- /dev/null
@@ -0,0 +1,40 @@
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-alpha.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-cris.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-arm.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-armeb.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-i386.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-m68k.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-mips.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-mipsel.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-ppc.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-ppc64.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-ppc64abi32.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sh4.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sh4eb.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sparc.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sparc32plus.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-sparc64.1
+usr/share/man/man1/qemu-user.1 usr/share/man/man1/qemu-x86_64.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-arm.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-cris.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-i386.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-m68k.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mips.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mips64.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mips64el.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-mipsel.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-ppc.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-ppc64.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-ppcemb.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sh4.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sh4eb.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sparc.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-sparc64.1
+usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-x86_64.1
+usr/share/bochs/BIOS-qemu-latest usr/share/qemu/bios.bin
+usr/share/vgabios/vgabios.bin usr/share/qemu/vgabios.bin
+usr/share/vgabios/vgabios.cirrus.bin usr/share/qemu/vgabios-cirrus.bin
+usr/share/proll/proll-qemu.elf usr/share/qemu/proll.elf
+usr/share/openhackware/ppc_rom.bin usr/share/qemu/ppc_rom.bin
+usr/share/openbios/openbios-sparc32 usr/share/qemu/openbios-sparc32
+usr/share/openbios/openbios-sparc64 usr/share/qemu/openbios-sparc64
diff --git a/debian/qemu.manpages b/debian/qemu.manpages
new file mode 100644 (file)
index 0000000..ae4f28d
--- /dev/null
@@ -0,0 +1,2 @@
+debian/qemu-make-debian-root.8
+debian/qemu-user.1
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..b0743d8
--- /dev/null
@@ -0,0 +1,154 @@
+#!/usr/bin/make -f
+#
+# $Id: rules 366 2008-12-23 16:19:26Z aurel32 $
+#
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+       CFLAGS = -O0
+endif
+
+# Support multiple makes at once
+ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+NJOBS := -j $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+endif
+
+# Architecture/system specific configuration
+DEB_HOST_ARCH_OS = $(shell dpkg-architecture -qDEB_HOST_ARCH_OS)
+DEB_HOST_ARCH_CPU = $(shell dpkg-architecture -qDEB_HOST_ARCH_CPU)
+
+
+TARGET_SYSTEM_TCG    = arm-softmmu i386-softmmu
+TARGET_LINUX_TCG     = arm-linux-user i386-linux-user
+package_list         = obj-sb2/config-host.mak obj-system/config-host.mak
+install_list         = sb2-qemu-install sb-system-qemu-install
+sb1_prefix           = /scratchbox/devkits/qemu
+
+target_system_list = $(TARGET_SYSTEM_TCG)
+
+ifeq ($(DEB_HOST_ARCH_OS),linux)
+       conf_arch += --audio-drv-list=sdl
+       target_linux_list += $(TARGET_LINUX_TCG)
+endif
+ifeq ($(DEB_HOST_ARCH_OS),kfreebsd)
+       conf_arch += --audio-drv-list=oss,sdl,esd,pa
+endif
+
+BUILD_SB1_QEMU=$(shell test -r /scratchbox/tools/lib/libsb.a && echo YES || echo NO)
+
+ifeq ($(DEB_HOST_ARCH_CPU),i386)
+       conf_arch += --cpu=i386
+ifeq ($(BUILD_SB1_QEMU),YES)
+       package_list += obj-sb1/config-host.mak
+       install_list += sb1-qemu-install
+       sb1_target_list += arm-linux-user ppc-linux-user sparc-linux-user i386-linux-user armeb-linux-user mips-linux-user mipsel-linux-user
+endif
+endif
+ifeq ($(DEB_HOST_ARCH_CPU),sparc)
+       conf_arch += --cpu=sparc
+endif
+
+qemu_docs = \
+       qemu-doc.html \
+       qemu-tech.html \
+       qemu.1 \
+       qemu-img.1
+
+obj-sb2/config-host.mak: configure
+       dh_testdir
+       mkdir obj-sb2
+       ( cd obj-sb2; CFLAGS="$(CFLAGS)" ../configure \
+               --prefix=/usr \
+               --interp-prefix=/ \
+               --disable-blobs \
+               --enable-guest-base \
+               --target-list="$(target_linux_list)" \
+               $(conf_arch) )
+       ( cd obj-sb2; $(MAKE) $(NJOBS) )
+
+obj-sb1/config-host.mak: configure
+       dh_testdir
+       mkdir obj-sb1
+       ( cd obj-sb1; CFLAGS="$(CFLAGS) $(SB1_CFLAGS)"  ../configure \
+               --prefix=$(sb1_prefix) \
+               --interp-prefix=/ \
+               --static \
+               --enable-guest-base \
+               --target-list="$(sb1_target_list)"\
+               --disable-kqemu --disable-sdl )
+       ( cd obj-sb1; $(MAKE) $(NJOBS) )
+
+obj-system/config-host.mak: configure
+       dh_testdir
+       mkdir obj-system
+       ( cd obj-system; CFLAGS="$(CFLAGS)" ../configure \
+               --prefix=/usr \
+               --interp-prefix=/ \
+               --disable-blobs \
+               --enable-guest-base \
+               --target-list="$(target_system_list)" \
+               $(conf_arch) )
+       ( cd obj-system; $(MAKE) $(NJOBS) )
+
+build: $(package_list)
+
+clean:
+       dh_testdir
+       dh_testroot
+       [ ! -f config-host.mak ] || $(MAKE) distclean
+       rm -rf obj-sb1 obj-sb2 obj-system
+       rm -f $(qemu_docs)
+       dh_clean
+
+# cputransp-methods should be generated at postinst
+sb1-qemu-install:
+       mkdir -p debian/scratchbox-devkit-qemu/$(sb1_prefix)/{bin,etc}
+       cp debian/cputransp-methods \
+               debian/scratchbox-devkit-qemu/$(sb1_prefix)/etc
+       for i in obj-sb1/*-linux-user/qemu-* ; do \
+               install -m 755 $$i debian/scratchbox-devkit-qemu/$(sb1_prefix)/bin/`basename $$i`-sb ; \
+       done
+
+sb2-qemu-install:
+       mkdir -p debian/sb2-qemu-arm/usr/bin
+       cp obj-sb2/arm-linux-user/qemu-arm debian/sb2-qemu-arm/usr/bin/sb2-qemu-arm
+       cp obj-sb2/i386-linux-user/qemu-i386  debian/sb2-qemu-arm/usr/bin/sb2-qemu-i386
+
+sb-system-qemu-install:
+       mkdir -p debian/sb-system-qemu/usr/bin
+       cp obj-system/arm-softmmu/qemu-system-arm  debian/sb-system-qemu/usr/bin/sb-qemu-system-arm
+       cp obj-system/i386-softmmu/qemu  debian/sb-system-qemu/usr/bin/sb-qemu-system-i386
+
+install: build $(install_list)
+       dh_testdir
+       dh_testroot
+#      dh_clean -k
+       dh_installdirs -a
+
+binary-indep:
+# Nothing to do.
+
+binary-arch: install
+       dh_testdir
+       dh_testroot
+#      dh_install -a
+#      dh_installdebconf -a
+       dh_installdocs -s
+       dh_installexamples -s
+#      dh_installlogrotate -a
+       dh_installman -s
+       dh_installinfo -s
+       dh_installchangelogs -s Changelog
+       dh_link -s
+       dh_strip -s
+       dh_compress -s
+       dh_fixperms -s
+       dh_installdeb -s
+       dh_shlibdeps -s
+       dh_gencontrol -s
+       dh_md5sums -s
+       dh_builddeb -s
+
+binary: binary-indep binary-arch
+
+.PHONY: build clean binary-indep binary-arch binary install
+
diff --git a/debian/tundev.c b/debian/tundev.c
new file mode 100644 (file)
index 0000000..43ed62a
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * $Id: tundev.c 325 2008-08-09 21:39:16Z aurel32 $
+ */
+
+#define _GNU_SOURCE /* asprintf */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+
+/* Tiny code to open tap/tun device, and hand the fd to qemu.
+   Run as root, drops to given user. */
+int main(int argc, char *argv[])
+{
+       struct ifreq ifr;
+       struct passwd *p;
+       unsigned int i;
+       char *newargs[argc + 1];
+       int fd;
+
+       if (argc < 4) {
+               fprintf(stderr,
+                       "Usage: tundev user logfile qemu <qemu options>...\n");
+               exit(1);
+       }
+
+       fd = open("/dev/net/tun", O_RDWR);
+       if (fd < 0) {
+               perror("Could not open /dev/net/tun");
+               exit(1);
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+       strncpy(ifr.ifr_name, "tun%d", IFNAMSIZ);
+       if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) {
+               perror("Could not get tun device");
+               exit(1);
+       }
+
+       /* Set userid. */
+       p = getpwnam(argv[1]);
+       if (!p) {
+               fprintf(stderr, "No user '%s'\n", argv[1]);
+               exit(1);
+       }
+       setgroups(0, NULL);
+       setgid(p->pw_gid);
+       if (setuid(p->pw_uid) != 0) {
+               perror("setting uid");
+               exit(1);
+       }
+
+       /* Insert -tun-fd */
+       newargs[0] = argv[3];
+       newargs[1] = "-tun-fd";
+       asprintf(&newargs[2], "%d", fd);
+       for (i = 4; i <= argc; i++)
+               newargs[i-1] = argv[i];
+
+       if (strcmp(argv[2], "-") == 0) {
+               execvp(newargs[0], newargs);
+               exit(1);
+       }
+
+       switch (fork()) {
+       case 0: {
+               close(1);
+               close(2);
+               open(argv[2], O_WRONLY|O_APPEND);
+               open(argv[2], O_WRONLY|O_APPEND);
+               close(0);
+               execvp(newargs[0], newargs);
+               exit(1);
+       }
+       case -1:
+               perror("fork failed");
+               exit(1);
+       }
+       printf("%s\n", ifr.ifr_name);
+       exit(0);
+}
diff --git a/debian/watch b/debian/watch
new file mode 100644 (file)
index 0000000..b33ee8e
--- /dev/null
@@ -0,0 +1,3 @@
+version=3
+
+http://bellard.org/qemu/download.html  qemu-([\d.]*).tar.gz    debian  uupdate
diff --git a/elf.h b/elf.h
index 861f1d3..4baf2c7 100644 (file)
--- a/elf.h
+++ b/elf.h
@@ -1079,7 +1079,23 @@ typedef struct elf64_shdr {
 #define        EI_CLASS        4
 #define        EI_DATA         5
 #define        EI_VERSION      6
-#define        EI_PAD          7
+#define        EI_OSABI        7
+#define        EI_PAD          8
+
+#define ELFOSABI_NONE           0       /* UNIX System V ABI */
+#define ELFOSABI_SYSV           0       /* Alias.  */
+#define ELFOSABI_HPUX           1       /* HP-UX */
+#define ELFOSABI_NETBSD         2       /* NetBSD.  */
+#define ELFOSABI_LINUX          3       /* Linux.  */
+#define ELFOSABI_SOLARIS        6       /* Sun Solaris.  */
+#define ELFOSABI_AIX            7       /* IBM AIX.  */
+#define ELFOSABI_IRIX           8       /* SGI Irix.  */
+#define ELFOSABI_FREEBSD        9       /* FreeBSD.  */
+#define ELFOSABI_TRU64          10      /* Compaq TRU64 UNIX.  */
+#define ELFOSABI_MODESTO        11      /* Novell Modesto.  */
+#define ELFOSABI_OPENBSD        12      /* OpenBSD.  */
+#define ELFOSABI_ARM            97      /* ARM */
+#define ELFOSABI_STANDALONE     255     /* Standalone (embedded) application */
 
 #define        ELFMAG0         0x7f            /* EI_MAG */
 #define        ELFMAG1         'E'
@@ -1106,6 +1122,7 @@ typedef struct elf64_shdr {
 #define NT_PRFPREG     2
 #define NT_PRPSINFO    3
 #define NT_TASKSTRUCT  4
+#define NT_AUXV                6
 #define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
 
 
diff --git a/exec.c b/exec.c
index 5e94a8f..a575ab3 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -2070,36 +2070,29 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
     return 0;
 }
 
-/* dump memory mappings */
-void page_dump(FILE *f)
+void walk_memory_regions(void *priv,
+    int (*fn)(void *, unsigned long, unsigned long, unsigned long))
 {
     unsigned long start, end;
+    PageDesc *p = NULL;
     int i, j, prot, prot1;
-    PageDesc *p;
 
-    fprintf(f, "%-8s %-8s %-8s %s\n",
-            "start", "end", "size", "prot");
-    start = -1;
-    end = -1;
+    start = end = -1;
     prot = 0;
-    for(i = 0; i <= L1_SIZE; i++) {
-        if (i < L1_SIZE)
-            p = l1_map[i];
-        else
-            p = NULL;
-        for(j = 0;j < L2_SIZE; j++) {
-            if (!p)
-                prot1 = 0;
-            else
-                prot1 = p[j].flags;
+
+    for (i = 0; i <= L1_SIZE; i++) {
+        p = (i < L1_SIZE) ? l1_map[i] : NULL;
+        for (j = 0; j < L2_SIZE; j++) {
+            prot1 = (p == NULL) ? 0 : p[j].flags;
+            /*
+             * "region" is one continuous chunk of memory
+             * that has same protection flags set.
+             */
             if (prot1 != prot) {
                 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
                 if (start != -1) {
-                    fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
-                            start, end, end - start,
-                            prot & PAGE_READ ? 'r' : '-',
-                            prot & PAGE_WRITE ? 'w' : '-',
-                            prot & PAGE_EXEC ? 'x' : '-');
+                    if ((*fn)(priv, start, end, prot) != 0)
+                        goto out;
                 }
                 if (prot1 != 0)
                     start = end;
@@ -2107,10 +2100,34 @@ void page_dump(FILE *f)
                     start = -1;
                 prot = prot1;
             }
-            if (!p)
+            if (p == NULL)
                 break;
         }
     }
+out:
+    ; /* null statement to make compiler happy */
+}
+
+static int dump_region(void *priv, unsigned long start,
+    unsigned long end, unsigned long prot)
+{
+    FILE *f = (FILE *)priv;
+
+    (void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
+        start, end, end - start,
+        ((prot & PAGE_READ) ? 'r' : '-'),
+        ((prot & PAGE_WRITE) ? 'w' : '-'),
+        ((prot & PAGE_EXEC) ? 'x' : '-'));
+
+    return (0);
+}
+
+/* dump memory mappings */
+void page_dump(FILE *f)
+{
+    (void) fprintf(f, "%-8s %-8s %-8s %s\n",
+            "start", "end", "size", "prot");
+    walk_memory_regions(f, dump_region);
 }
 
 int page_get_flags(target_ulong address)
@@ -2830,7 +2847,7 @@ static int get_free_io_mem_idx(void)
             io_mem_used[i] = 1;
             return i;
         }
-
+    fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
     return -1;
 }
 
diff --git a/hw/beagle.c b/hw/beagle.c
new file mode 100644 (file)
index 0000000..613d1c2
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Beagle board emulation. http://beagleboard.org/
+ * 
+ * Original code Copyright (C) 2008 yajin(yajin@vm-kernel.org)
+ * Rewrite Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "omap.h"
+#include "arm-misc.h"
+#include "boards.h"
+#include "i2c.h"
+#include "net.h"
+#include "devices.h"
+#include "flash.h"
+
+#define BEAGLE_NAND_CS       0
+#define BEAGLE_SMC_CS        1
+#define BEAGLE_NAND_PAGESIZE 0x800
+#define BEAGLE_SDRAM_SIZE    (128 * 1024 * 1024) /* 128MB */
+
+/* Beagle board support */
+struct beagle_s {
+    struct omap_mpu_state_s *cpu;
+    
+    struct nand_flash_s *nand;
+    struct omap3_lcd_panel_s *lcd_panel;
+    i2c_bus *i2c;
+    struct twl4030_s *twl4030;
+};
+
+static void beagle_init(ram_addr_t ram_size, int vga_ram_size,
+                const char *boot_device,
+                const char *kernel_filename, const char *kernel_cmdline,
+                const char *initrd_filename, const char *cpu_model)
+{
+    struct beagle_s *s = (struct beagle_s *) qemu_mallocz(sizeof(*s));
+    int sdindex = drive_get_index(IF_SD, 0, 0);
+    void *opaque;
+    
+    if (sdindex == -1) {
+        fprintf(stderr, "%s: missing SecureDigital device\n", __FUNCTION__);
+        exit(1);
+    }
+       s->cpu = omap3530_mpu_init(ram_size, NULL, NULL, serial_hds[0]);
+
+       s->nand = nand_init(NAND_MFR_MICRON, 0xba); /* MT29F2G16ABC */
+       nand_setpins(s->nand, 0, 0, 0, 1, 0); /* no write-protect */
+    omap_gpmc_attach(s->cpu->gpmc, BEAGLE_NAND_CS, 0, NULL, NULL, s->nand, 2);
+    omap3_mmc_attach(s->cpu->omap3_mmc[0], drives_table[sdindex].bdrv);
+
+    s->i2c = omap_i2c_bus(s->cpu->i2c[0]);
+    s->twl4030 = twl4030_init(s->i2c, s->cpu->irq[0][OMAP_INT_3XXX_SYS_NIRQ]);
+    opaque = smc91c111_init(&nd_table[0], 0x08000000,
+                    omap2_gpio_in_get(s->cpu->gpif, 54)[0], 0);
+    omap_gpmc_attach(s->cpu->gpmc, BEAGLE_SMC_CS, smc91c111_iomemtype(opaque),
+                     0, 0, opaque, 0);
+
+       s->lcd_panel = omap3_lcd_panel_init();
+       omap3_lcd_panel_attach(s->cpu->dss, 0, s->lcd_panel);
+    
+    omap3_boot_rom_emu(s->cpu);
+}
+
+QEMUMachine beagle_machine = {
+    .name =        "beagle",
+    .desc =        "Beagle board (OMAP3530)",
+    .init =        beagle_init,
+    .ram_require = OMAP3XXX_SRAM_SIZE + OMAP3XXX_BOOTROM_SIZE,
+};
+
index 1e18ba6..8dfe2fd 100644 (file)
@@ -127,4 +127,7 @@ extern QEMUMachine musicpal_machine;
 /* tosa.c */
 extern QEMUMachine tosapda_machine;
 
+/* beagle.c */
+extern QEMUMachine beagle_machine;
+
 #endif
index a8afa94..92518c5 100644 (file)
@@ -4,7 +4,8 @@
 /* Devices that have nowhere better to go.  */
 
 /* smc91c111.c */
-void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
+void *smc91c111_init(NICInfo *, uint32_t, qemu_irq, int phys_alloc);
+int smc91c111_iomemtype(void *opaque);
 
 /* ssd0323.c */
 int ssd0323_xfer_ssi(void *opaque, int data);
index faba93d..8cbd9e0 100644 (file)
@@ -23,8 +23,9 @@ void nand_done(struct nand_flash_s *s);
 void nand_setpins(struct nand_flash_s *s,
                 int cle, int ale, int ce, int wp, int gnd);
 void nand_getpins(struct nand_flash_s *s, int *rb);
-void nand_setio(struct nand_flash_s *s, uint8_t value);
-uint8_t nand_getio(struct nand_flash_s *s);
+void nand_setio(struct nand_flash_s *s, uint32_t value);
+uint32_t nand_getio(struct nand_flash_s *s);
+uint32_t nand_getbuswidth(struct nand_flash_s *s);
 
 #define NAND_MFR_TOSHIBA       0x98
 #define NAND_MFR_SAMSUNG       0xec
index 70abbdc..dfa239b 100644 (file)
@@ -78,7 +78,7 @@ static void connex_init(ram_addr_t ram_size, int vga_ram_size,
 
     /* Interrupt line of NIC is connected to GPIO line 36 */
     smc91c111_init(&nd_table[0], 0x04000300,
-                    pxa2xx_gpio_in_get(cpu->gpio)[36]);
+                    pxa2xx_gpio_in_get(cpu->gpio)[36], 1);
 }
 
 static void verdex_init(ram_addr_t ram_size, int vga_ram_size,
@@ -118,7 +118,7 @@ static void verdex_init(ram_addr_t ram_size, int vga_ram_size,
 
     /* Interrupt line of NIC is connected to GPIO line 99 */
     smc91c111_init(&nd_table[0], 0x04000300,
-                    pxa2xx_gpio_in_get(cpu->gpio)[99]);
+                    pxa2xx_gpio_in_get(cpu->gpio)[99], 1);
 }
 
 QEMUMachine connex_machine = {
index 396c562..7a80bcb 100644 (file)
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -87,4 +87,8 @@ void tmp105_set(i2c_slave *i2c, int temp);
 struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq);
 void lm832x_key_event(struct i2c_slave *i2c, int key, int state);
 
+/* twl4030.c */
+struct twl4030_s;
+struct twl4030_s *twl4030_init(i2c_bus *bus, qemu_irq irq);
+
 #endif
index f990afe..145ae4d 100644 (file)
@@ -496,7 +496,7 @@ static void integratorcp_init(ram_addr_t ram_size, int vga_ram_size,
     }
     pl181_init(0x1c000000, drives_table[sd].bdrv, pic[23], pic[24]);
     if (nd_table[0].vlan)
-        smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
+        smc91c111_init(&nd_table[0], 0xc8000000, pic[27], 1);
     pl110_init(0xc0000000, pic[22], 0);
 
     integrator_binfo.ram_size = ram_size;
index 5f4cc91..36c6f4b 100644 (file)
@@ -125,7 +125,7 @@ static void mainstone_common_init(ram_addr_t ram_size, int vga_ram_size,
     /* MMC/SD host */
     pxa2xx_mmci_handlers(cpu->mmc, NULL, mst_irq[MMC_IRQ]);
 
-    smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]);
+    smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ], 1);
 
     mainstone_binfo.kernel_filename = kernel_filename;
     mainstone_binfo.kernel_cmdline = kernel_cmdline;
index e73a1b8..2cadbe4 100644 (file)
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -6,6 +6,10 @@
  * Copyright (c) 2006 Openedhand Ltd.
  * Written by Andrzej Zaborowski <balrog@zabor.org>
  *
+ * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
+ * datasheet from Micron Technology and "NAND02G-B2C" datasheet
+ * from ST Microelectronics.
+ *
  * This code is licensed under the GNU GPL v2.
  */
 
@@ -21,6 +25,9 @@
 # define NAND_CMD_READ1                0x01
 # define NAND_CMD_READ2                0x50
 # define NAND_CMD_LPREAD2      0x30
+# define NAND_CMD_READCACHESTART 0x31
+# define NAND_CMD_READCACHEEXIT  0x34
+# define NAND_CMD_READCACHELAST  0x3f
 # define NAND_CMD_NOSERIALREAD2        0x35
 # define NAND_CMD_RANDOMREAD1  0x05
 # define NAND_CMD_RANDOMREAD2  0xe0
@@ -39,7 +46,7 @@
 # define NAND_IOSTATUS_PLANE1  (1 << 2)
 # define NAND_IOSTATUS_PLANE2  (1 << 3)
 # define NAND_IOSTATUS_PLANE3  (1 << 4)
-# define NAND_IOSTATUS_BUSY    (1 << 6)
+# define NAND_IOSTATUS_READY   (3 << 5)
 # define NAND_IOSTATUS_UNPROTCT        (1 << 7)
 
 # define MAX_PAGE              0x800
@@ -47,6 +54,7 @@
 
 struct nand_flash_s {
     uint8_t manf_id, chip_id;
+    uint8_t buswidth; /* in BYTES */
     int size, pages;
     int page_shift, oob_shift, erase_shift, addr_shift;
     uint8_t *storage;
@@ -59,14 +67,15 @@ struct nand_flash_s {
     uint8_t *ioaddr;
     int iolen;
 
-    uint32_t cmd, addr;
+    uint32_t cmd;
+    uint64_t addr;
     int addrlen;
     int status;
     int offset;
 
     void (*blk_write)(struct nand_flash_s *s);
     void (*blk_erase)(struct nand_flash_s *s);
-    void (*blk_load)(struct nand_flash_s *s, uint32_t addr, int offset);
+    void (*blk_load)(struct nand_flash_s *s, uint64_t addr, int offset);
 };
 
 # define NAND_NO_AUTOINCR      0x00000001
@@ -208,25 +217,34 @@ static void nand_reset(struct nand_flash_s *s)
     s->iolen = 0;
     s->offset = 0;
     s->status &= NAND_IOSTATUS_UNPROTCT;
+    s->status |= NAND_IOSTATUS_READY;
+}
+
+static inline void nand_pushio_byte(struct nand_flash_s *s, uint8_t value)
+{
+    s->ioaddr[s->iolen++] = value;
+    for (value = s->buswidth; --value;)
+        s->ioaddr[s->iolen++] = 0;
 }
 
 static void nand_command(struct nand_flash_s *s)
 {
     switch (s->cmd) {
     case NAND_CMD_READ0:
+    case NAND_CMD_READCACHEEXIT:
         s->iolen = 0;
         break;
 
     case NAND_CMD_READID:
-        s->io[0] = s->manf_id;
-        s->io[1] = s->chip_id;
-        s->io[2] = 'Q';                /* Don't-care byte (often 0xa5) */
+        s->ioaddr = s->io;
+        s->iolen = 0;
+        nand_pushio_byte(s, s->manf_id);
+        nand_pushio_byte(s, s->chip_id);
+        nand_pushio_byte(s, 'Q'); /* Don't-case byte (often 0xa5) */
         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
-            s->io[3] = 0x15;   /* Page Size, Block Size, Spare Size.. */
+            nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
         else
-            s->io[3] = 0xc0;   /* Multi-plane */
-        s->ioaddr = s->io;
-        s->iolen = 4;
+            nand_pushio_byte(s, 0xc0); /* Multi-plane */
         break;
 
     case NAND_CMD_RANDOMREAD2:
@@ -234,7 +252,7 @@ static void nand_command(struct nand_flash_s *s)
         if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
             break;
 
-        s->blk_load(s, s->addr, s->addr & ((1 << s->addr_shift) - 1));
+        s->blk_load(s, s->addr, (int)(s->addr & ((1 << s->addr_shift) - 1)));
         break;
 
     case NAND_CMD_RESET:
@@ -267,9 +285,9 @@ static void nand_command(struct nand_flash_s *s)
         break;
 
     case NAND_CMD_READSTATUS:
-        s->io[0] = s->status;
         s->ioaddr = s->io;
-        s->iolen = 1;
+        s->iolen = 0;
+        nand_pushio_byte(s, s->status);
         break;
 
     default:
@@ -290,7 +308,7 @@ static void nand_save(QEMUFile *f, void *opaque)
     qemu_put_be32(f, s->iolen);
 
     qemu_put_be32s(f, &s->cmd);
-    qemu_put_be32s(f, &s->addr);
+    qemu_put_be64s(f, &s->addr);
     qemu_put_be32(f, s->addrlen);
     qemu_put_be32(f, s->status);
     qemu_put_be32(f, s->offset);
@@ -312,7 +330,7 @@ static int nand_load(QEMUFile *f, void *opaque, int version_id)
         return -EINVAL;
 
     qemu_get_be32s(f, &s->cmd);
-    qemu_get_be32s(f, &s->addr);
+    qemu_get_be64s(f, &s->addr);
     s->addrlen = qemu_get_be32(f);
     s->status = qemu_get_be32(f);
     s->offset = qemu_get_be32(f);
@@ -344,11 +362,16 @@ void nand_getpins(struct nand_flash_s *s, int *rb)
     *rb = 1;
 }
 
-void nand_setio(struct nand_flash_s *s, uint8_t value)
+void nand_setio(struct nand_flash_s *s, uint32_t value)
 {
+    int i;
+    
     if (!s->ce && s->cle) {
         if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
-            if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
+            if (s->cmd == NAND_CMD_READ0 
+                && (value == NAND_CMD_LPREAD2
+                    || value == NAND_CMD_READCACHESTART
+                    || value == NAND_CMD_READCACHELAST))
                 return;
             if (value == NAND_CMD_RANDOMREAD1) {
                 s->addr &= ~((1 << s->addr_shift) - 1);
@@ -375,7 +398,8 @@ void nand_setio(struct nand_flash_s *s, uint8_t value)
                 s->cmd == NAND_CMD_BLOCKERASE2 ||
                 s->cmd == NAND_CMD_NOSERIALREAD2 ||
                 s->cmd == NAND_CMD_RANDOMREAD2 ||
-                s->cmd == NAND_CMD_RESET)
+                s->cmd == NAND_CMD_RESET ||
+            s->cmd == NAND_CMD_READCACHEEXIT)
             nand_command(s);
 
         if (s->cmd != NAND_CMD_RANDOMREAD2) {
@@ -388,40 +412,60 @@ void nand_setio(struct nand_flash_s *s, uint8_t value)
         s->addr |= value << (s->addrlen * 8);
         s->addrlen ++;
 
-        if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
-            nand_command(s);
-
-        if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
-                s->addrlen == 3 && (
-                    s->cmd == NAND_CMD_READ0 ||
-                    s->cmd == NAND_CMD_PAGEPROGRAM1))
-            nand_command(s);
-        if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
-               s->addrlen == 4 && (
-                    s->cmd == NAND_CMD_READ0 ||
-                    s->cmd == NAND_CMD_PAGEPROGRAM1))
-            nand_command(s);
+        switch (s->addrlen) {
+            case 1:
+                if (s->cmd == NAND_CMD_READID)
+                    nand_command(s);
+                break;
+            case 2: /* fix cache address as a byte address */
+                s->addr <<= (s->buswidth - 1);
+                break;
+            case 3:
+                if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+                    && (s->cmd == NAND_CMD_READ0
+                        || s->cmd == NAND_CMD_PAGEPROGRAM1))
+                    nand_command(s);
+                break;
+            case 4:
+                if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+                    && nand_flash_ids[s->chip_id].size < 256 /* 1Gb or less */
+                    && (s->cmd == NAND_CMD_READ0 ||
+                        s->cmd == NAND_CMD_PAGEPROGRAM1))
+                    nand_command(s);
+                break;
+            case 5:
+                if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+                    && nand_flash_ids[s->chip_id].size >= 256 /* 2Gb or more */
+                    && (s->cmd == NAND_CMD_READ0 ||
+                        s->cmd == NAND_CMD_PAGEPROGRAM1))
+                    nand_command(s);
+                break;
+            default:
+                break;
+        }
     }
 
     if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
         if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
-            s->io[s->iolen ++] = value;
+            for (i = s->buswidth; i--; value >>= 8)
+                s->io[s->iolen++] = (uint8_t)(value & 0xff);
     } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
         if ((s->addr & ((1 << s->addr_shift) - 1)) <
-                (1 << s->page_shift) + (1 << s->oob_shift)) {
-            s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
-            s->addr ++;
-        }
+                (1 << s->page_shift) + (1 << s->oob_shift))
+            for (i = s->buswidth; i--; s->addr++, value >>= 8)
+                s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
+                    (uint8_t)(value & 0xff);
     }
 }
 
-uint8_t nand_getio(struct nand_flash_s *s)
+uint32_t nand_getio(struct nand_flash_s *s)
 {
     int offset;
+    uint32_t x = 0;
 
     /* Allow sequential reading */
     if (!s->iolen && s->cmd == NAND_CMD_READ0) {
-        offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
+        offset = (int)((s->addr & ((1 << s->addr_shift) - 1))) + s->offset;
         s->offset = 0;
 
         s->blk_load(s, s->addr, offset);
@@ -434,8 +478,22 @@ uint8_t nand_getio(struct nand_flash_s *s)
     if (s->ce || s->iolen <= 0)
         return 0;
 
-    s->iolen --;
-    return *(s->ioaddr ++);
+    for (offset = s->buswidth; offset--;)
+        x |= s->ioaddr[offset] << (offset << 3);
+    /* after receiving READ STATUS command all subsequent reads will
+       return the status register value until another command is issued */
+    if (s->cmd != NAND_CMD_READSTATUS) {
+        s->ioaddr += s->buswidth;
+        s->iolen  -= s->buswidth;
+    }
+    return x;
+}
+
+uint32_t nand_getbuswidth(struct nand_flash_s *s)
+{
+    if (!s)
+        return 0;
+    return (s->buswidth << 3);
 }
 
 struct nand_flash_s *nand_init(int manf_id, int chip_id)
@@ -455,6 +513,7 @@ struct nand_flash_s *nand_init(int manf_id, int chip_id)
         s->bdrv = drives_table[index].bdrv;
     s->manf_id = manf_id;
     s->chip_id = chip_id;
+    s->buswidth = (uint8_t)(nand_flash_ids[s->chip_id].width >> 3);
     s->size = nand_flash_ids[s->chip_id].size << 20;
     if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
         s->page_shift = 11;
@@ -519,7 +578,7 @@ void nand_done(struct nand_flash_s *s)
 /* Program a single page */
 static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s)
 {
-    uint32_t off, page, sector, soff;
+    uint64_t off, page, sector, soff;
     uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
     if (PAGE(s->addr) >= s->pages)
         return;
@@ -532,7 +591,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s)
         off = (s->addr & PAGE_MASK) + s->offset;
         soff = SECTOR_OFFSET(s->addr);
         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
-            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: read error in sector %lli\n", __FUNCTION__, sector);
             return;
         }
 
@@ -544,20 +603,20 @@ static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s)
         }
 
         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: write error in sector %lli\n", __FUNCTION__, sector);
     } else {
         off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
         sector = off >> 9;
         soff = off & 0x1ff;
         if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
-            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: read error in sector %lli\n", __FUNCTION__, sector);
             return;
         }
 
         memcpy(iobuf + soff, s->io, s->iolen);
 
         if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+            printf("%s: write error in sector %lli\n", __FUNCTION__, sector);
     }
     s->offset = 0;
 }
@@ -565,7 +624,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s)
 /* Erase a single block */
 static void glue(nand_blk_erase_, PAGE_SIZE)(struct nand_flash_s *s)
 {
-    uint32_t i, page, addr;
+    uint64_t i, page, addr;
     uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
     addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
 
@@ -582,34 +641,34 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(struct nand_flash_s *s)
         page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
         for (; i < page; i ++)
             if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
-                printf("%s: write error in sector %i\n", __FUNCTION__, i);
+                printf("%s: write error in sector %lli\n", __FUNCTION__, i);
     } else {
         addr = PAGE_START(addr);
         page = addr >> 9;
         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+            printf("%s: read error in sector %lli\n", __FUNCTION__, page);
         memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+            printf("%s: write error in sector %lli\n", __FUNCTION__, page);
 
         memset(iobuf, 0xff, 0x200);
         i = (addr & ~0x1ff) + 0x200;
         for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
                         i < addr; i += 0x200)
             if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
-                printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
+                printf("%s: write error in sector %lli\n", __FUNCTION__, i >> 9);
 
         page = i >> 9;
         if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+            printf("%s: read error in sector %lli\n", __FUNCTION__, page);
         memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
         if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
-            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+            printf("%s: write error in sector %lli\n", __FUNCTION__, page);
     }
 }
 
 static void glue(nand_blk_load_, PAGE_SIZE)(struct nand_flash_s *s,
-                uint32_t addr, int offset)
+                uint64_t addr, int offset)
 {
     if (PAGE(addr) >= s->pages)
         return;
@@ -617,7 +676,7 @@ static void glue(nand_blk_load_, PAGE_SIZE)(struct nand_flash_s *s,
     if (s->bdrv) {
         if (s->mem_oob) {
             if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
-                printf("%s: read error in sector %i\n",
+                printf("%s: read error in sector %lli\n",
                                 __FUNCTION__, SECTOR(addr));
             memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
                             s->storage + (PAGE(s->addr) << OOB_SHIFT),
@@ -626,7 +685,7 @@ static void glue(nand_blk_load_, PAGE_SIZE)(struct nand_flash_s *s,
         } else {
             if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
                                     s->io, (PAGE_SECTORS + 2)) == -1)
-                printf("%s: read error in sector %i\n",
+                printf("%s: read error in sector %lli\n",
                                 __FUNCTION__, PAGE_START(addr) >> 9);
             s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
         }
index 0c7da77..2d12705 100644 (file)
@@ -169,7 +169,7 @@ static void n8x0_nand_setup(struct n800_s *s)
                     onenand_base_unmap,
                     (s->nand = onenand_init(0xec4800, 1,
                                             omap2_gpio_in_get(s->cpu->gpif,
-                                                    N8X0_ONENAND_GPIO)[0])));
+                                                    N8X0_ONENAND_GPIO)[0])),0);
     otp_region = onenand_raw_otp(s->nand);
 
     memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
@@ -769,9 +769,9 @@ static void n8x0_usb_setup(struct n800_s *s)
 
     /* Using the NOR interface */
     omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_ASYNC_CS,
-                    tusb6010_async_io(tusb), 0, 0, tusb);
+                     tusb6010_async_io(tusb), 0, 0, tusb, 0);
     omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_SYNC_CS,
-                    tusb6010_sync_io(tusb), 0, 0, tusb);
+                     tusb6010_sync_io(tusb), 0, 0, tusb, 0);
 
     s->usb = tusb;
     omap2_gpio_out_set(s->cpu->gpif, N8X0_TUSB_ENABLE_GPIO, tusb_pwr);
index e940474..41fef42 100644 (file)
--- a/hw/omap.h
+++ b/hw/omap.h
 # define OMAP2_L3_BASE         0x68000000
 # define OMAP2_Q2_BASE         0x80000000
 # define OMAP2_Q3_BASE         0xc0000000
+# define OMAP3_Q1_BASE      0x40000000
+# define OMAP3_L4_BASE      0x48000000
+# define OMAP3_SRAM_BASE    0x40200000
+# define OMAP3_L3_BASE      0x68000000
+# define OMAP3_Q2_BASE      0x80000000
+# define OMAP3_Q3_BASE      0xc0000000
 # define OMAP_MPUI_BASE                0xe1000000
 
-# define OMAP730_SRAM_SIZE     0x00032000
-# define OMAP15XX_SRAM_SIZE    0x00030000
-# define OMAP16XX_SRAM_SIZE    0x00004000
-# define OMAP1611_SRAM_SIZE    0x0003e800
-# define OMAP242X_SRAM_SIZE    0x000a0000
-# define OMAP243X_SRAM_SIZE    0x00010000
-# define OMAP_CS0_SIZE         0x04000000
-# define OMAP_CS1_SIZE         0x04000000
-# define OMAP_CS2_SIZE         0x04000000
-# define OMAP_CS3_SIZE         0x04000000
+# define OMAP730_SRAM_SIZE      0x00032000
+# define OMAP15XX_SRAM_SIZE     0x00030000
+# define OMAP16XX_SRAM_SIZE     0x00004000
+# define OMAP1611_SRAM_SIZE     0x0003e800
+# define OMAP242X_SRAM_SIZE     0x000a0000
+# define OMAP243X_SRAM_SIZE     0x00010000
+# define OMAP3XXX_SRAM_SIZE     0x00010000
+# define OMAP3XXX_BOOTROM_SIZE  0x00008000
+# define OMAP_CS0_SIZE          0x04000000
+# define OMAP_CS1_SIZE          0x04000000
+# define OMAP_CS2_SIZE          0x04000000
+# define OMAP_CS3_SIZE          0x04000000
 
 /* omap_clk.c */
 struct omap_mpu_state_s;
@@ -64,19 +72,22 @@ void omap_clk_reparent(omap_clk clk, omap_clk parent);
 
 /* omap[123].c */
 struct omap_l4_s;
+struct omap_l3_s;
 struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num);
 
 struct omap_target_agent_s;
-struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs);
 target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
                 int iotype);
+target_phys_addr_t omap_l4_base(struct omap_target_agent_s *ta, int region);
+uint32_t omap_l4_size(struct omap_target_agent_s *ta, int region);
 # define l4_register_io_memory cpu_register_io_memory
 
 struct omap_intr_handler_s;
 struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
                 unsigned long size, unsigned char nbanks, qemu_irq **pins,
                 qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk);
-struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
+struct omap_intr_handler_s *omap2_inth_init(struct omap_mpu_state_s *mpu,
+                target_phys_addr_t base,
                 int size, int nbanks, qemu_irq **pins,
                 qemu_irq parent_irq, qemu_irq parent_fiq,
                 omap_clk fclk, omap_clk iclk);
@@ -93,12 +104,15 @@ struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
 
 struct omap_sdrc_s;
 struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base);
+void omap_sdrc_write_mcfg(struct omap_sdrc_s *s, uint32_t value, uint32_t cs);
 
 struct omap_gpmc_s;
-struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq);
+struct nand_flash_s;
+struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
+                                   target_phys_addr_t base, qemu_irq irq);
 void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
                 void (*base_upd)(void *opaque, target_phys_addr_t new),
-                void (*unmap)(void *opaque), void *opaque);
+                void (*unmap)(void *opaque), void *opaque, int devicetype);
 
 /*
  * Common IRQ numbers for level 1 interrupt handler
@@ -408,6 +422,106 @@ void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
 # define OMAP_INT_243X_CARKIT          94
 # define OMAP_INT_34XX_GPTIMER12       95
 
+/*
+ * OMAP-3XXX common IRQ numbers
+ */
+#define OMAP_INT_3XXX_EMUINT        0  /* MPU emulation */
+#define OMAP_INT_3XXX_COMMTX        1  /* MPU emulation */
+#define OMAP_INT_3XXX_COMMRX        2  /* MPU emulation */
+#define OMAP_INT_3XXX_BENCH         3  /* MPU emulation */
+#define OMAP_INT_3XXX_MCBSP2_ST_IRQ 4  /* Sidetone MCBSP2 overflow */
+#define OMAP_INT_3XXX_MCBSP3_ST_IRQ 5  /* Sidetone MCBSP3 overflow */
+#define OMAP_INT_3XXX_SSM_ABORT_IRQ 6
+#define OMAP_INT_3XXX_SYS_NIRQ      7  /* External source (active low) */
+#define OMAP_INT_3XXX_D2D_FW_IRQ    8
+#define OMAP_INT_3XXX_SMX_DBG_IRQ   9  /* L3 interconnect error for debug */
+#define OMAP_INT_3XXX_SMX_APP_IRQ   10 /* L3 interconnect error for application */
+#define OMAP_INT_3XXX_PRCM_MPU_IRQ  11 /* PRCM module IRQ */
+#define OMAP_INT_3XXX_SDMA_IRQ0     12 /* System DMA request 0 */ 
+#define OMAP_INT_3XXX_SDMA_IRQ1     13 /* System DMA request 1 */
+#define OMAP_INT_3XXX_SDMA_IRQ2     14 /* System DMA request 2 */
+#define OMAP_INT_3XXX_SDMA_IRQ3     15 /* System DMA request 3 */
+#define OMAP_INT_3XXX_MCBSP1_IRQ    16 /* MCBSP module 1 IRQ */
+#define OMAP_INT_3XXX_MCBSP2_IRQ    17 /* MCBSP module 2 IRQ */
+/* IRQ18 is reserved */
+/* IRQ19 is reserved */
+#define OMAP_INT_3XXX_GPMC_IRQ      20 /* General-purpose memory controller module */ 
+#define OMAP_INT_3XXX_SGX_IRQ       21 /* 2D/3D graphics module */
+#define OMAP_INT_3XXX_MCBSP3_IRQ    22 /* MCBSP module 3 */
+#define OMAP_INT_3XXX_MCBSP4_IRQ    23 /* MCBSP module 4 */
+#define OMAP_INT_3XXX_CAM_IRQ0      24 /* Camera interface request 0 */
+#define OMAP_INT_3XXX_DSS_IRQ       25 /* Display subsystem module */
+#define OMAP_INT_3XXX_MAIL_U0_MPU   26 /* Mailbox user 0 request */
+#define OMAP_INT_3XXX_MCBSP5_IRQ    27 /* MCBSP module 5 */
+#define OMAP_INT_3XXX_IVA2_MMU_IRQ  28 /* IVA2 MMU */
+#define OMAP_INT_3XXX_GPIO1_MPU_IRQ 29 /* GPIO module 1 */
+#define OMAP_INT_3XXX_GPIO2_MPU_IRQ 30 /* GPIO module 2 */
+#define OMAP_INT_3XXX_GPIO3_MPU_IRQ 31 /* GPIO module 3 */
+#define OMAP_INT_3XXX_GPIO4_MPU_IRQ 32 /* GPIO module 4 */
+#define OMAP_INT_3XXX_GPIO5_MPU_IRQ 33 /* GPIO module 5 */
+#define OMAP_INT_3XXX_GPIO6_MPU_IRQ 34 /* GPIO module 6 */
+#define OMAP_INT_3XXX_USIM_IRQ      35
+#define OMAP_INT_3XXX_WDT3_IRQ      36 /* Watchdog timer module 3 overflow */
+#define OMAP_INT_3XXX_GPT1_IRQ      37 /* General-purpose timer module 1 */
+#define OMAP_INT_3XXX_GPT2_IRQ      38 /* General-purpose timer module 2 */
+#define OMAP_INT_3XXX_GPT3_IRQ      39 /* General-purpose timer module 3 */
+#define OMAP_INT_3XXX_GPT4_IRQ      40 /* General-purpose timer module 4 */
+#define OMAP_INT_3XXX_GPT5_IRQ      41 /* General-purpose timer module 5 */
+#define OMAP_INT_3XXX_GPT6_IRQ      42 /* General-purpose timer module 6 */
+#define OMAP_INT_3XXX_GPT7_IRQ      43 /* General-purpose timer module 7 */
+#define OMAP_INT_3XXX_GPT8_IRQ      44 /* General-purpose timer module 8 */
+#define OMAP_INT_3XXX_GPT9_IRQ      45 /* General-purpose timer module 9 */
+#define OMAP_INT_3XXX_GPT10_IRQ     46 /* General-purpose timer module 10 */
+#define OMAP_INT_3XXX_GPT11_IRQ     47 /* General-purpose timer module 11 */
+#define OMAP_INT_3XXX_MCSPI4_IRQ    48 /* MCSPI module 4 */
+#define OMAP_INT_3XXX_SHA1MD52_IRQ  49
+#define OMAP_INT_3XXX_FPKA_READY    50
+#define OMAP_INT_3XXX_SHA1MD51_IRQ  51
+#define OMAP_INT_3XXX_RNG_IRQ       52
+#define OMAP_INT_3XXX_MG_IRQ        53
+#define OMAP_INT_3XXX_MCBSP4_IRQ_TX 54 /* MCBSP module 4 transmit */
+#define OMAP_INT_3XXX_MCBSP4_IRQ_RX 55 /* MCBSP module 4 receive */
+#define OMAP_INT_3XXX_I2C1_IRQ      56 /* I2C module 1 */
+#define OMAP_INT_3XXX_I2C2_IRQ      57 /* I2C module 2 */
+#define OMAP_INT_3XXX_HDQ_IRQ       58 /* HDQ/1-Wire */
+#define OMAP_INT_3XXX_MCBSP1_IRQ_TX 59 /* MCBSP module 1 transmit */
+#define OMAP_INT_3XXX_MCBSP1_IRQ_RX 60 /* MCBSP module 1 receive */
+#define OMAP_INT_3XXX_I2C3_IRQ      61 /* I2C module 3 */
+#define OMAP_INT_3XXX_MCBSP2_IRQ_TX 62 /* MCBSP module 2 transmit */
+#define OMAP_INT_3XXX_MCBSP2_IRQ_RX 63 /* MCBSP module 2 receive */
+#define OMAP_INT_3XXX_FPKA_ERROR    64
+#define OMAP_INT_3XXX_MCSPI1_IRQ    65 /* MCSPI module 1 */
+#define OMAP_INT_3XXX_MCSPI2_IRQ    66 /* MCSPI module 2 */
+/* IRQ67 is reserved */
+/* IRQ68 is reserved */
+/* IRQ69 is reserved */
+/* IRQ70 is reserved */
+/* IRQ71 is reserved */
+#define OMAP_INT_3XXX_UART1_IRQ     72 /* UART module 1 */
+#define OMAP_INT_3XXX_UART2_IRQ     73 /* UART module 2 */
+#define OMAP_INT_3XXX_UART3_IRQ     74 /* UART module 3 (also infrared)*/
+#define OMAP_INT_3XXX_PBIAS_IRQ     75 /* Merged interrupt for PBIASlite1 and 2 */
+#define OMAP_INT_3XXX_OHCI_IRQ      76 /* OHCI controller HSUSB MP Host interrupt */
+#define OMAP_INT_3XXX_EHCI_IRQ      77 /* EHCI controller HSUSB MP Host interrupt */
+#define OMAP_INT_3XXX_TLL_IRQ       78 /* HSUSB MP TLL interrupt */
+/* IRQ79 is reserved */
+/* IRQ80 is reserved */
+#define OMAP_INT_3XXX_MCBSP5_IRQ_TX 81 /* MCBSP module 5 transmit */
+#define OMAP_INT_3XXX_MCBSP5_IRQ_RX 82 /* MCBSP module 5 receive */
+#define OMAP_INT_3XXX_MMC1_IRQ      83 /* MMC/SD module 1 */
+#define OMAP_INT_3XXX_MS_IRQ           84
+/* IRQ85 is reserved */
+#define OMAP_INT_3XXX_MMC2_IRQ         86 /* MMC/SD module 2 */
+#define OMAP_INT_3XXX_MPU_ICR_IRQ   87 /* MPU ICR */
+#define OMAP_INT_3XXX_D2DFRINT      88 /* 3G coprocessor */
+#define OMAP_INT_3XXX_MCBSP3_IRQ_TX 89 /* MCBSP module 3 transmit */
+#define OMAP_INT_3XXX_MCBSP3_IRQ_RX 90 /* MCBSP module 3 receive */
+#define OMAP_INT_3XXX_MCSPI3_IRQ    91 /* MCSPI module 3 */
+#define OMAP_INT_3XXX_HSUSB_MC      92 /* High-Speed USB OTG controller */
+#define OMAP_INT_3XXX_HSUSB_DMA     93 /* High-Speed USB OTG DMA controller */
+#define OMAP_INT_3XXX_MMC3_IRQ      94 /* MMC/SD module 3 */
+#define OMAP_INT_3XXX_GPT12_IRQ     95 /* General-purpose timer module 12 */
+
 /* omap_dma.c */
 enum omap_dma_model {
     omap_dma_3_0,
@@ -423,6 +537,10 @@ struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
 struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
                 struct omap_mpu_state_s *mpu, int fifo,
                 int chans, omap_clk iclk, omap_clk fclk);
+struct soc_dma_s *omap3_dma4_init(struct omap_target_agent_s *ta,
+                                  struct omap_mpu_state_s *mpu,
+                                  qemu_irq *irqs, int chans,
+                                  omap_clk iclk, omap_clk fclk);
 void omap_dma_reset(struct soc_dma_s *s);
 
 struct dma_irq_map {
@@ -627,6 +745,85 @@ struct omap_dma_lcd_channel_s {
 # define OMAP24XX_DMA_MS               63      /* Not in OMAP2420 */
 # define OMAP24XX_DMA_EXT_DMAREQ5      64
 
+/*
+ * DMA request numbers for the OMAP3
+ * Note that the numbers have to match the values that are
+ * written to CCRi SYNCHRO_CONTROL bits, i.e. actual line
+ * number plus one! Zero is a reserved value (defined as
+ * NO_DEVICE here). Other missing values are reserved.
+ */
+#define OMAP3XXX_DMA_NO_DEVICE        0
+
+#define OMAP3XXX_DMA_EXT_DMAREQ0      2
+#define OMAP3XXX_DMA_EXT_DMAREQ1      3
+#define OMAP3XXX_DMA_GPMC             4
+
+#define OMAP3XXX_DMA_DSS_LINETRIGGER  6
+#define OMAP3XXX_DMA_EXT_DMAREQ2      7
+
+#define OMAP3XXX_DMA_SPI3_TX0         15
+#define OMAP3XXX_DMA_SPI3_RX0         16
+#define OMAP3XXX_DMA_MCBSP3_TX        17
+#define OMAP3XXX_DMA_MCBSP3_RX        18
+#define OMAP3XXX_DMA_MCBSP4_TX        19
+#define OMAP3XXX_DMA_MCBSP4_RX        20
+#define OMAP3XXX_DMA_MCBSP5_TX        21
+#define OMAP3XXX_DMA_MCBSP5_RX        22
+#define OMAP3XXX_DMA_SPI3_TX1         23
+#define OMAP3XXX_DMA_SPI3_RX1         24
+#define OMAP3XXX_DMA_I2C3_TX          25
+#define OMAP3XXX_DMA_I2C3_RX          26
+#define OMAP3XXX_DMA_I2C1_TX          27
+#define OMAP3XXX_DMA_I2C1_RX          28
+#define OMAP3XXX_DMA_I2C2_TX          29
+#define OMAP3XXX_DMA_I2C2_RX          30
+#define OMAP3XXX_DMA_MCBSP1_TX        31
+#define OMAP3XXX_DMA_MCBSP1_RX        32
+#define OMAP3XXX_DMA_MCBSP2_TX        33
+#define OMAP3XXX_DMA_MCBSP2_RX        34
+#define OMAP3XXX_DMA_SPI1_TX0         35
+#define OMAP3XXX_DMA_SPI1_RX0         36
+#define OMAP3XXX_DMA_SPI1_TX1         37
+#define OMAP3XXX_DMA_SPI1_RX1         38
+#define OMAP3XXX_DMA_SPI1_TX2         39
+#define OMAP3XXX_DMA_SPI1_RX2         40
+#define OMAP3XXX_DMA_SPI1_TX3         41
+#define OMAP3XXX_DMA_SPI1_RX3         42
+#define OMAP3XXX_DMA_SPI2_TX0         43
+#define OMAP3XXX_DMA_SPI2_RX0         44
+#define OMAP3XXX_DMA_SPI2_TX1         45
+#define OMAP3XXX_DMA_SPI2_RX1         46
+#define OMAP3XXX_DMA_MMC2_TX          47
+#define OMAP3XXX_DMA_MMC2_RX          48
+#define OMAP3XXX_DMA_UART1_TX         49
+#define OMAP3XXX_DMA_UART1_RX         50
+#define OMAP3XXX_DMA_UART2_TX         51
+#define OMAP3XXX_DMA_UART2_RX         52
+#define OMAP3XXX_DMA_UART3_TX         53
+#define OMAP3XXX_DMA_UART3_RX         54
+
+#define OMAP3XXX_DMA_MMC1_TX          61
+#define OMAP3XXX_DMA_MMC1_RX          62
+#define OMAP3XXX_DMA_MS               63
+#define OMAP3XXX_DMA_EXT_DMAREQ3      64
+#define OMAP3XXX_DMA_AES2_TX          65
+#define OMAP3XXX_DMA_AES2_RX          66
+#define OMAP3XXX_DMA_DES2_TX          67
+#define OMAP3XXX_DMA_DES2_RX          68
+#define OMAP3XXX_DMA_SHA1MD5_RX       69
+#define OMAP3XXX_DMA_SPI4_TX0         70
+#define OMAP3XXX_DMA_SPI4_RX0         71
+#define OMAP3XXX_DMA_DSS0             72
+#define OMAP3XXX_DMA_DSS1             73
+#define OMAP3XXX_DMA_DSS2             74
+#define OMAP3XXX_DMA_DSS3             75
+
+#define OMAP3XXX_DMA_MMC3_TX          77
+#define OMAP3XXX_DMA_MMC3_RX          78
+#define OMAP3XXX_DMA_USIM_TX          79
+#define OMAP3XXX_DMA_USIM_RX          80
+
+
 /* omap[123].c */
 struct omap_mpu_timer_s;
 struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
@@ -635,6 +832,7 @@ struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
 struct omap_gp_timer_s;
 struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk);
+void omap_gp_timer_change_clk(struct omap_gp_timer_s *timer);
 
 struct omap_watchdog_timer_s;
 struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
@@ -676,8 +874,13 @@ qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s);
 void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler);
 
 struct omap_gpif_s;
-struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
+struct omap_gpif_s *omap2_gpio_init(struct omap_mpu_state_s *mpu,
+                struct omap_target_agent_s *ta,
                 qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules);
+struct omap_gpif_s *omap3_gpif_init(void);
+void omap3_gpio_init(struct omap_mpu_state_s *mpu,
+                     struct omap_gpif_s *s, struct omap_target_agent_s *ta,
+                     qemu_irq irq, omap_clk *fclk, omap_clk iclk, int module_index);
 qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start);
 void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler);
 
@@ -692,13 +895,6 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
 void omap_uwire_attach(struct omap_uwire_s *s,
                 struct uwire_slave_s *slave, int chipselect);
 
-struct omap_mcspi_s;
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
-                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk);
-void omap_mcspi_attach(struct omap_mcspi_s *s,
-                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
-                int chipselect);
-
 struct omap_rtc_s;
 struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base,
                 qemu_irq *irq, omap_clk clk);
@@ -756,14 +952,18 @@ struct rfbi_chip_s {
     void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch);
     uint16_t (*read)(void *opaque, int dc);
 };
+typedef void (*omap3_lcd_panel_fn_t)(uint8_t *, const uint8_t *, unsigned int);
+struct omap3_lcd_panel_s;
 struct omap_dss_s;
 void omap_dss_reset(struct omap_dss_s *s);
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
-                target_phys_addr_t l3_base,
-                qemu_irq irq, qemu_irq drq,
-                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
-                omap_clk ick1, omap_clk ick2);
+struct omap_dss_s *omap_dss_init(struct omap_mpu_state_s *mpu,
+                                 struct omap_target_agent_s *ta,
+                                 qemu_irq irq, qemu_irq drq,
+                                 omap_clk fck1, omap_clk fck2, omap_clk ck54m,
+                                 omap_clk ick1, omap_clk ick2);
 void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip);
+void omap3_lcd_panel_attach(struct omap_dss_s *s, int cs, struct omap3_lcd_panel_s *lcd_panel);
+void *omap3_lcd_panel_init(void);
 
 /* omap_mmc.c */
 struct omap_mmc_s;
@@ -777,15 +977,53 @@ void omap_mmc_reset(struct omap_mmc_s *s);
 void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
 void omap_mmc_enable(struct omap_mmc_s *s, int enable);
 
+/* omap3_mmc.c */
+struct omap3_mmc_s;
+struct omap3_mmc_s *omap3_mmc_init(struct omap_target_agent_s *ta,
+                                   qemu_irq irq, qemu_irq dma[],
+                                   omap_clk fclk, omap_clk iclk);
+void omap3_mmc_attach(struct omap3_mmc_s *s,
+                      BlockDriverState *bd);
+
 /* omap_i2c.c */
 struct omap_i2c_s;
 struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
                 qemu_irq irq, qemu_irq *dma, omap_clk clk);
 struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
                 qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk);
+struct omap_i2c_s *omap3_i2c_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk,
+                int fifosize);
 void omap_i2c_reset(struct omap_i2c_s *s);
 i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
 
+/* omap_spi.c */
+struct omap_mcspi_s;
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta,
+                                     struct omap_mpu_state_s *mpu,
+                                     int chnum, qemu_irq irq, qemu_irq *drq,
+                                     omap_clk fclk, omap_clk iclk);
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+                       uint32_t (*txrx)(void *opaque, uint32_t, int),
+                       void *opaque, int chipselect);
+void omap_mcspi_reset(struct omap_mcspi_s *s);
+
+/* omap3_usb.c */
+struct omap3_hsusb_s;
+struct omap3_hsusb_s *omap3_hsusb_init(struct omap_target_agent_s *otg_ta,
+                                       struct omap_target_agent_s *host_ta,
+                                       struct omap_target_agent_s *tll_ta,
+                                       qemu_irq mc_irq,
+                                       qemu_irq dma_irq,
+                                       qemu_irq ohci_irq,
+                                       qemu_irq ehci_irq,
+                                       qemu_irq tll_irq);
+
+/* usb-ohci.c */
+int usb_ohci_init_omap(target_phys_addr_t base, uint32_t region_size,
+                       int num_ports, qemu_irq irq);
+
+
 # define cpu_is_omap310(cpu)           (cpu->mpu_model == omap310)
 # define cpu_is_omap1510(cpu)          (cpu->mpu_model == omap1510)
 # define cpu_is_omap1610(cpu)          (cpu->mpu_model == omap1610)
@@ -794,6 +1032,7 @@ i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
 # define cpu_is_omap2420(cpu)          (cpu->mpu_model == omap2420)
 # define cpu_is_omap2430(cpu)          (cpu->mpu_model == omap2430)
 # define cpu_is_omap3430(cpu)          (cpu->mpu_model == omap3430)
+# define cpu_is_omap3530(cpu)       (cpu->mpu_model == omap3530)
 
 # define cpu_is_omap15xx(cpu)          \
         (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu))
@@ -805,7 +1044,8 @@ i2c_bus *omap_i2c_bus(struct omap_i2c_s *s);
 # define cpu_class_omap1(cpu)          \
         (cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu))
 # define cpu_class_omap2(cpu)          cpu_is_omap24xx(cpu)
-# define cpu_class_omap3(cpu)          cpu_is_omap3430(cpu)
+# define cpu_class_omap3(cpu)          \
+        (cpu_is_omap3430(cpu) || cpu_is_omap3530(cpu))
 
 struct omap_mpu_state_s {
     enum omap_mpu_model {
@@ -819,6 +1059,7 @@ struct omap_mpu_state_s {
         omap2423,
         omap2430,
         omap3430,
+        omap3530,
     } mpu_model;
 
     CPUState *env;
@@ -871,7 +1112,7 @@ struct omap_mpu_state_s {
         omap_clk clk;
     } pwt;
 
-    struct omap_i2c_s *i2c[2];
+    struct omap_i2c_s *i2c[3];
 
     struct omap_rtc_s *rtc;
 
@@ -938,6 +1179,7 @@ struct omap_mpu_state_s {
     struct omap_synctimer_s {
         uint32_t val;
         uint16_t readh;
+        uint32_t sysconfig; /*OMAP3*/
     } synctimer;
 
     struct omap_prcm_s *prcm;
@@ -947,11 +1189,51 @@ struct omap_mpu_state_s {
 
     struct omap_gpif_s *gpif;
 
-    struct omap_mcspi_s *mcspi[2];
+    struct omap_mcspi_s *mcspi[4];
 
     struct omap_dss_s *dss;
 
     struct omap_eac_s *eac;
+    
+    /* OMAP3-only */
+    struct omap3_prm_s *omap3_prm;
+    struct omap3_cm_s *omap3_cm;
+    struct omap3_wdt_s *omap3_mpu_wdt;
+    struct omap_l3_s *omap3_l3;
+    struct omap3_scm_s *omap3_scm;
+    struct omap3_sms_s *omap3_sms;
+    struct omap3_mmc_s *omap3_mmc[3];
+    struct omap3_hsusb_s *omap3_usb;
+};
+
+struct omap_target_agent_s {
+    struct omap_l4_s *bus;
+    int regions;
+    struct omap_l4_region_s *start;
+    target_phys_addr_t base;
+    uint32_t component;
+    uint32_t control;
+    uint32_t control_h; /* OMAP3 */
+    uint32_t status;
+};
+
+struct omap_l4_s {
+    target_phys_addr_t base;
+    int ta_num;
+    struct omap_target_agent_s ta[0];
+};
+
+struct omap_l4_region_s {
+    target_phys_addr_t offset;
+    size_t size;
+    int access;
+};
+
+struct omap_l4_agent_info_s {
+    int ta;
+    int region;
+    int regions;
+    int ta_region;
 };
 
 /* omap1.c */
@@ -962,10 +1244,20 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
 struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                 const char *core);
 
+/* omap3.c */
+struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
+                                           CharDriverState *chr_uart1,
+                                           CharDriverState *chr_uart2,
+                                           CharDriverState *chr_uart3);
+void omap3_set_mem_type(struct omap_mpu_state_s *s, int bootfrom);
+
+/* omap3_boot.c */
+void omap3_boot_rom_emu(struct omap_mpu_state_s *s);
+
 # if TARGET_PHYS_ADDR_BITS == 32
-#  define OMAP_FMT_plx "%#08x"
+#  define OMAP_FMT_plx "0x%08x"
 # elif TARGET_PHYS_ADDR_BITS == 64
-#  define OMAP_FMT_plx "%#08" PRIx64
+#  define OMAP_FMT_plx "0x%08" PRIx64
 # else
 #  error TARGET_PHYS_ADDR_BITS undefined
 # endif
@@ -985,9 +1277,15 @@ void omap_mpu_wakeup(void *opaque, int irq, int req);
 # define OMAP_BAD_REG(paddr)           \
         fprintf(stderr, "%s: Bad register " OMAP_FMT_plx "\n", \
                         __FUNCTION__, paddr)
+# define OMAP_BAD_REGV(paddr, value) \
+        fprintf(stderr, "%s: Bad register " OMAP_FMT_plx " (value 0x%08x)\n", \
+                __FUNCTION__, paddr, value)
 # define OMAP_RO_REG(paddr)            \
         fprintf(stderr, "%s: Read-only register " OMAP_FMT_plx "\n",   \
                         __FUNCTION__, paddr)
+# define OMAP_RO_REGV(paddr, value) \
+        fprintf(stderr, "%s: Read-only register " OMAP_FMT_plx " (value 0x%08x)\n", \
+                __FUNCTION__, paddr, value)
 
 /* OMAP-specific Linux bootloader tags for the ATAG_BOARD area
    (Board-specifc tags are not here)  */
index c32d3f7..e38b918 100644 (file)
@@ -96,6 +96,7 @@ struct omap_intr_handler_s {
     qemu_irq parent_intr[2];
     unsigned char nbanks;
     int level_only;
+    uint8_t revision;
 
     /* state */
     uint32_t new_agr[2];
@@ -407,6 +408,63 @@ void omap_inth_reset(struct omap_intr_handler_s *s)
     qemu_set_irq(s->parent_intr[1], 0);
 }
 
+static void omap_inth_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)opaque;
+    int i, j;
+    
+    qemu_put_be32(f, s->new_agr[0]);
+    qemu_put_be32(f, s->new_agr[1]);
+    qemu_put_sbe32(f, s->sir_intr[0]);
+    qemu_put_sbe32(f, s->sir_intr[1]);
+    qemu_put_sbe32(f, s->autoidle);
+    qemu_put_be32(f, s->mask);
+    qemu_put_byte(f, s->nbanks);
+    for (i = 0; i < s->nbanks; i++) {
+        qemu_put_be32(f, s->bank[i].irqs);
+        qemu_put_be32(f, s->bank[i].inputs);
+        qemu_put_be32(f, s->bank[i].mask);
+        qemu_put_be32(f, s->bank[i].fiq);
+        qemu_put_be32(f, s->bank[i].sens_edge);
+        qemu_put_be32(f, s->bank[i].swi);
+        for (j = 0; j < 32; j++)
+            qemu_put_byte(f, s->bank[i].priority[j]);
+    }
+}
+
+static int omap_inth_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)opaque;
+    int i, j;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->new_agr[0] = qemu_get_be32(f);
+    s->new_agr[1] = qemu_get_be32(f);
+    s->sir_intr[0] = qemu_get_sbe32(f);
+    s->sir_intr[1] = qemu_get_sbe32(f);
+    s->autoidle = qemu_get_sbe32(f);
+    s->mask = qemu_get_be32(f);
+    if (qemu_get_byte(f) != s->nbanks)
+        return -EINVAL;
+    for (i = 0; i < s->nbanks; i++) {
+        s->bank[i].irqs = qemu_get_be32(f);
+        s->bank[i].inputs = qemu_get_be32(f);
+        s->bank[i].mask = qemu_get_be32(f);
+        s->bank[i].fiq = qemu_get_be32(f);
+        s->bank[i].sens_edge = qemu_get_be32(f);
+        s->bank[i].swi = qemu_get_be32(f);
+        for (j = 0; j < 32; j++)
+            s->bank[i].priority[j] = qemu_get_byte(f);
+    }
+    
+    omap_inth_update(s, 0);
+    omap_inth_update(s, 1);
+    
+    return 0;
+}
+
 struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
                 unsigned long size, unsigned char nbanks, qemu_irq **pins,
                 qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk)
@@ -429,6 +487,8 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
                     omap_inth_writefn, s);
     cpu_register_physical_memory(base, size, iomemtype);
 
+    register_savevm("omap_inth", -1, 0,
+                    omap_inth_save_state, omap_inth_load_state, s);
     return s;
 }
 
@@ -449,7 +509,7 @@ static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr)
 
     switch (offset) {
     case 0x00: /* INTC_REVISION */
-        return 0x21;
+        return s->revision;
 
     case 0x10: /* INTC_SYSCONFIG */
         return (s->autoidle >> 2) & 1;
@@ -625,7 +685,9 @@ static CPUWriteMemoryFunc *omap2_inth_writefn[] = {
     omap2_inth_write,
 };
 
-struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
+struct omap_intr_handler_s *omap2_inth_init(
+                struct omap_mpu_state_s *mpu,
+                target_phys_addr_t base,
                 int size, int nbanks, qemu_irq **pins,
                 qemu_irq parent_irq, qemu_irq parent_fiq,
                 omap_clk fclk, omap_clk iclk)
@@ -635,6 +697,7 @@ struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
             qemu_mallocz(sizeof(struct omap_intr_handler_s) +
                             sizeof(struct omap_intr_handler_bank_s) * nbanks);
 
+    s->revision = cpu_class_omap3(mpu) ? 0x40 : 0x21;
     s->parent_intr[0] = parent_irq;
     s->parent_intr[1] = parent_fiq;
     s->nbanks = nbanks;
@@ -649,6 +712,8 @@ struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
                     omap2_inth_writefn, s);
     cpu_register_physical_memory(base, size, iomemtype);
 
+    register_savevm("omap_inth", -1, 0,
+                    omap_inth_save_state, omap_inth_load_state, s);
     return s;
 }
 
@@ -1968,6 +2033,39 @@ struct omap_uart_s {
     uint8_t clksel;
 };
 
+static void omap_uart_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *)opaque;
+    
+    qemu_put_byte(f, s->eblr);
+    qemu_put_byte(f, s->syscontrol);
+    qemu_put_byte(f, s->wkup);
+    qemu_put_byte(f, s->cfps);
+    qemu_put_byte(f, s->mdr[0]);
+    qemu_put_byte(f, s->mdr[1]);
+    qemu_put_byte(f, s->scr);
+    qemu_put_byte(f, s->clksel);
+}
+
+static int omap_uart_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->eblr = qemu_get_byte(f);
+    s->syscontrol = qemu_get_byte(f);
+    s->wkup = qemu_get_byte(f);
+    s->cfps = qemu_get_byte(f);
+    s->mdr[0] = qemu_get_byte(f);
+    s->mdr[1] = qemu_get_byte(f);
+    s->scr = qemu_get_byte(f);
+    s->clksel = qemu_get_byte(f);
+    
+    return  0;
+}
+
 void omap_uart_reset(struct omap_uart_s *s)
 {
     s->eblr = 0x00;
@@ -1990,6 +2088,8 @@ struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
     s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
                                chr ?: qemu_chr_open("null", "null", NULL), 1);
 
+    register_savevm("omap_uart", base >> 8, 0,
+                    omap_uart_save_state, omap_uart_load_state, s);
     return s;
 }
 
@@ -2102,9 +2202,12 @@ struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
 void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
 {
     /* TODO: Should reuse or destroy current s->serial */
+    fprintf(stderr, "%s: WARNING - this function is broken, avoid using it\n",
+            __FUNCTION__);
     s->serial = serial_mm_init(s->base, 2, s->irq,
-                    omap_clk_getrate(s->fclk) / 16,
-                    chr ?: qemu_chr_open("null", "null", NULL), 1);
+                               omap_clk_getrate(s->fclk) / 16,
+                               chr ?: qemu_chr_open("null", "null", NULL),
+                               1);
 }
 
 /* MPU Clock/Reset/Power Mode Control */
index 20b3811..895a1c7 100644 (file)
@@ -81,6 +81,12 @@ struct omap_gp_timer_s {
 #define GPT_OVF_IT     (1 << 1)
 #define GPT_MAT_IT     (1 << 0)
 
+/*if the clock source of gptimer changes, rate must be regenerated*/
+void omap_gp_timer_change_clk(struct omap_gp_timer_s *timer)
+{
+    timer->rate = omap_clk_getrate(timer->clk);
+}
+
 static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
 {
     if (timer->it_ena & it) {
@@ -106,11 +112,18 @@ static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
 
 static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
 {
-    uint64_t distance;
+    uint64_t distance, rate;
 
     if (timer->st && timer->rate) {
         distance = qemu_get_clock(vm_clock) - timer->time;
-        distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
+        
+        /*if ticks_per_sec is bigger than 32bit we cannot use muldiv64*/
+        if (timer->ticks_per_sec > 0xffffffff) {
+            distance /= ticks_per_sec / 1000; /*distance ms*/
+            rate = timer->rate >> (timer->pre ? timer->ptv + 1 : 0);
+            distance = muldiv64(distance, rate, 1000);
+        } else
+            distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
 
         if (distance >= 0xffffffff - timer->val)
             return 0xffffffff;
@@ -130,15 +143,23 @@ static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
 
 static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
 {
-    int64_t expires, matches;
+    int64_t expires, matches, rate;
 
     if (timer->st && timer->rate) {
-        expires = muldiv64(0x100000000ll - timer->val,
+        if (timer->ticks_per_sec > 0xffffffff) {
+            rate = timer->rate >> (timer->pre ? timer->ptv + 1 : 0); /*1s -> rate ticks*/
+            expires = muldiv64(0x100000000ll - timer->val, ticks_per_sec, rate);
+        } else
+            expires = muldiv64(0x100000000ll - timer->val,
                         timer->ticks_per_sec, timer->rate);
         qemu_mod_timer(timer->timer, timer->time + expires);
 
         if (timer->ce && timer->match_val >= timer->val) {
-            matches = muldiv64(timer->match_val - timer->val,
+            if (timer->ticks_per_sec > 0xffffffff) {
+                rate = timer->rate >> (timer->pre ? timer->ptv + 1 : 0); /*1s -> rate ticks*/
+                matches = muldiv64(timer->match_val - timer->val, ticks_per_sec, rate);
+            } else
+                matches = muldiv64(timer->match_val - timer->val,
                             timer->ticks_per_sec, timer->rate);
             qemu_mod_timer(timer->match, timer->time + matches);
         } else
@@ -235,6 +256,7 @@ static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
     omap_clk_adduser(timer->clk,
                     qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
     timer->rate = omap_clk_getrate(timer->clk);
+    //fprintf(stderr, "omap gptimer clk rate 0x%llx\n", timer->rate);
 }
 
 static void omap_gp_timer_reset(struct omap_gp_timer_s *s)
@@ -467,6 +489,89 @@ static CPUWriteMemoryFunc *omap_gp_timer_writefn[] = {
     omap_gp_timer_write,
 };
 
+static void omap_gp_timer_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)opaque;
+    
+    qemu_put_timer(f, s->timer);
+    qemu_put_timer(f, s->match);
+    qemu_put_sbe32(f, s->in_val);
+    qemu_put_sbe32(f, s->out_val);
+    qemu_put_sbe64(f, s->time);
+    qemu_put_sbe64(f, s->rate);
+    qemu_put_sbe64(f, s->ticks_per_sec);
+    qemu_put_sbe16(f, s->config);
+    qemu_put_sbe32(f, s->status);
+    qemu_put_sbe32(f, s->it_ena);
+    qemu_put_sbe32(f, s->wu_ena);
+    qemu_put_sbe32(f, s->enable);
+    qemu_put_sbe32(f, s->inout);
+    qemu_put_sbe32(f, s->capt2);
+    qemu_put_sbe32(f, s->pt);
+    qemu_put_sbe32(f, s->trigger);
+    qemu_put_sbe32(f, s->capture);
+    qemu_put_sbe32(f, s->scpwm);
+    qemu_put_sbe32(f, s->ce);
+    qemu_put_sbe32(f, s->pre);
+    qemu_put_sbe32(f, s->ptv);
+    qemu_put_sbe32(f, s->ar);
+    qemu_put_sbe32(f, s->st);
+    qemu_put_sbe32(f, s->posted);
+    qemu_put_be32(f, s->val);
+    qemu_put_be32(f, s->load_val);
+    qemu_put_be32(f, s->capture_val[0]);
+    qemu_put_be32(f, s->capture_val[1]);
+    qemu_put_be32(f, s->match_val);
+    qemu_put_sbe32(f, s->capt_num);
+    qemu_put_be16(f, s->writeh);
+    qemu_put_be16(f, s->readh);
+}
+
+static int omap_gp_timer_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    qemu_get_timer(f, s->timer);
+    qemu_get_timer(f, s->match);
+    s->in_val = qemu_get_sbe32(f);
+    s->out_val = qemu_get_sbe32(f);
+    s->time = qemu_get_sbe64(f);
+    s->rate = qemu_get_sbe64(f);
+    s->ticks_per_sec = qemu_get_sbe64(f);
+    s->config = qemu_get_sbe16(f);
+    s->status = qemu_get_sbe32(f);
+    s->it_ena = qemu_get_sbe32(f);
+    s->wu_ena = qemu_get_sbe32(f);
+    s->enable = qemu_get_sbe32(f);
+    s->inout = qemu_get_sbe32(f);
+    s->capt2 = qemu_get_sbe32(f);
+    s->pt = qemu_get_sbe32(f);
+    s->trigger = qemu_get_sbe32(f);
+    s->capture = qemu_get_sbe32(f);
+    s->scpwm = qemu_get_sbe32(f);
+    s->ce = qemu_get_sbe32(f);
+    s->pre = qemu_get_sbe32(f);
+    s->ptv = qemu_get_sbe32(f);
+    s->ar = qemu_get_sbe32(f);
+    s->st = qemu_get_sbe32(f);
+    s->posted = qemu_get_sbe32(f);
+    s->val = qemu_get_be32(f);
+    s->load_val = qemu_get_be32(f);
+    s->capture_val[0] = qemu_get_be32(f);
+    s->capture_val[1] = qemu_get_be32(f);
+    s->match_val = qemu_get_be32(f);
+    s->capt_num = qemu_get_sbe32(f);
+    s->writeh = qemu_get_be16(f);
+    s->readh = qemu_get_be16(f);
+    
+    omap_gp_timer_update(s);
+    
+    return 0;
+}
+
 struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk)
 {
@@ -487,6 +592,8 @@ struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
                     omap_gp_timer_writefn, s);
     omap_l4_attach(ta, 0, iomemtype);
 
+    register_savevm("omap_gp_timer", (ta->base >> 12) & 0xfffff, 0,
+                    omap_gp_timer_save_state, omap_gp_timer_load_state, s);
     return s;
 }
 
@@ -503,11 +610,10 @@ static void omap_synctimer_reset(struct omap_synctimer_s *s)
 static uint32_t omap_synctimer_readw(void *opaque, target_phys_addr_t addr)
 {
     struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
-
+    
     switch (addr) {
     case 0x00: /* 32KSYNCNT_REV */
         return 0x21;
-
     case 0x10: /* CR */
         return omap_synctimer_read(s) - s->val;
     }
@@ -516,6 +622,14 @@ static uint32_t omap_synctimer_readw(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
+static uint32_t omap3_synctimer_readw(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *)opaque;
+    return (addr == 0x04) 
+        ? s->sysconfig 
+        : omap_synctimer_readw(opaque, addr);
+}
+
 static uint32_t omap_synctimer_readh(void *opaque, target_phys_addr_t addr)
 {
     struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
@@ -523,11 +637,23 @@ static uint32_t omap_synctimer_readh(void *opaque, target_phys_addr_t addr)
 
     if (addr & 2)
         return s->readh;
-    else {
-        ret = omap_synctimer_readw(opaque, addr);
-        s->readh = ret >> 16;
-        return ret & 0xffff;
-    }
+
+    ret = omap_synctimer_readw(opaque, addr);
+    s->readh = ret >> 16;
+    return ret & 0xffff;
+}
+
+static uint32_t omap3_synctimer_readh(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
+    uint32_t ret;
+    
+    if (addr & 2)
+        return s->readh;
+    
+    ret = omap3_synctimer_readw(opaque, addr);
+    s->readh = ret >> 16;
+    return ret & 0xffff;
 }
 
 static CPUReadMemoryFunc *omap_synctimer_readfn[] = {
@@ -536,26 +662,80 @@ static CPUReadMemoryFunc *omap_synctimer_readfn[] = {
     omap_synctimer_readw,
 };
 
+static CPUReadMemoryFunc *omap3_synctimer_readfn[] = {
+    omap_badwidth_read32,
+    omap3_synctimer_readh,
+    omap3_synctimer_readw,
+};
+
 static void omap_synctimer_write(void *opaque, target_phys_addr_t addr,
                 uint32_t value)
 {
     OMAP_BAD_REG(addr);
 }
 
+static void omap3_synctimer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *)opaque;
+    if (addr == 0x04) /* SYSCONFIG */
+        s->sysconfig = value & 0x0c;
+    else
+        OMAP_BAD_REG(addr);
+}
+
 static CPUWriteMemoryFunc *omap_synctimer_writefn[] = {
     omap_badwidth_write32,
     omap_synctimer_write,
     omap_synctimer_write,
 };
 
+static CPUWriteMemoryFunc *omap3_synctimer_writefn[] = {
+    omap_badwidth_write32,
+    omap3_synctimer_write,
+    omap3_synctimer_write,
+};
+
+static void omap_synctimer_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *)opaque;
+    
+    qemu_put_be32(f, s->val);
+    qemu_put_be16(f, s->readh);
+    qemu_put_be32(f, s->sysconfig);
+}
+
+static int omap_synctimer_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->val = qemu_get_be32(f);
+    s->readh = qemu_get_be16(f);
+    s->sysconfig = qemu_get_be32(f);
+    
+    omap_synctimer_reset(s);
+    
+    return 0;
+}
+
 void omap_synctimer_init(struct omap_target_agent_s *ta,
                 struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
 {
     struct omap_synctimer_s *s = &mpu->synctimer;
 
     omap_synctimer_reset(s);
-    omap_l4_attach(ta, 0, l4_register_io_memory(0,
-                      omap_synctimer_readfn, omap_synctimer_writefn, s));
+    if (cpu_class_omap3(mpu))
+        omap_l4_attach(ta, 0, l4_register_io_memory(0,
+                    omap3_synctimer_readfn, omap3_synctimer_writefn, s));
+    else
+        omap_l4_attach(ta, 0, l4_register_io_memory(0,
+                    omap_synctimer_readfn, omap_synctimer_writefn, s));
+    
+    register_savevm("omap_synctimer", -1, 0,
+                    omap_synctimer_save_state, omap_synctimer_load_state, s);
 }
 
 /* General-Purpose Interface of OMAP2 */
@@ -565,6 +745,7 @@ struct omap2_gpio_s {
     qemu_irq *in;
     qemu_irq handler[32];
 
+    uint8_t revision;
     uint8_t config[2];
     uint32_t inputs;
     uint32_t outputs;
@@ -665,7 +846,7 @@ static uint32_t omap_gpio_module_read(void *opaque, target_phys_addr_t addr)
 
     switch (addr) {
     case 0x00: /* GPIO_REVISION */
-        return 0x18;
+        return s->revision;
 
     case 0x10: /* GPIO_SYSCONFIG */
         return s->config[0];
@@ -742,7 +923,7 @@ static void omap_gpio_module_write(void *opaque, target_phys_addr_t addr,
     case 0x00: /* GPIO_REVISION */
     case 0x14: /* GPIO_SYSSTATUS */
     case 0x38: /* GPIO_DATAIN */
-        OMAP_RO_REG(addr);
+        OMAP_RO_REGV(addr, value);
         break;
 
     case 0x10: /* GPIO_SYSCONFIG */
@@ -868,7 +1049,7 @@ static void omap_gpio_module_write(void *opaque, target_phys_addr_t addr,
         break;
 
     default:
-        OMAP_BAD_REG(addr);
+        OMAP_BAD_REGV(addr, value);
         return;
     }
 }
@@ -940,16 +1121,18 @@ static CPUWriteMemoryFunc *omap_gpio_module_writefn[] = {
     omap_gpio_module_write,
 };
 
-static void omap_gpio_module_init(struct omap2_gpio_s *s,
+static void omap_gpio_module_init(struct omap_mpu_state_s *mpu,
+                struct omap2_gpio_s *s,
                 struct omap_target_agent_s *ta, int region,
-                qemu_irq mpu, qemu_irq dsp, qemu_irq wkup,
+                qemu_irq mpu_irq, qemu_irq dsp_irq, qemu_irq wkup_irq,
                 omap_clk fclk, omap_clk iclk)
 {
     int iomemtype;
 
-    s->irq[0] = mpu;
-    s->irq[1] = dsp;
-    s->wkup = wkup;
+    s->revision = cpu_class_omap3(mpu) ? 0x25 : 0x18;
+    s->irq[0] = mpu_irq;
+    s->irq[1] = dsp_irq;
+    s->wkup = wkup_irq;
     s->in = qemu_allocate_irqs(omap_gpio_module_set, s, 32);
 
     iomemtype = l4_register_io_memory(0, omap_gpio_module_readfn,
@@ -958,13 +1141,72 @@ static void omap_gpio_module_init(struct omap2_gpio_s *s,
 }
 
 struct omap_gpif_s {
-    struct omap2_gpio_s module[5];
+    struct omap2_gpio_s module[6];
     int modules;
 
     int autoidle;
     int gpo;
 };
 
+static void omap_gpif_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_gpif_s *s = (struct omap_gpif_s *)opaque;
+    int i, j;
+    
+    qemu_put_sbe32(f, s->autoidle);
+    qemu_put_sbe32(f, s->gpo);
+    qemu_put_sbe32(f, s->modules);
+    for (i = 0; i < s->modules; i++) {
+        for (j = 0; j < 2; j++) {
+            qemu_put_byte(f, s->module[i].config[j]);
+            qemu_put_be32(f, s->module[i].level[j]);
+            qemu_put_be32(f, s->module[i].edge[j]);
+            qemu_put_be32(f, s->module[i].mask[j]);
+            qemu_put_be32(f, s->module[i].ints[j]);
+        }
+        qemu_put_be32(f, s->module[i].inputs);
+        qemu_put_be32(f, s->module[i].outputs);
+        qemu_put_be32(f, s->module[i].dir);
+        qemu_put_be32(f, s->module[i].wumask);
+        qemu_put_be32(f, s->module[i].debounce);
+        qemu_put_byte(f, s->module[i].delay);
+    }
+}
+
+static int omap_gpif_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_gpif_s *s = (struct omap_gpif_s *)opaque;
+    int i, j;
+
+    if (version_id)
+        return -EINVAL;
+    
+    s->autoidle = qemu_get_sbe32(f);
+    s->gpo = qemu_get_sbe32(f);
+    if (qemu_get_sbe32(f) != s->modules)
+        return -EINVAL;
+    for (i = 0; i < s->modules; i++) {
+        for (j = 0; j < 2; j++) {
+            s->module[i].config[j] = qemu_get_byte(f);
+            s->module[i].level[j] = qemu_get_be32(f);
+            s->module[i].edge[j] = qemu_get_be32(f);
+            s->module[i].mask[j] = qemu_get_be32(f);
+            s->module[i].ints[j] = qemu_get_be32(f);
+        }
+        s->module[i].inputs = qemu_get_be32(f);
+        s->module[i].outputs = qemu_get_be32(f);
+        s->module[i].dir = qemu_get_be32(f);
+        s->module[i].wumask = qemu_get_be32(f);
+        s->module[i].debounce = qemu_get_be32(f);
+        s->module[i].delay = qemu_get_byte(f);
+
+        omap_gpio_module_level_update(&s->module[i], 0);
+        omap_gpio_module_level_update(&s->module[i], 1);
+    }
+    
+    return 0;
+}
+
 static void omap_gpif_reset(struct omap_gpif_s *s)
 {
     int i;
@@ -1045,7 +1287,8 @@ static CPUWriteMemoryFunc *omap_gpif_top_writefn[] = {
     omap_gpif_top_write,
 };
 
-struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
+struct omap_gpif_s *omap2_gpio_init(struct omap_mpu_state_s *mpu,
+                struct omap_target_agent_s *ta,
                 qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules)
 {
     int iomemtype, i;
@@ -1055,7 +1298,7 @@ struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
 
     s->modules = modules;
     for (i = 0; i < modules; i ++)
-        omap_gpio_module_init(s->module + i, ta, region[i],
+        omap_gpio_module_init(mpu, s->module + i, ta, region[i],
                         irq[i], 0, 0, fclk[i], iclk);
 
     omap_gpif_reset(s);
@@ -1067,6 +1310,26 @@ struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
     return s;
 }
 
+struct omap_gpif_s *omap3_gpif_init()
+{
+    struct omap_gpif_s *s = (struct omap_gpif_s *)
+        qemu_mallocz(sizeof(struct omap_gpif_s));
+    omap_gpif_reset(s);
+    
+    register_savevm("omap_gpif", -1, 0,
+                    omap_gpif_save_state, omap_gpif_load_state, s);
+    return s;
+}
+
+void omap3_gpio_init(struct omap_mpu_state_s *mpu,
+                     struct omap_gpif_s *s,struct omap_target_agent_s *ta,
+                     qemu_irq irq, omap_clk *fclk, omap_clk iclk, int module_index)
+{
+    s->modules++;
+    omap_gpio_module_init(mpu, s->module + module_index, ta, 0,
+                          irq, 0, 0, NULL,NULL);
+}
+
 qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start)
 {
     if (start >= s->modules * 32 || start < 0)
@@ -1082,330 +1345,6 @@ void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler)
     s->module[line >> 5].handler[line & 31] = handler;
 }
 
-/* Multichannel SPI */
-struct omap_mcspi_s {
-    qemu_irq irq;
-    int chnum;
-
-    uint32_t sysconfig;
-    uint32_t systest;
-    uint32_t irqst;
-    uint32_t irqen;
-    uint32_t wken;
-    uint32_t control;
-
-    struct omap_mcspi_ch_s {
-        qemu_irq txdrq;
-        qemu_irq rxdrq;
-        uint32_t (*txrx)(void *opaque, uint32_t, int);
-        void *opaque;
-
-        uint32_t tx;
-        uint32_t rx;
-
-        uint32_t config;
-        uint32_t status;
-        uint32_t control;
-    } ch[4];
-};
-
-static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
-{
-    qemu_set_irq(s->irq, s->irqst & s->irqen);
-}
-
-static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
-{
-    qemu_set_irq(ch->txdrq,
-                    (ch->control & 1) &&               /* EN */
-                    (ch->config & (1 << 14)) &&                /* DMAW */
-                    (ch->status & (1 << 1)) &&         /* TXS */
-                    ((ch->config >> 12) & 3) != 1);    /* TRM */
-    qemu_set_irq(ch->rxdrq,
-                    (ch->control & 1) &&               /* EN */
-                    (ch->config & (1 << 15)) &&                /* DMAW */
-                    (ch->status & (1 << 0)) &&         /* RXS */
-                    ((ch->config >> 12) & 3) != 2);    /* TRM */
-}
-
-static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
-{
-    struct omap_mcspi_ch_s *ch = s->ch + chnum;
-
-    if (!(ch->control & 1))                            /* EN */
-        return;
-    if ((ch->status & (1 << 0)) &&                     /* RXS */
-                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
-                    !(ch->config & (1 << 19)))         /* TURBO */
-        goto intr_update;
-    if ((ch->status & (1 << 1)) &&                     /* TXS */
-                    ((ch->config >> 12) & 3) != 1)     /* TRM */
-        goto intr_update;
-
-    if (!(s->control & 1) ||                           /* SINGLE */
-                    (ch->config & (1 << 20))) {                /* FORCE */
-        if (ch->txrx)
-            ch->rx = ch->txrx(ch->opaque, ch->tx,      /* WL */
-                            1 + (0x1f & (ch->config >> 7)));
-    }
-
-    ch->tx = 0;
-    ch->status |= 1 << 2;                              /* EOT */
-    ch->status |= 1 << 1;                              /* TXS */
-    if (((ch->config >> 12) & 3) != 2)                 /* TRM */
-        ch->status |= 1 << 0;                          /* RXS */
-
-intr_update:
-    if ((ch->status & (1 << 0)) &&                     /* RXS */
-                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
-                    !(ch->config & (1 << 19)))         /* TURBO */
-        s->irqst |= 1 << (2 + 4 * chnum);              /* RX_FULL */
-    if ((ch->status & (1 << 1)) &&                     /* TXS */
-                    ((ch->config >> 12) & 3) != 1)     /* TRM */
-        s->irqst |= 1 << (0 + 4 * chnum);              /* TX_EMPTY */
-    omap_mcspi_interrupt_update(s);
-    omap_mcspi_dmarequest_update(ch);
-}
-
-static void omap_mcspi_reset(struct omap_mcspi_s *s)
-{
-    int ch;
-
-    s->sysconfig = 0;
-    s->systest = 0;
-    s->irqst = 0;
-    s->irqen = 0;
-    s->wken = 0;
-    s->control = 4;
-
-    for (ch = 0; ch < 4; ch ++) {
-        s->ch[ch].config = 0x060000;
-        s->ch[ch].status = 2;                          /* TXS */
-        s->ch[ch].control = 0;
-
-        omap_mcspi_dmarequest_update(s->ch + ch);
-    }
-
-    omap_mcspi_interrupt_update(s);
-}
-
-static uint32_t omap_mcspi_read(void *opaque, target_phys_addr_t addr)
-{
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
-    int ch = 0;
-    uint32_t ret;
-
-    switch (addr) {
-    case 0x00: /* MCSPI_REVISION */
-        return 0x91;
-
-    case 0x10: /* MCSPI_SYSCONFIG */
-        return s->sysconfig;
-
-    case 0x14: /* MCSPI_SYSSTATUS */
-        return 1;                                      /* RESETDONE */
-
-    case 0x18: /* MCSPI_IRQSTATUS */
-        return s->irqst;
-
-    case 0x1c: /* MCSPI_IRQENABLE */
-        return s->irqen;
-
-    case 0x20: /* MCSPI_WAKEUPENABLE */
-        return s->wken;
-
-    case 0x24: /* MCSPI_SYST */
-        return s->systest;
-
-    case 0x28: /* MCSPI_MODULCTRL */
-        return s->control;
-
-    case 0x68: ch ++;
-    case 0x54: ch ++;
-    case 0x40: ch ++;
-    case 0x2c: /* MCSPI_CHCONF */
-        return s->ch[ch].config;
-
-    case 0x6c: ch ++;
-    case 0x58: ch ++;
-    case 0x44: ch ++;
-    case 0x30: /* MCSPI_CHSTAT */
-        return s->ch[ch].status;
-
-    case 0x70: ch ++;
-    case 0x5c: ch ++;
-    case 0x48: ch ++;
-    case 0x34: /* MCSPI_CHCTRL */
-        return s->ch[ch].control;
-
-    case 0x74: ch ++;
-    case 0x60: ch ++;
-    case 0x4c: ch ++;
-    case 0x38: /* MCSPI_TX */
-        return s->ch[ch].tx;
-
-    case 0x78: ch ++;
-    case 0x64: ch ++;
-    case 0x50: ch ++;
-    case 0x3c: /* MCSPI_RX */
-        s->ch[ch].status &= ~(1 << 0);                 /* RXS */
-        ret = s->ch[ch].rx;
-        omap_mcspi_transfer_run(s, ch);
-        return ret;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_mcspi_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
-{
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
-    int ch = 0;
-
-    switch (addr) {
-    case 0x00: /* MCSPI_REVISION */
-    case 0x14: /* MCSPI_SYSSTATUS */
-    case 0x30: /* MCSPI_CHSTAT0 */
-    case 0x3c: /* MCSPI_RX0 */
-    case 0x44: /* MCSPI_CHSTAT1 */
-    case 0x50: /* MCSPI_RX1 */
-    case 0x58: /* MCSPI_CHSTAT2 */
-    case 0x64: /* MCSPI_RX2 */
-    case 0x6c: /* MCSPI_CHSTAT3 */
-    case 0x78: /* MCSPI_RX3 */
-        OMAP_RO_REG(addr);
-        return;
-
-    case 0x10: /* MCSPI_SYSCONFIG */
-        if (value & (1 << 1))                          /* SOFTRESET */
-            omap_mcspi_reset(s);
-        s->sysconfig = value & 0x31d;
-        break;
-
-    case 0x18: /* MCSPI_IRQSTATUS */
-        if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
-            s->irqst &= ~value;
-            omap_mcspi_interrupt_update(s);
-        }
-        break;
-
-    case 0x1c: /* MCSPI_IRQENABLE */
-        s->irqen = value & 0x1777f;
-        omap_mcspi_interrupt_update(s);
-        break;
-
-    case 0x20: /* MCSPI_WAKEUPENABLE */
-        s->wken = value & 1;
-        break;
-
-    case 0x24: /* MCSPI_SYST */
-        if (s->control & (1 << 3))                     /* SYSTEM_TEST */
-            if (value & (1 << 11)) {                   /* SSB */
-                s->irqst |= 0x1777f;
-                omap_mcspi_interrupt_update(s);
-            }
-        s->systest = value & 0xfff;
-        break;
-
-    case 0x28: /* MCSPI_MODULCTRL */
-        if (value & (1 << 3))                          /* SYSTEM_TEST */
-            if (s->systest & (1 << 11)) {              /* SSB */
-                s->irqst |= 0x1777f;
-                omap_mcspi_interrupt_update(s);
-            }
-        s->control = value & 0xf;
-        break;
-
-    case 0x68: ch ++;
-    case 0x54: ch ++;
-    case 0x40: ch ++;
-    case 0x2c: /* MCSPI_CHCONF */
-        if ((value ^ s->ch[ch].config) & (3 << 14))    /* DMAR | DMAW */
-            omap_mcspi_dmarequest_update(s->ch + ch);
-        if (((value >> 12) & 3) == 3)                  /* TRM */
-            fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
-        if (((value >> 7) & 0x1f) < 3)                 /* WL */
-            fprintf(stderr, "%s: invalid WL value (%i)\n",
-                            __FUNCTION__, (value >> 7) & 0x1f);
-        s->ch[ch].config = value & 0x7fffff;
-        break;
-
-    case 0x70: ch ++;
-    case 0x5c: ch ++;
-    case 0x48: ch ++;
-    case 0x34: /* MCSPI_CHCTRL */
-        if (value & ~s->ch[ch].control & 1) {          /* EN */
-            s->ch[ch].control |= 1;
-            omap_mcspi_transfer_run(s, ch);
-        } else
-            s->ch[ch].control = value & 1;
-        break;
-
-    case 0x74: ch ++;
-    case 0x60: ch ++;
-    case 0x4c: ch ++;
-    case 0x38: /* MCSPI_TX */
-        s->ch[ch].tx = value;
-        s->ch[ch].status &= ~(1 << 1);                 /* TXS */
-        omap_mcspi_transfer_run(s, ch);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static CPUReadMemoryFunc *omap_mcspi_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_mcspi_read,
-};
-
-static CPUWriteMemoryFunc *omap_mcspi_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_mcspi_write,
-};
-
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
-                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
-{
-    int iomemtype;
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
-            qemu_mallocz(sizeof(struct omap_mcspi_s));
-    struct omap_mcspi_ch_s *ch = s->ch;
-
-    s->irq = irq;
-    s->chnum = chnum;
-    while (chnum --) {
-        ch->txdrq = *drq ++;
-        ch->rxdrq = *drq ++;
-        ch ++;
-    }
-    omap_mcspi_reset(s);
-
-    iomemtype = l4_register_io_memory(0, omap_mcspi_readfn,
-                    omap_mcspi_writefn, s);
-    omap_l4_attach(ta, 0, iomemtype);
-
-    return s;
-}
-
-void omap_mcspi_attach(struct omap_mcspi_s *s,
-                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
-                int chipselect)
-{
-    if (chipselect < 0 || chipselect >= s->chnum)
-        cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n",
-                        __FUNCTION__, chipselect);
-
-    s->ch[chipselect].txrx = txrx;
-    s->ch[chipselect].opaque = opaque;
-}
-
 /* Enhanced Audio Controller (CODEC only) */
 struct omap_eac_s {
     qemu_irq irq;
@@ -2175,22 +2114,6 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
 }
 
 /* L4 Interconnect */
-struct omap_target_agent_s {
-    struct omap_l4_s *bus;
-    int regions;
-    struct omap_l4_region_s *start;
-    target_phys_addr_t base;
-    uint32_t component;
-    uint32_t control;
-    uint32_t status;
-};
-
-struct omap_l4_s {
-    target_phys_addr_t base;
-    int ta_num;
-    struct omap_target_agent_s ta[0];
-};
-
 #ifdef L4_MUX_HACK
 static int omap_l4_io_entries;
 static int omap_cpu_io_entry;
@@ -2359,11 +2282,7 @@ static CPUWriteMemoryFunc *omap_l4ta_writefn[] = {
 #define L4TA(n)                (n)
 #define L4TAO(n)       ((n) + 39)
 
-static struct omap_l4_region_s {
-    target_phys_addr_t offset;
-    size_t size;
-    int access;
-} omap_l4_region[125] = {
+static struct omap_l4_region_s omap_l4_region[125] = {
     [  1] = { 0x40800,  0x800, 32          }, /* Initiator agent */
     [  2] = { 0x41000, 0x1000, 32          }, /* Link agent */
     [  0] = { 0x40000,  0x800, 32          }, /* Address and protection */
@@ -2491,12 +2410,7 @@ static struct omap_l4_region_s {
     [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */
 };
 
-static struct omap_l4_agent_info_s {
-    int ta;
-    int region;
-    int regions;
-    int ta_region;
-} omap_l4_agent_info[54] = {
+static struct omap_l4_agent_info_s omap_l4_agent_info[54] = {
     { 0,           0, 3, 2 }, /* L4IA initiatior agent */
     { L4TAO(1),    3, 2, 1 }, /* Control and pinout module */
     { L4TAO(2),    5, 2, 1 }, /* 32K timer */
@@ -2556,7 +2470,7 @@ static struct omap_l4_agent_info_s {
 #define omap_l4ta(bus, cs)     omap_l4ta_get(bus, L4TA(cs))
 #define omap_l4tao(bus, cs)    omap_l4ta_get(bus, L4TAO(cs))
 
-struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs)
+static struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs)
 {
     int i, iomemtype;
     struct omap_target_agent_s *ta = 0;
@@ -2625,6 +2539,16 @@ target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
     return base;
 }
 
+target_phys_addr_t omap_l4_base(struct omap_target_agent_s *ta, int region)
+{
+    return ta->bus->base + ta->start[region].offset;
+}
+
+uint32_t omap_l4_size(struct omap_target_agent_s *ta, int region)
+{
+    return ta->start[region].size;
+}
+
 /* TEST-Chip-level TAP */
 static uint32_t omap_tap_read(void *opaque, target_phys_addr_t addr)
 {
@@ -2641,6 +2565,8 @@ static uint32_t omap_tap_read(void *opaque, target_phys_addr_t addr)
             return 0x5b68a02f; /* ES 2.2 */
         case omap3430:
             return 0x1b7ae02f; /* ES 2 */
+        case omap3530:
+            return 0x3b7ae02f;  /* ES 3.0 */
         default:
             cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__);
         }
@@ -2658,6 +2584,8 @@ static uint32_t omap_tap_read(void *opaque, target_phys_addr_t addr)
             return 0x000000f0;
         case omap3430:
             return 0x000000f0;
+        case omap3530:
+            return 0x000f00f0;
         default:
             cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__);
         }
@@ -2671,6 +2599,7 @@ static uint32_t omap_tap_read(void *opaque, target_phys_addr_t addr)
         case omap2430:
             return 0xcafeb68a; /* ES 2.2 */
         case omap3430:
+        case omap3530:
             return 0xcafeb7ae; /* ES 2 */
         default:
             cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__);
@@ -3904,16 +3833,88 @@ struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
 /* SDRAM Controller Subsystem */
 struct omap_sdrc_s {
     uint8_t config;
+    uint32_t cscfg;
+    uint32_t sharing;
+    uint32_t dlla_ctrl;
+    uint32_t power_reg;
+    struct {
+        uint32_t mcfg;
+        uint32_t mr;
+        uint32_t emr2;
+        uint32_t actim_ctrla;
+        uint32_t actim_ctrlb;
+        uint32_t rfr_ctrl;
+        uint32_t manual;
+    } cs[2];
 };
 
+static void omap_sdrc_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *)opaque;
+    int i;
+    
+    qemu_put_byte(f, s->config);
+    qemu_put_be32(f, s->cscfg);
+    qemu_put_be32(f, s->sharing);
+    qemu_put_be32(f, s->dlla_ctrl);
+    qemu_put_be32(f, s->power_reg);
+    for (i = 0; i < 2; i++) {
+        qemu_put_be32(f, s->cs[i].mcfg);
+        qemu_put_be32(f, s->cs[i].mr);
+        qemu_put_be32(f, s->cs[i].emr2);
+        qemu_put_be32(f, s->cs[i].actim_ctrla);
+        qemu_put_be32(f, s->cs[i].actim_ctrlb);
+        qemu_put_be32(f, s->cs[i].rfr_ctrl);
+        qemu_put_be32(f, s->cs[i].manual);
+    }
+}
+
+static int omap_sdrc_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->config = qemu_get_byte(f);
+    s->cscfg = qemu_get_be32(f);
+    s->sharing = qemu_get_be32(f);
+    s->dlla_ctrl = qemu_get_be32(f);
+    s->power_reg = qemu_get_be32(f);
+    for (i = 0; i < 2; i++) {
+        s->cs[i].mcfg = qemu_get_be32(f);
+        s->cs[i].mr = qemu_get_be32(f);
+        s->cs[i].emr2 = qemu_get_be32(f);
+        s->cs[i].actim_ctrla = qemu_get_be32(f);
+        s->cs[i].actim_ctrlb = qemu_get_be32(f);
+        s->cs[i].rfr_ctrl = qemu_get_be32(f);
+        s->cs[i].manual = qemu_get_be32(f);
+    }
+    
+    return 0;
+}
+
 static void omap_sdrc_reset(struct omap_sdrc_s *s)
 {
-    s->config = 0x10;
+    s->config    = 0x10;
+    s->cscfg     = 0x4;
+    s->sharing   = 0; // TODO: copy from system control module
+    s->dlla_ctrl = 0;
+    s->power_reg = 0x85;
+    s->cs[0].mcfg        = s->cs[1].mcfg        = 0; // TODO: copy from system control module!
+    s->cs[0].mr          = s->cs[1].mr          = 0x0024;
+    s->cs[0].emr2        = s->cs[1].emr2        = 0;
+    s->cs[0].actim_ctrla = s->cs[1].actim_ctrla = 0;
+    s->cs[0].actim_ctrlb = s->cs[1].actim_ctrlb = 0;
+    s->cs[0].rfr_ctrl    = s->cs[1].rfr_ctrl    = 0;
+    s->cs[0].manual      = s->cs[1].manual      = 0;
 }
 
 static uint32_t omap_sdrc_read(void *opaque, target_phys_addr_t addr)
 {
     struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
+    int cs = 0;
 
     switch (addr) {
     case 0x00: /* SDRC_REVISION */
@@ -3923,38 +3924,77 @@ static uint32_t omap_sdrc_read(void *opaque, target_phys_addr_t addr)
         return s->config;
 
     case 0x14: /* SDRC_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
+        return 1; /* RESETDONE */
 
     case 0x40: /* SDRC_CS_CFG */
+        return s->cscfg;
+
     case 0x44: /* SDRC_SHARING */
+        return s->sharing;
+            
     case 0x48: /* SDRC_ERR_ADDR */
+        return 0;
+
     case 0x4c: /* SDRC_ERR_TYPE */
+        return 0x8;
+            
     case 0x60: /* SDRC_DLLA_SCTRL */
+        return s->dlla_ctrl;
+        
     case 0x64: /* SDRC_DLLA_STATUS */
+        return ~(s->dlla_ctrl & 0x4);
+
     case 0x68: /* SDRC_DLLB_CTRL */
     case 0x6c: /* SDRC_DLLB_STATUS */
-    case 0x70: /* SDRC_POWER */
-    case 0x80: /* SDRC_MCFG_0 */
-    case 0x84: /* SDRC_MR_0 */
-    case 0x88: /* SDRC_EMR1_0 */
-    case 0x8c: /* SDRC_EMR2_0 */
-    case 0x90: /* SDRC_EMR3_0 */
-    case 0x94: /* SDRC_DCDL1_CTRL */
-    case 0x98: /* SDRC_DCDL2_CTRL */
-    case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
-    case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
-    case 0xa4: /* SDRC_RFR_CTRL_0 */
-    case 0xa8: /* SDRC_MANUAL_0 */
-    case 0xb0: /* SDRC_MCFG_1 */
-    case 0xb4: /* SDRC_MR_1 */
-    case 0xb8: /* SDRC_EMR1_1 */
-    case 0xbc: /* SDRC_EMR2_1 */
-    case 0xc0: /* SDRC_EMR3_1 */
-    case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
-    case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
-    case 0xd4: /* SDRC_RFR_CTRL_1 */
-    case 0xd8: /* SDRC_MANUAL_1 */
         return 0x00;
+    
+    case 0x70: /* SDRC_POWER */
+        return s->power_reg;
+
+    case 0xb0 ... 0xd8:
+        cs = 1;
+        addr -= 0x30;
+        /* fall through */
+    case 0x80 ... 0xa8:
+        switch (addr & 0x3f) {
+        case 0x00: /* SDRC_MCFG_x */
+            return s->cs[cs].mcfg;
+        case 0x04: /* SDRC_MR_x */
+            return s->cs[cs].mr;
+        case 0x08: /* SDRC_EMR1_x */
+            return 0x00;
+        case 0x0c: /* SDRC_EMR2_x */
+            return s->cs[cs].emr2;
+        case 0x10: /* SDRC_EMR3_x */
+            return 0x00;
+        case 0x14:
+            if (cs)
+                return s->cs[1].actim_ctrla; /* SDRC_ACTIM_CTRLA_1 */
+            return 0x00;                     /* SDRC_DCDL1_CTRL */
+        case 0x18:
+            if (cs)
+                return s->cs[1].actim_ctrlb; /* SDRC_ACTIM_CTRLB_1 */
+            return 0x00;                     /* SDRC_DCDL2_CTRL */
+        case 0x1c:
+            if (!cs)
+                return s->cs[0].actim_ctrla; /* SDRC_ACTIM_CTRLA_0 */
+            break;
+        case 0x20:
+            if (!cs)
+                return s->cs[0].actim_ctrlb; /* SDRC_ACTIM_CTRLB_0 */
+            break;
+        case 0x24: /* SDRC_RFR_CTRL_x */
+            return s->cs[cs].rfr_ctrl;
+        case 0x28: /* SDRC_MANUAL_x */
+            return s->cs[cs].manual;
+        default:
+            break;
+        }
+        addr += cs * 0x30; // restore address to get correct error messages
+        break;
+
+    default:
+        break;
     }
 
     OMAP_BAD_REG(addr);
@@ -3965,6 +4005,7 @@ static void omap_sdrc_write(void *opaque, target_phys_addr_t addr,
                 uint32_t value)
 {
     struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
+    int cs = 0;
 
     switch (addr) {
     case 0x00: /* SDRC_REVISION */
@@ -3972,49 +4013,104 @@ static void omap_sdrc_write(void *opaque, target_phys_addr_t addr,
     case 0x48: /* SDRC_ERR_ADDR */
     case 0x64: /* SDRC_DLLA_STATUS */
     case 0x6c: /* SDRC_DLLB_STATUS */
-        OMAP_RO_REG(addr);
-        return;
+        OMAP_RO_REGV(addr, value);
+        break;
 
     case 0x10: /* SDRC_SYSCONFIG */
-        if ((value >> 3) != 0x2)
-            fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
-                            __FUNCTION__, value >> 3);
+        /* ignore invalid idle mode settings */
+        /*if ((value >> 3) != 0x2)
+            fprintf(stderr, "%s: bad SDRAM idle mode %i for SDRC_SYSCONFIG (full value 0x%08x)\n",
+                            __FUNCTION__, value >> 3, value);*/
         if (value & 2)
             omap_sdrc_reset(s);
         s->config = value & 0x18;
         break;
 
     case 0x40: /* SDRC_CS_CFG */
+        s->cscfg = value & 0x30f;
+        break;
+
     case 0x44: /* SDRC_SHARING */
+        if (!(s->sharing & 0x40000000)) /* LOCK */
+            s->sharing = value & 0x40007f00;
+        break;
+
     case 0x4c: /* SDRC_ERR_TYPE */
-    case 0x60: /* SDRC_DLLA_SCTRL */
+        OMAP_BAD_REGV(addr, value);
+        break;
+
+    case 0x60: /* SDRC_DLLA_CTRL */
+        s->dlla_ctrl = value & 0xffff00fe;
+        break;
+
     case 0x68: /* SDRC_DLLB_CTRL */
-    case 0x70: /* SDRC_POWER */
-    case 0x80: /* SDRC_MCFG_0 */
-    case 0x84: /* SDRC_MR_0 */
-    case 0x88: /* SDRC_EMR1_0 */
-    case 0x8c: /* SDRC_EMR2_0 */
-    case 0x90: /* SDRC_EMR3_0 */
-    case 0x94: /* SDRC_DCDL1_CTRL */
-    case 0x98: /* SDRC_DCDL2_CTRL */
-    case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
-    case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
-    case 0xa4: /* SDRC_RFR_CTRL_0 */
-    case 0xa8: /* SDRC_MANUAL_0 */
-    case 0xb0: /* SDRC_MCFG_1 */
-    case 0xb4: /* SDRC_MR_1 */
-    case 0xb8: /* SDRC_EMR1_1 */
-    case 0xbc: /* SDRC_EMR2_1 */
-    case 0xc0: /* SDRC_EMR3_1 */
-    case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
-    case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
-    case 0xd4: /* SDRC_RFR_CTRL_1 */
-    case 0xd8: /* SDRC_MANUAL_1 */
+        /* silently ignore */
+        /*OMAP_BAD_REGV(addr, value);*/
+        break;
+        
+    case 0x70: /* SDRC_POWER_REG */
+        s->power_reg = value & 0x04fffffd;
+        break;
+
+    case 0xb0 ... 0xd8:
+        cs = 1;
+        addr -= 0x30;
+        /* fall through */
+    case 0x80 ... 0xa8:
+        switch (addr & 0x3f) {
+        case 0x00: /* SDRC_MCFG_x */
+            if (!(s->cs[cs].mcfg & 0x40000000)) { /* LOCKSTATUS */
+                if (value & 0x00080000) /* ADDRMUXLEGACY */
+                    s->cs[cs].mcfg = value & 0x477bffdf;
+                else
+                    s->cs[cs].mcfg = value & 0x41fbffdf; // ????
+            }
+            break;
+        case 0x04: /* SDRC_MR_x */
+            s->cs[cs].mr = value & 0xfff;
+            break;
+        case 0x08: /* SDRC_EMR1_x */
+            break;
+        case 0x0c: /* SDRC_EMR2_x */
+            s->cs[cs].emr2 = value & 0xfff;
+            break;
+        case 0x10: /* SDRC_EMR3_x */
+            break;
+        case 0x14:
+            if (cs)
+                s->cs[1].actim_ctrla = value & 0xffffffdf; /* SDRC_ACTIM_CTRLA_1 */
+            break;                                         /* SDRC_DCDL1_CTRL */
+        case 0x18:
+            if (cs)
+                s->cs[1].actim_ctrlb = value & 0x000377ff; /* SDRC_ACTIM_CTRLB_1 */
+            break;                                         /* SDRC_DCDL2_CTRL */
+        case 0x1c:
+            if (!cs)
+                s->cs[0].actim_ctrla = value & 0xffffffdf; /* SDRC_ACTIM_CTRLA_0 */
+            else
+                OMAP_BAD_REGV(addr + 0x30, value);
+            break;
+        case 0x20:
+            if (!cs)
+                s->cs[0].actim_ctrlb = value & 0x000377ff; /* SDRC_ACTIM_CTRLB_0 */
+            else
+                OMAP_BAD_REGV(addr + 0x30, value);
+            break;
+        case 0x24: /* SDRC_RFR_CTRL_x */
+            s->cs[cs].rfr_ctrl = value & 0x00ffff03;
+            break;
+        case 0x28: /* SDRC_MANUAL_x */
+            s->cs[cs].manual = value & 0xffff000f;
+            break;
+        default:
+            OMAP_BAD_REGV(addr + cs * 0x30, value);
+            break;
+        }
         break;
 
     default:
-        OMAP_BAD_REG(addr);
-        return;
+        OMAP_BAD_REGV(addr, value);
+        break;
     }
 }
 
@@ -4042,6 +4138,8 @@ struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base)
                     omap_sdrc_writefn, s);
     cpu_register_physical_memory(base, 0x1000, iomemtype);
 
+    register_savevm("omap_sdrc", -1, 0,
+                    omap_sdrc_save_state, omap_sdrc_load_state, s);
     return s;
 }
 
@@ -4049,6 +4147,7 @@ struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base)
 struct omap_gpmc_s {
     qemu_irq irq;
 
+    uint8_t revision;
     uint8_t sysconfig;
     uint16_t irqst;
     uint16_t irqen;
@@ -4144,7 +4243,7 @@ static void omap_gpmc_reset(struct omap_gpmc_s *s)
         s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6);
         if (s->cs_file[i].config[6] & (1 << 6))                        /* CSVALID */
             omap_gpmc_cs_map(&s->cs_file[i],
-                            s->cs_file[i].config[6] & 0x1f,    /* MASKADDR */
+                            s->cs_file[i].config[6] & 0x3f,    /* MASKADDR */
                         (s->cs_file[i].config[6] >> 8 & 0xf)); /* BASEADDR */
     }
     omap_gpmc_cs_map(s->cs_file, 0, 0xf);
@@ -4155,15 +4254,86 @@ static void omap_gpmc_reset(struct omap_gpmc_s *s)
         ecc_reset(&s->ecc[i]);
 }
 
+static void omap_gpmc_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *)opaque;
+    int i, j;
+    
+    qemu_put_byte(f, s->sysconfig);
+    qemu_put_be16(f, s->irqst);
+    qemu_put_be16(f, s->irqen);
+    qemu_put_be16(f, s->timeout);
+    qemu_put_be16(f, s->config);
+    qemu_put_be32(f, s->prefconfig[0]);
+    qemu_put_be32(f, s->prefconfig[1]);
+    qemu_put_sbe32(f, s->prefcontrol);
+    qemu_put_sbe32(f, s->preffifo);
+    qemu_put_sbe32(f, s->prefcount);
+    for (i = 0; i < 8; i++)
+        for (j = 0; j < 7; j++)
+            qemu_put_be32(f, s->cs_file[i].config[j]);
+    qemu_put_sbe32(f, s->ecc_cs);
+    qemu_put_sbe32(f, s->ecc_ptr);
+    qemu_put_be32(f, s->ecc_cfg);
+    for (i = 0; i < 9; i++) {
+        qemu_put_byte(f, s->ecc[i].cp);
+        qemu_put_be16(f, s->ecc[i].lp[0]);
+        qemu_put_be16(f, s->ecc[i].lp[1]);
+        qemu_put_be16(f, s->ecc[i].count);
+    }
+}
+
+static int omap_gpmc_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *)opaque;
+    int i, j;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->sysconfig = qemu_get_byte(f);
+    s->irqst = qemu_get_be16(f);
+    s->irqen = qemu_get_be16(f);
+    s->timeout = qemu_get_be16(f);
+    s->config = qemu_get_be16(f);
+    s->prefconfig[0] = qemu_get_be32(f);
+    s->prefconfig[1] = qemu_get_be32(f);
+    s->prefcontrol = qemu_get_sbe32(f);
+    s->preffifo = qemu_get_sbe32(f);
+    s->prefcount = qemu_get_sbe32(f);
+    for (i = 0; i < 8; i++) {
+        for (j = 0; j < 7; j++)
+            s->cs_file[i].config[j] = qemu_get_be32(f);
+        if (s->cs_file[i].config[6] & (1 << 6)) /* CSVALID */
+            omap_gpmc_cs_map(&s->cs_file[i],
+                             s->cs_file[i].config[6] & 0x3f, /* MASKADDR */
+                             (s->cs_file[i].config[6] >> 8 & 0xf));    /* BASE */
+    }        
+    s->ecc_cs = qemu_get_sbe32(f);
+    s->ecc_ptr = qemu_get_sbe32(f);
+    s->ecc_cfg = qemu_get_be32(f);
+    for (i = 0; i < 9; i++) {
+        s->ecc[i].cp = qemu_get_byte(f);
+        s->ecc[i].lp[0] = qemu_get_be16(f);
+        s->ecc[i].lp[1] = qemu_get_be16(f);
+        s->ecc[i].count = qemu_get_be16(f);
+    }
+    
+    omap_gpmc_int_update(s);
+    
+    return 0;
+}
+
 static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr)
 {
     struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
     int cs;
     struct omap_gpmc_cs_file_s *f;
+    uint32_t x1, x2, x3, x4;
 
     switch (addr) {
     case 0x000:        /* GPMC_REVISION */
-        return 0x20;
+        return s->revision;
 
     case 0x010:        /* GPMC_SYSCONFIG */
         return s->sysconfig;
@@ -4210,7 +4380,27 @@ static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr)
             case 0x78: /* GPMC_CONFIG7 */
                 return f->config[6];
             case 0x84: /* GPMC_NAND_DATA */
+                if (((f->config[0] >> 10) & 3) == 2 /* NAND device type ? */
+                    && f->opaque) {
+                    nand_setpins(f->opaque, 0, 0, 0, 1, 0);
+                    switch (((f->config[0] >> 12) & 3)) {
+                        case 0: /* 8bit */
+                            x1 = nand_getio(f->opaque);
+                            x2 = nand_getio(f->opaque);
+                            x3 = nand_getio(f->opaque);
+                            x4 = nand_getio(f->opaque);
+                            return (x4 << 24) | (x3 << 16) | (x2 << 8) | x1;
+                        case 1: /* 16bit */
+                            x1 = nand_getio(f->opaque);
+                            x2 = nand_getio(f->opaque);
+                            return (x2 << 16) | x1;
+                        default:
+                            return 0;
+                    }
+                }
                 return 0;
+            default:
+                break;
         }
         break;
 
@@ -4252,6 +4442,85 @@ static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
+static uint32_t omap_gpmc_read8(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+    
+    switch (addr) {
+        case 0x060 ... 0x1d4:
+            cs = (addr - 0x060) / 0x30;
+            addr -= cs * 0x30;
+            f = s->cs_file + cs;
+            switch (addr) {
+                case 0x84 ... 0x87:    /* GPMC_NAND_DATA */
+                    if (((f->config[0] >> 10) & 3) == 2 /* NAND device type ? */
+                        && f->opaque) {
+                        nand_setpins(f->opaque, 0, 0, 0, 1, 0);
+                        switch (((f->config[0] >> 12) & 3)) {
+                            case 0: /* 8bit */
+                                return nand_getio(f->opaque);
+                            case 1: /* 16bit */
+                                /* reading 8bits from a 16bit device?! */
+                                return nand_getio(f->opaque);
+                            default:
+                                return 0;
+                        }
+                    }
+                    return 0;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_gpmc_read16(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+    uint32_t x1, x2;
+    
+    switch (addr) {
+        case 0x060 ... 0x1d4:
+            cs = (addr - 0x060) / 0x30;
+            addr -= cs * 0x30;
+            f = s->cs_file + cs;
+            switch (addr) {
+                case 0x84:     /* GPMC_NAND_DATA */
+                case 0x86:
+                    if (((f->config[0] >> 10) & 3) == 2 /* NAND device type ? */
+                        && f->opaque) {
+                        nand_setpins(f->opaque, 0, 0, 0, 1, 0);
+                        switch (((f->config[0] >> 12) & 3)) {
+                            case 0: /* 8bit */
+                                x1 = nand_getio(f->opaque);
+                                x2 = nand_getio(f->opaque);
+                                return (x2 << 8) | x1;
+                            case 1: /* 16bit */
+                                return nand_getio(f->opaque);
+                            default:
+                                return 0;
+                        }
+                    }
+                    return 0;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
 static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
                 uint32_t value)
 {
@@ -4267,7 +4536,7 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
     case 0x200 ... 0x220:      /* GPMC_ECC_RESULT */
     case 0x234:        /* GPMC_PSA_LSB */
     case 0x238:        /* GPMC_PSA_MSB */
-        OMAP_RO_REG(addr);
+        OMAP_RO_REGV(addr, value);
         break;
 
     case 0x010:        /* GPMC_SYSCONFIG */
@@ -4329,7 +4598,7 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
                     if (f->config[6] & (1 << 6))               /* CSVALID */
                         omap_gpmc_cs_unmap(f);
                     if (value & (1 << 6))                      /* CSVALID */
-                        omap_gpmc_cs_map(f, value & 0x1f,      /* MASKADDR */
+                        omap_gpmc_cs_map(f, value & 0x3f,      /* MASKADDR */
                                         (value >> 8 & 0xf));   /* BASEADDR */
                 }
                 f->config[6] = value & 0x00000f7f;
@@ -4337,8 +4606,30 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
             case 0x7c: /* GPMC_NAND_COMMAND */
             case 0x80: /* GPMC_NAND_ADDRESS */
             case 0x84: /* GPMC_NAND_DATA */
+                if (((f->config[0] >> 10) & 3) == 2 /* NAND device type ? */
+                    && f->opaque) {
+                    switch (addr) {
+                        case 0x7c: nand_setpins(f->opaque, 1, 0, 0, 1, 0); break; /* CLE */
+                        case 0x80: nand_setpins(f->opaque, 0, 1, 0, 1, 0); break; /* ALE */
+                        case 0x84: nand_setpins(f->opaque, 0, 0, 0, 1, 0); break;
+                        default: break;
+                    }
+                    switch (((f->config[0] >> 12) & 3)) {
+                        case 0: /* 8bit */
+                            nand_setio(f->opaque, value & 0xff);
+                            nand_setio(f->opaque, (value >> 8) & 0xff);
+                            nand_setio(f->opaque, (value >> 16) & 0xff);
+                            nand_setio(f->opaque, (value >> 24) & 0xff);
+                            break;
+                        case 1: /* 16bit */
+                            nand_setio(f->opaque, value & 0xffff);
+                            nand_setio(f->opaque, (value >> 16) & 0xffff);
+                            break;
+                        default:
+                            break;
+                    }
+                }
                 break;
-
             default:
                 goto bad_reg;
         }
@@ -4387,41 +4678,162 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
 
     default:
     bad_reg:
-        OMAP_BAD_REG(addr);
+        OMAP_BAD_REGV(addr, value);
         return;
     }
 }
 
+static void omap_gpmc_write8(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+
+    switch (addr) {
+        case 0x060 ... 0x1d4:
+            cs = (addr - 0x060) / 0x30;
+            addr -= cs * 0x30;
+            f = s->cs_file + cs;
+            switch (addr) {
+                case 0x7c ... 0x7f:    /* GPMC_NAND_COMMAND */
+                case 0x80 ... 0x83:    /* GPMC_NAND_ADDRESS */
+                case 0x84 ... 0x87:    /* GPMC_NAND_DATA */
+                    if (((f->config[0] >> 10) & 3) == 2 /* NAND device type ? */
+                        && f->opaque) {
+                        switch (addr) {
+                            case 0x7c ... 0x7f:
+                                nand_setpins(f->opaque, 1, 0, 0, 1, 0); /* CLE */
+                                break;
+                            case 0x80 ... 0x83:
+                                nand_setpins(f->opaque, 0, 1, 0, 1, 0); /* ALE */
+                                break;
+                            case 0x84 ... 0x87:
+                                nand_setpins(f->opaque, 0, 0, 0, 1, 0);
+                                break;
+                            default:
+                                break;
+                        }
+                        switch (((f->config[0] >> 12) & 3)) {
+                            case 0: /* 8bit */
+                                nand_setio(f->opaque, value & 0xff);
+                                break;
+                            case 1: /* 16bit */
+                                /* writing to a 16bit device with 8bit access!? */
+                                nand_setio(f->opaque, value & 0xffff);
+                                break;
+                            default:
+                                break;
+                        }
+                    }
+                    break;
+                default:
+                    goto bad_reg;
+            }
+            break;
+        default:
+        bad_reg:
+            OMAP_BAD_REGV(addr, value);
+            return;
+    }
+}
+
+static void omap_gpmc_write16(void *opaque, target_phys_addr_t addr,
+                              uint32_t value)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+    
+    switch (addr) {
+        case 0x060 ... 0x1d4:
+            cs = (addr - 0x060) / 0x30;
+            addr -= cs * 0x30;
+            f = s->cs_file + cs;
+            switch (addr) {
+                case 0x7c:     /* GPMC_NAND_COMMAND */
+                case 0x7e:
+                case 0x80:     /* GPMC_NAND_ADDRESS */
+                case 0x82:
+                case 0x84:     /* GPMC_NAND_DATA */
+                case 0x86:
+                    if (((f->config[0] >> 10) & 3) == 2 /* NAND device type ? */
+                        && f->opaque) {
+                        switch (addr) {
+                            case 0x7c:
+                            case 0x7e: 
+                                nand_setpins(f->opaque, 1, 0, 0, 1, 0); /* CLE */
+                                break;
+                            case 0x80:
+                            case 0x82:
+                                nand_setpins(f->opaque, 0, 1, 0, 1, 0); /* ALE */
+                                break;
+                            case 0x84:
+                            case 0x86:
+                                nand_setpins(f->opaque, 0, 0, 0, 1, 0);
+                                break;
+                            default:
+                                break;
+                        }
+                        switch (((f->config[0] >> 12) & 3)) {
+                            case 0: /* 8bit */
+                                nand_setio(f->opaque, value & 0xff);
+                                nand_setio(f->opaque, (value >> 8) & 0xff);
+                                break;
+                            case 1: /* 16bit */
+                                nand_setio(f->opaque, value & 0xffff);
+                                break;
+                            default:
+                                break;
+                        }
+                    }
+                    break;
+                default:
+                    goto bad_reg;
+            }
+            break;
+        default:
+        bad_reg:
+            OMAP_BAD_REGV(addr, value);
+            return;
+    }
+}
+
 static CPUReadMemoryFunc *omap_gpmc_readfn[] = {
-    omap_badwidth_read32,      /* TODO */
-    omap_badwidth_read32,      /* TODO */
+    omap_gpmc_read8,
+    omap_gpmc_read16,
     omap_gpmc_read,
 };
 
 static CPUWriteMemoryFunc *omap_gpmc_writefn[] = {
-    omap_badwidth_write32,     /* TODO */
-    omap_badwidth_write32,     /* TODO */
+    omap_gpmc_write8,
+    omap_gpmc_write16,
     omap_gpmc_write,
 };
 
-struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq)
+struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
+                                   target_phys_addr_t base, qemu_irq irq)
 {
     int iomemtype;
     struct omap_gpmc_s *s = (struct omap_gpmc_s *)
             qemu_mallocz(sizeof(struct omap_gpmc_s));
 
+    s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20;
     omap_gpmc_reset(s);
 
     iomemtype = cpu_register_io_memory(0, omap_gpmc_readfn,
                     omap_gpmc_writefn, s);
     cpu_register_physical_memory(base, 0x1000, iomemtype);
 
+    register_savevm("omap_gpmc", -1, 0,
+                    omap_gpmc_save_state, omap_gpmc_load_state, s);
     return s;
 }
 
 void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
                 void (*base_upd)(void *opaque, target_phys_addr_t new),
-                void (*unmap)(void *opaque), void *opaque)
+                void (*unmap)(void *opaque), void *opaque,
+                int devicetype)
 {
     struct omap_gpmc_cs_file_s *f;
 
@@ -4436,8 +4848,16 @@ void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
     f->unmap = unmap;
     f->opaque = opaque;
 
+    f->config[0] &= ~(0x3 << 10);
+    f->config[0] |= (devicetype & 3) << 10;
+    if (devicetype == 2) { /* NAND */
+        f->config[0] &= ~(0x3 << 12);
+        if (nand_getbuswidth(f->opaque) == 16)
+            f->config[0] |= 1 << 12;
+    }
+    
     if (f->config[6] & (1 << 6))                               /* CSVALID */
-        omap_gpmc_cs_map(f, f->config[6] & 0x1f,               /* MASKADDR */
+        omap_gpmc_cs_map(f, f->config[6] & 0x3f,               /* MASKADDR */
                         (f->config[6] >> 8 & 0xf));            /* BASEADDR */
 }
 
@@ -4528,7 +4948,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
 
     /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
     cpu_irq = arm_pic_init_cpu(s->env);
-    s->ih[0] = omap2_inth_init(0x480fe000, 0x1000, 3, &s->irq[0],
+    s->ih[0] = omap2_inth_init(s,
+                    0x480fe000, 0x1000, 3, &s->irq[0],
                     cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
                     omap_findclk(s, "mpu_intc_fclk"),
                     omap_findclk(s, "mpu_intc_iclk"));
@@ -4642,12 +5063,12 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
     gpio_clks[1] = omap_findclk(s, "gpio2_dbclk");
     gpio_clks[2] = omap_findclk(s, "gpio3_dbclk");
     gpio_clks[3] = omap_findclk(s, "gpio4_dbclk");
-    s->gpif = omap2_gpio_init(omap_l4ta(s->l4, 3),
+    s->gpif = omap2_gpio_init(s, omap_l4ta(s->l4, 3),
                     &s->irq[0][OMAP_INT_24XX_GPIO_BANK1],
                     gpio_clks, omap_findclk(s, "gpio_iclk"), 4);
 
     s->sdrc = omap_sdrc_init(0x68009000);
-    s->gpmc = omap_gpmc_init(0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ]);
+    s->gpmc = omap_gpmc_init(s, 0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ]);
 
     sdindex = drive_get_index(IF_SD, 0, 0);
     if (sdindex == -1) {
@@ -4659,18 +5080,18 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     &s->drq[OMAP24XX_DMA_MMC1_TX],
                     omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
 
-    s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
+    s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), s, 4,
                     s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ],
                     &s->drq[OMAP24XX_DMA_SPI1_TX0],
                     omap_findclk(s, "spi1_fclk"),
                     omap_findclk(s, "spi1_iclk"));
-    s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
+    s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), s, 2,
                     s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ],
                     &s->drq[OMAP24XX_DMA_SPI2_TX0],
                     omap_findclk(s, "spi2_fclk"),
                     omap_findclk(s, "spi2_iclk"));
 
-    s->dss = omap_dss_init(omap_l4ta(s->l4, 10), 0x68000800,
+    s->dss = omap_dss_init(s, omap_l4ta(s->l4, 10),
                     /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
                     s->irq[0][OMAP_INT_24XX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
                     omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
diff --git a/hw/omap3.c b/hw/omap3.c
new file mode 100644 (file)
index 0000000..5e0d89d
--- /dev/null
@@ -0,0 +1,4778 @@
+/*
+ * TI OMAP3 processors emulation.
+ *
+ * Copyright (C) 2008 yajin <yajin@vm-kernel.org>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "hw.h"
+#include "arm-misc.h"
+#include "omap.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "flash.h"
+#include "soc_dma.h"
+#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_
+#define TRACE(fmt, ...) fprintf(stderr, "%s " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...) 
+#endif
+
+typedef enum {
+    /* 68000000-680003FF */ L3ID_L3RT = 0,
+    /* 68000400-680007FF */ L3ID_L3SI,
+    /* 68000800-680013FF */
+    /* 68001400-680017FF */ L3ID_MPUSS_IA,
+    /* 68001800-68001BFF */ L3ID_IVASS_IA,
+    /* 68001C00-68001FFF */ L3ID_SGXSS_IA,
+    /* 68002000-680023FF */ L3ID_SMS_TA,
+    /* 68002400-680027FF */ L3ID_GPMC_TA,
+    /* 68002800-68002BFF */ L3ID_OCM_RAM_TA,
+    /* 68002C00-68002FFF */ L3ID_OCM_ROM_TA,
+    /* 68003000-680033FF */ L3ID_D2D_IA,
+    /* 68003400-680037FF */ L3ID_D2D_TA,
+    /* 68003800-68003FFF */
+    /* 68004000-680043FF */ L3ID_HSUSB_HOST_IA,
+    /* 68004400-680047FF */ L3ID_HSUSB_OTG_IA,
+    /* 68004800-68004BFF */
+    /* 68004C00-68004FFF */ L3ID_SDMA_RD_IA,
+    /* 68005000-680053FF */ L3ID_SDMA_WR_IA,
+    /* 68005400-680057FF */ L3ID_DSS_IA,
+    /* 68005800-68005BFF */ L3ID_CAMISP_IA,
+    /* 68005C00-68005FFF */ L3ID_DAP_IA,
+    /* 68006000-680063FF */ L3ID_IVASS_TA,
+    /* 68006400-680067FF */ L3ID_SGXSS_TA,
+    /* 68006800-68006BFF */ L3ID_L4_CORE_TA,
+    /* 68006C00-68006FFF */ L3ID_L4_PER_TA,
+    /* 68007000-680073FF */ L3ID_L4_EMU_TA,
+    /* 68007400-6800FFFF */
+    /* 68010000-680103FF */ L3ID_RT_PM,
+    /* 68010400-680123FF */
+    /* 68012400-680127FF */ L3ID_GPMC_PM,
+    /* 68012800-68012BFF */ L3ID_OCM_RAM_PM,
+    /* 68012C00-68012FFF */ L3ID_OCM_ROM_PM,
+    /* 68013000-680133FF */ L3ID_D2D_PM,
+    /* 68013400-68013FFF */
+    /* 68014000-680143FF */ L3ID_IVA_PM,
+    /* 68014400-68FFFFFF */
+} omap3_l3_region_id_t;
+
+struct omap_l3_region_s {
+    target_phys_addr_t offset;
+    size_t size;
+    enum {
+        L3TYPE_GENERIC = 0, /* needs to be mapped separately */
+        L3TYPE_IA,          /* initiator agent */
+        L3TYPE_TA,          /* target agent */
+        L3TYPE_PM,          /* protection mechanism */
+        L3TYPE_UNDEFINED,   /* every access will emit an error message */
+    } type;
+};
+
+struct omap3_l3_initiator_agent_s {
+    target_phys_addr_t base;
+    
+    uint32_t component;
+    uint32_t control;
+    uint32_t status;
+};
+
+struct omap3_l3pm_s {
+    target_phys_addr_t base;
+    
+    uint32_t error_log;
+    uint8_t  control;
+    uint16_t req_info_permission[8];
+    uint16_t read_permission[8];
+    uint16_t write_permission[8];
+    uint32_t addr_match[7];
+};
+
+union omap3_l3_port_s {
+    struct omap_target_agent_s ta;
+    struct omap3_l3_initiator_agent_s ia;
+    struct omap3_l3pm_s pm;
+};
+
+struct omap_l3_s {
+    target_phys_addr_t base;
+    int region_count;
+    union omap3_l3_port_s region[0];
+};
+
+static struct omap_l3_region_s omap3_l3_region[] = {
+    [L3ID_L3RT         ] = {0x00000000, 0x0400, L3TYPE_UNDEFINED},
+    [L3ID_L3SI         ] = {0x00000400, 0x0400, L3TYPE_UNDEFINED},
+    [L3ID_MPUSS_IA     ] = {0x00001400, 0x0400, L3TYPE_IA},
+    [L3ID_IVASS_IA     ] = {0x00001800, 0x0400, L3TYPE_IA},
+    [L3ID_SGXSS_IA     ] = {0x00001c00, 0x0400, L3TYPE_IA},
+    [L3ID_SMS_TA       ] = {0x00002000, 0x0400, L3TYPE_TA},
+    [L3ID_GPMC_TA      ] = {0x00002400, 0x0400, L3TYPE_TA},
+    [L3ID_OCM_RAM_TA   ] = {0x00002800, 0x0400, L3TYPE_TA},
+    [L3ID_OCM_ROM_TA   ] = {0x00002c00, 0x0400, L3TYPE_TA},
+    [L3ID_D2D_IA       ] = {0x00003000, 0x0400, L3TYPE_IA},
+    [L3ID_D2D_TA       ] = {0x00003400, 0x0400, L3TYPE_TA},
+    [L3ID_HSUSB_HOST_IA] = {0x00004000, 0x0400, L3TYPE_IA},
+    [L3ID_HSUSB_OTG_IA ] = {0x00004400, 0x0400, L3TYPE_IA},
+    [L3ID_SDMA_RD_IA   ] = {0x00004c00, 0x0400, L3TYPE_IA},
+    [L3ID_SDMA_WR_IA   ] = {0x00005000, 0x0400, L3TYPE_IA},
+    [L3ID_DSS_IA       ] = {0x00005400, 0x0400, L3TYPE_IA},
+    [L3ID_CAMISP_IA    ] = {0x00005800, 0x0400, L3TYPE_IA},
+    [L3ID_DAP_IA       ] = {0x00005c00, 0x0400, L3TYPE_IA},
+    [L3ID_IVASS_TA     ] = {0x00006000, 0x0400, L3TYPE_TA},
+    [L3ID_SGXSS_TA     ] = {0x00006400, 0x0400, L3TYPE_TA},
+    [L3ID_L4_CORE_TA   ] = {0x00006800, 0x0400, L3TYPE_TA},
+    [L3ID_L4_PER_TA    ] = {0x00006c00, 0x0400, L3TYPE_TA},
+    [L3ID_L4_EMU_TA    ] = {0x00007000, 0x0400, L3TYPE_TA},
+    [L3ID_RT_PM        ] = {0x00010000, 0x0400, L3TYPE_PM},
+    [L3ID_GPMC_PM      ] = {0x00012400, 0x0400, L3TYPE_PM},
+    [L3ID_OCM_RAM_PM   ] = {0x00012800, 0x0400, L3TYPE_PM},
+    [L3ID_OCM_ROM_PM   ] = {0x00012c00, 0x0400, L3TYPE_PM},
+    [L3ID_D2D_PM       ] = {0x00013000, 0x0400, L3TYPE_PM},
+    [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;
+    
+    switch (addr) {
+        case 0x00: /* COMPONENT_L */
+            return s->component;
+        case 0x04: /* COMPONENT_H */
+            return 0;
+        case 0x18: /* CORE_L */
+            return s->component;
+        case 0x1c: /* CORE_H */
+            return (s->component >> 16);
+        case 0x20: /* AGENT_CONTROL_L */
+            return s->control;
+        case 0x24: /* AGENT_CONTROL_H */
+            return 0;
+        case 0x28: /* AGENT_STATUS_L */
+            return s->status;
+        case 0x2c: /* AGENT_STATUS_H */
+            return 0;
+        case 0x58: /* ERROR_LOG_L */
+            return 0;
+        case 0x5c: /* ERROR_LOG_H */
+            return 0;
+        case 0x60: /* ERROR_LOG_ADDR_L */
+            return 0;
+        case 0x64: /* ERROR_LOG_ADDR_H */
+            return 0;
+        default:
+            break;
+    }
+    
+    OMAP_BAD_REG(s->base + addr);
+    return 0;
+}
+
+static void omap3_l3ia_write(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    struct omap3_l3_initiator_agent_s *s = (struct omap3_l3_initiator_agent_s *)opaque;
+    
+    switch (addr) {
+        case 0x00: /* COMPONENT_L */
+        case 0x04: /* COMPONENT_H */
+        case 0x18: /* CORE_L */
+        case 0x1c: /* CORE_H */
+        case 0x60: /* ERROR_LOG_ADDR_L */
+        case 0x64: /* ERROR_LOG_ADDR_H */
+            OMAP_RO_REG(s->base + addr);
+            break;
+        case 0x24: /* AGENT_CONTROL_H */
+        case 0x2c: /* AGENT_STATUS_H */
+        case 0x5c: /* ERROR_LOG_H */
+            /* RW register but all bits are reserved/read-only */
+            break;
+        case 0x20: /* AGENT_CONTROL_L */
+            s->control = value & 0x3e070711;
+            /* TODO: some bits are reserved for some IA instances */
+            break;
+        case 0x28: /* AGENT_STATUS_L */
+            s->status &= ~(value & 0x30000000);
+            break;
+        case 0x58: /* ERROR_LOG_L */
+            /* error logging is not implemented, so ignore */
+            break;
+        default:
+            OMAP_BAD_REG(s->base + addr);
+            break;
+    }
+}
+
+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[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap3_l3ia_read,
+};
+
+static CPUWriteMemoryFunc *omap3_l3ia_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_l3ia_write,
+};
+
+static uint32_t omap3_l3ta_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+    
+    switch (addr) {
+        case 0x00: /* COMPONENT_L */
+            return s->component;
+        case 0x04: /* COMPONENT_H */
+            return 0;
+        case 0x18: /* CORE_L */
+            return s->component;
+        case 0x1c: /* CORE_H */
+            return (s->component >> 16);
+        case 0x20: /* AGENT_CONTROL_L */
+            return s->control;
+        case 0x24: /* AGENT_CONTROL_H */
+            return s->control_h;
+        case 0x28: /* AGENT_STATUS_L */
+            return s->status;
+        case 0x2c: /* AGENT_STATUS_H */
+            return 0;
+        case 0x58: /* ERROR_LOG_L */
+            return 0;
+        case 0x5c: /* ERROR_LOG_H */
+            return 0;
+        case 0x60: /* ERROR_LOG_ADDR_L */
+            return 0;
+        case 0x64: /* ERROR_LOG_ADDR_H */
+            return 0;
+        default:
+            break;
+    }
+    
+    OMAP_BAD_REG(s->base + addr);
+    return 0;
+}
+
+static void omap3_l3ta_write(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+    
+    switch (addr) {
+        case 0x00: /* COMPONENT_L */
+        case 0x04: /* COMPONENT_H */
+        case 0x18: /* CORE_L */
+        case 0x1c: /* CORE_H */
+        case 0x60: /* ERROR_LOG_ADDR_L */
+        case 0x64: /* ERROR_LOG_ADDR_H */
+            OMAP_RO_REG(s->base + addr);
+            break;
+        case 0x24: /* AGENT_CONTROL_H */
+        case 0x5c: /* ERROR_LOG_H */
+            /* RW register but all bits are reserved/read-only */
+            break;
+        case 0x20: /* AGENT_CONTROL_L */
+            s->control = value & 0x03000711;
+            break;
+        case 0x28: /* AGENT_STATUS_L */
+            if (s->base == OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_CORE_TA].offset
+                || s->base == OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_PER_TA].offset
+                || s->base == OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_EMU_TA].offset) {
+                s->status &= ~(value & (1 << 24));
+            } else
+                OMAP_RO_REG(s->base + addr);
+            break;
+        case 0x2c: /* AGENT_STATUS_H */
+            if (s->base != OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_CORE_TA].offset
+                && s->base != OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_PER_TA].offset
+                && s->base != OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_EMU_TA].offset)
+                OMAP_RO_REG(s->base + addr);
+            /* for L4 core, per, emu TAs this is RW reg */
+            break;
+        case 0x58: /* ERROR_LOG_L */
+            /* error logging is not implemented, so ignore */
+            break;
+        default:
+            OMAP_BAD_REG(s->base + addr);
+            break;
+    }
+}
+
+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[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap3_l3ta_read,
+};
+
+static CPUWriteMemoryFunc *omap3_l3ta_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_l3ta_write,
+};
+
+static uint32_t omap3_l3pm_read8(void *opaque, target_phys_addr_t addr)
+{
+    struct omap3_l3pm_s *s = (struct omap3_l3pm_s *)opaque;
+    int i;
+    
+    switch (addr) {
+        case 0x00 ... 0x1f:
+        case 0x40 ... 0x47:
+            OMAP_BAD_REG(s->base + addr);
+            return 0;
+        /* ERROR_LOG */
+        case 0x20: return s->error_log & 0xff;
+        case 0x21: return (s->error_log >> 8) & 0xff;
+        case 0x22: return (s->error_log >> 16) & 0xff;
+        case 0x23: return (s->error_log >> 24) & 0xff;
+        case 0x24 ... 0x27: return 0;
+        /* CONTROL */
+        case 0x28 ... 0x2a: return 0;
+        case 0x2b: return s->control;
+        case 0x2c ... 0x2f: return 0;
+        /* ERROR_CLEAR_SINGLE */
+        case 0x30: return 0; /* TODO: clear single error from log */
+        case 0x31 ... 0x37: return 0;
+        /* ERROR_CLEAR_MULTI */
+        case 0x38: return 0; /* TODO: clear multiple errors from log */
+        case 0x39 ... 0x3f: return 0;
+        default:
+            break;
+    }
+    
+    i = (addr - 0x48) / 0x20;
+    addr -= i * 0x20;
+    if (i < 7 || (i < 8 && addr < 0x60)) 
+        switch (addr) {
+            /* REQ_INFO_PERMISSION_i */
+            case 0x48: return s->req_info_permission[i] & 0xff;
+            case 0x49: return (s->req_info_permission[i] >> 8) & 0xff;
+            case 0x4a ... 0x4f: return 0;
+            /* READ_PERMISSION_i */
+            case 0x50: return s->read_permission[i] & 0xff;
+            case 0x51: return (s->read_permission[i] >> 8) & 0xff;
+            case 0x52 ... 0x57: return 0;
+            /* WRITE_PERMISSION_i */
+            case 0x58: return s->write_permission[i] & 0xff;
+            case 0x59: return (s->write_permission[i] >> 8) & 0xff;
+            case 0x5a ... 0x5f: return 0;
+            /* ADDR_MATCH_i */
+            case 0x60: return s->addr_match[i] & 0xff;
+            case 0x61: return (s->addr_match[i] >> 8) & 0xff;
+            case 0x62: return (s->addr_match[i] >> 16) & 0xff;
+            case 0x63 ... 0x67: return 0;
+            default:
+                break;
+        }
+
+    OMAP_BAD_REG(s->base + addr);
+    return 0;
+}
+
+static uint32_t omap3_l3pm_read16(void *opaque, target_phys_addr_t addr)
+{
+    return omap3_l3pm_read8(opaque, addr)
+        | (omap3_l3pm_read8(opaque, addr + 1) << 8);
+}
+
+static uint32_t omap3_l3pm_read32(void *opaque, target_phys_addr_t addr)
+{
+    return omap3_l3pm_read16(opaque, addr)
+        | (omap3_l3pm_read16(opaque, addr + 2) << 16);
+}
+
+static void omap3_l3pm_write8(void *opaque, target_phys_addr_t addr,
+                              uint32_t value)
+{
+    struct omap3_l3pm_s *s = (struct omap3_l3pm_s *)opaque;
+    int i;
+    
+    switch (addr) {
+        case 0x00 ... 0x1f:
+        case 0x40 ... 0x47:
+            OMAP_BAD_REGV(s->base + addr, value);
+            return;
+        /* ERROR_LOG */
+        case 0x23:
+            s->error_log &= ~((value & 0xcf) << 24);
+        case 0x20 ... 0x22:
+        case 0x24 ... 0x27:
+            return;
+        /* CONTROL */
+        case 0x2b:
+            s->control = value & 3;
+        case 0x28 ... 0x2a:
+        case 0x2c ... 0x2f:
+            return;
+        /* ERROR_CLEAR_SINGLE / ERROR_CLEAR_MULTI */
+        case 0x30 ... 0x3f:
+            OMAP_RO_REGV(s->base + addr, value);
+            return;
+        default:
+            break;
+    }
+    
+    i = (addr - 0x48) / 0x20;
+    addr -= i * 0x20;
+    if (i < 7 || (i < 8 && addr < 0x60)) 
+        switch (addr) {
+            /* REQ_INFO_PERMISSION_i */
+            case 0x48:
+                s->req_info_permission[i] =
+                    (s->req_info_permission[i] & ~0xff) | (value & 0xff);
+                return;
+            case 0x49:
+                s->req_info_permission[i] =
+                    (s->req_info_permission[i] & ~0xff00) | ((value & 0xff) << 8);
+                return;
+            case 0x4a ... 0x4f:
+                return;
+            /* READ_PERMISSION_i */
+            case 0x50:
+                s->read_permission[i] =
+                    (s->read_permission[i] & ~0xff) | (value & 0x3e);
+                return;
+            case 0x51:
+                s->read_permission[i] =
+                    (s->read_permission[i] & ~0xff00) | ((value & 0x5f) << 8);
+                return;
+            case 0x52 ... 0x57:
+                return;
+            /* WRITE_PERMISSION_i */
+            case 0x58:
+                s->write_permission[i] =
+                    (s->write_permission[i] & ~0xff) | (value & 0x3e);
+                return;
+            case 0x59:
+                s->write_permission[i] =
+                    (s->write_permission[i] & ~0xff00) | ((value & 0x5f) << 8);
+                return;
+            case 0x5a ... 0x5f:
+                return;
+            /* ADDR_MATCH_i */
+            case 0x60:
+                s->addr_match[i] = (s->addr_match[i] & ~0xff) | (value & 0xff);
+                return;
+            case 0x61:
+                s->addr_match[i] =
+                    (s->addr_match[i] & ~0xfe00) | ((value & 0xfe) << 8);
+                return;
+            case 0x62:
+                s->addr_match[i] =
+                    (s->addr_match[i] & ~0x0f0000) | ((value & 0x0f) << 16);
+                return;
+            case 0x63 ... 0x67:
+                return;
+            default:
+                break;
+        }
+    
+    OMAP_BAD_REGV(s->base + addr, value);
+}
+
+static void omap3_l3pm_write16(void *opaque, target_phys_addr_t addr,
+                               uint32_t value)
+{
+    omap3_l3pm_write8(opaque, addr + 0, value & 0xff);
+    omap3_l3pm_write8(opaque, addr + 1, (value >> 8) & 0xff);
+}
+
+static void omap3_l3pm_write32(void *opaque, target_phys_addr_t addr,
+                               uint32_t value)
+{
+    omap3_l3pm_write16(opaque, addr + 0, value & 0xffff);
+    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;
+    
+    s->error_log = 0;
+    s->control = 0x03;
+    switch (s->base) {
+        case 0x68010000: /* PM_RT */
+            s->req_info_permission[0] = 0xffff;
+            s->req_info_permission[1] = 0;
+            for (i = 0; i < 2; i++)
+                s->read_permission[i] = s->write_permission[i] = 0x1406;
+            s->addr_match[0] = 0x10230;
+            break;
+        case 0x68012400: /* PM_GPMC */
+            s->req_info_permission[0] = 0;
+            for (i = 3; i < 8; i++)
+                s->req_info_permission[i] = 0xffff;
+            for (i = 0; i < 8; i++)
+                s->read_permission[i] = s->write_permission[i] = 0x563e;
+            s->addr_match[0] = 0x00098;
+            break;
+        case 0x68012800: /* PM_OCM_RAM */
+            s->req_info_permission[0] = 0;
+            for (i = 1; i < 8; i++)
+                s->req_info_permission[i] = 0xffff;
+            for (i = 0; i < 8; i++)
+                s->read_permission[i] = s->write_permission[i] = 0x5f3e;
+            s->addr_match[1] = 0x0f810;
+            break;
+        case 0x68012C00: /* PM_OCM_ROM */
+            s->req_info_permission[1] = 0xffff;
+            for (i = 0; i < 2; i++) {
+                s->read_permission[i] = 0x1002;
+                s->write_permission[i] = 0;
+            }
+            s->addr_match[0] = 0x14028;
+            break;
+        case 0x68013000: /* PM_MAD2D */
+            s->req_info_permission[0] = 0;
+            for (i = 1; i < 8; i++)
+                s->req_info_permission[i] = 0xffff;
+            for (i = 0; i < 8; i++)
+                s->read_permission[i] = s->write_permission[i] = 0x5f1e;
+            break;
+        case 0x68014000: /* PM_IVA2.2 */
+            s->req_info_permission[0] = 0;
+            for (i = 1; i < 4; i++)
+                s->req_info_permission[i] = 0xffff;
+            for (i = 0; i < 4; i++)
+                s->read_permission[i] = s->write_permission[i] = 0x140e;
+            break;
+        default:
+            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[] = {
+    omap3_l3pm_read8,
+    omap3_l3pm_read16,
+    omap3_l3pm_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_l3pm_writefn[] = {
+    omap3_l3pm_write8,
+    omap3_l3pm_write16,
+    omap3_l3pm_write32,
+};
+
+static uint32_t omap3_l3undef_read8(void *opaque, target_phys_addr_t addr)
+{
+    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 " 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 " OMAP_FMT_plx "\n",
+            __FUNCTION__, addr);
+    return 0;
+}
+
+static void omap3_l3undef_write8(void *opaque, target_phys_addr_t addr,
+                               uint32_t value)
+{
+    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 " 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 " OMAP_FMT_plx ", value %08x\n",
+            __FUNCTION__, addr, value);
+}
+
+static CPUReadMemoryFunc *omap3_l3undef_readfn[] = {
+    omap3_l3undef_read8,
+    omap3_l3undef_read16,
+    omap3_l3undef_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_l3undef_writefn[] = {
+    omap3_l3undef_write8,
+    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));
+    bus->region_count = n;
+    bus->base = base;
+    
+    for (i = 0; i < n; i++) {
+        switch (regions[i].type) {
+            case L3TYPE_GENERIC:
+                /* not mapped for now, mapping will be done later by
+                   specialized code */
+                break;
+            case L3TYPE_IA:
+                iomemtype = cpu_register_io_memory(0, omap3_l3ia_readfn,
+                                                   omap3_l3ia_writefn,
+                                                   &bus->region[i].ia);
+                bus->region[i].ia.base = base + regions[i].offset;
+                omap3_l3ia_init(&bus->region[i].ia);
+                break;
+            case L3TYPE_TA:
+                iomemtype = cpu_register_io_memory(0, omap3_l3ta_readfn,
+                                                   omap3_l3ta_writefn,
+                                                   &bus->region[i].ta);
+                bus->region[i].ta.base = base + regions[i].offset;
+                omap3_l3ta_init(&bus->region[i].ta);
+                break;
+            case L3TYPE_PM:
+                iomemtype = cpu_register_io_memory(0, omap3_l3pm_readfn,
+                                                   omap3_l3pm_writefn,
+                                                   &bus->region[i].pm);
+                bus->region[i].pm.base = base + regions[i].offset;
+                omap3_l3pm_init(&bus->region[i].pm);
+                break;
+            case L3TYPE_UNDEFINED:
+                iomemtype = cpu_register_io_memory(0, omap3_l3undef_readfn,
+                                                   omap3_l3undef_writefn,
+                                                   &bus->region[i]);
+                break;
+            default:
+                fprintf(stderr, "%s: unknown L3 region type: %d\n",
+                        __FUNCTION__, regions[i].type);
+                exit(-1);
+                break;
+        }
+        cpu_register_physical_memory(base + regions[i].offset,
+                                     regions[i].size,
+                                     iomemtype);
+    }
+    
+    return bus;
+#endif
+}
+
+typedef enum {
+    /* 48000000-48001FFF */
+    /* 48002000-48002FFF */ L4ID_SCM = 0,
+    /* 48003000-48003FFF */ L4ID_SCM_TA,
+    /* 48004000-48005FFF */ L4ID_CM_A,
+    /* 48006000-480067FF */ L4ID_CM_B,
+    /* 48006800-48006FFF */
+    /* 48007000-48007FFF */ L4ID_CM_TA,
+    /* 48008000-48023FFF */
+    /* 48024000-48024FFF */
+    /* 48025000-48025FFF */
+    /* 48026000-4803FFFF */
+    /* 48040000-480407FF */ L4ID_CORE_AP,
+    /* 48040800-48040FFF */ L4ID_CORE_IP,
+    /* 48041000-48041FFF */ L4ID_CORE_LA,
+    /* 48042000-4804FBFF */
+    /* 4804FC00-4804FFFF */ L4ID_DSI,
+    /* 48050000-480503FF */ L4ID_DSS,
+    /* 48050400-480507FF */ L4ID_DISPC,
+    /* 48050800-48050BFF */ L4ID_RFBI,
+    /* 48050C00-48050FFF */ L4ID_VENC,
+    /* 48051000-48051FFF */ L4ID_DSS_TA,
+    /* 48052000-48055FFF */
+    /* 48056000-48056FFF */ L4ID_SDMA,
+    /* 48057000-48057FFF */ L4ID_SDMA_TA,
+    /* 48058000-4805FFFF */
+    /* 48060000-48060FFF */ L4ID_I2C3,
+    /* 48061000-48061FFF */ L4ID_I2C3_TA,
+    /* 48062000-48062FFF */ L4ID_USBTLL,
+    /* 48063000-48063FFF */ L4ID_USBTLL_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,
+    /* 4806C000-4806CFFF */ L4ID_UART2,
+    /* 4806D000-4806DFFF */ L4ID_UART2_TA,
+    /* 4806E000-4806FFFF */
+    /* 48070000-48070FFF */ L4ID_I2C1,
+    /* 48071000-48071FFF */ L4ID_I2C1_TA,
+    /* 48072000-48072FFF */ L4ID_I2C2,
+    /* 48073000-48073FFF */ L4ID_I2C2_TA,
+    /* 48074000-48074FFF */ L4ID_MCBSP1,
+    /* 48075000-48075FFF */ L4ID_MCBSP1_TA,
+    /* 48076000-48085FFF */
+    /* 48086000-48086FFF */ L4ID_GPTIMER10,
+    /* 48087000-48087FFF */ L4ID_GPTIMER10_TA,
+    /* 48088000-48088FFF */ L4ID_GPTIMER11,
+    /* 48089000-48089FFF */ L4ID_GPTIMER11_TA,
+    /* 4808A000-4808AFFF */
+    /* 4808B000-4808BFFF */
+    /* 4808C000-48093FFF */
+    /* 48094000-48094FFF */ L4ID_MAILBOX,
+    /* 48095000-48095FFF */ L4ID_MAILBOX_TA,
+    /* 48096000-48096FFF */ L4ID_MCBSP5,
+    /* 48097000-48097FFF */ L4ID_MCBSP5_TA,
+    /* 48098000-48098FFF */ L4ID_MCSPI1,
+    /* 48099000-48099FFF */ L4ID_MCSPI1_TA,
+    /* 4809A000-4809AFFF */ L4ID_MCSPI2,
+    /* 4809B000-4809BFFF */ L4ID_MCSPI2_TA,
+    /* 4809C000-4809CFFF */ L4ID_MMCSDIO1,
+    /* 4809D000-4809DFFF */ L4ID_MMCSDIO1_TA,
+    /* 4809E000-4809EFFF */ L4ID_MSPRO,
+    /* 4809F000-4809FFFF */ L4ID_MSPRO_TA,
+    /* 480A0000-480AAFFF */
+    /* 480AB000-480ABFFF */ L4ID_HSUSBOTG,
+    /* 480AC000-480ACFFF */ L4ID_HSUSBOTG_TA,
+    /* 480AD000-480ADFFF */ L4ID_MMCSDIO3,
+    /* 480AE000-480AEFFF */ L4ID_MMCSDIO3_TA,
+    /* 480AF000-480AFFFF */
+    /* 480B0000-480B0FFF */
+    /* 480B1000-480B1FFF */
+    /* 480B2000-480B2FFF */ L4ID_HDQ1WIRE,
+    /* 480B3000-480B2FFF */ L4ID_HDQ1WIRE_TA,
+    /* 480B4000-480B4FFF */ L4ID_MMCSDIO2,
+    /* 480B5000-480B5FFF */ L4ID_MMCSDIO2_TA,
+    /* 480B6000-480B6FFF */ L4ID_ICRMPU,
+    /* 480B7000-480B7FFF */ L4ID_ICRMPU_TA,
+    /* 480B8000-480B8FFF */ L4ID_MCSPI3,
+    /* 480B9000-480B9FFF */ L4ID_MCSPI3_TA,
+    /* 480BA000-480BAFFF */ L4ID_MCSPI4,
+    /* 480BB000-480BBFFF */ L4ID_MCSPI4_TA,
+    /* 480BC000-480BFFFF */ L4ID_CAMERAISP,
+    /* 480C0000-480C0FFF */ L4ID_CAMERAISP_TA,
+    /* 480C1000-480CCFFF */
+    /* 480CD000-480CDFFF */ L4ID_ICRMODEM,
+    /* 480CE000-480CEFFF */ L4ID_ICRMODEM_TA,
+    /* 480CF000-482FFFFF */
+    /* 48300000-48303FFF */
+    /* 48304000-48304FFF */ L4ID_GPTIMER12,
+    /* 48305000-48305FFF */ L4ID_GPTIMER12_TA,
+    /* 48306000-48307FFF */ L4ID_PRM_A,
+    /* 48308000-483087FF */ L4ID_PRM_B,
+    /* 48308800-48308FFF */
+    /* 48309000-48309FFF */ L4ID_PRM_TA,
+    /* 4830A000-4830AFFF */ L4ID_TAP,
+    /* 4830B000-4830BFFF */ L4ID_TAP_TA,
+    /* 4830C000-4830FFFF */
+    /* 48310000-48310FFF */ L4ID_GPIO1,
+    /* 48311000-48311FFF */ L4ID_GPIO1_TA,
+    /* 48312000-48313FFF */
+    /* 48314000-48314FFF */ L4ID_WDTIMER2,
+    /* 48315000-48315FFF */ L4ID_WDTIMER2_TA,
+    /* 48316000-48317FFF */
+    /* 48318000-48318FFF */ L4ID_GPTIMER1,
+    /* 48319000-48319FFF */ L4ID_GPTIMER1_TA,
+    /* 4831A000-4831FFFF */
+    /* 48320000-48320FFF */ L4ID_32KTIMER,
+    /* 48321000-48321FFF */ L4ID_32KTIMER_TA,
+    /* 48322000-48327FFF */
+    /* 48328000-483287FF */ L4ID_WAKEUP_AP,
+    /* 48328800-48328FFF */ L4ID_WAKEUP_C_IP,
+    /* 48329000-48329FFF */ L4ID_WAKEUP_LA,
+    /* 4832A000-4832A7FF */ L4ID_WAKEUP_E_IP,
+    /* 4832A800-4833FFFF */
+    /* 48340000-48340FFF */
+    /* 48341000-48FFFFFF */
+    /* 49000000-490007FF */ L4ID_PER_AP,
+    /* 49000800-49000FFF */ L4ID_PER_IP,
+    /* 49001000-49001FFF */ L4ID_PER_LA,
+    /* 49002000-4901FFFF */
+    /* 49020000-49020FFF */ L4ID_UART3,
+    /* 49021000-49021FFF */ L4ID_UART3_TA,
+    /* 49022000-49022FFF */ L4ID_MCBSP2,
+    /* 49023000-49023FFF */ L4ID_MCBSP2_TA,
+    /* 49024000-49024FFF */ L4ID_MCBSP3,
+    /* 49025000-49025FFF */ L4ID_MCBSP3_TA,
+    /* 49026000-49026FFF */ L4ID_MCBSP4,
+    /* 49027000-49027FFF */ L4ID_MCBSP4_TA,
+    /* 49028000-49028FFF */ L4ID_MCBSP2S,
+    /* 49029000-49029FFF */ L4ID_MCBSP2S_TA,
+    /* 4902A000-4902AFFF */ L4ID_MCBSP3S,
+    /* 4902B000-4902BFFF */ L4ID_MCBSP3S_TA,
+    /* 4902C000-4902FFFF */
+    /* 49030000-49030FFF */ L4ID_WDTIMER3,
+    /* 49031000-49031FFF */ L4ID_WDTIMER3_TA,
+    /* 49032000-49032FFF */ L4ID_GPTIMER2,
+    /* 49033000-49033FFF */ L4ID_GPTIMER2_TA,
+    /* 49034000-49034FFF */ L4ID_GPTIMER3,
+    /* 49035000-49035FFF */ L4ID_GPTIMER3_TA,
+    /* 49036000-49036FFF */ L4ID_GPTIMER4,
+    /* 49037000-49037FFF */ L4ID_GPTIMER4_TA,
+    /* 49038000-49038FFF */ L4ID_GPTIMER5,
+    /* 49039000-49039FFF */ L4ID_GPTIMER5_TA,
+    /* 4903A000-4903AFFF */ L4ID_GPTIMER6,
+    /* 4903B000-4903BFFF */ L4ID_GPTIMER6_TA,
+    /* 4903C000-4903CFFF */ L4ID_GPTIMER7,
+    /* 4903D000-4903DFFF */ L4ID_GPTIMER7_TA,
+    /* 4903E000-4903EFFF */ L4ID_GPTIMER8,
+    /* 4903F000-4903FFFF */ L4ID_GPTIMER8_TA,
+    /* 49040000-49040FFF */ L4ID_GPTIMER9,
+    /* 49041000-49041FFF */ L4ID_GPTIMER9_TA,
+    /* 49042000-4904FFFF */
+    /* 49050000-49050FFF */ L4ID_GPIO2,
+    /* 49051000-49051FFF */ L4ID_GPIO2_TA,
+    /* 49052000-49052FFF */ L4ID_GPIO3,
+    /* 49053000-49053FFF */ L4ID_GPIO3_TA,
+    /* 49054000-49054FFF */ L4ID_GPIO4,
+    /* 49055000-49055FFF */ L4ID_GPIO4_TA,
+    /* 49056000-49056FFF */ L4ID_GPIO5,
+    /* 49057000-49057FFF */ L4ID_GPIO5_TA,
+    /* 49058000-49058FFF */ L4ID_GPIO6,
+    /* 49059000-49059FFF */ L4ID_GPIO6_TA,
+    /* 4905A000-490FFFFF */
+    /* 54000000-54003FFF */
+    /* 54004000-54005FFF */
+    /* 54006000-540067FF */ L4ID_EMU_AP,
+    /* 54006800-54006FFF */ L4ID_EMU_IP_C,
+    /* 54007000-54007FFF */ L4ID_EMU_LA,
+    /* 54008000-540087FF */ L4ID_EMU_IP_DAP,
+    /* 54008800-5400FFFF */
+    /* 54010000-54017FFF */ L4ID_MPUEMU,
+    /* 54018000-54018FFF */ L4ID_MPUEMU_TA,
+    /* 54019000-54019FFF */ L4ID_TPIU,
+    /* 5401A000-5401AFFF */ L4ID_TPIU_TA,
+    /* 5401B000-5401BFFF */ L4ID_ETB,
+    /* 5401C000-5401CFFF */ L4ID_ETB_TA,
+    /* 5401D000-5401DFFF */ L4ID_DAPCTL,
+    /* 5401E000-5401EFFF */ L4ID_DAPCTL_TA,
+    /* 5401F000-5401FFFF */ L4ID_SDTI_TA,
+    /* 54020000-544FFFFF */
+    /* 54500000-5450FFFF */ L4ID_SDTI_CFG,
+    /* 54510000-545FFFFF */
+    /* 54600000-546FFFFF */ L4ID_SDTI,
+    /* 54700000-54705FFF */
+    /* 54706000-54707FFF */ L4ID_EMU_PRM_A,
+    /* 54708000-547087FF */ L4ID_EMU_PRM_B,
+    /* 54708800-54708FFF */
+    /* 54709000-54709FFF */ L4ID_EMU_PRM_TA,
+    /* 5470A000-5470FFFF */
+    /* 54710000-54710FFF */ L4ID_EMU_GPIO1,
+    /* 54711000-54711FFF */ L4ID_EMU_GPIO1_TA,
+    /* 54712000-54713FFF */
+    /* 54714000-54714FFF */ L4ID_EMU_WDTM2,
+    /* 54715000-54715FFF */ L4ID_EMU_WDTM2_TA,
+    /* 54716000-54717FFF */
+    /* 54718000-54718FFF */ L4ID_EMU_GPTM1,
+    /* 54719000-54719FFF */ L4ID_EMU_GPTM1_TA,
+    /* 5471A000-5471FFFF */
+    /* 54720000-54720FFF */ L4ID_EMU_32KTM,
+    /* 54721000-54721FFF */ L4ID_EMU_32KTM_TA,
+    /* 54722000-54727FFF */
+    /* 54728000-547287FF */ L4ID_EMU_WKUP_AP,
+    /* 54728800-54728FFF */ L4ID_EMU_WKUP_IPC,
+    /* 54729000-54729FFF */ L4ID_EMU_WKUP_LA,
+    /* 5472A000-5472A7FF */ L4ID_EMU_WKUP_IPE,
+    /* 5472A800-547FFFFF */
+} omap3_l4_region_id_t;
+
+typedef enum {
+    L4TYPE_GENERIC = 0, /* not mapped by default, must be mapped separately */
+    L4TYPE_IA,          /* initiator agent */
+    L4TYPE_TA,          /* target agent */
+    L4TYPE_LA,          /* link register agent */
+    L4TYPE_AP           /* address protection */
+} omap3_l4_region_type_t;
+
+/* we reuse the "access" member for defining region type -- the original
+   omap_l4_region_s "access" member is not used anywhere else anyway! */
+static struct omap_l4_region_s omap3_l4_region[] = {
+    /* L4-Core */
+    [L4ID_SCM         ] = {0x00002000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_SCM_TA      ] = {0x00003000, 0x1000, L4TYPE_TA},
+    [L4ID_CM_A        ] = {0x00004000, 0x2000, L4TYPE_GENERIC},
+    [L4ID_CM_B        ] = {0x00006000, 0x0800, L4TYPE_GENERIC},
+    [L4ID_CM_TA       ] = {0x00007000, 0x1000, L4TYPE_TA},
+    [L4ID_CORE_AP     ] = {0x00040000, 0x0800, L4TYPE_AP},
+    [L4ID_CORE_IP     ] = {0x00040800, 0x0800, L4TYPE_IA},
+    [L4ID_CORE_LA     ] = {0x00041000, 0x1000, L4TYPE_LA},
+    [L4ID_DSI         ] = {0x0004fc00, 0x0400, L4TYPE_GENERIC},
+    [L4ID_DSS         ] = {0x00050000, 0x0400, L4TYPE_GENERIC},
+    [L4ID_DISPC       ] = {0x00050400, 0x0400, L4TYPE_GENERIC},
+    [L4ID_RFBI        ] = {0x00050800, 0x0400, L4TYPE_GENERIC},
+    [L4ID_VENC        ] = {0x00050c00, 0x0400, L4TYPE_GENERIC},
+    [L4ID_DSS_TA      ] = {0x00051000, 0x1000, L4TYPE_TA},
+    [L4ID_SDMA        ] = {0x00056000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_SDMA_TA     ] = {0x00057000, 0x1000, L4TYPE_TA},
+    [L4ID_I2C3        ] = {0x00060000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_I2C3_TA     ] = {0x00061000, 0x1000, L4TYPE_TA},
+    [L4ID_USBTLL      ] = {0x00062000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_USBTLL_TA   ] = {0x00063000, 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},
+    [L4ID_UART2_TA    ] = {0x0006d000, 0x1000, L4TYPE_TA},
+    [L4ID_I2C1        ] = {0x00070000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_I2C1_TA     ] = {0x00071000, 0x1000, L4TYPE_TA},
+    [L4ID_I2C2        ] = {0x00072000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_I2C2_TA     ] = {0x00073000, 0x1000, L4TYPE_TA},
+    [L4ID_MCBSP1      ] = {0x00074000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCBSP1_TA   ] = {0x00075000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER10   ] = {0x00086000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER10_TA] = {0x00087000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER11   ] = {0x00088000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER11_TA] = {0x00089000, 0x1000, L4TYPE_TA},
+    [L4ID_MAILBOX     ] = {0x00094000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MAILBOX_TA  ] = {0x00095000, 0x1000, L4TYPE_TA},
+    [L4ID_MCBSP5      ] = {0x00096000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCBSP5_TA   ] = {0x00097000, 0x1000, L4TYPE_TA},
+    [L4ID_MCSPI1      ] = {0x00098000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCSPI1_TA   ] = {0x00099000, 0x1000, L4TYPE_TA},
+    [L4ID_MCSPI2      ] = {0x0009a000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCSPI2_TA   ] = {0x0009b000, 0x1000, L4TYPE_TA},
+    [L4ID_MMCSDIO1    ] = {0x0009c000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MMCSDIO1_TA ] = {0x0009d000, 0x1000, L4TYPE_TA},
+    [L4ID_MSPRO       ] = {0x0009e000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MSPRO_TA    ] = {0x0009f000, 0x1000, L4TYPE_TA},
+    [L4ID_HSUSBOTG    ] = {0x000ab000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_HSUSBOTG_TA ] = {0x000ac000, 0x1000, L4TYPE_TA},
+    [L4ID_MMCSDIO3    ] = {0x000ad000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MMCSDIO3_TA ] = {0x000ae000, 0x1000, L4TYPE_TA},
+    [L4ID_HDQ1WIRE    ] = {0x000b2000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_HDQ1WIRE_TA ] = {0x000b3000, 0x1000, L4TYPE_TA},
+    [L4ID_MMCSDIO2    ] = {0x000b4000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MMCSDIO2_TA ] = {0x000b5000, 0x1000, L4TYPE_TA},
+    [L4ID_ICRMPU      ] = {0x000b6000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_ICRMPU_TA   ] = {0x000b7000, 0x1000, L4TYPE_TA},
+    [L4ID_MCSPI3      ] = {0x000b8000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCSPI3_TA   ] = {0x000b9000, 0x1000, L4TYPE_TA},
+    [L4ID_MCSPI4      ] = {0x000ba000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCSPI4_TA   ] = {0x000bb000, 0x1000, L4TYPE_TA},
+    [L4ID_CAMERAISP   ] = {0x000bc000, 0x4000, L4TYPE_GENERIC},
+    [L4ID_CAMERAISP_TA] = {0x000c0000, 0x1000, L4TYPE_TA},
+    [L4ID_ICRMODEM    ] = {0x000cd000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_ICRMODEM_TA ] = {0x000ce000, 0x1000, L4TYPE_TA},
+    /* L4-Wakeup interconnect region A */
+    [L4ID_GPTIMER12   ] = {0x00304000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER12_TA] = {0x00305000, 0x1000, L4TYPE_TA},
+    [L4ID_PRM_A       ] = {0x00306000, 0x2000, L4TYPE_GENERIC},
+    [L4ID_PRM_B       ] = {0x00308000, 0x0800, L4TYPE_GENERIC},
+    [L4ID_PRM_TA      ] = {0x00309000, 0x1000, L4TYPE_TA},
+    /* L4-Core */
+    [L4ID_TAP         ] = {0x0030a000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_TAP_TA      ] = {0x0030b000, 0x1000, L4TYPE_TA},
+    /* L4-Wakeup interconnect region B */
+    [L4ID_GPIO1       ] = {0x00310000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPIO1_TA    ] = {0x00311000, 0x1000, L4TYPE_TA},
+    [L4ID_WDTIMER2    ] = {0x00314000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_WDTIMER2_TA ] = {0x00315000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER1    ] = {0x00318000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER1_TA ] = {0x00319000, 0x1000, L4TYPE_TA},
+    [L4ID_32KTIMER    ] = {0x00320000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_32KTIMER_TA ] = {0x00321000, 0x1000, L4TYPE_TA},
+    [L4ID_WAKEUP_AP   ] = {0x00328000, 0x0800, L4TYPE_AP},
+    [L4ID_WAKEUP_C_IP ] = {0x00328800, 0x0800, L4TYPE_IA},
+    [L4ID_WAKEUP_LA   ] = {0x00329000, 0x1000, L4TYPE_LA},
+    [L4ID_WAKEUP_E_IP ] = {0x0032a000, 0x0800, L4TYPE_IA},
+    /* L4-Per */
+    [L4ID_PER_AP      ] = {0x01000000, 0x0800, L4TYPE_AP},
+    [L4ID_PER_IP      ] = {0x01000800, 0x0800, L4TYPE_IA},
+    [L4ID_PER_LA      ] = {0x01001000, 0x1000, L4TYPE_LA},
+    [L4ID_UART3       ] = {0x01020000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_UART3_TA    ] = {0x01021000, 0x1000, L4TYPE_TA},
+    [L4ID_MCBSP2      ] = {0x01022000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCBSP2_TA   ] = {0x01023000, 0x1000, L4TYPE_TA},
+    [L4ID_MCBSP3      ] = {0x01024000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCBSP3_TA   ] = {0x01025000, 0x1000, L4TYPE_TA},
+    [L4ID_MCBSP4      ] = {0x01026000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCBSP4_TA   ] = {0x01027000, 0x1000, L4TYPE_TA},
+    [L4ID_MCBSP2S     ] = {0x01028000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCBSP2S_TA  ] = {0x01029000, 0x1000, L4TYPE_TA},
+    [L4ID_MCBSP3S     ] = {0x0102a000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_MCBSP3S_TA  ] = {0x0102b000, 0x1000, L4TYPE_TA},
+    [L4ID_WDTIMER3    ] = {0x01030000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_WDTIMER3_TA ] = {0x01031000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER2    ] = {0x01032000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER2_TA ] = {0x01033000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER3    ] = {0x01034000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER3_TA ] = {0x01035000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER4    ] = {0x01036000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER4_TA ] = {0x01037000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER5    ] = {0x01038000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER5_TA ] = {0x01039000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER6    ] = {0x0103a000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER6_TA ] = {0x0103b000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER7    ] = {0x0103c000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER7_TA ] = {0x0103d000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER8    ] = {0x0103e000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER8_TA ] = {0x0103f000, 0x1000, L4TYPE_TA},
+    [L4ID_GPTIMER9    ] = {0x01040000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPTIMER9_TA ] = {0x01041000, 0x1000, L4TYPE_TA},
+    [L4ID_GPIO2       ] = {0x01050000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPIO2_TA    ] = {0x01051000, 0x1000, L4TYPE_TA},
+    [L4ID_GPIO3       ] = {0x01052000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPIO3_TA    ] = {0x01053000, 0x1000, L4TYPE_TA},
+    [L4ID_GPIO4       ] = {0x01054000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPIO4_TA    ] = {0x01055000, 0x1000, L4TYPE_TA},
+    [L4ID_GPIO5       ] = {0x01056000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPIO5_TA    ] = {0x01057000, 0x1000, L4TYPE_TA},
+    [L4ID_GPIO6       ] = {0x01058000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_GPIO6_TA    ] = {0x01059000, 0x1000, L4TYPE_TA},
+    /* L4-Emu */
+    [L4ID_EMU_AP      ] = {0x0c006000, 0x0800, L4TYPE_AP},
+    [L4ID_EMU_IP_C    ] = {0x0c006800, 0x0800, L4TYPE_IA},
+    [L4ID_EMU_LA      ] = {0x0c007000, 0x1000, L4TYPE_LA},
+    [L4ID_EMU_IP_DAP  ] = {0x0c008000, 0x0800, L4TYPE_IA},
+    [L4ID_MPUEMU      ] = {0x0c010000, 0x8000, L4TYPE_GENERIC},
+    [L4ID_MPUEMU_TA   ] = {0x0c018000, 0x1000, L4TYPE_TA},
+    [L4ID_TPIU        ] = {0x0c019000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_TPIU_TA     ] = {0x0c01a000, 0x1000, L4TYPE_TA},
+    [L4ID_ETB         ] = {0x0c01b000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_ETB_TA      ] = {0x0c01c000, 0x1000, L4TYPE_TA},
+    [L4ID_DAPCTL      ] = {0x0c01d000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_DAPCTL_TA   ] = {0x0c01e000, 0x1000, L4TYPE_TA},
+    [L4ID_EMU_PRM_A   ] = {0x0c706000, 0x2000, L4TYPE_GENERIC},
+    [L4ID_EMU_PRM_B   ] = {0x0c706800, 0x0800, L4TYPE_GENERIC},
+    [L4ID_EMU_PRM_TA  ] = {0x0c709000, 0x1000, L4TYPE_TA},
+    [L4ID_EMU_GPIO1   ] = {0x0c710000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_EMU_GPIO1_TA] = {0x0c711000, 0x1000, L4TYPE_TA},
+    [L4ID_EMU_WDTM2   ] = {0x0c714000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_EMU_WDTM2_TA] = {0x0c715000, 0x1000, L4TYPE_TA},
+    [L4ID_EMU_GPTM1   ] = {0x0c718000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_EMU_GPTM1_TA] = {0x0c719000, 0x1000, L4TYPE_TA},
+    [L4ID_EMU_32KTM   ] = {0x0c720000, 0x1000, L4TYPE_GENERIC},
+    [L4ID_EMU_32KTM_TA] = {0x0c721000, 0x1000, L4TYPE_TA},
+    [L4ID_EMU_WKUP_AP ] = {0x0c728000, 0x0800, L4TYPE_AP},
+    [L4ID_EMU_WKUP_IPC] = {0x0c728800, 0x0800, L4TYPE_IA},
+    [L4ID_EMU_WKUP_LA ] = {0x0c729000, 0x1000, L4TYPE_LA},
+    [L4ID_EMU_WKUP_IPE] = {0x0c72a000, 0x0800, L4TYPE_IA},
+};
+
+typedef enum {
+    L4A_SCM = 0,
+    L4A_CM,
+    L4A_PRM,
+    L4A_GPTIMER1,
+    L4A_GPTIMER2,
+    L4A_GPTIMER3,
+    L4A_GPTIMER4,
+    L4A_GPTIMER5,
+    L4A_GPTIMER6,
+    L4A_GPTIMER7,
+    L4A_GPTIMER8,
+    L4A_GPTIMER9,
+    L4A_GPTIMER10,
+    L4A_GPTIMER11,
+    L4A_GPTIMER12,
+    L4A_WDTIMER2,
+    L4A_32KTIMER,
+    L4A_UART1,
+    L4A_UART2,
+    L4A_UART3,
+    L4A_DSS,
+    L4A_GPIO1,
+    L4A_GPIO2,
+    L4A_GPIO3,
+    L4A_GPIO4,
+    L4A_GPIO5,
+    L4A_GPIO6,
+    L4A_MMC1,
+    L4A_MMC2,
+    L4A_MMC3,
+    L4A_I2C1,
+    L4A_I2C2,
+    L4A_I2C3,
+    L4A_TAP,
+    L4A_USBHS_OTG,
+    L4A_USBHS_HOST,
+    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 {
+    omap3_l4_agent_info_id_t agent_id;
+    omap3_l4_region_id_t     first_region_id;
+    int                      region_count;
+};
+
+static const struct omap3_l4_agent_info_s omap3_l4_agent_info[] = {
+    /* L4-Core Agents */
+    {L4A_DSS,        L4ID_DSI,       6},
+    /* TODO: camera */
+    {L4A_USBHS_OTG,  L4ID_HSUSBOTG,  2},
+    {L4A_USBHS_HOST, L4ID_USBHOST,   4},
+    {L4A_USBHS_TLL,  L4ID_USBTLL,    2},
+    {L4A_UART1,      L4ID_UART1,     2},
+    {L4A_UART2,      L4ID_UART2,     2},
+    {L4A_I2C1,       L4ID_I2C1,      2},
+    {L4A_I2C2,       L4ID_I2C2,      2},
+    {L4A_I2C3,       L4ID_I2C3,      2},
+    /* TODO: McBSP1 */
+    /* TODO: McBSP5 */
+    {L4A_GPTIMER10,  L4ID_GPTIMER10, 2},
+    {L4A_GPTIMER11,  L4ID_GPTIMER11, 2},
+    {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 */
+    {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},
+    /* L4-Wakeup Agents */
+    {L4A_GPTIMER12,  L4ID_GPTIMER12, 2},
+    {L4A_PRM,        L4ID_PRM_A,     3},
+    {L4A_GPIO1,      L4ID_GPIO1,     2},
+    {L4A_WDTIMER2,   L4ID_WDTIMER2,  2},
+    {L4A_GPTIMER1,   L4ID_GPTIMER1,  2},
+    {L4A_32KTIMER,   L4ID_32KTIMER,  2},
+    /* L4-Per Agents */
+    {L4A_UART3,      L4ID_UART3,     2},
+    /* TODO: McBSP2 */
+    /* TODO: McBSP3 */
+    {L4A_GPTIMER2,   L4ID_GPTIMER2,  2},
+    {L4A_GPTIMER3,   L4ID_GPTIMER3,  2},
+    {L4A_GPTIMER4,   L4ID_GPTIMER4,  2},
+    {L4A_GPTIMER5,   L4ID_GPTIMER5,  2},
+    {L4A_GPTIMER6,   L4ID_GPTIMER6,  2},
+    {L4A_GPTIMER7,   L4ID_GPTIMER7,  2},
+    {L4A_GPTIMER8,   L4ID_GPTIMER8,  2},
+    {L4A_GPTIMER9,   L4ID_GPTIMER9,  2},
+    {L4A_GPIO2,      L4ID_GPIO2,     2},
+    {L4A_GPIO3,      L4ID_GPIO3,     2},
+    {L4A_GPIO4,      L4ID_GPIO4,     2},
+    {L4A_GPIO5,      L4ID_GPIO5,     2},
+    {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;
+    
+    switch (addr) {
+        case 0x00: /* COMPONENT_L */
+            return s->component;
+        case 0x04: /* COMPONENT_H */
+            return 0;
+        case 0x18: /* CORE_L */
+            return s->component;
+        case 0x1c: /* CORE_H */
+            return (s->component >> 16);
+        case 0x20: /* AGENT_CONTROL_L */
+            return s->control;
+        case 0x24: /* AGENT_CONTROL_H */
+            return s->control_h;
+        case 0x28: /* AGENT_STATUS_L */
+            return s->status;
+        case 0x2c: /* AGENT_STATUS_H */
+            return 0;
+        default:
+            break;
+    }
+    
+    OMAP_BAD_REG(s->base + addr);
+    return 0;
+}
+
+static void omap3_l4ta_write(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+    
+    switch (addr) {
+        case 0x00: /* COMPONENT_L */
+        case 0x04: /* COMPONENT_H */
+        case 0x18: /* CORE_L */
+        case 0x1c: /* CORE_H */
+            OMAP_RO_REG(s->base + addr);
+            break;
+        case 0x20: /* AGENT_CONTROL_L */
+            s->control = value & 0x00000701;
+            break;
+        case 0x24: /* AGENT_CONTROL_H */
+            s->control_h = value & 0x100; /* TODO: shouldn't this be read-only? */
+            break;
+        case 0x28: /* AGENT_STATUS_L */
+            if (value & 0x100)
+                s->status &= ~0x100; /* REQ_TIMEOUT */
+            break;
+        case 0x2c: /* AGENT_STATUS_H */
+            /* no writable bits although the register is listed as RW */
+            break;
+        default:
+            OMAP_BAD_REG(s->base + addr);
+            break;
+    }
+}
+
+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,
+    omap3_l4ta_read,
+};
+
+static CPUWriteMemoryFunc *omap3_l4ta_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_l4ta_write,
+};
+#endif
+
+static struct omap_target_agent_s *omap3_l4ta_init(struct omap_l4_s *bus, int cs)
+{
+#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;
+
+    for (i = 0; i < bus->ta_num; i++)
+        if (omap3_l4_agent_info[i].agent_id == cs) {
+            ta = &bus->ta[i];
+            info = &omap3_l4_agent_info[i];
+            break;
+        }
+    if (!ta) {
+        fprintf(stderr, "%s: invalid agent id (%i)\n", __FUNCTION__, cs);
+        exit(-1);
+    }
+    if (ta->bus) {
+        fprintf(stderr, "%s: target agent (%d) already initialized\n",
+                __FUNCTION__, cs);
+        exit(-1);
+    }
+
+    ta->bus = bus;
+    ta->start = &omap3_l4_region[info->first_region_id];
+    ta->regions = info->region_count;
+
+    ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    ta->status = 0x00000000;
+    ta->control = 0x00000200;
+
+    for (i = 0; i < info->region_count; i++)
+        if (omap3_l4_region[info->first_region_id + i].access == L4TYPE_TA)
+            break;
+    if (i >= info->region_count) {
+        fprintf(stderr, "%s: specified agent (%d) has no TA region\n",
+                __FUNCTION__, 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_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 {
+    qemu_irq mpu_irq;
+    qemu_irq iva_irq;
+    struct omap_mpu_state_s *omap;
+
+    struct omap3_prm_domain_s iva2;
+    struct omap3_prm_domain_s mpu;
+    struct omap3_prm_domain_s core;
+    struct omap3_prm_domain_s sgx;
+    struct omap3_prm_domain_s wkup;
+    struct omap3_prm_domain_s dss;
+    struct omap3_prm_domain_s cam;
+    struct omap3_prm_domain_s per;
+    struct omap3_prm_domain_s emu;
+    struct omap3_prm_domain_s neon;
+    struct omap3_prm_domain_s usbhost;
+
+    uint32_t prm_irqstatus_iva2;
+    uint32_t prm_irqenable_iva2;
+    
+    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;
+        /* the following smartreflex control registers taken from linux kernel
+         * source as their descriptions are missing in the OMAP3 TRM */
+        struct {
+            uint32_t config;
+            uint32_t vstepmin;
+            uint32_t vstepmax;
+            uint32_t vlimitto;
+            uint32_t voltage;
+            uint32_t status;
+        } prm_vp[2];
+    } gr; /* global_reg */
+};
+
+static void omap3_prm_int_update(struct omap3_prm_s *s)
+{
+    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->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_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_pwstctrl    = 0xf0307;
+    s->core.pm_pwstst      = 0xf7;
+    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;
+
+    bzero(&s->wkup, sizeof(s->wkup));
+    s->wkup.pm_wken      = 0x3cb;
+    s->wkup.pm_mpugrpsel = 0x3cb;
+    s->wkup.pm_pwstst    = 0x3; /* TODO: check on real hardware */
+
+    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;
+
+    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;
+
+    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_wkdep     = 0x17;
+    s->per.pm_pwstctrl  = 0x30107;
+    s->per.pm_pwstst    = 0x7;
+
+    bzero(&s->emu, sizeof(s->emu));
+    s->emu.rm_rstst  = 0x1;
+    s->emu.pm_pwstst = 0x13;
+
+    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;
+    /* TODO: figure out reset values for prm_vp[1,2] registers */
+
+    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;
+
+    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_wkdep     = 0x17;
+    s->usbhost.pm_pwstctrl  = 0x30107;
+    s->usbhost.pm_pwstst    = 0x3;
+
+    omap3_prm_int_update(s);
+}
+
+static uint32_t omap3_prm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap3_prm_s *s = (struct omap3_prm_s *)opaque;
+    struct omap3_prm_domain_s *d = 0;
+
+    TRACE("%04x", addr);
+    
+    /* handle common domain registers first - all domains may not
+       have all common registers though but we're returning zeroes there */
+    switch ((addr >> 8) & 0xff) {
+        case 0x00: d = &s->iva2; break;
+        case 0x09: d = &s->mpu; break;
+        case 0x0a: d = &s->core; break;
+        case 0x0b: d = &s->sgx; break;
+        case 0x0c: d = &s->wkup; break;
+        case 0x0e: d = &s->dss; break;
+        case 0x0f: d = &s->cam; break;
+        case 0x10: d = &s->per; break;
+        case 0x11: d = &s->emu; break;
+        case 0x13: d = &s->neon; break;
+        case 0x14: d = &s->usbhost; break;
+        default: break;
+    }
+    if (d)
+        switch (addr & 0xff) {
+            case 0x50: return d->rm_rstctrl;
+            case 0x58: return d->rm_rstst;
+            case 0xa0: return d->pm_wken;
+            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->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->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;
+        case 0x12b0: return s->gr.prm_vp[0].config;
+        case 0x12b4: return s->gr.prm_vp[0].vstepmin;
+        case 0x12b8: return s->gr.prm_vp[0].vstepmax;
+        case 0x12bc: return s->gr.prm_vp[0].vlimitto;
+        case 0x12c0: return s->gr.prm_vp[0].voltage;
+        case 0x12c4: return s->gr.prm_vp[0].status;
+        case 0x12d0: return s->gr.prm_vp[1].config;
+        case 0x12d4: return s->gr.prm_vp[1].vstepmin;
+        case 0x12d8: return s->gr.prm_vp[1].vstepmax;
+        case 0x12dc: return s->gr.prm_vp[1].vlimitto;
+        case 0x12e0: return s->gr.prm_vp[1].voltage;
+        case 0x12e4: return s->gr.prm_vp[1].status;
+        default: break;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+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)
+{
+    struct omap3_prm_s *s = (struct omap3_prm_s *)opaque;
+
+    TRACE("%04x = %08x", addr, value);
+    switch (addr) {
+        /* IVA2_PRM */
+        case 0x0050: s->iva2.rm_rstctrl = value & 0x7; break;
+        case 0x0058: s->iva2.rm_rstst &= ~(value & 0x3f0f); break;
+        case 0x00c8: s->iva2.pm_wkdep = value & 0xb3; break;
+        case 0x00e0: s->iva2.pm_pwstctrl = 0xcff000 | (value & 0x300f0f); break;
+        case 0x00e4: OMAP_RO_REG(addr); break;
+        case 0x00e8: s->iva2.pm_prepwstst = value & 0xff7;
+        case 0x00f8:
+            s->prm_irqstatus_iva2 &= ~(value & 0x7);
+            omap3_prm_int_update(s);
+            break;
+        case 0x00fc:
+            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->ocp.prm_sysconfig = value & 0x1; break;
+        case 0x0818:
+            s->ocp.prm_irqstatus_mpu &= ~(value & 0x03c003fd);
+            omap3_prm_int_update(s);
+            break;
+        case 0x081c:
+            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 0x09e0: s->mpu.pm_pwstctrl = value & 0x3010f; break;
+        case 0x09e4: OMAP_RO_REG(addr); break;
+        case 0x09e8: s->mpu.pm_prepwstst = value & 0xc7; break;
+        /* CORE_PRM */
+        case 0x0a50: s->core.rm_rstctrl = value & 0x3; break; /* TODO: check if available on real hw */
+        case 0x0a58: s->core.rm_rstst &= ~(value & 0x7); break;
+        case 0x0aa0: s->core.pm_wken = 0x80000008 | (value & 0x433ffe10); break;
+        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 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->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;
+        case 0x0be0: s->sgx.pm_pwstctrl = 0x030104 | (value & 0x3); break;
+        case 0x0be4: OMAP_RO_REG(addr); break;
+        case 0x0be8: s->sgx.pm_prepwstst = value & 0x3; break;
+        /* WKUP_PRM */
+        case 0x0ca0: s->wkup.pm_wken = 0x2 | (value & 0x0103c9); break;
+        case 0x0ca4: s->wkup.pm_mpugrpsel = 0x0102 | (value & 0x02c9); break;
+        case 0x0ca8: s->wkup.pm_ivagrpsel = value & 0x03cb; break;
+        case 0x0cb0: s->wkup.pm_wkst &= ~(value & 0x0103cb); break;
+        /* Clock_Control_Reg_PRM */
+        case 0x0d40: 
+            s->ccr.prm_clksel = value & 0x7;
+            omap3_prm_clksel_update(s);
+            break;
+        case 0x0d70:
+            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;
+        case 0x0ea0: s->dss.pm_wken = value & 1; break;
+        case 0x0ec8: s->dss.pm_wkdep = value & 0x16; break;
+        case 0x0ee0: s->dss.pm_pwstctrl = 0x030104 | (value & 3); break;
+        case 0x0ee4: OMAP_RO_REG(addr); break;
+        case 0x0ee8: s->dss.pm_prepwstst = value & 3; break;
+        /* CAM_PRM */
+        case 0x0f58: s->cam.rm_rstst &= (value & 0xf); break;
+        case 0x0fc8: s->cam.pm_wkdep = value & 0x16; break;
+        case 0x0fe0: s->cam.pm_pwstctrl = 0x030104 | (value & 3); break;
+        case 0x0fe4: OMAP_RO_REG(addr); break;
+        case 0x0fe8: s->cam.pm_prepwstst = value & 0x3; break;
+        /* PER_PRM */
+        case 0x1058: s->per.rm_rstst &= ~(value & 0xf); break;
+        case 0x10a0: s->per.pm_wken = value & 0x03efff; break;
+        case 0x10a4: s->per.pm_mpugrpsel = value & 0x03efff; break;
+        case 0x10a8: s->per.pm_ivagrpsel = value & 0x03efff; break;
+        case 0x10b0: s->per.pm_wkst &= ~(value & 0x03efff); break;
+        case 0x10c8: s->per.pm_wkdep = value & 0x17; break;
+        case 0x10e0: s->per.pm_pwstctrl = 0x030100 | (value & 7); break;
+        case 0x10e4: OMAP_RO_REG(addr); break;
+        case 0x10e8: s->per.pm_prepwstst = value & 0x7; break;
+        /* EMU_PRM */
+        case 0x1158: s->emu.rm_rstst &= ~(value & 7); break;
+        case 0x11e4: OMAP_RO_REG(addr); break;
+        /* Global_Reg_PRM */
+        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->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->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;
+        /* TODO: check if any functionality is needed behind writes to the
+         * prm_vp[1,2] registers */
+        case 0x12b0: s->gr.prm_vp[0].config = value; break;
+        case 0x12b4: s->gr.prm_vp[0].vstepmin = value; break;
+        case 0x12b8: s->gr.prm_vp[0].vstepmax = value; break;
+        case 0x12bc: s->gr.prm_vp[0].vlimitto = value; break;
+        case 0x12c0: s->gr.prm_vp[0].voltage = value; break;
+        case 0x12c4: s->gr.prm_vp[0].status = value; break;
+        case 0x12d0: s->gr.prm_vp[1].config = value; break;
+        case 0x12d4: s->gr.prm_vp[1].vstepmin = value; break;
+        case 0x12d8: s->gr.prm_vp[1].vstepmax = value; break;
+        case 0x12dc: s->gr.prm_vp[1].vlimitto = value; break;
+        case 0x12e0: s->gr.prm_vp[1].voltage = value; break;
+        case 0x12e4: s->gr.prm_vp[1].status = value; break;
+        /* NEON_PRM */
+        case 0x1358: s->neon.rm_rstst &= ~(value & 0xf); break;
+        case 0x13c8: s->neon.pm_wkdep = value & 0x2; break;
+        case 0x13e0: s->neon.pm_pwstctrl = 0x4 | (value & 3); break;
+        case 0x13e4: OMAP_RO_REG(addr); break;
+        case 0x13e8: s->neon.pm_prepwstst = value & 3; break;
+        /* USBHOST_PRM */
+        case 0x1458: s->usbhost.rm_rstst &= ~(value & 0xf); break;
+        case 0x14a0: s->usbhost.pm_wken = value & 1; break;
+        case 0x14a4: s->usbhost.pm_mpugrpsel = value & 1; break;
+        case 0x14a8: s->usbhost.pm_ivagrpsel = value & 1; break;
+        case 0x14b0: s->usbhost.pm_wkst &= ~(value & 1); break;
+        case 0x14c8: s->usbhost.pm_wkdep = value & 0x17; break;
+        case 0x14e0: s->usbhost.pm_pwstctrl = 0x030104 | (value & 0x13); break;
+        case 0x14e4: OMAP_RO_REG(addr); break;
+        case 0x14e8: s->usbhost.pm_prepwstst = value & 3; break;
+        default:
+            OMAP_BAD_REGV(addr, value);
+            break;
+    }
+}
+
+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;
+    int i;
+    
+    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);
+    for (i = 0; i < 2; i++) {
+        qemu_put_be32(f, s->gr.prm_vp[i].config);
+        qemu_put_be32(f, s->gr.prm_vp[i].vstepmin);
+        qemu_put_be32(f, s->gr.prm_vp[i].vstepmax);
+        qemu_put_be32(f, s->gr.prm_vp[i].vlimitto);
+        qemu_put_be32(f, s->gr.prm_vp[i].voltage);
+        qemu_put_be32(f, s->gr.prm_vp[i].status);
+    }
+}
+
+static int omap3_prm_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap3_prm_s *s = (struct omap3_prm_s *)opaque;
+    int i;
+    
+    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);
+    for (i = 0; i < 2; i++) {
+        s->gr.prm_vp[i].config = qemu_get_be32(f);
+        s->gr.prm_vp[i].vstepmin = qemu_get_be32(f);
+        s->gr.prm_vp[i].vstepmax = qemu_get_be32(f);
+        s->gr.prm_vp[i].vlimitto = qemu_get_be32(f);
+        s->gr.prm_vp[i].voltage = qemu_get_be32(f);
+        s->gr.prm_vp[i].status = 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,
+    omap3_prm_read,
+};
+
+static CPUWriteMemoryFunc *omap3_prm_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_prm_write,
+};
+
+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));
+
+    s->mpu_irq = mpu_int;
+    s->iva_irq = iva_int;
+    s->omap = mpu;
+    omap3_prm_reset(s);
+
+    iomemtype = l4_register_io_memory(0, omap3_prm_readfn,
+                                      omap3_prm_writefn, s);
+    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 {
+    qemu_irq irq[3];
+    struct omap_mpu_state_s *mpu;
+
+    /* 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_fclken2_core;   /* 0a04 */
+    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_clksel_wkup_update(struct omap3_cm_s *s)
+{
+    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("gptimer1 fclk=%lld",
+          omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp1_fclk")));
+
+    /* TODO: CM_USIM_CLK */
+}
+
+static inline void omap3_cm_iva2_update(struct omap3_cm_s *s)
+{
+    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");
+
+    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;
+    }
+    
+    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_mpu_update(struct omap3_cm_s *s)
+{
+    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;
+    }
+    
+    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 core_dpll_mul = ((s->cm_clksel1_pll >> 16) & 0x7ff);
+    uint32_t core_dpll_div, core_dpll_clkout_div, div_dpll3;
+
+    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;
+    }
+
+    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"),
+                         (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 per_dpll_mul = ((s->cm_clksel2_pll >> 8) & 0x7ff);
+    uint32_t per_dpll_div, div_96m, clksel_tv, clksel_dss1, clksel_cam, div_dpll4;
+
+    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 (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);
+    }
+}
+
+static inline void omap3_cm_dpll5_update(struct omap3_cm_s *s)
+{
+    uint32_t per2_dpll_mul = ((s->cm_clksel4_pll >> 8) & 0x7ff);
+    uint32_t per2_dpll_div, div_120m;
+
+    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 (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);
+    }
+}
+
+static inline void omap3_cm_48m_update(struct omap3_cm_s *s)
+{
+    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_gp10gp11_update(struct omap3_cm_s *s)
+{
+    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");
+
+    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]);
+    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_per_gptimer_update(struct omap3_cm_s *s)
+{
+    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_clkout2_update(struct omap3_cm_s *s)
+{
+    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_fclken1_core_update(struct omap3_cm_s *s)
+{
+    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_iclken1_core_update(struct omap3_cm_s *s)
+{
+    uint32_t v = s->cm_iclken1_core;
+    
+    /* 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_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;
+    s->cm_clken_pll_iva2 = 0x11;
+    s->cm_idlest_iva2 = 0x1;
+    s->cm_idlest_pll_iva2 = 0;
+    s->cm_autoidle_pll_iva2 = 0x0;
+    s->cm_clksel1_pll_iva2 = 0x80000;
+    s->cm_clksel2_pll_iva2 = 0x1;
+    s->cm_clkstctrl_iva2 = 0x0;
+    s->cm_clkstst_iva2 = 0x0;
+
+    s->cm_revision = 0x10;
+    s->cm_sysconfig = 0x1;
+
+    s->cm_clken_pll_mpu = 0x15;
+    s->cm_idlest_mpu = 0x1;
+    s->cm_idlest_pll_mpu = 0;
+    s->cm_autoidle_pll_mpu = 0x0;
+    s->cm_clksel1_pll_mpu = 0x80000;
+    s->cm_clksel2_pll_mpu = 0x1;
+    s->cm_clkstctrl_mpu = 0x0;
+    s->cm_clkstst_mpu = 0x0;
+
+    s->cm_fclken1_core = 0x0;
+    s->cm_fclken2_core = 0x0;
+    s->cm_fclken3_core = 0x0;
+    s->cm_iclken1_core = 0x42;
+    s->cm_iclken2_core = 0x0;
+    s->cm_iclken3_core = 0x0;
+    /*allow access to devices*/
+    s->cm_idlest1_core = 0x0;
+    s->cm_idlest2_core = 0x0;
+    /*ide status =0 */
+    s->cm_idlest3_core = 0xa; 
+    s->cm_autoidle1_core = 0x0;
+    s->cm_autoidle2_core = 0x0;
+    s->cm_autoidle3_core = 0x0;
+    s->cm_clksel_core = 0x105;
+    s->cm_clkstctrl_core = 0x0;
+    s->cm_clkstst_core = 0x0;
+
+    s->cm_fclken_sgx = 0x0;
+    s->cm_iclken_sgx = 0x0;
+    s->cm_idlest_sgx = 0x1;
+    s->cm_clksel_sgx = 0x0;
+    s->cm_sleepdep_sgx = 0x0;
+    s->cm_clkstctrl_sgx = 0x0;
+    s->cm_clkstst_sgx = 0x0;
+
+    s->cm_fclken_wkup = 0x0;
+    s->cm_iclken_wkup = 0x0;
+    /*assume all clock can be accessed*/
+    s->cm_idlest_wkup = 0x0;
+    s->cm_autoidle_wkup = 0x0;
+    s->cm_clksel_wkup = 0x12;
+
+    s->cm_clken_pll = 0x110015;
+    s->cm_clken2_pll = 0x11;
+    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;
+    s->cm_clksel2_pll = 0x0;
+    s->cm_clksel3_pll = 0x1;
+    s->cm_clksel4_pll = 0x0;
+    s->cm_clksel5_pll = 0x1;
+    s->cm_clkout_ctrl = 0x3;
+
+
+    s->cm_fclken_dss = 0x0;
+    s->cm_iclken_dss = 0x0;
+    /*dss can be accessed*/
+    s->cm_idlest_dss = 0x0;
+    s->cm_autoidle_dss = 0x0;
+    s->cm_clksel_dss = 0x1010;
+    s->cm_sleepdep_dss = 0x0;
+    s->cm_clkstctrl_dss = 0x0;
+    s->cm_clkstst_dss = 0x0;
+
+    s->cm_fclken_cam = 0x0;
+    s->cm_iclken_cam = 0x0;
+    s->cm_idlest_cam = 0x1;
+    s->cm_autoidle_cam = 0x0;
+    s->cm_clksel_cam = 0x10;
+    s->cm_sleepdep_cam = 0x0;
+    s->cm_clkstctrl_cam = 0x0;
+    s->cm_clkstst_cam = 0x0;
+
+    s->cm_fclken_per = 0x0;
+    s->cm_iclken_per = 0x0;
+    //s->cm_idlest_per = 0x3ffff;
+    s->cm_idlest_per = 0x0; //enable GPIO access
+    s->cm_autoidle_per = 0x0;
+    s->cm_clksel_per = 0x0;
+    s->cm_sleepdep_per = 0x0;
+    s->cm_clkstctrl_per = 0x0;
+    s->cm_clkstst_per = 0x0;
+
+    s->cm_clksel1_emu = 0x10100a50;
+    s->cm_clkstctrl_emu = 0x2;
+    s->cm_clkstst_emu = 0x0;
+    s->cm_clksel2_emu = 0x0;
+    s->cm_clksel3_emu = 0x0;
+
+    s->cm_polctrl = 0x0;
+
+    s->cm_idlest_neon = 0x1;
+    s->cm_clkstctrl_neon = 0x0;
+
+    s->cm_fclken_usbhost = 0x0;
+    s->cm_iclken_usbhost = 0x0;
+    s->cm_idlest_usbhost = 0x3;
+    s->cm_autoidle_usbhost = 0x0;
+    s->cm_sleepdep_usbhost = 0x0;
+    s->cm_clkstctrl_usbhost = 0x0;
+    s->cm_clkstst_usbhost = 0x0;
+}
+
+static uint32_t omap3_cm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap3_cm_s *s = (struct omap3_cm_s *) opaque;
+
+    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 0x0a04: return s->cm_fclken2_core;
+        case 0x0a08: return s->cm_fclken3_core;
+        case 0x0a10: return s->cm_iclken1_core;
+        case 0x0a14: return s->cm_iclken2_core;
+        case 0x0a18: return s->cm_iclken3_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 0x0b44: return s->cm_sleepdep_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,
+                           uint32_t value)
+{
+    struct omap3_cm_s *s = (struct omap3_cm_s *)opaque;
+
+    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 0xa04:
+            /* TODO: check if modifying this has any effect */
+            s->cm_fclken2_core = value;
+            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;
+    
+    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_fclken2_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_fclken2_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,
+    omap_badwidth_read32,
+    omap3_cm_read,
+};
+
+static CPUWriteMemoryFunc *omap3_cm_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_cm_write,
+};
+
+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));
+
+    s->irq[0] = mpu_int;
+    s->irq[1] = dsp_int;
+    s->irq[2] = iva_int;
+    s->mpu = mpu;
+    omap3_cm_reset(s);
+
+    iomemtype = l4_register_io_memory(0, omap3_cm_readfn, omap3_cm_writefn, s);
+    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;
+}
+
+#define OMAP3_SEC_WDT          1
+#define OMAP3_MPU_WDT         2
+#define OMAP3_IVA2_WDT        3
+/*omap3 watchdog timer*/
+struct omap3_wdt_s
+{
+    qemu_irq irq;               /*IVA2 IRQ */
+    struct omap_mpu_state_s *mpu;
+    omap_clk clk;
+    QEMUTimer *timer;
+
+    int active;
+    int64_t rate;
+    int64_t time;
+    //int64_t ticks_per_sec;
+
+    uint32_t wd_sysconfig;
+    uint32_t wd_sysstatus;
+    uint32_t wisr;
+    uint32_t wier;
+    uint32_t wclr;
+    uint32_t wcrr;
+    uint32_t wldr;
+    uint32_t wtgr;
+    uint32_t wwps;
+    uint32_t wspr;
+
+    /*pre and ptv in wclr */
+    uint32_t pre;
+    uint32_t ptv;
+    //uint32_t val;
+
+    uint16_t writeh;            /* LSB */
+    uint16_t readh;             /* MSB */
+};
+
+static inline void omap3_wdt_timer_update(struct omap3_wdt_s *wdt_timer)
+{
+    int64_t expires;
+    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
+        qemu_del_timer(wdt_timer->timer);
+}
+
+static void omap3_wdt_clk_setup(struct omap3_wdt_s *timer)
+{
+    /*TODO: Add irq as user to clk */
+}
+
+static inline uint32_t omap3_wdt_timer_read(struct omap3_wdt_s *timer)
+{
+    uint64_t distance;
+
+    if (timer->active) {
+        distance = qemu_get_clock(vm_clock) - timer->time;
+        distance = muldiv64(distance, timer->rate, ticks_per_sec);
+
+        if (distance >= 0xffffffff - timer->wcrr)
+            return 0xffffffff;
+        else
+            return timer->wcrr + distance;
+    } else
+        return timer->wcrr;
+}
+
+/*
+static inline void omap3_wdt_timer_sync(struct omap3_wdt_s *timer)
+{
+    if (timer->active) {
+        timer->val = omap3_wdt_timer_read(timer);
+        timer->time = qemu_get_clock(vm_clock);
+    }
+}*/
+
+static void omap3_wdt_reset(struct omap3_wdt_s *s, int wdt_index)
+{
+    s->wd_sysconfig = 0x0;
+    s->wd_sysstatus = 0x0;
+    s->wisr = 0x0;
+    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;
+        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;
+        default:
+            break;
+    }
+    s->pre = s->wclr & (1 << 5);
+    s->ptv = (s->wclr & 0x1c) >> 2;
+    s->rate = omap_clk_getrate(s->clk) >> (s->pre ? s->ptv : 0);
+
+    s->active = 1;
+    s->time = qemu_get_clock(vm_clock);
+    omap3_wdt_timer_update(s);
+}
+
+static uint32_t omap3_wdt_read32(void *opaque, target_phys_addr_t addr,
+                                 int wdt_index)
+{
+    struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
+
+    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)
+{
+    struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
+    uint32_t ret;
+
+    if (addr & 2)
+        return s->readh;
+
+    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)
+{
+    return omap3_wdt_read32(opaque, addr, OMAP3_MPU_WDT);
+}
+
+static void omap3_wdt_write32(void *opaque, target_phys_addr_t addr,
+                              uint32_t value, int wdt_index)
+{
+    struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
+
+    switch (addr) {
+    case 0x14: /* WD_SYSSTATUS */
+    case 0x34: /* WWPS */
+        OMAP_RO_REGV(addr, value);
+        break;
+    case 0x10: /*WD_SYSCONFIG */
+        s->wd_sysconfig = value & 0x33f;
+        break;
+    case 0x18: /* WISR */
+         s->wisr = value & 0x1;
+        break;
+    case 0x1c: /* WIER */
+        s->wier = value & 0x1;
+        break;
+    case 0x24: /* WCLR */
+        s->wclr = value & 0x3c;
+        break;
+    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 */
+        break;
+    case 0x30: /* WTGR */
+        if (value != s->wtgr) {
+            s->wcrr = s->wldr;
+            s->pre = s->wclr & (1 << 5);
+            s->ptv = (s->wclr & 0x1c) >> 2;
+            s->rate = omap_clk_getrate(s->clk) >> (s->pre ? s->ptv : 0);
+            s->time = qemu_get_clock(vm_clock);
+            omap3_wdt_timer_update(s);
+        }
+        s->wtgr = value;
+        break;
+    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)) {
+            s->active = 1;
+            s->time = qemu_get_clock(vm_clock);
+            omap3_wdt_timer_update(s);
+        }
+        s->wspr = value;
+        break;
+    default:
+        OMAP_BAD_REGV(addr, value);
+        break;
+    }
+}
+
+static void omap3_mpu_wdt_write16(void *opaque, target_phys_addr_t addr,
+                                  uint32_t value)
+{
+    struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
+
+    if (addr & 2)
+        return omap3_wdt_write32(opaque, addr, (value << 16) | s->writeh,
+                                 OMAP3_MPU_WDT);
+    else
+        s->writeh = (uint16_t) value;
+}
+
+static void omap3_mpu_wdt_write32(void *opaque, target_phys_addr_t addr,
+                                  uint32_t value)
+{
+    omap3_wdt_write32(opaque, addr, value, OMAP3_MPU_WDT);
+}
+
+static CPUReadMemoryFunc *omap3_mpu_wdt_readfn[] = {
+    omap_badwidth_read32,
+    omap3_mpu_wdt_read16,
+    omap3_mpu_wdt_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_mpu_wdt_writefn[] = {
+    omap_badwidth_write32,
+    omap3_mpu_wdt_write16,
+    omap3_mpu_wdt_write32,
+};
+
+static void omap3_mpu_wdt_timer_tick(void *opaque)
+{
+    struct omap3_wdt_s *wdt_timer = (struct omap3_wdt_s *) opaque;
+
+    /*TODO:Sent reset pulse to PRCM */
+    wdt_timer->wcrr = wdt_timer->wldr;
+
+    /*after overflow, generate the new wdt_timer->rate */
+    wdt_timer->pre = wdt_timer->wclr & (1 << 5);
+    wdt_timer->ptv = (wdt_timer->wclr & 0x1c) >> 2;
+    wdt_timer->rate =
+        omap_clk_getrate(wdt_timer->clk) >> (wdt_timer->pre ? wdt_timer->
+                                             ptv : 0);
+
+    wdt_timer->time = qemu_get_clock(vm_clock);
+    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,
+                                              struct omap_mpu_state_s *mpu)
+{
+    int iomemtype;
+    struct omap3_wdt_s *s = (struct omap3_wdt_s *) qemu_mallocz(sizeof(*s));
+
+    s->irq = irq;
+    s->clk = fclk;
+    s->timer = qemu_new_timer(vm_clock, omap3_mpu_wdt_timer_tick, s);
+
+    omap3_wdt_reset(s, OMAP3_MPU_WDT);
+    if (irq != NULL)
+        omap3_wdt_clk_setup(s);
+
+    iomemtype = l4_register_io_memory(0, omap3_mpu_wdt_readfn,
+                                      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 {
+    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 padconfs_wkup[84]; /*0x4800 2a00*/
+       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 { \
+                *(padconfs+offset/4) = (wakeup0 <<14)|(offmode0<<9)|(inputenable0<<8)|(pupd0<<3)|(muxmode0); \
+                *(padconfs+offset/4) |= (wakeup1 <<30)|(offmode1<<25)|(inputenable1<<24)|(pupd1<<19)|(muxmode1<<16); \
+} while (0)
+
+
+static void omap3_scm_reset(struct omap3_scm_s *s)
+{
+    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);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x8);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0xc);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x10);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x14);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x18);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x1c);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x20);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x24);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x28);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x2c);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x30);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x34);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x38);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x3c);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x40);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x44);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,1,0,7,0x48);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x4c);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x50);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x54);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x58);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,0,0x5c);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x60);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x64);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x68);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x6c);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x70);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x74);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x78);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x7c);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,3,0,7,0x80);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x84);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x88);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,0,7,0,0x8c);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x90);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x94);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,0,7,0,0x98);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,7,0x9c);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0xa0);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0xa4);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0xa8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xac);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xb0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xb4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xb8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xbc);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xc0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xc4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xc8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xcc);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xd0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xd4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xd8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xdc);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xe0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xe4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xe8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xec);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xf0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xf4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xf8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xfc);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x100);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x104);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x108);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x10c);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x110);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x114);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x118);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x11c);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x120);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x124);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,3,7,7,0x128);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x12c);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x130);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x134);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x138);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x13c);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x140);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x144);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x148);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x14c);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x150);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x154);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x158);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x15c);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x160);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x164);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,3,7,7,0x168);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x16c);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x170);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x174);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x178);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x17c);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x180);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x184);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,3,7,7,0x188);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x18c);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x190);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x194);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x198);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,3,7,7,0x19c);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x1a0);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x1a4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x1a8);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x1ac);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x1b0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1b4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1b8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1bc);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1c0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1c4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1c8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1cc);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1d0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1d4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1d8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1dc);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1e0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1e4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1e8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1ec);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1f0);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1f4);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1f8);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1fc);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x200);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x204);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x208);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x20c);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x210);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x214);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x218);
+    PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x21c);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x220);
+    PADCONFS_VALUE(0,0,0,0,1,1,3,1,0,0,0x224);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,1,0,0,0x228);
+    PADCONFS_VALUE(0,0,0,0,1,1,0,1,0,0,0x22c);
+    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);
+    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);
+       PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x4);
+       PADCONFS_VALUE(0,0,0,0,1,1,3,0,0,0,0x8);
+       PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0xc);
+       PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x10);
+       PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x14);
+       PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x18);
+       PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1c);
+       PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x20);
+       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; /* 0x48002A60?? */
+}
+
+static uint32_t omap3_scm_read8(void *opaque, target_phys_addr_t addr)
+{
+    struct omap3_scm_s *s = (struct omap3_scm_s *) opaque;
+    uint8_t* temp;
+       
+    switch (addr) {
+        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;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap3_scm_read16(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+    v = omap3_scm_read8(opaque, addr);
+    v |= omap3_scm_read8(opaque, addr + 1) << 8;
+    return v;
+}
+
+static uint32_t omap3_scm_read32(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+    v = omap3_scm_read8(opaque, addr);
+    v |= omap3_scm_read8(opaque, addr + 1) << 8;
+    v |= omap3_scm_read8(opaque, addr + 2) << 16;
+    v |= omap3_scm_read8(opaque, addr + 3) << 24;
+    return v;
+}
+
+static void omap3_scm_write8(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    struct omap3_scm_s *s = (struct omap3_scm_s *) opaque;
+    uint8_t* temp;
+
+    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;
+    }
+}
+
+static void omap3_scm_write16(void *opaque, target_phys_addr_t addr,
+                              uint32_t value)
+{
+    omap3_scm_write8(opaque, addr + 0, (value) & 0xff);
+    omap3_scm_write8(opaque, addr + 1, (value >> 8) & 0xff);
+}
+
+static void omap3_scm_write32(void *opaque, target_phys_addr_t addr,
+                              uint32_t value)
+{
+    omap3_scm_write8(opaque, addr + 0, (value) & 0xff);
+    omap3_scm_write8(opaque, addr + 1, (value >> 8) & 0xff);
+    omap3_scm_write8(opaque, addr + 2, (value >> 16) & 0xff);
+    omap3_scm_write8(opaque, addr + 3, (value >> 24) & 0xff);
+}
+
+static CPUReadMemoryFunc *omap3_scm_readfn[] = {
+    omap3_scm_read8,
+    omap3_scm_read16,
+    omap3_scm_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_scm_writefn[] = {
+    omap3_scm_write8,
+    omap3_scm_write16,
+    omap3_scm_write32,
+};
+
+static struct omap3_scm_s *omap3_scm_init(struct omap_target_agent_s *ta,
+                                          struct omap_mpu_state_s *mpu)
+{
+    int iomemtype;
+    struct omap3_scm_s *s = (struct omap3_scm_s *) qemu_mallocz(sizeof(*s));
+
+    s->mpu = mpu;
+
+    omap3_scm_reset(s);
+
+    iomemtype = l4_register_io_memory(0, omap3_scm_readfn,
+                                      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;
+}
+
+/*dummy SDRAM Memory Scheduler emulation*/
+struct omap3_sms_s
+{
+    struct omap_mpu_state_s *mpu;
+
+    uint32 sms_sysconfig;
+    uint32 sms_sysstatus;
+    uint32 sms_rg_att[8];
+    uint32 sms_rg_rdperm[8];
+    uint32 sms_rg_wrperm[8];
+    uint32 sms_rg_start[7];
+    uint32 sms_rg_end[7];
+    uint32 sms_security_control;
+    uint32 sms_class_arbiter0;
+    uint32 sms_class_arbiter1;
+    uint32 sms_class_arbiter2;
+    uint32 sms_interclass_arbiter;
+    uint32 sms_class_rotation[3];
+    uint32 sms_err_addr;
+    uint32 sms_err_type;
+    uint32 sms_pow_ctrl;
+    uint32 sms_rot_control[12];
+    uint32 sms_rot_size[12];
+    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;
+
+    switch (addr)
+    {
+    case 0x10:
+       return s->sms_sysconfig;
+    case 0x14:
+       return s->sms_sysstatus;
+    case 0x48:
+    case 0x68:
+    case 0x88:
+    case 0xa8:
+    case 0xc8:
+    case 0xe8:
+    case 0x108:
+    case 0x128:
+       return s->sms_rg_att[(addr-0x48)/0x20];
+    case 0x50:
+    case 0x70:
+    case 0x90:
+    case 0xb0:
+    case 0xd0:
+    case 0xf0:
+    case 0x110:
+    case 0x130:
+       return s->sms_rg_rdperm[(addr-0x50)/0x20];
+    case 0x58:
+    case 0x78:
+    case 0x98:
+    case 0xb8:
+    case 0xd8:
+    case 0xf8:
+    case 0x118:
+       return s->sms_rg_wrperm[(addr-0x58)/0x20];
+    case 0x60:
+    case 0x80:
+    case 0xa0:
+    case 0xc0:
+    case 0xe0:
+    case 0x100:
+    case 0x120:
+       return s->sms_rg_start[(addr-0x60)/0x20];
+
+    case 0x64:
+    case 0x84:
+    case 0xa4:
+    case 0xc4:
+    case 0xe4:
+    case 0x104:
+    case 0x124:
+       return s->sms_rg_end[(addr-0x64)/0x20];
+    case 0x140:
+       return s->sms_security_control;
+    case 0x150:
+       return s->sms_class_arbiter0;
+       case 0x154:
+               return s->sms_class_arbiter1;
+       case 0x158:
+               return s->sms_class_arbiter2;
+       case 0x160:
+               return s->sms_interclass_arbiter;
+       case 0x164:
+       case 0x168:
+       case 0x16c:
+               return s->sms_class_rotation[(addr-0x164)/4];
+       case 0x170:
+               return s->sms_err_addr;
+       case 0x174:
+               return s->sms_err_type;
+       case 0x178:
+               return s->sms_pow_ctrl;
+       case 0x180:
+       case 0x190:
+       case 0x1a0:
+       case 0x1b0:
+       case 0x1c0:
+       case 0x1d0:
+       case 0x1e0:
+       case 0x1f0:
+       case 0x200:
+       case 0x210:
+       case 0x220:
+       case 0x230:
+               return s->sms_rot_control[(addr-0x180)/0x10];
+       case 0x184:
+       case 0x194:
+       case 0x1a4:
+       case 0x1b4:
+       case 0x1c4:
+       case 0x1d4:
+       case 0x1e4:
+       case 0x1f4:
+       case 0x204:
+       case 0x214:
+       case 0x224:
+       case 0x234:
+               return s->sms_rot_size[(addr-0x184)/0x10];
+
+       case 0x188:
+       case 0x198:
+       case 0x1a8:
+       case 0x1b8:
+       case 0x1c8:
+       case 0x1d8:
+       case 0x1e8:
+       case 0x1f8:
+       case 0x208:
+       case 0x218:
+       case 0x228:
+       case 0x238:
+               return s->sms_rot_size[(addr-0x188)/0x10];
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap3_sms_write32(void *opaque, target_phys_addr_t addr,
+                              uint32_t value)
+{
+    struct omap3_sms_s *s = (struct omap3_sms_s *) opaque;
+    //int i;
+
+    switch (addr)
+    {
+    case 0x14:
+       OMAP_RO_REG(addr);
+        return;
+    case 0x10:
+       s->sms_sysconfig = value & 0x1f;
+       break;
+    
+    case 0x48:
+    case 0x68:
+    case 0x88:
+    case 0xa8:
+    case 0xc8:
+    case 0xe8:
+    case 0x108:
+    case 0x128:
+       s->sms_rg_att[(addr-0x48)/0x20] = value;
+       break;
+    case 0x50:
+    case 0x70:
+    case 0x90:
+    case 0xb0:
+    case 0xd0:
+    case 0xf0:
+    case 0x110:
+    case 0x130:
+       s->sms_rg_rdperm[(addr-0x50)/0x20] = value&0xffff;
+       break;
+    case 0x58:
+    case 0x78:
+    case 0x98:
+    case 0xb8:
+    case 0xd8:
+    case 0xf8:
+    case 0x118:
+       s->sms_rg_wrperm[(addr-0x58)/0x20] = value&0xffff;
+       break;          
+    case 0x60:
+    case 0x80:
+    case 0xa0:
+    case 0xc0:
+    case 0xe0:
+    case 0x100:
+    case 0x120:
+       s->sms_rg_start[(addr-0x60)/0x20] = value;
+       break;
+    case 0x64:
+    case 0x84:
+    case 0xa4:
+    case 0xc4:
+    case 0xe4:
+    case 0x104:
+    case 0x124:
+       s->sms_rg_end[(addr-0x64)/0x20] = value;
+       break;
+    case 0x140:
+       s->sms_security_control = value &0xfffffff;
+       break;
+    case 0x150:
+       s->sms_class_arbiter0 = value;
+       break;
+       case 0x154:
+               s->sms_class_arbiter1 = value;
+               break;
+       case 0x158:
+               s->sms_class_arbiter2 = value;
+               break;
+       case 0x160:
+               s->sms_interclass_arbiter = value;
+               break;
+       case 0x164:
+       case 0x168:
+       case 0x16c:
+               s->sms_class_rotation[(addr-0x164)/4] = value;
+               break;
+       case 0x170:
+               s->sms_err_addr = value;
+               break;
+       case 0x174:
+               s->sms_err_type = value;
+               break;
+       case 0x178:
+               s->sms_pow_ctrl = value;
+               break;
+       case 0x180:
+       case 0x190:
+       case 0x1a0:
+       case 0x1b0:
+       case 0x1c0:
+       case 0x1d0:
+       case 0x1e0:
+       case 0x1f0:
+       case 0x200:
+       case 0x210:
+       case 0x220:
+       case 0x230:
+               s->sms_rot_control[(addr-0x180)/0x10] = value;
+               break;
+       case 0x184:
+       case 0x194:
+       case 0x1a4:
+       case 0x1b4:
+       case 0x1c4:
+       case 0x1d4:
+       case 0x1e4:
+       case 0x1f4:
+       case 0x204:
+       case 0x214:
+       case 0x224:
+       case 0x234:
+               s->sms_rot_size[(addr-0x184)/0x10] = value;
+               break;
+
+       case 0x188:
+       case 0x198:
+       case 0x1a8:
+       case 0x1b8:
+       case 0x1c8:
+       case 0x1d8:
+       case 0x1e8:
+       case 0x1f8:
+       case 0x208:
+       case 0x218:
+       case 0x228:
+       case 0x238:
+               s->sms_rot_size[(addr-0x188)/0x10] = value;   
+               break;
+       default:
+        OMAP_BAD_REGV(addr, value);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *omap3_sms_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap3_sms_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_sms_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_sms_write32,
+};
+
+static void omap3_sms_reset(struct omap3_sms_s *s)
+{
+       s->sms_sysconfig = 0x1;
+       s->sms_class_arbiter0 = 0x500000;
+       s->sms_class_arbiter1 = 0x500;
+       s->sms_class_arbiter2 = 0x55000;
+       s->sms_interclass_arbiter = 0x400040;
+       s->sms_class_rotation[0] = 0x1;
+       s->sms_class_rotation[1] = 0x1;
+       s->sms_class_rotation[2] = 0x1;
+       s->sms_pow_ctrl = 0x80;
+}
+
+static struct omap3_sms_s *omap3_sms_init(struct omap_mpu_state_s *mpu)
+{
+    int iomemtype;
+    struct omap3_sms_s *s = (struct omap3_sms_s *) qemu_mallocz(sizeof(*s));
+
+    s->mpu = mpu;
+
+    omap3_sms_reset(s);
+    
+    iomemtype = cpu_register_io_memory(0, omap3_sms_readfn,
+                                       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_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,
+                               target_phys_addr_t addr)
+{
+    return 1;
+}
+
+struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
+                                           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 drqs[4];
+    int i;
+
+    s->mpu_model = omap3530;
+    s->env = cpu_init("cortex-a8-r2");
+    if (!s->env) {
+        fprintf(stderr, "Unable to find CPU definition\n");
+        exit(1);
+    }
+    s->sdram_size = sdram_size;
+    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);
+    sram_base = qemu_ram_alloc(s->sram_size);
+    cpu_register_physical_memory(OMAP3_SRAM_BASE, s->sram_size,
+                                 sram_base | IO_MEM_RAM);
+
+    s->l4 = omap_l4_init(OMAP3_L4_BASE, 
+                         sizeof(omap3_l4_agent_info) 
+                         / sizeof(struct omap3_l4_agent_info_s));
+
+    cpu_irq = arm_pic_init_cpu(s->env);
+    s->ih[0] = omap2_inth_init(s, 0x48200000, 0x1000, 3, &s->irq[0],
+                               cpu_irq[ARM_PIC_CPU_IRQ],
+                               cpu_irq[ARM_PIC_CPU_FIQ], 
+                               omap_findclk(s, "omap3_mpu_intc_fclk"),
+                               omap_findclk(s, "omap3_mpu_intc_iclk"));
+
+    for (i = 0; i < 4; i++)
+        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;
+    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);
+
+
+    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_3XXX_PRCM_MPU_IRQ],
+                                  NULL, s);
+
+    s->omap3_mpu_wdt = omap3_mpu_wdt_init(omap3_l4ta_init(s->l4, L4A_WDTIMER2),
+                                          NULL,
+                                          omap_findclk(s, "omap3_wkup_32k_fclk"),
+                                          omap_findclk(s, "omap3_wkup_l4_iclk"),
+                                          s);
+
+    s->omap3_l3 = omap3_l3_init(OMAP3_L3_BASE, 
+                                omap3_l3_region,
+                                sizeof(omap3_l3_region)
+                                / sizeof(struct omap_l3_region_s));
+    s->omap3_scm = omap3_scm_init(omap3_l4ta_init(s->l4, L4A_SCM), s);
+
+    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_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_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_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_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_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_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_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_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_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_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_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_3XXX_GPT12_IRQ],
+                                        omap_findclk(s, "omap3_gp12_fclk"),
+                                        omap_findclk(s, "omap3_wkup_l4_iclk"));
+    
+       
+    omap_synctimer_init(omap3_l4ta_init(s->l4, L4A_32KTIMER), s,
+                        omap_findclk(s, "omap3_sys_32k"), NULL);
+
+    s->sdrc = omap_sdrc_init(0x6d000000);
+    
+    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_3XXX_UART1_IRQ],
+                                 omap_findclk(s, "omap3_uart1_fclk"),
+                                 omap_findclk(s, "omap3_uart1_iclk"),
+                                 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_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],
+                                 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],
+                                 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], 
+                    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], 
+                    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], 
+                    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], 
+                    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], 
+                    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], 
+                    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),
+                                     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),
+                                     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),
+                                     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_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_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_3XXX_I2C3_IRQ],
+                               &s->drq[OMAP3XXX_DMA_I2C3_TX],
+                               omap_findclk(s, "omap3_i2c3_fclk"),
+                               omap_findclk(s, "omap3_i2c3_iclk"),
+                               64);
+
+    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_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"));
+    
+    return s;
+}
diff --git a/hw/omap3_boot.c b/hw/omap3_boot.c
new file mode 100644 (file)
index 0000000..e0c61a9
--- /dev/null
@@ -0,0 +1,903 @@
+/*
+ * TI OMAP3 boot ROM emulation. Based on information in the OMAP34xx 3.1
+ * Technical Reference Manual from Texas Instruments.
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * The OMAP3 boot ROM service routines accessed via ARM SMC instruction
+ * are not available in this emulation due to the limited availability
+ * of public documentation on the ARM TrustZone functionality. However
+ * it seems executing the SMC instruction as a NOP causes no harm.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "hw.h"
+#include "arm-misc.h"
+#include "omap.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "flash.h"
+#include "block.h"
+
+/* list of supported NAND devices according to the OMAP34xx TRM */
+static const struct {
+    uint8_t id;
+    uint32_t pagesize;
+    uint32_t capacity_Mb;
+} omap3_boot_nand_devices[] = {
+    {0xe6,  512,    64}, {0x33,  512,   128}, {0x73,  512,   128},
+    {0x43,  512,   128}, {0x53,  512,   128}, {0x35,  512,   256},
+    {0x75,  512,   256}, {0x45,  512,   256}, {0x55,  512,   256},
+    {0x36,  512,   512}, {0x76,  512,   512}, {0x46,  512,   512},
+    {0x56,  512,   512}, {0xa2, 2048,   512}, {0xf2, 2048,   512},
+    {0xb2, 2048,   512}, {0xc2, 2048,   512}, {0x39,  512,  1024},
+    {0x79,  512,  1024}, {0x49,  512,  1024}, {0x59,  512,  1024},
+    {0x78,  512,  1024}, {0x72,  512,  1024}, {0x74,  512,  1024},
+    {0xa1, 2048,  1024}, {0xf1, 2048,  1024}, {0xb1, 2048,  1024},
+    {0xc1, 2048,  1024}, {0xaa, 2048,  2048}, {0xda, 2048,  2048},
+    {0xba, 2048,  2048}, {0xca, 2048,  2048}, {0x71,  512,  2048},
+    {0x51,  512,  2048}, {0x31,  512,  2048}, {0x41,  512,  2048},
+    {0xac, 2048,  4096}, {0xdc, 2048,  4096}, {0xbc, 2048,  4096},
+    {0xcc, 2048,  4096}, {0xa3, 2048,  8192}, {0xd3, 2048,  8192},
+    {0xb3, 2048,  8192}, {0xc3, 2048,  8192}, {0xa5, 2048, 16384},
+    {0xd5, 2048, 16384}, {0xb5, 2048, 16384}, {0xc5, 2048, 16384},
+    {0xa7, 2048, 32768}, {0xb7, 2048, 32768}, {0xae, 2048, 65536},
+    {0xbe, 2048, 65536},
+    {0, 0, 0}
+};
+
+struct omap3_nand_boot_desc_s {
+    uint32_t pagesize;
+    uint32_t capacity_Mb;
+    uint8_t bus16;
+};
+
+static const uint8_t omap3_boot_rom[] = { /* 0x40014000-0x4001bfff */
+    /* 0x40014000: ROM Exception vectors */
+    0x3e, 0x00, 0x00, 0xea, /* b 0x40014100 */
+    0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
+    0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
+    0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
+    0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
+    0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
+    0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
+    0x18, 0xf0, 0x9f, 0xe5, /* ldr pc, [pc, #0x18] */
+    /* 0x40014020: ROM CRC */
+    0xff, 0xff, 0xff, 0xff, 
+    /* 0x40014024: unused(?), we use it for some data */
+    0xc8, 0xff, 0x20, 0x40, /* 0x40014024: undef sram vector address */
+    0xcc, 0xff, 0x20, 0x40, /* 0x40014028: swi sram vector address */
+    0xd0, 0xff, 0x20, 0x40, /* 0x4001402c: pabt sram vector address */
+    0xd4, 0xff, 0x20, 0x40, /* 0x40014030: dabt sram vector address */
+    0xd8, 0xff, 0x20, 0x40, /* 0x40014034: unused sram vector address */
+    0xdc, 0xff, 0x20, 0x40, /* 0x40014038: irq sram vector address */
+    0xe0, 0xff, 0x20, 0x40, /* 0x4001403c: fiq sram vector address */
+    0xff, 0xff, 0xff, 0xff, /* 0x40014040: boot loader image start address */
+    0xff, 0xff, 0xff, 0xff, /* 0x40014044: booting parameter structure 0-3 */
+    0xff, 0xff, 0xff, 0xff, /* 0x40014048: booting parameter structure 4-7 */
+    0xff, 0xff, 0xff, 0xff, /* 0x4001404c: booting parameter structure 8-11 */
+    0x0e, 0xf0, 0xb0, 0xe1, /* 0x40014050: "movs pc, lr" */
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    /* 0x40014080: Dead loops */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x40014080 @ undefined exception */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x40014084 @ swi exception */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x40014088 @ prefetch abort exception */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x4001408c @ data abort exception */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x40014090 @ unused exception */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x40014094 @ irq exception */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x40014098 @ fiq exception */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x4001409c @ validation tests pass */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x400140a0 @ validation tests fail */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x400140a4 @ boot failed: no more devices */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x400140a8 @ image not executed or returned */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x400140ac @ reserved */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x400140b0 @ reserved */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x400140b4 @ reserved */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x400140b8 @ reserved */
+    0xfe, 0xff, 0xff, 0xea, /* b 0x400140bc @ reserved */
+    /* 0x400140c0: should perform a software reset & jump to r0 */
+    0x00, 0xf0, 0xa0, 0xe1, /* mov pc, r0 */
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    /* 0x40014100: code, ROM emulation uses this to launch the
+     * boot loader after it has been read into memory */
+    0xc8, 0x10, 0x1f, 0xe5, /* ldr r1, [#0x40014040] @ boot loader start */
+    0xb0, 0x0c, 0x0f, 0xe3, /* movw r0, #0xfcb0 */
+    0x20, 0x00, 0x44, 0xe3, /* movt r0, #0x4020   @ stack top at 0x4020fcb0 */
+    0xdf, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xdf  @ enter SYS mode */
+    0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
+    0x80, 0x0c, 0x40, 0xe2, /* sub r0, r0, #32768 @ 32kB SYS/USR stack */
+    0xd1, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xd1  @ enter FIQ mode */
+    0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
+    0x08, 0x0c, 0x40, 0xe2, /* sub r0, r0, #2048  @ 2kB FIQ stack */
+    0xd2, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xd2  @ enter IRQ mode */
+    0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
+    0x08, 0x0c, 0x40, 0xe2, /* sub r0, r0, #2048  @ 2kB IRQ stack */
+    0xd7, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xd7  @ enter ABT mode */
+    0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
+    0x08, 0x0c, 0x40, 0xe2, /* sub r0, r0, #2048  @ 2kB ABT stack */
+    0xdb, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xdb  @ enter UND mode */
+    0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0 */
+    0x08, 0x0c, 0x40, 0xe2, /* sub r0, r0, #2048  @ 2kB UND stack */
+    0xd3, 0xf0, 0x21, 0xe3, /* msr cpsr_c, #0xd3  @ enter SVC mode */
+    0x00, 0xd0, 0xa0, 0xe1, /* mov sp, r0         @ 23kB left for SVC stack */
+    0x44, 0x00, 0x04, 0xe3, /* movw r0, #0x4044 */
+    0x01, 0x00, 0x44, 0xe3, /* movt r0, #0x4001   @ r0 -> booting parameter struct */
+    0x01, 0xf0, 0xa0, 0xe1, /* mov pc, r1 */
+};
+
+/* SRAM exception vectors, to be placed at 0x4020ffc8 */
+static const uint8_t omap3_sram_vectors[] = {
+    0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020ffe4] @ undefined */
+    0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020ffe8] @ swi */
+    0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020ffec] @ prefetch abort */
+    0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020fff0] @ data abort */
+    0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020fff4] @ unused */
+    0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020fff8] @ irq */
+    0x14, 0xf0, 0x9f, 0xe5, /* ldr pc, [#0x4020fffc] @ fiq */
+    0x80, 0x40, 0x01, 0x00, /* 0x14080 */
+    0x50, 0x40, 0x01, 0x40, /* 0x40014050 (default is 0x14084) */
+    0x88, 0x40, 0x01, 0x00, /* 0x14088 */
+    0x8c, 0x40, 0x01, 0x00, /* 0x1408c */
+    0x90, 0x40, 0x01, 0x00, /* 0x14090 */
+    0x94, 0x40, 0x01, 0x00, /* 0x14094 */
+    0x98, 0x40, 0x01, 0x00, /* 0x14098 */
+};
+
+static inline uint32_t omap3_get_le32(const void *p)
+{
+    const uint8_t *q = (const uint8_t *)p;
+    uint32_t v;
+    v = q[3]; v <<= 8;
+    v |= q[2]; v <<= 8;
+    v |= q[1]; v <<= 8;
+    v |= q[0];
+    return v;
+}
+
+static inline uint32_t omap3_get_le16(const void *p)
+{
+    const uint8_t *q = (const uint8_t *)p;
+    uint32_t v;
+    v = q[1]; v <<= 8;
+    v |= q[0];
+    return v;
+}
+
+static inline void omap3_boot_setlsb(target_phys_addr_t addr, uint16_t lsb)
+{
+    uint8_t x[4];
+    
+    cpu_physical_memory_read(addr, x, 4);
+    x[0] = lsb & 0xff;
+    x[1] = (lsb >> 8) & 0xff;
+    cpu_physical_memory_write(addr, x, 4);
+}
+
+typedef enum {
+    xip = 1,
+    nand,
+    onenand,
+    doc,
+    mmc2,
+    mmc1,
+    xipwait,
+    uart = 0x10,
+    hsusb,
+}  omap3_boot_device_t;
+
+struct omap3_boot_s {
+    struct omap_mpu_state_s *mpu;
+    omap3_boot_device_t devicetype;
+    enum {
+        undefined = 0,
+        confighdr,
+        chdone,
+        imagehdr,
+        copy,
+        done
+    } state;
+    uint8_t chflags;
+    target_phys_addr_t addr;
+    uint32_t count;
+};
+
+static struct omap3_boot_s *omap3_boot_init(struct omap_mpu_state_s *mpu,
+                                            omap3_boot_device_t dtype,
+                                            const uint8_t *data,
+                                            uint32_t data_len)
+{
+    struct omap3_boot_s *s = qemu_mallocz(sizeof(struct omap3_boot_s));
+    s->mpu = mpu;
+    s->devicetype = dtype;
+    s->state = chdone;
+    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(struct omap3_boot_s *boot,
+                                  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;
+    }
+    boot->chflags |= 0x01;
+    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(struct omap3_boot_s *boot,
+                             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;
+    }
+    boot->chflags |= 0x02;
+    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(struct omap3_boot_s *boot,
+                               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;
+    }
+    boot->chflags |= 0x04;
+    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(struct omap3_boot_s *boot,
+                               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;
+    }
+    boot->chflags |= 0x08;
+    /* 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(s, p + omap3_get_le32(p));
+                else if (!strcasecmp((char *)(p + 0x14), "chram"))
+                    omap3_boot_chram(s, p + omap3_get_le32(p));
+                else if (!strcasecmp((char *)(p + 0x14), "chflash"))
+                    omap3_boot_chflash(s, p + omap3_get_le32(p));
+                else if (!strcasecmp((char *)(p + 0x14), "chmmcsd"))
+                    omap3_boot_chmmcsd(s, p + omap3_get_le32(p));
+                else
+                    fprintf(stderr, "%s: unknown CHTOC item \"%s\"\n",
+                            __FUNCTION__, (char *)(p + 0x14));
+            }
+            data += 512;
+            data_len -= 512;
+            s->state = chdone;
+            /* fallthrough */
+        case chdone:
+            s->state = imagehdr;
+            /* fallthrough */
+        case imagehdr:
+            if (!data_len)
+                return 1;
+            if (data_len < 8)
+                break;
+            s->count = omap3_get_le32(data);
+            s->addr = omap3_get_le32(data + 4);
+            if (!s->count || (s->count >> 24) || !s->addr || s->addr == 0xffffffff)
+                break;
+            /* patch image start address in boot ROM */
+            cpu_physical_memory_write_rom(0x40014040, data + 4, 4);
+            /* start copying image */
+            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 non-zero if boot has finished succesfully */
+static int omap3_boot_finish(struct omap3_boot_s *s)
+{
+    uint8_t x[12] = {
+        0, 0, 0, 0, /* last received booting message */
+        (uint8_t)s->devicetype,
+        0,
+        1, /* POR */
+        s->chflags,
+        0, 0, 0, 0 /* device descriptor */
+    };
+    int result = (s->state == done);
+
+    if (result) {
+        /* fill in the booting parameter structure */
+        cpu_physical_memory_write_rom(0x40014044, x, 12);
+    }
+    free(s);
+    return result;
+}
+
+/* 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(mpu, mmc1, data, j);
+            boot->state = imagehdr; /* override CH detection */
+            while (omap3_boot_block(data, j, boot))
+                i = omap3_read_fat_cluster(data, &drv, i);
+            result = omap3_boot_finish(boot);
+        } else
+            fprintf(stderr, "%s: unable to read MLO file contents from SD card\n",
+                    __FUNCTION__);
+        free(data);
+    } else
+        fprintf(stderr, "%s: MLO file not found in the root directory\n",
+                __FUNCTION__);
+    
+    return result;
+}
+
+static int omap3_mmc_raw_boot(BlockDriverState *bs,
+                              uint8_t *sector,
+                              struct omap_mpu_state_s *mpu)
+{
+    struct omap3_boot_s *boot;
+    uint32_t i = 0;
+    int result = 0;
+    
+    if (bdrv_pread(bs, 0, sector, 0x200) == 0x200) {
+        boot = omap3_boot_init(mpu, mmc1, sector, 0x200);
+        if (boot->state == confighdr) { /* CH must be present for raw boot */
+            while (omap3_boot_block(sector, 0x200, boot)) {
+                if (bdrv_pread(bs, ++i, sector, 0x200) != 0x200) {
+                    fprintf(stderr, "%s: error trying to read sector %u on boot device\n",
+                            __FUNCTION__, i);
+                    break;
+                }
+            }
+        }
+        result = (boot->state == done);
+        free(boot);
+    }
+    return result;
+}
+
+/* returns non-zero if successful, zero if unsuccessful */
+static 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;
+}
+
+static inline void omap3_nand_sendcmd(struct omap3_nand_boot_desc_s *nd,
+                                      uint8_t cmd)
+{
+    uint8_t x[2] = { cmd, 0 };
+    
+    cpu_physical_memory_write(0x6e00007c, x, nd->bus16 ? 2 : 1);
+}
+
+static inline void omap3_nand_sendaddr_byte(struct omap3_nand_boot_desc_s *nd,
+                                            uint8_t a)
+{
+    uint8_t x[2] = { a, 0 };
+    
+    cpu_physical_memory_write(0x6e000080, x, nd->bus16 ? 2 : 1);
+}
+
+static inline uint8_t omap3_nand_readbyte(struct omap3_nand_boot_desc_s *nd)
+{
+    uint8_t x[2];
+    
+    cpu_physical_memory_read(0x6e000084, x, nd->bus16 ? 2 : 1);
+    return x[0];
+}
+
+static inline void omap3_nand_readpage(struct omap3_nand_boot_desc_s *nd,
+                                       uint32_t pageaddr,
+                                       uint8_t *data)
+{
+    uint32_t i;
+    
+    omap3_nand_sendcmd(nd, 0x00); /* read page */
+    omap3_nand_sendaddr_byte(nd, 0x00);
+    if (nd->pagesize >= 2048) {
+        omap3_nand_sendaddr_byte(nd, 0x00);
+        omap3_nand_sendaddr_byte(nd, (uint8_t)(pageaddr & 0xff));
+        omap3_nand_sendaddr_byte(nd, (uint8_t)((pageaddr >> 8) & 0xff));
+        if (nd->capacity_Mb >= 2048)
+            omap3_nand_sendaddr_byte(nd, (uint8_t)((pageaddr >> 16) & 0xff));
+        omap3_nand_sendcmd(nd, 0x30); /* confirm read */
+    } else {
+        omap3_nand_sendaddr_byte(nd, (uint8_t)(pageaddr & 0xff));
+        omap3_nand_sendaddr_byte(nd, (uint8_t)((pageaddr >> 8) & 0xff));
+    }
+    if (nd->bus16) {
+        for (i = nd->pagesize / 2; i--; data += 2)
+            cpu_physical_memory_read(0x6e000084, data, 2);
+    } else {
+        for (i = nd->pagesize; i--; data++)
+            cpu_physical_memory_read(0x6e000084, data, 1);
+    }
+}
+
+/* returns non-zero if successful, zero if unsuccessful */
+static int omap3_nand_boot(struct omap_mpu_state_s *mpu, int bus16)
+{
+    struct omap3_nand_boot_desc_s *nd;
+    struct omap3_boot_s *boot;
+    uint8_t *data;
+    uint32_t page = 0;
+    int result = 0, i;
+    uint8_t id[4];
+    
+    /* TODO: support bad block marks */
+    nd = qemu_mallocz(sizeof(struct omap3_nand_boot_desc_s));
+    nd->bus16 = bus16;
+    omap3_nand_sendcmd(nd, 0xff); /* reset */
+    omap3_nand_sendcmd(nd, 0x90); /* read id */
+    omap3_nand_sendaddr_byte(nd, 0);
+    id[0] = omap3_nand_readbyte(nd); /* manufacturer id */
+    id[1] = omap3_nand_readbyte(nd); /* device id */
+    id[2] = omap3_nand_readbyte(nd); /* don't care */
+    id[3] = omap3_nand_readbyte(nd); /* attributes */
+    for (i = 0; omap3_boot_nand_devices[i].id; i++) {
+        if (omap3_boot_nand_devices[i].id == id[1]) {
+            nd->capacity_Mb = omap3_boot_nand_devices[i].capacity_Mb;
+            if (nd->capacity_Mb > 1024)
+                nd->pagesize = 1024 * (1 << (id[3] & 3));
+            else
+                nd->pagesize = omap3_boot_nand_devices[i].pagesize;
+            break;
+        }
+    }
+    /* TODO: if device is not recognized at this state, we should
+     * issue READ ID2 command to the device and get device parameters
+     * from there */
+    if (nd->pagesize) {
+        data = qemu_mallocz(nd->pagesize);
+        /* TODO: scan through 4 first blocks for image */
+        omap3_nand_readpage(nd, 0, data);
+        boot = omap3_boot_init(mpu, nand, data, nd->pagesize);
+        while (omap3_boot_block(data, nd->pagesize, boot))
+            omap3_nand_readpage(nd, ++page, data);
+        result = omap3_boot_finish(boot);
+        free(data);
+    }
+    free(nd);
+    return result;
+}
+
+static inline void omap3_onenand_writereg(uint16_t reg, uint16_t value)
+{
+    cpu_to_le16s(&value);
+    cpu_physical_memory_write(0x08000000 + (reg << 1), (void *)&value, 2);
+}
+
+static inline uint16_t omap3_onenand_readreg(uint16_t reg)
+{
+    uint16_t value;
+    cpu_physical_memory_read(0x08000000 + (reg << 1), (void *)&value, 2);
+    return le16_to_cpu(value);
+}
+
+static int omap3_onenand_readpage(uint16_t pagesize,
+                                  uint16_t b,
+                                  uint16_t p,
+                                  uint8_t *d)
+{
+    omap3_onenand_writereg(0xf100, b);
+    omap3_onenand_writereg(0xf107, (p & 0x3f) << 2);
+    omap3_onenand_writereg(0xf200, 0x0800);
+    omap3_onenand_writereg(0xf101, 0);
+    omap3_onenand_writereg(0xf241, 0);
+    omap3_onenand_writereg(0xf220, 0);
+    if (!(omap3_onenand_readreg(0xf241) & 0x8000) ||
+        (omap3_onenand_readreg(0xf240) & 0x0400))
+        return 0;
+    cpu_physical_memory_read(0x08000400, (void *)d, pagesize);
+    return 1;
+}
+
+static int omap3_onenand_boot(struct omap_mpu_state_s *s)
+{
+    uint32_t x;
+    uint16_t i, j, pagesize;
+    uint8_t *page;
+    struct omap3_boot_s *boot;
+    int result = 0;
+    
+    /* reset device type at cs0: 16bit NOR, no wait monitoring */
+    cpu_to_le32wu(&x, 0x79001000);
+    cpu_physical_memory_write(0x6e000060, (void *)&x, 4); /* GPMC_CONFIG1_0 */
+    /* map cs0 at 0x08000000 */
+    cpu_to_le32wu(&x, 0x00000848);
+    cpu_physical_memory_write(0x6e000078, (void *)&x, 4); /* GPMC_CONFIG7_0 */
+    /* try to read onenand registers */
+    if (omap3_onenand_readreg(0xf000) != 0x00ec) /* manufacturer id */
+        return 0;
+    pagesize = omap3_onenand_readreg(0xf003);
+    if (pagesize != 2048 && pagesize != 1024) {
+        fprintf(stderr, "%s: OneNAND page size %d not supported\n",
+                __FUNCTION__, pagesize);
+        return 0;
+    }
+    /* search for boot loader */
+    page = qemu_mallocz(pagesize);
+    for (i = 0; i < 4; i++) { /* search 4 blocks */
+        if (omap3_onenand_readpage(pagesize, i, 0, page)) {
+            boot = omap3_boot_init(s, onenand, page, pagesize);
+            for (j = 1; omap3_boot_block(page, pagesize, boot); j++)
+                if (!omap3_onenand_readpage(pagesize, i, j, page))
+                    break;
+            result = omap3_boot_finish(boot);
+            if (result)
+                break;
+        }
+    }
+    free(page);
+    return result;
+}
+
+
+void omap3_boot_rom_emu(struct omap_mpu_state_s *s)
+{
+    const uint8_t rom_version[4] = { 0x00, 0x14, 0x00, 0x00 }; /* v. 14.00 */
+    uint8_t x[4] = {0, 0, 0, 0};
+    int result = 0;
+    ram_addr_t bootrom_base;
+    
+    bootrom_base = qemu_ram_alloc(OMAP3XXX_BOOTROM_SIZE);
+    cpu_register_physical_memory(OMAP3_Q1_BASE + 0x14000,
+                                 OMAP3XXX_BOOTROM_SIZE,
+                                 bootrom_base | IO_MEM_ROM);
+    cpu_physical_memory_write_rom(OMAP3_Q1_BASE + 0x14000,
+                                  omap3_boot_rom,
+                                  sizeof(omap3_boot_rom));
+    cpu_physical_memory_write_rom(OMAP3_Q1_BASE + 0x1bffc,
+                                  rom_version,
+                                  sizeof(rom_version));
+    cpu_physical_memory_write(OMAP3_SRAM_BASE + 0xffc8,
+                              omap3_sram_vectors,
+                              sizeof(omap3_sram_vectors));
+
+    /* here we are relying on all memories to be attached and gpmc_attach
+     * to fill in DEVICETYPE field correctly for CS0 for us */
+    cpu_physical_memory_read(0x6e000060, x, 4); /* GPMC_CONFIG1_0 */
+    switch (((x[1] >> 2) & 3)) {
+        case 0: /* NOR */
+            result = omap3_onenand_boot(s);
+            break;
+        case 2: /* NAND */
+            result = omap3_nand_boot(s, ((x[1] >> 4) & 3) == 1);
+            break;
+        default:
+            break;
+    }
+
+    /* if no boot loader found yet, try the MMC/SD card... */
+    if (!result)
+        result = omap3_mmc_boot(s);
+    
+    /* ensure boot ROM is mapped at zero address */
+    cpu_register_physical_memory(0, OMAP3XXX_BOOTROM_SIZE,
+                                 bootrom_base | IO_MEM_ROM);
+    
+    if (!result) { /* no boot device found */
+        /* move PC to the appropriate ROM dead loop address */
+        s->env->regs[15] = 0x400140a4;
+        /* ...on second thought, let's just call it a day and quit */
+        cpu_abort(s->env, "no boot device found");
+    }
+}
diff --git a/hw/omap3_lcd_panel_template.h b/hw/omap3_lcd_panel_template.h
new file mode 100644 (file)
index 0000000..dc56f03
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * QEMU Epson S1D13744/S1D13745 templates
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * QEMU OMAP3 LCD Panel Emulation templates
+ *
+ * Copyright (c) 2008 yajin  <yajin@vm-kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#define SKIP_PIXEL(to)         to += deststep
+#if DEPTH == 8
+# define PIXEL_TYPE            uint8_t
+# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) *to ++ = from
+#elif DEPTH == 15 || DEPTH == 16
+# define PIXEL_TYPE            uint16_t
+# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) *to ++ = from
+#elif DEPTH == 24
+# define PIXEL_TYPE            uint8_t
+# define COPY_PIXEL(to, from)  \
+    to[0] = from; to[1] = (from) >> 8; to[2] = (from) >> 16; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) \
+    *to ++ = from; *to ++ = (from) >> 8; *to ++ = (from) >> 16
+#elif DEPTH == 32
+# define PIXEL_TYPE            uint32_t
+# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) *to ++ = from
+#else
+# error unknown bit depth
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP_WORDS    1
+#endif
+
+
+static void glue(omap3_lcd_panel_draw_line16_, DEPTH)(PIXEL_TYPE *dest,
+                                                      const uint16_t *src,
+                                                      unsigned int width)
+{
+#if !defined(SWAP_WORDS) && DEPTH == 16
+    memcpy(dest, src, width);
+#else
+    uint16_t data;
+    unsigned int r, g, b;
+    const uint16_t *end = (const void *) src + width;
+    while (src < end) {
+        data = lduw_raw(src ++);
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+    }
+#endif
+}
+
+static void glue(omap3_lcd_panel_draw_line24a_, DEPTH)(PIXEL_TYPE *dest,
+                                                       const uint8_t *src,
+                                                       unsigned int width)
+{
+#if !defined(SWAP_WORDS) && DEPTH == 32
+    memcpy(dest, src, width);
+#else
+    unsigned int r, g, b;
+    const uint8_t *end = (const void *) src + width;
+    while (src < end) {
+        b = *(src++);
+        g = *(src++);
+        r = *(src++);
+        src++;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+    }
+#endif
+}
+
+static void glue(omap3_lcd_panel_draw_line24b_, DEPTH)(PIXEL_TYPE *dest,
+                                                       const uint8_t *src,
+                                                       unsigned int width)
+{
+#if DEPTH == 24
+    memcpy(dest, src, width);
+#else
+    unsigned int r, g, b;
+    const uint8_t *end = (const void *) src + width;
+    while (src < end) {
+        b = *(src++);
+        g = *(src++);
+        r = *(src++);
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+    }
+#endif
+}
+
+/* No rotation */
+static omap3_lcd_panel_fn_t glue(omap3_lcd_panel_draw_fn_, DEPTH)[0x10] = {
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    (omap3_lcd_panel_fn_t)glue(omap3_lcd_panel_draw_line16_, DEPTH),
+    NULL,
+    (omap3_lcd_panel_fn_t)glue(omap3_lcd_panel_draw_line24a_, DEPTH),
+    (omap3_lcd_panel_fn_t)glue(omap3_lcd_panel_draw_line24b_, DEPTH),
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+};
+
+/* 90deg, 180deg and 270deg rotation */
+static omap3_lcd_panel_fn_t glue(omap3_lcd_panel_draw_fn_r_, DEPTH)[0x10] = {
+    /* TODO */
+    [0 ... 0xf] = NULL,
+};
+
+#undef DEPTH
+#undef SKIP_PIXEL
+#undef COPY_PIXEL
+#undef COPY_PIXEL1
+#undef PIXEL_TYPE
+
+#undef SWAP_WORDS
+
diff --git a/hw/omap3_mmc.c b/hw/omap3_mmc.c
new file mode 100644 (file)
index 0000000..402db19
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ * OMAP3 Multimedia Card/Secure Digital/Secure Digital I/O (MMC/SD/SDIO) Card Interface emulation
+ *
+ * Copyright (C) 2008 yajin  <yajin@vm-kernel.org>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "hw.h"
+#include "omap.h"
+#include "sd.h"
+
+/* debug levels:
+   0 - no debug
+   1 - print out all commands in processing order
+   2 - dump all register accesses and buffer management */
+#define MMC_DEBUG_LEVEL 0
+
+#if MMC_DEBUG_LEVEL>0
+#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#if MMC_DEBUG_LEVEL>1
+#define TRACE2(...) TRACE(__VA_ARGS__)
+#else
+#define TRACE2(...)
+#endif
+#else
+#define TRACE(...)
+#define TRACE2(...)
+#endif
+
+struct omap3_mmc_s
+{
+    qemu_irq irq;
+    qemu_irq *dma;
+    qemu_irq coverswitch;
+    omap_clk clk;
+    SDState *card;
+
+    uint32_t sysconfig;
+    uint32_t sysstatus;
+    uint32_t csre;
+    uint32_t systest;
+    uint32_t con;
+    uint32_t pwcnt;
+    uint32_t blk;
+    uint32_t arg;
+    uint32_t cmd;
+    uint32_t rsp10;
+    uint32_t rsp32;
+    uint32_t rsp54;
+    uint32_t rsp76;
+    uint32_t data;
+    uint32_t pstate;
+    uint32_t hctl;
+    uint32_t sysctl;
+    uint32_t stat;
+    uint32_t ie;
+    uint32_t ise;
+    uint32_t ac12;
+    uint32_t capa;
+    uint32_t cur_capa;
+    uint32_t rev;
+
+    uint16_t blen_counter;
+    uint16_t nblk_counter;
+
+    uint32_t fifo[256];
+    int fifo_start;
+    int fifo_len;
+
+    int ddir;
+    int transfer;
+    int stop;
+    
+    uint32_t stat_pending;
+};
+
+
+typedef enum
+{
+    sd_nore = 0,     /* no response */
+    sd_136_bits = 1, /* response length 136 bits */
+    sd_48_bits = 2,  /* response length 48 bits */
+    sd_48b_bits = 3, /* response length 48 bits with busy after response */
+} omap3_sd_rsp_type_t;
+
+static void omap3_mmc_command(struct omap3_mmc_s *host);
+
+static void omap3_mmc_interrupts_update(struct omap3_mmc_s *s)
+{
+    qemu_set_irq(s->irq, !!((s->stat | s->stat_pending) & s->ie & s->ise));
+}
+
+static void omap3_mmc_fifolevel_update(struct omap3_mmc_s *host)
+{
+    enum { ongoing, ready, aborted } state = ongoing;
+    
+    if ((host->cmd & (1 << 21))) { /* DP */
+        if (host->ddir) {
+            TRACE2("receive, dma=%d, fifo_len=%d bytes",
+                   host->cmd & 1, host->fifo_len * 4);
+            
+            /* omap3_mmc_transfer ensures we always have data in FIFO
+               during receive as long as all data has not been transferred -
+               NOTE that the actual transfer may be finished already (i.e.
+               host->transfer is cleared) but not all data has been read out
+               from FIFO yet */
+            if (host->fifo_len) {
+                if (host->cmd & 1) { /* DE */
+                    if (host->fifo_len * 4 == (host->blk & 0x7ff)) { /* BLEN */
+                        if (host->stop)
+                            state = aborted;
+                        else
+                            qemu_irq_raise(host->dma[1]);
+                    } else
+                        qemu_irq_lower(host->dma[1]);
+                } else {
+                    if (host->stop 
+                        && host->fifo_len * 4 == (host->blk & 0x7ff))
+                        state = aborted;
+                    else {
+                        host->pstate |= 0x0800;      /* BRE */
+                        host->stat_pending |= 0x20;  /* BRR */
+                    }
+                }
+            }
+            else
+                state = host->stop ? aborted : ready;
+        } else {
+            /* omap3_mmc_transfer keeps FIFO empty during transmit so
+               we just check all blocks have been transferred or not */
+            if (host->transfer) {
+                if (host->cmd & 1) { /* DE */
+                    if (host->blen_counter == (host->blk & 0x7ff)) { /* BLEN */
+                        if (host->stop)
+                            state = aborted;
+                        else
+                            qemu_irq_raise(host->dma[0]);
+                    } else
+                        qemu_irq_lower(host->dma[0]);
+                } else {
+                    if (host->stop
+                        && host->blen_counter == (host->blk & 0x7ff))
+                        state = aborted;
+                    else {
+                        host->pstate |= 0x0400;      /* BWE */
+                        host->stat_pending |= 0x10;  /* BWR */
+                    }
+                }
+            } else
+                state = host->stop ? aborted : ready;
+        }
+
+        if ((host->cmd & 1) || state != ongoing) { /* DE */
+            host->pstate &= ~0x0c00;               /* BRE | BWE */
+            host->stat_pending &= ~0x30;           /* BRR | BWR */
+            host->stat &= ~0x30;                   /* BRR | BWR */
+            if (state != ongoing) {
+                TRACE2("transfer %s", 
+                       state == ready
+                       ? "complete"
+                       : "aborted --> complete");
+                host->stat_pending |= 0x2;         /* TC */
+                if (host->cmd & 0x04) {            /* ACEN */
+                    host->stop = 0x0cc30000;
+                    state = aborted;
+                }
+                if (state == aborted) {
+                    host->cmd = host->stop;
+                    host->stop = 0;
+                    omap3_mmc_command(host);
+                }
+            }
+        }
+    }
+}
+
+static void omap3_mmc_transfer(struct omap3_mmc_s *host)
+{
+    int i;
+    uint32_t x;
+#if MMC_DEBUG_LEVEL>1
+    int j;
+    uint8_t c, sym[17];
+#endif
+
+    /* IF data transfer is inactive
+       OR block count enabled with zero block count
+       OR in receive mode and we have unread data in FIFO
+       OR in transmit mode and we have no data in FIFO,
+       THEN don't do anything */
+    if (!host->transfer
+        || ((host->cmd & 2) && !host->nblk_counter)
+        || (host->ddir && host->fifo_len)
+        || (!host->ddir && !host->fifo_len))
+        return;
+    
+    if (host->ddir) {
+        TRACE2("begin, %d blocks (%d bytes/block) left to receive, %d bytes in FIFO",
+               (host->cmd & 2) ? host->nblk_counter : 1,
+               host->blk & 0x7ff, 
+               host->fifo_len * 4);
+        while (host->blen_counter && host->fifo_len < 255) {
+            for (i = 0, x = 0; i < 32 && host->blen_counter; i += 8, host->blen_counter--)
+                x |= sd_read_data(host->card) << i;
+            host->fifo[(host->fifo_start + host->fifo_len) & 0xff] = x;
+            host->fifo_len++;
+        }
+        TRACE2("end, %d bytes in FIFO:", host->fifo_len * 4);
+#if MMC_DEBUG_LEVEL>1
+        for (i = 0; i < host->fifo_len; ) {
+            fprintf(stderr, "%s: [0x%03x] ", __FUNCTION__, i * 4);
+            do {
+                x = host->fifo[(host->fifo_start + i) & 0xff];
+                for (j = 0; j < 4; j++) {
+                    c = (x >> (j * 8)) & 0xff;
+                    fprintf(stderr, "%02x ", c);
+                    sym[(i & 3) * 4 + j] = (c < 32 || c > 126) ? '.' : c;
+                }
+            } while (((++i) & 3));
+            sym[16] = 0;
+            fprintf(stderr, "%s\n", sym);
+        }
+#endif
+    } else {
+        TRACE2("%d bytes left to transmit in current block", host->blen_counter);
+        while (host->blen_counter && host->fifo_len) {
+            for (i = 0; i < 32 && host->blen_counter; i += 8, host->blen_counter--)
+                sd_write_data(host->card, (host->fifo[host->fifo_start] >> i) & 0xff);
+            host->fifo_start++;
+            host->fifo_len--;
+            host->fifo_start &= 0xff;
+        }
+    }
+
+    if (!host->blen_counter) {
+        if (host->cmd & 2) /* BCE */
+            host->nblk_counter--;
+        TRACE2("block done, %d blocks left",
+               (host->cmd & (1 << 5)) ? host->nblk_counter : 0);
+        host->blen_counter = host->blk & 0x7ff;
+        if (!(host->cmd & (1 << 5)) /* MSBS */
+            || !host->nblk_counter) {
+            host->nblk_counter = (host->blk >> 16) & 0xffff;
+            host->transfer = 0;
+            host->pstate &= ~0x0306; /* RTA | WTA | DLA | DATI */
+        }
+    }
+}
+
+static void omap3_mmc_command(struct omap3_mmc_s *host)
+{
+    uint32_t rspstatus, mask;
+    int rsplen, timeout;
+    struct sd_request_s request;
+    uint8_t response[16];
+    int cmd = (host->cmd >> 24) & 0x3f; /* INDX */
+    
+    TRACE("%d type=%d arg=0x%08x blk=0x%08x, fifo=%d/%d",
+          cmd, (host->cmd >> 22) & 3, host->arg, host->blk,
+          host->fifo_start, host->fifo_len);
+
+    if ((host->con & 2) && !cmd) { /* INIT and CMD0 */
+        host->stat_pending |= 0x1;
+        host->pstate &= 0xfffffffe;
+        return;
+    }
+    
+    if (host->cmd & (1 << 21)) { /* DP */
+        host->fifo_start = 0;
+        host->fifo_len = 0;
+        host->transfer = 1;
+        host->ddir = (host->cmd >> 4) & 1;
+        /* DLA | DATI | (RTA/WTA) */
+        host->pstate |= 0x6 | (host->ddir ? 0x200 : 0x100);
+    } else {
+        host->transfer = 0;
+        host->pstate &= ~0x306; /* RTA | WTA | DLA | DATI */
+    }
+    
+    timeout = 0;
+    mask = 0;
+    rspstatus = 0;
+    
+    request.cmd = cmd;
+    request.arg = host->arg;
+    request.crc = 0; /* FIXME */
+    
+    rsplen = sd_do_command(host->card, &request, response);
+    
+    switch ((host->cmd >> 16) & 3) { /* RSP_TYPE */
+        case sd_nore:
+            rsplen = 0;
+            break;
+        case sd_136_bits:
+            if (rsplen < 16) {
+                timeout = 1;
+                break;
+            }
+            rsplen = 16;
+            host->rsp76 = (response[0] << 24) | (response[1] << 16) |
+            (response[2] << 8) | (response[3] << 0);
+            host->rsp54 = (response[4] << 24) | (response[5] << 16) |
+            (response[6] << 8) | (response[7] << 0);
+            host->rsp32 = (response[8] << 24) | (response[9] << 16) |
+            (response[10] << 8) | (response[11] << 0);
+            host->rsp10 = (response[12] << 24) | (response[13] << 16) |
+            (response[14] << 8) | (response[15] << 0);
+            break;
+            case sd_48_bits:
+            case sd_48b_bits:
+            if (rsplen < 4) {
+                timeout = 1;
+                break;
+            }
+            rsplen = 4;
+            host->rsp10 = (response[0] << 24) | (response[1] << 16) |
+            (response[2] << 8) | (response[3] << 0);
+            switch (cmd) {
+                case 41: /* r3 */
+                case 8:  /* r7 */
+                    break;
+                case 3:  /* r6 */
+                    mask = 0xe00;
+                    rspstatus = (response[2] << 8) | response[3];
+                    break;
+                default:
+                    mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
+                    ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
+                    LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
+                    CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
+                    CID_CSD_OVERWRITE | WP_ERASE_SKIP;
+                    rspstatus = (response[0] << 24) | (response[1] << 16) |
+                    (response[2] << 8) | (response[3] << 0);
+                    break;
+            }
+            default:
+            break;
+    }
+    
+    if (cmd == 12 || cmd == 52) { /* stop transfer commands */
+        /*host->fifo_start = 0;*/
+        /*host->fifo_len = 0;*/
+        host->transfer = 0;
+        host->pstate &= ~0x0f06;     /* BRE | BWE | RTA | WTA | DLA | DATI */
+        host->stat_pending &= ~0x30; /* BRR | BWR */
+        host->stat &= ~0x30;         /* BRR | BWR */
+        host->stat_pending |= 0x2;   /* TC */
+        qemu_irq_lower(host->dma[0]);
+        qemu_irq_lower(host->dma[1]);
+    }
+    
+    if (rspstatus & mask & host->csre) {
+        host->stat_pending |= 1 << 28;    /* CERR */
+        host->pstate &= ~0x306;           /* RTA | WTA | DLA | DATI */
+        host->transfer = 0;
+    } else {
+        host->stat &= ~(1 << 28);         /* CERR */
+        host->stat_pending &= ~(1 << 28); /* CERR */
+    }
+    host->stat_pending |= timeout ? (1 << 16) : 0x1; /* CTO : CC */
+}
+
+static void omap3_mmc_reset(struct omap3_mmc_s *s)
+{
+    s->sysconfig = 0x00000015;
+    s->con       = 0x00000500;
+    s->pstate    = 0x00040000;
+    s->capa      = 0x00e10080;
+    s->rev       = 0x26000000;
+
+    s->fifo_start = 0;
+    s->fifo_len   = 0;
+    s->stop       = 0;
+}
+
+static uint32_t omap3_mmc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap3_mmc_s *s = (struct omap3_mmc_s *) opaque;
+    uint32_t i ;
+
+    switch (addr) {
+        case 0x10:
+            TRACE2("SYSCONFIG = %08x", s->sysconfig);
+            return s->sysconfig;
+        case 0x14:
+            TRACE2("SYSSTATUS = %08x", s->sysstatus | 0x1);
+            return s->sysstatus | 0x1; /*reset completed */
+        case 0x24:
+            TRACE2("CSRE = %08x", s->csre);
+            return s->csre;
+        case 0x28:
+            TRACE2("SYSTEST = %08x", s->systest);
+            return s->systest;
+        case 0x2c: /* MMCHS_CON */
+            TRACE2("CON = %08x", s->con);
+            return s->con;
+        case 0x30:
+            TRACE2("PWCNT = %08x", s->pwcnt);
+            return s->pwcnt;
+        case 0x104: /* MMCHS_BLK */
+            TRACE2("BLK = %08x", s->blk);
+            return s->blk;
+        case 0x108: /* MMCHS_ARG */
+            TRACE2("ARG = %08x", s->arg);
+            return s->arg;
+        case 0x10c:
+            TRACE2("CMD = %08x", s->cmd);
+            return s->cmd;
+        case 0x110:
+            TRACE2("RSP10 = %08x", s->rsp10);
+            return s->rsp10;
+        case 0x114:
+            TRACE2("RSP32 = %08x", s->rsp32);
+            return s->rsp32;
+        case 0x118:
+            TRACE2("RSP54 = %08x", s->rsp54);
+            return s->rsp54;
+        case 0x11c:
+            TRACE2("RSP76 = %08x", s->rsp76);
+            return s->rsp76;
+        case 0x120:
+            /* in PIO mode, access allowed only when BRE is set */
+            if (!(s->cmd & 1) && !(s->pstate & 0x0800)) {
+                s->stat_pending |= 1 << 29; /* BADA */
+                i = 0;
+            } else {
+                i = s->fifo[s->fifo_start];
+                s->fifo[s->fifo_start] = 0;
+                if (s->fifo_len == 0) {
+                    fprintf(stderr, "%s: FIFO underrun\n", __FUNCTION__);
+                    return i;
+                }
+                s->fifo_start++;
+                s->fifo_len--;
+                s->fifo_start &= 255;
+                omap3_mmc_transfer(s);
+                omap3_mmc_fifolevel_update(s);
+            }
+            omap3_mmc_interrupts_update(s);
+            return i;
+        case 0x124: /* MMCHS_PSTATE */
+            TRACE2("PSTATE = %08x", s->pstate);
+            return s->pstate;
+        case 0x128:
+            TRACE2("HCTL = %08x", s->hctl);
+            return s->hctl;
+        case 0x12c: /* MMCHS_SYSCTL */
+            TRACE2("SYSCTL = %08x", s->sysctl);
+            return s->sysctl;
+        case 0x130: /* MMCHS_STAT */
+            s->stat |= s->stat_pending;
+            if (s->stat & 0xffff0000)
+                   s->stat |= 1 << 15;    /* ERRI */
+            else
+                   s->stat &= ~(1 << 15); /* ERRI */
+            s->stat_pending = 0;
+            TRACE2("STAT = %08x", s->stat);
+            return s->stat;
+        case 0x134:
+            TRACE2("IE = %08x", s->ie);
+            return s->ie;
+        case 0x138:
+            TRACE2("ISE = %08x", s->ise);
+            return s->ise;
+        case 0x13c:
+            TRACE2("AC12 = %08x", s->ac12);
+            return s->ac12;
+        case 0x140: /* MMCHS_CAPA */
+            TRACE2("CAPA = %08x", s->capa);
+            return s->capa;
+        case 0x148:
+            TRACE2("CUR_CAPA = %08x", s->cur_capa);
+            return s->cur_capa;
+        case 0x1fc:
+            TRACE2("REV = %08x", s->rev);
+            return s->rev;
+        default:
+            OMAP_BAD_REG(addr);
+            exit(-1);
+            return 0;
+    }
+}
+
+static void omap3_mmc_write(void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+    struct omap3_mmc_s *s = (struct omap3_mmc_s *) opaque;
+    
+    switch (addr) {
+        case 0x014:
+        case 0x110:
+        case 0x114:
+        case 0x118:
+        case 0x11c:
+        case 0x124:
+        case 0x13c:
+        case 0x1fc:
+            OMAP_RO_REG(addr);
+            break;
+        case 0x010:
+            TRACE2("SYSCONFIG = %08x", value);
+            if (value & 2)
+                omap3_mmc_reset(s);
+            s->sysconfig = value & 0x31d;
+            break;
+        case 0x024:
+            TRACE2("CSRE = %08x", value);
+            s->csre = value;
+            break;
+        case 0x028:
+            TRACE2("SYSTEST = %08x", value);
+            s->systest = value;
+            break;
+        case 0x02c: /* MMCHS_CON */
+            TRACE2("CON = %08x", value);
+            if (value & 0x10)   /* MODE */
+                fprintf(stderr, "%s: SYSTEST mode is not supported\n",
+                        __FUNCTION__);
+            if (value & 0x20)   /* DW8 */
+                fprintf(stderr, "%s: 8-bit data width is not supported\n",
+                        __FUNCTION__);
+            if (value & 0x1000) /* CEATA */
+                fprintf(stderr, "%s: CE-ATA control mode not supported\n",
+                        __FUNCTION__);
+            s->con = value & 0x1ffff;
+            break;
+        case 0x030:
+            TRACE2("PWCNT = %08x", value);
+            s->pwcnt = value;
+            break;
+        case 0x104: /* MMCHS_BLK */
+            TRACE2("BLK = %08x", value);
+            s->blk = value & 0xffff07ff;
+            s->blen_counter = value & 0x7ff;
+            s->nblk_counter = (value >> 16) & 0xffff;
+            break;
+        case 0x108: /* MMCHS_ARG */
+            TRACE2("ARG = %08x", value);
+            s->arg = value;
+            break;
+        case 0x10c: /* MMCHS_CMD */
+            TRACE2("CMD = %08x", value);
+            if (!s->card) {
+                s->stat_pending |= (1 << 16); /* CTO */
+            } else {
+                /* TODO: writing to bits 0-15 should have no effect during
+                   an active data transfer */
+                if (!s->stop
+                    && (((value >> 24) & 0x3f) == 12
+                        || ((value >> 24) & 0x3f) == 52)) {
+                    s->stop = value & 0x3ffb0037;
+                } else {
+                    s->cmd = value & 0x3ffb0037;
+                    omap3_mmc_command(s);
+                }
+                omap3_mmc_transfer(s);
+                omap3_mmc_fifolevel_update(s);
+            }
+            omap3_mmc_interrupts_update(s);
+            break;
+        case 0x120:
+            /* in PIO mode, access allowed only when BWE is set */
+            if (!(s->cmd & 1) && !(s->pstate & 0x0400)) {
+                s->stat_pending |= 1 << 29; /* BADA */
+            } else {
+                if (s->fifo_len == 256) {
+                    fprintf(stderr, "%s: FIFO overrun\n", __FUNCTION__);
+                    break;
+                }
+                s->fifo[(s->fifo_start + s->fifo_len) & 255] = value;
+                s->fifo_len++;
+                omap3_mmc_transfer(s);
+                omap3_mmc_fifolevel_update(s);
+            }
+            omap3_mmc_interrupts_update(s);
+            break;
+        case 0x128: /* MMCHS_HCTL */
+            TRACE2("HCTL = %08x", value);
+            s->hctl = value & 0xf0f0f02;
+            if (s->hctl & (1 << 16)) /* SBGR */
+                fprintf(stderr, "%s: Stop at block gap feature not implemented!\n", __FUNCTION__);
+            break;
+        case 0x12c: /* MMCHS_SYSCTL */
+            TRACE2("SYSCTL = %08x", value);
+            if (value & 0x04000000) { /* SRD */
+                s->data    = 0;
+                s->pstate &= ~0x00000f06; /* BRE, BWE, RTA, WTA, DLA, DATI */
+                s->hctl   &= ~0x00030000; /* SGBR, CR */
+                s->stat   &= ~0x00000034; /* BRR, BWR, BGE */
+                s->stat_pending &= ~0x00000034;
+                s->fifo_start = 0;
+                s->fifo_len = 0;
+            }
+            if (value & 0x02000000) { /* SRC */
+                s->pstate &= ~0x00000001; /* CMDI */
+            }
+            if (value & 0x01000000) { /* SRA */
+                uint32_t capa = s->capa;
+                uint32_t cur_capa = s->cur_capa;
+                omap3_mmc_reset(s);
+                s->capa = capa;
+                s->cur_capa = cur_capa;
+            }
+            value = (value & ~2) | ((value & 1) << 1); /* copy ICE directly to ICS */
+            s->sysctl = value & 0x000fffc7;
+            break;
+        case 0x130:
+            TRACE2("STAT = %08x", value);
+            value = value & 0x317f0237;
+            s->stat &= ~value;
+            /* stat_pending is NOT cleared */
+            omap3_mmc_interrupts_update(s);
+            break;
+        case 0x134: /* MMCHS_IE */
+            TRACE2("IE = %08x", value);
+            if (!(s->con & 0x4000)) /* if CON:OBIE is clear, ignore write to OBI_ENABLE */
+                value = (value & ~0x200) | (s->ie & 0x200);
+            s->ie = value & 0x317f0337;
+            if (!(s->ie & 0x100)) {
+                s->stat &= ~0x100;
+                s->stat_pending &= ~0x100;
+            }
+            omap3_mmc_interrupts_update(s);
+            break;
+        case 0x138:
+            TRACE2("ISE = %08x", value);
+            s->ise = value & 0x317f0337;
+            omap3_mmc_interrupts_update(s);
+            break;
+        case 0x140: /* MMCHS_CAPA */
+            TRACE2("CAPA = %08x", value);
+            s->capa &= ~0x07000000;
+            s->capa |= value & 0x07000000;
+            break;
+        case 0x148:
+            TRACE2("CUR_CAPA = %08x", value);
+            s->cur_capa = value & 0xffffff;
+            break;
+        default:
+            OMAP_BAD_REG(addr);
+            exit(-1);
+    }
+}
+
+static CPUReadMemoryFunc *omap3_mmc_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap3_mmc_read,
+};
+
+static CPUWriteMemoryFunc *omap3_mmc_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_mmc_write,
+};
+
+static void omap3_mmc_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_mmc_s *s = (struct omap3_mmc_s *)opaque;
+    int i;
+    
+    qemu_put_be32(f, s->sysconfig);
+    qemu_put_be32(f, s->sysstatus);
+    qemu_put_be32(f, s->csre);
+    qemu_put_be32(f, s->systest);
+    qemu_put_be32(f, s->con);
+    qemu_put_be32(f, s->pwcnt);
+    qemu_put_be32(f, s->blk);
+    qemu_put_be32(f, s->arg);
+    qemu_put_be32(f, s->cmd);
+    qemu_put_be32(f, s->rsp10);
+    qemu_put_be32(f, s->rsp32);
+    qemu_put_be32(f, s->rsp54);
+    qemu_put_be32(f, s->rsp76);
+    qemu_put_be32(f, s->data);
+    qemu_put_be32(f, s->pstate);
+    qemu_put_be32(f, s->hctl);
+    qemu_put_be32(f, s->sysctl);
+    qemu_put_be32(f, s->stat);
+    qemu_put_be32(f, s->ie);
+    qemu_put_be32(f, s->ise);
+    qemu_put_be32(f, s->ac12);
+    qemu_put_be32(f, s->capa);
+    qemu_put_be32(f, s->cur_capa);
+    qemu_put_be32(f, s->rev);
+    qemu_put_be16(f, s->blen_counter);
+    qemu_put_be16(f, s->nblk_counter);
+    for (i = 0; i < sizeof(s->fifo)/sizeof(uint32_t); i++)
+        qemu_put_be32(f, s->fifo[i]);
+    qemu_put_sbe32(f, s->fifo_start);
+    qemu_put_sbe32(f, s->fifo_len);
+    qemu_put_sbe32(f, s->ddir);
+    qemu_put_sbe32(f, s->transfer);
+    qemu_put_sbe32(f, s->stop);
+    qemu_put_be32(f, s->stat_pending);
+}
+
+static int omap3_mmc_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap3_mmc_s *s = (struct omap3_mmc_s *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->sysconfig = qemu_get_be32(f);
+    s->sysstatus = qemu_get_be32(f);
+    s->csre = qemu_get_be32(f);
+    s->systest = qemu_get_be32(f);
+    s->con = qemu_get_be32(f);
+    s->pwcnt = qemu_get_be32(f);
+    s->blk = qemu_get_be32(f);
+    s->arg = qemu_get_be32(f);
+    s->cmd = qemu_get_be32(f);
+    s->rsp10 = qemu_get_be32(f);
+    s->rsp32 = qemu_get_be32(f);
+    s->rsp54 = qemu_get_be32(f);
+    s->rsp76 = qemu_get_be32(f);
+    s->data = qemu_get_be32(f);
+    s->pstate = qemu_get_be32(f);
+    s->hctl = qemu_get_be32(f);
+    s->sysctl = qemu_get_be32(f);
+    s->stat = qemu_get_be32(f);
+    s->ie = qemu_get_be32(f);
+    s->ise = qemu_get_be32(f);
+    s->ac12 = qemu_get_be32(f);
+    s->capa = qemu_get_be32(f);
+    s->cur_capa = qemu_get_be32(f);
+    s->rev = qemu_get_be32(f);
+    s->blen_counter = qemu_get_be16(f);
+    s->nblk_counter = qemu_get_be16(f);
+    for (i = 0; i < sizeof(s->fifo)/sizeof(uint32_t); i++)
+        s->fifo[i] = qemu_get_be32(f);
+    s->fifo_start = qemu_get_sbe32(f);
+    s->fifo_len = qemu_get_sbe32(f);
+    s->ddir = qemu_get_sbe32(f);
+    s->transfer = qemu_get_sbe32(f);
+    s->stop = qemu_get_sbe32(f);
+    s->stat_pending = qemu_get_be32(f);
+    
+    omap3_mmc_fifolevel_update(s);
+    omap3_mmc_interrupts_update(s);
+    
+    return 0;
+}
+
+struct omap3_mmc_s *omap3_mmc_init(struct omap_target_agent_s *ta,
+                                   qemu_irq irq, qemu_irq dma[],
+                                   omap_clk fclk, omap_clk iclk)
+{
+    int iomemtype;
+    struct omap3_mmc_s *s = (struct omap3_mmc_s *)
+        qemu_mallocz(sizeof(struct omap3_mmc_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->clk = fclk;
+
+    omap3_mmc_reset(s);
+
+    iomemtype = l4_register_io_memory(0, omap3_mmc_readfn,
+                                      omap3_mmc_writefn, s);
+    omap_l4_attach(ta, 0, iomemtype);
+
+    register_savevm("omap3_mmc", (ta->base >> 12) & 0xff, 0,
+                    omap3_mmc_save_state, omap3_mmc_load_state, s);
+    return s;
+}
+
+void omap3_mmc_attach(struct omap3_mmc_s *s,
+                      BlockDriverState *bd)
+{
+    if (s->card) {
+        fprintf(stderr, "%s: SD card already attached!\n", __FUNCTION__);
+        exit(-1);
+    }
+    s->card = sd_init(bd, 0);
+    sd_enable(s->card, 1);
+}
diff --git a/hw/omap3_usb.c b/hw/omap3_usb.c
new file mode 100644 (file)
index 0000000..ebb0eef
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * TI OMAP3 High-Speed USB Host and OTG Controller emulation.
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "omap.h"
+#include "irq.h"
+#include "devices.h"
+#include "hw.h"
+
+#define OMAP3_HSUSB_OTG
+//#define OMAP3_HSUSB_HOST
+
+/* #define OMAP3_HSUSB_DEBUG */
+
+#ifdef OMAP3_HSUSB_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+#ifdef OMAP3_HSUSB_OTG
+/* usb-musb.c */
+extern CPUReadMemoryFunc *musb_read[];
+extern CPUWriteMemoryFunc *musb_write[];
+
+struct omap3_hsusb_otg_s {
+    qemu_irq mc_irq;
+    qemu_irq dma_irq;
+    struct musb_s *musb;
+    
+    uint8_t rev;
+    uint16_t sysconfig;
+    uint8_t interfsel;
+    uint8_t simenable;
+    uint8_t forcestdby;
+};
+
+static void omap3_hsusb_otg_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
+    
+    qemu_put_be16(f, s->sysconfig);
+    qemu_put_byte(f, s->interfsel);
+    qemu_put_byte(f, s->simenable);
+    qemu_put_byte(f, s->forcestdby);
+}
+
+static int omap3_hsusb_otg_load_state(QEMUFile *f, void *opaque,
+                                      int version_id)
+{
+    struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->sysconfig = qemu_get_be16(f);
+    s->interfsel = qemu_get_byte(f);
+    s->simenable = qemu_get_byte(f);
+    s->forcestdby = qemu_get_byte(f);
+    
+    return 0;
+}
+
+static void omap3_hsusb_otg_reset(struct omap3_hsusb_otg_s *s)
+{
+    s->rev = 0x33;
+    s->sysconfig = 0;
+    s->interfsel = 0x1;
+    s->simenable = 0;
+    s->forcestdby = 1;
+}
+
+static uint32_t omap3_hsusb_otg_readb(void *opaque, target_phys_addr_t addr)
+{
+    struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
+    if (addr < 0x200)
+        return musb_read[0](s->musb, addr);
+    if (addr < 0x400)
+        return musb_read[0](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap3_hsusb_otg_readh(void *opaque, target_phys_addr_t addr)
+{
+    struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
+    if (addr < 0x200)
+        return musb_read[1](s->musb, addr);
+    if (addr < 0x400)
+        return musb_read[1](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap3_hsusb_otg_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
+    
+    if (addr < 0x200)
+        return musb_read[2](s->musb, addr);
+    if (addr < 0x400)
+        return musb_read[2](s->musb, 0x20 + ((addr >> 3 ) & 0x3c));
+    
+    switch (addr) {
+        case 0x400: /* OTG_REVISION */
+            TRACE("OTG_REVISION: 0x%08x", s->rev);
+            return s->rev;
+        case 0x404: /* OTG_SYSCONFIG */
+            TRACE("OTG_SYSCONFIG: 0x%08x", s->sysconfig);
+            return s->sysconfig;
+        case 0x408: /* OTG_SYSSTATUS */
+            TRACE("OTG_SYSSTATUS: 0x00000001");
+            return 1; /* reset finished */
+        case 0x40c: /* OTG_INTERFSEL */
+            TRACE("OTG_INTERFSEL: 0x%08x", s->interfsel);
+            return s->interfsel;
+        case 0x410: /* OTG_SIMENABLE */
+            TRACE("OTG_SIMENABLE: 0x%08x", s->simenable);
+            return s->simenable;
+        case 0x414: /* OTG_FORCESTDBY */
+            TRACE("OTG_FORCESTDBY: 0x%08x", s->forcestdby);
+            return s->forcestdby;
+        default:
+            break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap3_hsusb_otg_writeb(void *opaque, target_phys_addr_t addr,
+                                   uint32_t value)
+{
+    struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
+    
+    if (addr < 0x200)
+        musb_write[0](s->musb, addr, value);
+    else if (addr < 0x400)
+        musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+    else
+        OMAP_BAD_REG(addr);
+}
+
+static void omap3_hsusb_otg_writeh(void *opaque, target_phys_addr_t addr,
+                                   uint32_t value)
+{
+    struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
+    
+    if (addr < 0x200)
+        musb_write[1](s->musb, addr, value);
+    else if (addr < 0x400)
+        musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+    else
+        OMAP_BAD_REG(addr);
+}
+
+static void omap3_hsusb_otg_write(void *opaque, target_phys_addr_t addr,
+                                  uint32_t value)
+{
+    struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
+    
+    if (addr < 0x200)
+        musb_write[2](s->musb, addr, value);
+    else if (addr < 0x400)
+        musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+    else switch (addr) {
+        case 0x400: /* OTG_REVISION */
+        case 0x408: /* OTG_SYSSTATUS */
+            OMAP_RO_REGV(addr, value);
+            break;
+        case 0x404: /* OTG_SYSCONFIG */
+            TRACE("OTG_SYSCONFIG = 0x%08x", value);
+            if (value & 2) /* SOFTRESET */
+                omap3_hsusb_otg_reset(s);
+            s->sysconfig = value & 0x301f;
+            break;
+        case 0x40c: /* OTG_INTERFSEL */
+            TRACE("OTG_INTERFSEL = 0x%08x", value);
+            s->interfsel = value & 0x3;
+            break;
+        case 0x410: /* OTG_SIMENABLE */
+            TRACE("OTG_SIMENABLE = 0x%08x", value);
+            cpu_abort(cpu_single_env,
+                      "%s: USB simulation mode not supported\n",
+                      __FUNCTION__);
+            break;
+        case 0x414: /* OTG_FORCESTDBY */
+            TRACE("OTG_FORCESTDBY = 0x%08x", value);
+            s->forcestdby = value & 1;
+            break;
+        default:
+            OMAP_BAD_REGV(addr, value);
+            break;
+    }
+}
+
+static CPUReadMemoryFunc *omap3_hsusb_otg_readfn[] = {
+    omap3_hsusb_otg_readb,
+    omap3_hsusb_otg_readh,
+    omap3_hsusb_otg_read,
+};
+
+static CPUWriteMemoryFunc *omap3_hsusb_otg_writefn[] = {
+    omap3_hsusb_otg_writeb,
+    omap3_hsusb_otg_writeh,
+    omap3_hsusb_otg_write,
+};
+
+static void omap3_hsusb_musb_core_intr(void *opaque, int source, int level)
+{
+    struct omap3_hsusb_otg_s *s = (struct omap3_hsusb_otg_s *)opaque;
+    TRACE("intr 0x%08x, 0x%08x, 0x%08x", source, level, musb_core_intr_get(s->musb));
+    switch (source) {
+    case musb_set_vbus:
+       TRACE("ignoring VBUS");
+       break;
+    case musb_set_session:
+       TRACE("ignoring SESSION");
+       break;
+    case musb_irq_tx:
+    case musb_irq_rx:
+       TRACE("rxtx");
+       break;
+       /* Fall through */
+    default:
+       TRACE("other");
+    }
+    qemu_set_irq(s->mc_irq, level);
+}
+
+static void omap3_hsusb_otg_init(struct omap_target_agent_s *otg_ta,
+                                 qemu_irq mc_irq,
+                                 qemu_irq dma_irq,
+                                 struct omap3_hsusb_otg_s *s)
+{
+    s->mc_irq = mc_irq;
+    s->dma_irq = dma_irq;
+    
+    omap_l4_attach(otg_ta, 0, l4_register_io_memory(0,
+                                                    omap3_hsusb_otg_readfn,
+                                                    omap3_hsusb_otg_writefn,
+                                                    s));
+    
+    s->musb = musb_init(qemu_allocate_irqs(omap3_hsusb_musb_core_intr, s,
+                                           __musb_irq_max));
+    omap3_hsusb_otg_reset(s);
+    
+    register_savevm("omap3_hsusb_otg", -1, 0,
+                    omap3_hsusb_otg_save_state,
+                    omap3_hsusb_otg_load_state,
+                    s);
+}
+#endif
+
+#ifdef OMAP3_HSUSB_HOST
+struct omap3_hsusb_host_s {
+    qemu_irq ehci_irq;
+    qemu_irq tll_irq;
+    
+    uint32_t uhh_sysconfig;
+    uint32_t uhh_hostconfig;
+    uint32_t uhh_debug_csr;
+};
+
+static void omap3_hsusb_host_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
+    
+    qemu_put_be32(f, s->uhh_sysconfig);
+    qemu_put_be32(f, s->uhh_hostconfig);
+    qemu_put_be32(f, s->uhh_debug_csr);
+}
+
+static int omap3_hsusb_host_load_state(QEMUFile *f, void *opaque,
+                                       int version_id)
+{
+    struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->uhh_sysconfig = qemu_get_be32(f);
+    s->uhh_hostconfig = qemu_get_be32(f);
+    s->uhh_debug_csr = qemu_get_be32(f);
+    
+    return 0;
+}
+
+static void omap3_hsusb_host_reset(struct omap3_hsusb_host_s *s)
+{
+    s->uhh_sysconfig = 1;
+    s->uhh_hostconfig = 0x700;
+    s->uhh_debug_csr = 0x20;
+    /* TODO: perform OHCI & EHCI reset */
+}
+
+static uint32_t omap3_hsusb_host_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
+    
+    switch (addr) {
+        case 0x00: /* UHH_REVISION */
+            return 0x10;
+        case 0x10: /* UHH_SYSCONFIG */
+            return s->uhh_sysconfig;
+        case 0x14: /* UHH_SYSSTATUS */
+            return 0x7; /* EHCI_RESETDONE | OHCI_RESETDONE | RESETDONE */
+        case 0x40: /* UHH_HOSTCONFIG */
+            return s->uhh_hostconfig;
+        case 0x44: /* UHH_DEBUG_CSR */
+            return s->uhh_debug_csr;
+        default:
+            break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap3_hsusb_host_write(void *opaque, target_phys_addr_t addr,
+                                   uint32_t value)
+{
+    struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque;
+    
+    switch (addr) {
+        case 0x00: /* UHH_REVISION */
+        case 0x14: /* UHH_SYSSTATUS */
+            OMAP_RO_REGV(addr, value);
+            break;
+        case 0x10: /* UHH_SYSCONFIG */
+            s->uhh_sysconfig = value & 0x311d;
+            if (value & 2) { /* SOFTRESET */
+                omap3_hsusb_host_reset(s);
+            }
+            break;
+        case 0x40: /* UHH_HOSTCONFIG */
+            s->uhh_hostconfig = value & 0x1f3d;
+            break;
+        case 0x44: /* UHH_DEBUG_CSR */
+            s->uhh_debug_csr = value & 0xf00ff;
+            break;
+        default:
+            OMAP_BAD_REGV(addr, value);
+            break;
+    }
+}
+
+static CPUReadMemoryFunc *omap3_hsusb_host_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap3_hsusb_host_read,
+};
+
+static CPUWriteMemoryFunc *omap3_hsusb_host_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_hsusb_host_write,
+};
+
+static uint32_t omap3_hsusb_ehci_read(void *opaque, target_phys_addr_t addr)
+{
+    TRACE(OMAP_FMT_plx, addr);
+    return 0;
+}
+
+static void omap3_hsusb_ehci_write(void *opaque, target_phys_addr_t addr,
+                                   uint32_t value)
+{
+    TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
+}
+
+static CPUReadMemoryFunc *omap3_hsusb_ehci_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap3_hsusb_ehci_read,
+};
+
+static CPUWriteMemoryFunc *omap3_hsusb_ehci_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_hsusb_ehci_write,
+};
+
+static uint32_t omap3_hsusb_tll_read(void *opaque, target_phys_addr_t addr)
+{
+    TRACE(OMAP_FMT_plx, addr);
+    return 0;
+}
+
+static void omap3_hsusb_tll_write(void *opaque, target_phys_addr_t addr,
+                                  uint32_t value)
+{
+    TRACE(OMAP_FMT_plx " = 0x%08x", addr, value);
+}
+
+static CPUReadMemoryFunc *omap3_hsusb_tll_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap3_hsusb_tll_read,
+};
+
+static CPUWriteMemoryFunc *omap3_hsusb_tll_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap3_hsusb_tll_write,
+};
+
+static void omap3_hsusb_host_init(struct omap_target_agent_s *host_ta,
+                                  struct omap_target_agent_s *tll_ta,
+                                  qemu_irq ohci_irq,
+                                  qemu_irq ehci_irq,
+                                  qemu_irq tll_irq,
+                                  struct omap3_hsusb_host_s *s)
+{
+    s->ehci_irq = ehci_irq;
+    s->tll_irq  = tll_irq;
+    
+    omap_l4_attach(tll_ta, 0, l4_register_io_memory(0,
+                                                    omap3_hsusb_tll_readfn,
+                                                    omap3_hsusb_tll_writefn,
+                                                    s));
+    omap_l4_attach(host_ta, 0, l4_register_io_memory(0,
+                                                     omap3_hsusb_host_readfn,
+                                                     omap3_hsusb_host_writefn,
+                                                     s));
+    omap_l4_attach(host_ta, 1, usb_ohci_init_omap(omap_l4_base(host_ta, 1),
+                                                  omap_l4_size(host_ta, 1),
+                                                  3, ohci_irq));
+    omap_l4_attach(host_ta, 2, l4_register_io_memory(0,
+                                                     omap3_hsusb_ehci_readfn,
+                                                     omap3_hsusb_ehci_writefn,
+                                                     s));
+    
+    omap3_hsusb_host_reset(s);
+    
+    register_savevm("omap3_hsusb_host", -1, 0,
+                    omap3_hsusb_host_save_state,
+                    omap3_hsusb_host_load_state, s);
+}
+#endif
+
+struct omap3_hsusb_s {
+#ifdef OMAP3_HSUSB_OTG
+    struct omap3_hsusb_otg_s otg;
+#endif
+#ifdef OMAP3_HSUSB_HOST
+    struct omap3_hsusb_host_s host;
+#endif
+};
+
+struct omap3_hsusb_s *omap3_hsusb_init(struct omap_target_agent_s *otg_ta,
+                                       struct omap_target_agent_s *host_ta,
+                                       struct omap_target_agent_s *tll_ta,
+                                       qemu_irq mc_irq,
+                                       qemu_irq dma_irq,
+                                       qemu_irq ohci_irq,
+                                       qemu_irq ehci_irq,
+                                       qemu_irq tll_irq)
+{
+    struct omap3_hsusb_s *s = qemu_mallocz(sizeof(struct omap3_hsusb_s));
+#ifdef OMAP3_HSUSB_HOST
+    omap3_hsusb_host_init(host_ta, tll_ta,
+                          ohci_irq, ehci_irq, tll_irq,
+                          &s->host);
+#endif
+#ifdef OMAP3_HSUSB_OTG
+    omap3_hsusb_otg_init(otg_ta, mc_irq, dma_irq, &s->otg);
+#endif
+    return s;
+}
+
index d7a5a57..f4d20bc 100644 (file)
@@ -36,6 +36,7 @@ struct clk {
 #define CLOCK_IN_OMAP242X      (1 << 14)
 #define CLOCK_IN_OMAP243X      (1 << 15)
 #define CLOCK_IN_OMAP343X      (1 << 16)
+#define CLOCK_IN_OMAP3XXX   (1 << 17)
     uint32_t flags;
     int id;
 
@@ -944,6 +945,595 @@ static struct clk omapctrl_clk = {
     .parent    = &core_l4_iclk,
 };
 
+/* OMAP3 Clocks */
+
+static struct clk omap3_sys_32k = {
+    .name      = "omap3_sys_32k",
+    .rate      = 32768,
+    .flags     = CLOCK_IN_OMAP3XXX  | ALWAYS_ENABLED,
+};
+
+static struct clk omap3_osc_sys_clk12 = {
+    .name      = "omap3_osc_sys_clk12",
+    .rate      = 12000000,
+    .flags     = CLOCK_IN_OMAP3XXX  | ALWAYS_ENABLED,
+};
+
+static struct clk omap3_osc_sys_clk13 = {
+    .name      = "omap3_osc_sys_clk13",
+    .rate      = 13000000,
+    .flags     = CLOCK_IN_OMAP3XXX  | ALWAYS_ENABLED,
+};
+
+static struct clk omap3_osc_sys_clk168 = {
+    .name      = "omap3_osc_sys_clk168",
+    .rate      = 16800000,
+    .flags     = CLOCK_IN_OMAP3XXX  | ALWAYS_ENABLED,
+};
+
+static struct clk omap3_osc_sys_clk192 = {
+    .name      = "omap3_osc_sys_clk192",
+    .rate      = 19200000,
+    .flags     = CLOCK_IN_OMAP3XXX  | ALWAYS_ENABLED,
+};
+
+static struct clk omap3_osc_sys_clk26 = {
+    .name      = "omap3_osc_sys_clk26",
+    .rate      = 26000000,
+    .flags     = CLOCK_IN_OMAP3XXX  | ALWAYS_ENABLED,
+};
+
+static struct clk omap3_osc_sys_clk384 = {
+    .name      = "omap3_osc_sys_clk384",
+    .rate      = 38400000,
+    .flags     = CLOCK_IN_OMAP3XXX  | ALWAYS_ENABLED,
+};
+
+/*Is the altclk is enabled in beagle board?*/
+static struct clk omap3_sys_altclk = {
+    .name      = "omap3_sys_altclk",
+    .rate      = 13000000,
+    .flags     = CLOCK_IN_OMAP3XXX  ,
+};
+
+/*PRM*/
+static struct clk omap3_sys_clk = {
+    .name      = "omap3_sys_clk",
+    .flags     = CLOCK_IN_OMAP3XXX  | ALWAYS_ENABLED,
+    .parent = &omap3_osc_sys_clk26,
+};
+
+static struct clk omap3_32k_fclk = {
+    .name      = "omap3_32k_fclk",
+    .rate      = 32768,
+    .flags     = CLOCK_IN_OMAP3XXX  | ALWAYS_ENABLED,
+    .parent = &omap3_sys_32k,
+};
+
+/*DPLL3:
+ *     Input: SYS_CLK
+ *   Output:
+ *           DPLL3_M2_CLK  (CORE_CLK)
+ *           DPLL3_M2*2_CLK   (CORE*2_CLK)
+ *           EMULE_CORE_ALWON_CLK
+ */
+static struct clk omap3_core_clk = {
+    .name      = "omap3_core_clk",
+    .flags     = CLOCK_IN_OMAP3XXX | ALWAYS_ENABLED,
+    .parent    = &omap3_sys_clk,       
+};
+
+static struct clk omap3_core2_clk = {
+    .name      = "omap3_core2_clk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_sys_clk,       
+};
+
+static struct clk omap3_emu_core_alwon_clk = {
+    .name      = "omap3_emu_core_alwon_clk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_sys_clk,       
+};
+
+/*DPLL1 : it is for MPU
+ *    Input:
+ *           reference clock: SYS_CLK
+ *           bypass clock : CORE_CLK from dpll3
+ *    Output:
+ *           MPU_CLK (DPLL_CLK_M2)
+ */
+static struct clk omap3_mpu_clk = {
+    .name      = "omap3_mpu_clk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_clk,         /*between sys_clk and core_clk*/
+};
+
+/*DPLL2: it is for iva2*/
+static struct clk omap3_iva2_clk = {
+    .name      = "omap3_iva2_clk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_clk,         /*between sys_clk and core_clk*/
+};
+
+/* DPLL4:
+ *      INPUT: SYS_CLK
+ *      OUTPUT:
+ *              M2: 96M_FCLK
+ *              M3: TO TV(54M_FCLK)
+ *              M4: DSS1_ALWON_CLK
+ *              M5: CAM_CLK
+ *              M6: EMUL_PER_ALWON_CLK
+ */
+static struct clk omap3_96m_fclk = {
+    .name      = "omap3_96m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_sys_clk,
+};
+
+static struct clk omap3_54m_fclk = {
+    .name      = "omap3_54m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .parent    = &omap3_sys_clk,
+};
+
+static struct clk omap3_dss1_alwon_fclk = {
+    .name      = "omap3_dss1_alwon_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_sys_clk,           
+};
+
+static struct clk omap3_cam_mclk = {
+    .name      = "omap3_cam_mclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_sys_clk,           
+};
+static struct clk omap3_per_alwon_clk = {
+    .name      = "omap3_per_alwon_clk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_sys_clk,           
+};
+
+/* DPLL5:
+ *      INPUT: SYS_CLK
+ *      OUTPUT:
+ *              M2: 120M_FCLK
+ */
+static struct clk omap3_120m_fclk = {
+    .name      = "omap3_120m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_sys_clk,        
+};
+
+/*CM*/
+static struct clk omap3_48m_fclk = {
+    .name      = "omap3_48m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_96m_fclk, /* omap3_96m_fclk and omap3_sys_altclk */
+    .divisor = 2,
+    .multiplier = 1, 
+};
+
+static struct clk omap3_12m_fclk = {
+    .name      = "omap3_12m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_96m_fclk, /*omap3_96m_fclk and omap3_sys_altclk */
+    .divisor = 8,
+    .multiplier = 1,
+};
+
+/*Common interface clock*/
+/*   Input: core_clk
+ *   Output:
+ *           l3x2_iclk
+ *           l3_iclk
+ *           l4_iclk
+ *           rm_iclk
+ */
+static struct clk omap3_l3x2_iclk = {
+    .name      = "omap3_l3x2_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX | ALWAYS_ENABLED,
+    .parent    = &omap3_core_clk,
+};
+
+static struct clk omap3_l3_iclk = {
+    .name      = "omap3_l3_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX | ALWAYS_ENABLED,
+    .parent    = &omap3_core_clk,
+};
+
+static struct clk omap3_l4_iclk = {
+    .name      = "omap3_l4_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX | ALWAYS_ENABLED,
+    .parent    = &omap3_l3_iclk,
+};
+static struct clk omap3_rm_iclk = {
+    .name      = "omap3_rm_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX | ALWAYS_ENABLED,
+    .parent    = &omap3_l4_iclk,
+};
+
+/*Core power domain clock*/
+/*   Input: cm_sys_clk
+ *            cm_32k_clk
+ *            120m_fclk
+ *            96m_fclk
+ *            48m_fclk
+ *            12m_fclk
+ *            l3_iclk
+ *            l4_iclk
+ *   Output:
+ *           gp10_fclk
+ *           gp11_fclk
+ *           core_32k_fclk
+ *           cpefuse_fclk
+ *           core_120M_fclk
+ *           usbttl_sap_fclk
+ *           core_96m_fclk
+ *           core_48m_flck
+ *           core_12m_fclk
+ *           core_l3_iclk
+ *           security_l3_iclk
+ *           core_l4_iclk
+ *           security_l4_iclk2
+ */
+static struct clk omap3_gp10_fclk = {
+    .name      = "omap3_gp10_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .parent    = &omap3_32k_fclk,   /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_gp11_fclk = {
+    .name      = "omap3_gp11_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .parent    = &omap3_32k_fclk,   /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_core_32k_fclk = {
+    .name      = "omap3_core_32k_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .parent    = &omap3_32k_fclk, 
+};
+
+static struct clk omap3_cpefuse_fclk = {
+    .name      = "omap3_cpefuse_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .parent    = &omap3_sys_clk, 
+};
+
+static struct clk omap3_core_120m_fclk = {
+    .name      = "omap3_core_120m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .parent    = &omap3_120m_fclk, 
+};
+
+static struct clk omap3_core_96m_fclk = {
+    .name      = "omap3_core_96m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .parent    = &omap3_96m_fclk, 
+};
+
+static struct clk omap3_core_48m_fclk = {
+    .name      = "omap3_core_48m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .parent    = &omap3_48m_fclk, 
+};
+
+static struct clk omap3_core_12m_fclk = {
+    .name      = "omap3_core_12m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .parent    = &omap3_12m_fclk, 
+};
+
+static struct clk omap3_core_l3_iclk = {
+    .name      = "omap3_core_l3_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX | ALWAYS_ENABLED,
+    .parent    = &omap3_l3_iclk, 
+};
+
+
+static struct clk omap3_core_l4_iclk = {
+    .name      = "omap3_core_l4_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX | ALWAYS_ENABLED,
+    .parent    = &omap3_l4_iclk, 
+};
+
+/*WKUP Power Domain*/
+static struct clk omap3_wkup_32k_fclk = {
+    .name      = "omap3_wkup_32k_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk, 
+};
+
+static struct clk omap3_wkup_l4_iclk = {
+    .name      = "omap3_wkup_l4_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .enabled = 1,
+    .parent    = &omap3_sys_clk, 
+};
+
+static struct clk omap3_gp1_fclk = {
+    .name      = "omap3_gp1_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_gp12_fclk = {
+    .name      = "omap3_gp12_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*SECURE_32K_FCLK -> 32-kHz oscillator */
+};
+
+/*PER Power Domain clock*/
+/*gp2-gp9 timer*/
+static struct clk omap3_gp2_fclk = {
+    .name      = "omap3_gp2_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_gp3_fclk = {
+    .name      = "omap3_gp3_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_gp4_fclk = {
+    .name      = "omap3_gp4_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_gp5_fclk = {
+    .name      = "omap3_gp5_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_gp6_fclk = {
+    .name      = "omap3_gp6_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_gp7_fclk = {
+    .name      = "omap3_gp7_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_gp8_fclk = {
+    .name      = "omap3_gp8_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_gp9_fclk = {
+    .name      = "omap3_gp9_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_32k_fclk,        /*omap3_32k_fclk and omap3_sys_clk*/
+};
+
+static struct clk omap3_per_96m_fclk = {
+    .name      = "omap3_per_96m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_96m_fclk,        
+};
+
+static struct clk omap3_per_48m_fclk = {
+    .name      = "omap3_per_48m_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_48m_fclk,        
+};
+
+static struct clk omap3_per_l4_iclk = {
+    .name      = "omap3_per_l4_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX,
+    .enabled = 1,
+    .parent    = &omap3_l4_iclk, 
+};
+
+/*UART Clocks*/
+static struct clk omap3_uart1_fclk = {
+    .name      = "omap3_uart1_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_48m_fclk,        
+};
+
+static struct clk omap3_uart1_iclk = {
+    .name      = "omap3_uart1_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_l4_iclk,        
+};
+
+static struct clk omap3_uart2_fclk = {
+    .name      = "omap3_uart2_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_48m_fclk,        
+};
+
+static struct clk omap3_uart2_iclk = {
+    .name      = "omap3_uart2_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_l4_iclk,        
+};
+
+static struct clk omap3_uart3_fclk = {
+    .name      = "omap3_uart3_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_48m_fclk,        
+};
+
+static struct clk omap3_uart3_iclk = {
+    .name      = "omap3_uart3_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_l4_iclk,        
+};
+
+/*INTC Clock*/
+static struct clk omap3_mpu_intc_fclk = {
+    .name      = "omap3_mpu_intc_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .divisor = 2,
+    .parent    = &omap3_mpu_clk,        
+};
+
+static struct clk omap3_mpu_intc_iclk = {
+    .name      = "omap3_mpu_intc_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .divisor = 2,
+    .parent    = &omap3_mpu_clk,        
+};
+
+/*SDMA clock*/
+static struct clk omap3_sdma_fclk = {
+    .name      = "omap3_sdma_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_l3_iclk,        
+};
+
+static struct clk omap3_sdma_iclk = {
+    .name      = "omap3_sdma_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_l4_iclk,        
+};
+
+/*CLKOUT*/
+static struct clk omap3_sys_clkout1 = {
+    .name   = "omap3_sys_clkout1",
+    .flags  = CLOCK_IN_OMAP3XXX,
+    .parent = &omap3_osc_sys_clk26, /* same parent as as SYS_CLK */
+};
+
+static struct clk omap3_sys_clkout2 = {
+    .name      = "omap3_sys_clkout2",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_clk,        /*CORE_CLK CM_SYS_CLK CM_96M_FCLK 54 MHz clock*/
+};
+
+/*MMC Clock*/
+static struct clk omap3_mmc1_fclk = {
+    .name      = "omap3_mmc1_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_96m_fclk,       
+};
+
+static struct clk omap3_mmc1_iclk = {
+    .name      = "omap3_mmc1_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_l4_iclk,       
+};
+
+static struct clk omap3_mmc2_fclk = {
+    .name      = "omap3_mmc2_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_96m_fclk,       
+};
+
+static struct clk omap3_mmc2_iclk = {
+    .name      = "omap3_mmc2_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_l4_iclk,       
+};
+
+static struct clk omap3_mmc3_fclk = {
+    .name      = "omap3_mmc3_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_96m_fclk,       
+};
+
+static struct clk omap3_mmc3_iclk = {
+    .name      = "omap3_mmc3_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_l4_iclk,       
+};
+
+/*I2C Clocls*/
+static struct clk omap3_i2c1_fclk = {
+    .name      = "omap3_i2c1_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_96m_fclk,       
+};
+
+static struct clk omap3_i2c1_iclk = {
+    .name      = "omap3_i2c1_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_l4_iclk,       
+};
+
+static struct clk omap3_i2c2_fclk = {
+    .name      = "omap3_i2c2_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_96m_fclk,       
+};
+
+static struct clk omap3_i2c2_iclk = {
+    .name      = "omap3_i2c2_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_l4_iclk,       
+};
+
+static struct clk omap3_i2c3_fclk = {
+    .name      = "omap3_i2c3_fclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_per_96m_fclk,       
+};
+
+static struct clk omap3_i2c3_iclk = {
+    .name      = "omap3_i2c3_iclk",
+    .flags     = CLOCK_IN_OMAP3XXX ,
+    .parent    = &omap3_core_l4_iclk,
+};
+
+/* SPI clocks */
+static struct clk omap3_spi1_fclk = {
+    .name   = "omap3_spi1_fclk",
+    .flags  = CLOCK_IN_OMAP3XXX,
+    .parent = &omap3_core_48m_fclk,
+};
+
+static struct clk omap3_spi1_iclk = {
+    .name   = "omap3_spi1_iclk",
+    .flags  = CLOCK_IN_OMAP3XXX,
+    .parent = &omap3_core_l4_iclk,
+};
+
+static struct clk omap3_spi2_fclk = {
+    .name   = "omap3_spi2_fclk",
+    .flags  = CLOCK_IN_OMAP3XXX,
+    .parent = &omap3_core_48m_fclk,
+};
+
+static struct clk omap3_spi2_iclk = {
+    .name   = "omap3_spi2_iclk",
+    .flags  = CLOCK_IN_OMAP3XXX,
+    .parent = &omap3_core_l4_iclk,
+};
+
+static struct clk omap3_spi3_fclk = {
+    .name   = "omap3_spi3_fclk",
+    .flags  = CLOCK_IN_OMAP3XXX,
+    .parent = &omap3_core_48m_fclk,
+};
+
+static struct clk omap3_spi3_iclk = {
+    .name   = "omap3_spi3_iclk",
+    .flags  = CLOCK_IN_OMAP3XXX,
+    .parent = &omap3_core_l4_iclk,
+};
+
+static struct clk omap3_spi4_fclk = {
+    .name   = "omap3_spi4_fclk",
+    .flags  = CLOCK_IN_OMAP3XXX,
+    .parent = &omap3_core_48m_fclk,
+};
+
+static struct clk omap3_spi4_iclk = {
+    .name   = "omap3_spi4_iclk",
+    .flags  = CLOCK_IN_OMAP3XXX,
+    .parent = &omap3_core_l4_iclk,
+};
+
+
 static struct clk *onchip_clks[] = {
     /* OMAP 1 */
 
@@ -1087,6 +1677,93 @@ static struct clk *onchip_clks[] = {
     &dss_l4_iclk,
     &omapctrl_clk,
 
+    /* OMAP 3*/
+
+    &omap3_sys_32k,
+    &omap3_osc_sys_clk12,
+    &omap3_osc_sys_clk13,
+    &omap3_osc_sys_clk168,
+    &omap3_osc_sys_clk192,
+    &omap3_osc_sys_clk26,
+    &omap3_osc_sys_clk384,
+    &omap3_sys_altclk,
+    &omap3_sys_clk,
+    &omap3_32k_fclk,
+    &omap3_core_clk,
+    &omap3_core2_clk,
+    &omap3_emu_core_alwon_clk,
+    &omap3_mpu_clk,
+    &omap3_iva2_clk,
+    &omap3_96m_fclk,
+    &omap3_54m_fclk,
+    &omap3_dss1_alwon_fclk,
+    &omap3_cam_mclk,
+    &omap3_per_alwon_clk,
+    &omap3_120m_fclk,
+    &omap3_48m_fclk,
+    &omap3_12m_fclk,
+    &omap3_l3x2_iclk,
+    &omap3_l3_iclk,
+    &omap3_l4_iclk,
+    &omap3_rm_iclk,
+    &omap3_gp10_fclk,
+    &omap3_gp11_fclk,
+    &omap3_core_32k_fclk,
+    &omap3_cpefuse_fclk,
+    &omap3_core_120m_fclk,
+    &omap3_core_96m_fclk,
+    &omap3_core_48m_fclk,
+    &omap3_core_12m_fclk,
+    &omap3_core_l3_iclk,
+    &omap3_core_l4_iclk,
+    &omap3_wkup_32k_fclk,
+    &omap3_wkup_l4_iclk,
+    &omap3_gp1_fclk,
+    &omap3_gp12_fclk,
+    &omap3_gp2_fclk,
+    &omap3_gp3_fclk,
+    &omap3_gp4_fclk,
+    &omap3_gp5_fclk,
+    &omap3_gp6_fclk,
+    &omap3_gp7_fclk,
+    &omap3_gp8_fclk,
+    &omap3_gp9_fclk,
+    &omap3_per_96m_fclk,
+    &omap3_per_48m_fclk,
+    &omap3_per_l4_iclk,
+    &omap3_uart1_fclk,
+    &omap3_uart1_iclk,
+    &omap3_uart2_fclk,
+    &omap3_uart2_iclk,
+    &omap3_uart3_fclk,
+    &omap3_uart3_iclk,
+    &omap3_mpu_intc_fclk,
+    &omap3_mpu_intc_iclk,
+    &omap3_sdma_fclk,
+    &omap3_sdma_iclk,
+    &omap3_sys_clkout1,
+    &omap3_sys_clkout2,
+    &omap3_mmc1_fclk,
+    &omap3_mmc1_iclk,
+    &omap3_mmc2_fclk,
+    &omap3_mmc2_iclk,
+    &omap3_mmc3_fclk,
+    &omap3_mmc3_iclk,
+    &omap3_i2c1_fclk,
+    &omap3_i2c1_iclk,
+    &omap3_i2c2_fclk,
+    &omap3_i2c2_iclk,
+    &omap3_i2c3_fclk,
+    &omap3_i2c3_iclk,
+    &omap3_spi1_fclk,
+    &omap3_spi1_iclk,
+    &omap3_spi2_fclk,
+    &omap3_spi2_iclk,
+    &omap3_spi3_fclk,
+    &omap3_spi3_iclk,
+    &omap3_spi4_fclk,
+    &omap3_spi4_iclk,
+
     0
 };
 
@@ -1231,6 +1908,8 @@ void omap_clk_init(struct omap_mpu_state_s *mpu)
         flag = CLOCK_IN_OMAP243X;
     else if (cpu_is_omap3430(mpu))
         flag = CLOCK_IN_OMAP243X;
+    else if (cpu_is_omap3530(mpu))
+        flag = CLOCK_IN_OMAP3XXX;
     else
         return;
 
index 6df3800..0497988 100644 (file)
 #include "omap.h"
 #include "irq.h"
 #include "soc_dma.h"
+#include "hw.h"
+
+//#define OMAP_DMA_DEBUG
+
+#ifdef OMAP_DMA_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s:" fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
 
 struct omap_dma_channel_s {
     /* transfer data */
@@ -248,7 +257,7 @@ static void omap_dma_deactivate_channel(struct omap_dma_s *s,
 
     /* Don't deactive the channel if it is synchronized and the DMA request is
        active */
-    if (ch->sync && ch->enable && (s->dma->drqbmp & (1 << ch->sync)))
+    if (ch->sync && ch->enable && s->dma->drqst[ch->sync])
         return;
 
     if (ch->active) {
@@ -266,9 +275,9 @@ static void omap_dma_enable_channel(struct omap_dma_s *s,
         ch->waiting_end_prog = 0;
         omap_dma_channel_load(ch);
         /* TODO: theoretically if ch->sync && ch->prefetch &&
-         * !s->dma->drqbmp[ch->sync], we should also activate and fetch
+         * !s->dma->drqst[ch->sync], we should also activate and fetch
          * from source and then stall until signalled.  */
-        if ((!ch->sync) || (s->dma->drqbmp & (1 << ch->sync)))
+        if ((!ch->sync) || s->dma->drqst[ch->sync])
             omap_dma_activate_channel(s, ch);
     }
 }
@@ -374,6 +383,7 @@ static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma)
     uint16_t status = ch->status;
 #endif
 
+    TRACE("frame %d", a->frame);
     do {
         /* Transfer a single element */
         /* FIXME: check the endianness */
@@ -1544,12 +1554,12 @@ static void omap_dma_request(void *opaque, int drq, int req)
     struct omap_dma_s *s = (struct omap_dma_s *) opaque;
     /* The request pins are level triggered in QEMU.  */
     if (req) {
-        if (~s->dma->drqbmp & (1 << drq)) {
-            s->dma->drqbmp |= 1 << drq;
+        if (!s->dma->drqst[drq]) {
+            s->dma->drqst[drq] = 1;
             omap_dma_process_request(s, drq);
         }
     } else
-        s->dma->drqbmp &= ~(1 << drq);
+        s->dma->drqst[drq] = 0;
 }
 
 /* XXX: this won't be needed once soc_dma knows about clocks.  */
@@ -1670,7 +1680,7 @@ static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
     uint32_t bmp, bit;
 
     for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
-        if (ch->status) {
+        if ((ch->status &= ch->interrupts)) {
             bmp |= bit;
             ch->cstatus |= ch->status;
             ch->status = 0;
@@ -1768,6 +1778,7 @@ static uint32_t omap_dma4_read(void *opaque, target_phys_addr_t addr)
         return ch->interrupts;
 
     case 0x0c: /* DMA4_CSR */
+        TRACE("CSR = %04x", ch->cstatus);
         return ch->cstatus;
 
     case 0x10: /* DMA4_CSDP */
@@ -1825,7 +1836,7 @@ static uint32_t omap_dma4_read(void *opaque, target_phys_addr_t addr)
         return ch->color;
 
     default:
-        OMAP_BAD_REG(addr);
+        OMAP_BAD_REG(0x80 + chnum * 0x60 + addr);
         return 0;
     }
 }
@@ -1931,11 +1942,16 @@ static void omap_dma4_write(void *opaque, target_phys_addr_t addr,
         break;
 
     case 0x08: /* DMA4_CICR */
-        ch->interrupts = value & 0x09be;
+        if (cpu_class_omap3(s->mpu))
+            ch->interrupts = value & 0x1dbe;
+        else
+            ch->interrupts = value & 0x09be;
+        TRACE("CICR = 0x%04x", ch->interrupts);
         break;
 
     case 0x0c: /* DMA4_CSR */
         ch->cstatus &= ~value;
+        TRACE("CSR = 0x%04x --> 0x%04x", value, ch->cstatus);
         break;
 
     case 0x10: /* DMA4_CSDP */
@@ -1964,11 +1980,15 @@ static void omap_dma4_write(void *opaque, target_phys_addr_t addr,
     case 0x14: /* DMA4_CEN */
         ch->set_update = 1;
         ch->elements = value & 0xffffff;
+        TRACE("elements=%d, frames=%d, data=%d bytes",
+              ch->elements, ch->frames, ch->data_type);
         break;
 
     case 0x18: /* DMA4_CFN */
         ch->frames = value & 0xffff;
         ch->set_update = 1;
+        TRACE("elements=%d, frames=%d, data=%d bytes",
+              ch->elements, ch->frames, ch->data_type);
         break;
 
     case 0x1c: /* DMA4_CSSA */
@@ -2010,11 +2030,14 @@ static void omap_dma4_write(void *opaque, target_phys_addr_t addr,
     case 0x38: /* DMA4_CDAC */
     case 0x3c: /* DMA4_CCEN */
     case 0x40: /* DMA4_CCFN */
-        OMAP_RO_REG(addr);
+        /* f.ex. linux kernel writes zeroes to these registers as well
+           when performing a DMA channel reset. let's just ignore the
+           writes instead of reporting "dummy" errors */
+        /*OMAP_RO_REG(0x80 + chnum * 0x60 + addr);*/
         break;
 
     default:
-        OMAP_BAD_REG(addr);
+        OMAP_BAD_REG(0x80 + chnum * 0x60 + addr);
     }
 }
 
@@ -2030,44 +2053,249 @@ static CPUWriteMemoryFunc *omap_dma4_writefn[] = {
     omap_dma4_write,
 };
 
-struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
-                struct omap_mpu_state_s *mpu, int fifo,
-                int chans, omap_clk iclk, omap_clk fclk)
+static void omap_dma4_save_state(QEMUFile *f, void *opaque)
 {
-    int iomemtype, i;
-    struct omap_dma_s *s = (struct omap_dma_s *)
-            qemu_mallocz(sizeof(struct omap_dma_s));
+    struct omap_dma_s *s = (struct omap_dma_s *)opaque;
+    int i, j;
+        
+    qemu_put_be32(f, s->gcr);
+    qemu_put_be32(f, s->ocp);
+    for (i = 0; i < 5; i++) {
+        qemu_put_be32(f, s->caps[i]);
+        if (i < 4) {
+            qemu_put_be32(f, s->irqen[i]);
+            qemu_put_be32(f, s->irqstat[i]);
+        }
+    }
+    for (i = 0; i < 32; i++) {
+        qemu_put_be32(f, s->ch[i].elements);
+        qemu_put_be16(f, s->ch[i].frames);
+        qemu_put_sbe32(f, s->ch[i].data_type);
+        for (j = 0; j < 2; j++) {
+            qemu_put_sbe32(f, s->ch[i].burst[j]);
+            qemu_put_sbe32(f, s->ch[i].pack[j]);
+            qemu_put_sbe32(f, s->ch[i].endian[j]);
+            qemu_put_sbe32(f, s->ch[i].endian_lock[j]);
+            qemu_put_sbe32(f, s->ch[i].translate[j]);
+            qemu_put_sbe32(f, s->ch[i].port[j]);
+#if TARGET_PHYS_ADDR_BITS == 32
+            qemu_put_be32(f, s->ch[i].addr[j]);
+#elif TARGET_PHYS_ADDR_BITS == 64
+            qemu_put_be64(f, s->ch[i].addr[j]);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+            qemu_put_sbe32(f, s->ch[i].mode[j]);
+            qemu_put_sbe32(f, s->ch[i].frame_index[j]);
+            qemu_put_sbe16(f, s->ch[i].element_index[j]);
+        }
+        qemu_put_sbe32(f, s->ch[i].transparent_copy);
+        qemu_put_sbe32(f, s->ch[i].constant_fill);
+        qemu_put_be32(f, s->ch[i].color);
+        qemu_put_sbe32(f, s->ch[i].prefetch);
+        qemu_put_sbe32(f, s->ch[i].end_prog);
+        qemu_put_sbe32(f, s->ch[i].repeat);
+        qemu_put_sbe32(f, s->ch[i].auto_init);
+        qemu_put_sbe32(f, s->ch[i].link_enabled);
+        qemu_put_sbe32(f, s->ch[i].link_next_ch);
+        qemu_put_sbe32(f, s->ch[i].interrupts);
+        qemu_put_sbe32(f, s->ch[i].status);
+        qemu_put_sbe32(f, s->ch[i].cstatus);
+        qemu_put_sbe32(f, s->ch[i].active);
+        qemu_put_sbe32(f, s->ch[i].enable);
+        qemu_put_sbe32(f, s->ch[i].sync);
+        qemu_put_sbe32(f, s->ch[i].src_sync);
+        qemu_put_sbe32(f, s->ch[i].pending_request);
+        qemu_put_sbe32(f, s->ch[i].waiting_end_prog);
+        qemu_put_be16(f, s->ch[i].cpc);
+        qemu_put_sbe32(f, s->ch[i].set_update);
+        qemu_put_sbe32(f, s->ch[i].fs);
+        qemu_put_sbe32(f, s->ch[i].bs);
+        qemu_put_sbe32(f, s->ch[i].omap_3_1_compatible_disable);
+#if TARGET_PHYS_ADDR_BITS == 32
+        qemu_put_be32(f, s->ch[i].active_set.src);
+        qemu_put_be32(f, s->ch[i].active_set.dest);
+#elif TARGET_PHYS_ADDR_BITS == 64
+        qemu_put_be64(f, s->ch[i].active_set.src);
+        qemu_put_be64(f, s->ch[i].active_set.dest);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+        qemu_put_sbe32(f, s->ch[i].active_set.frame);
+        qemu_put_sbe32(f, s->ch[i].active_set.element);
+        qemu_put_sbe32(f, s->ch[i].active_set.pck_element);
+        qemu_put_sbe32(f, s->ch[i].active_set.frame_delta[0]);
+        qemu_put_sbe32(f, s->ch[i].active_set.frame_delta[1]);
+        qemu_put_sbe32(f, s->ch[i].active_set.elem_delta[0]);
+        qemu_put_sbe32(f, s->ch[i].active_set.elem_delta[1]);
+        qemu_put_sbe32(f, s->ch[i].active_set.frames);
+        qemu_put_sbe32(f, s->ch[i].active_set.elements);
+        qemu_put_sbe32(f, s->ch[i].active_set.pck_elements);
+        qemu_put_sbe32(f, s->ch[i].write_mode);
+        qemu_put_sbe32(f, s->ch[i].priority);
+        qemu_put_sbe32(f, s->ch[i].interleave_disabled);
+        qemu_put_sbe32(f, s->ch[i].type);
+        qemu_put_sbe32(f, s->ch[i].suspend);
+        qemu_put_sbe32(f, s->ch[i].buf_disable);
+    }
+}
+
+static int omap_dma4_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *)opaque;
+    int i, j;
+
+    if (version_id)
+        return -EINVAL;
+
+    s->gcr = qemu_get_be32(f);
+    s->ocp = qemu_get_be32(f);
+    for (i = 0; i < 5; i++) {
+        s->caps[i] = qemu_get_be32(f);
+        if (i < 4) {
+            s->irqen[i] = qemu_get_be32(f);
+            s->irqstat[i] = qemu_get_be32(f);
+        }
+    }
+    for (i = 0; i < 32; i++) {
+        s->ch[i].elements = qemu_get_be32(f);
+        s->ch[i].frames = qemu_get_be16(f);
+        s->ch[i].data_type = qemu_get_sbe32(f);
+        for (j = 0; j < 2; j++) {
+            s->ch[i].burst[j] = qemu_get_sbe32(f);
+            s->ch[i].pack[j] = qemu_get_sbe32(f);
+            s->ch[i].endian[j] = qemu_get_sbe32(f);
+            s->ch[i].endian_lock[j] = qemu_get_sbe32(f);
+            s->ch[i].translate[j] = qemu_get_sbe32(f);
+            s->ch[i].port[j] = qemu_get_sbe32(f);
+#if TARGET_PHYS_ADDR_BITS == 32
+            s->ch[i].addr[j] = qemu_get_be32(f);
+#elif TARGET_PHYS_ADDR_BITS == 64
+            s->ch[i].addr[j] = qemu_get_be64(f);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+            s->ch[i].mode[j] = qemu_get_sbe32(f);
+            s->ch[i].frame_index[j] = qemu_get_sbe32(f);
+            s->ch[i].element_index[j] = qemu_get_sbe16(f);
+        }
+        s->ch[i].transparent_copy = qemu_get_sbe32(f);
+        s->ch[i].constant_fill = qemu_get_sbe32(f);
+        s->ch[i].color = qemu_get_be32(f);
+        s->ch[i].prefetch = qemu_get_sbe32(f);
+        s->ch[i].end_prog = qemu_get_sbe32(f);
+        s->ch[i].repeat = qemu_get_sbe32(f);
+        s->ch[i].auto_init = qemu_get_sbe32(f);
+        s->ch[i].link_enabled = qemu_get_sbe32(f);
+        s->ch[i].link_next_ch = qemu_get_sbe32(f);
+        s->ch[i].interrupts = qemu_get_sbe32(f);
+        s->ch[i].status = qemu_get_sbe32(f);
+        s->ch[i].cstatus = qemu_get_sbe32(f);
+        s->ch[i].active = qemu_get_sbe32(f);
+        s->ch[i].enable = qemu_get_sbe32(f);
+        s->ch[i].sync = qemu_get_sbe32(f);
+        s->ch[i].src_sync = qemu_get_sbe32(f);
+        s->ch[i].pending_request = qemu_get_sbe32(f);
+        s->ch[i].waiting_end_prog = qemu_get_sbe32(f);
+        s->ch[i].cpc = qemu_get_be16(f);
+        s->ch[i].set_update = qemu_get_sbe32(f);
+        s->ch[i].fs = qemu_get_sbe32(f);
+        s->ch[i].bs = qemu_get_sbe32(f);
+        s->ch[i].omap_3_1_compatible_disable = qemu_get_sbe32(f);
+#if TARGET_PHYS_ADDR_BITS == 32
+        s->ch[i].active_set.src = qemu_get_be32(f);
+        s->ch[i].active_set.dest = qemu_get_be32(f);
+#elif TARGET_PHYS_ADDR_BITS == 64
+        s->ch[i].active_set.src = qemu_get_be64(f);
+        s->ch[i].active_set.dest = qemu_get_be64(f);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+        s->ch[i].active_set.frame = qemu_get_sbe32(f);
+        s->ch[i].active_set.element = qemu_get_sbe32(f);
+        s->ch[i].active_set.pck_element = qemu_get_sbe32(f);
+        s->ch[i].active_set.frame_delta[0] = qemu_get_sbe32(f);
+        s->ch[i].active_set.frame_delta[1] = qemu_get_sbe32(f);
+        s->ch[i].active_set.elem_delta[0] = qemu_get_sbe32(f);
+        s->ch[i].active_set.elem_delta[1] = qemu_get_sbe32(f);
+        s->ch[i].active_set.frames = qemu_get_sbe32(f);
+        s->ch[i].active_set.elements = qemu_get_sbe32(f);
+        s->ch[i].active_set.pck_elements = qemu_get_sbe32(f);
+        s->ch[i].write_mode = qemu_get_sbe32(f);
+        s->ch[i].priority = qemu_get_sbe32(f);
+        s->ch[i].interleave_disabled = qemu_get_sbe32(f);
+        s->ch[i].type = qemu_get_sbe32(f);
+        s->ch[i].suspend = qemu_get_sbe32(f);
+        s->ch[i].buf_disable = qemu_get_sbe32(f);
+    }
+    
+    return 0;
+}
 
+static struct omap_dma_s *omap_dma4_init_internal(struct omap_mpu_state_s *mpu,
+                                                  qemu_irq *irqs,
+                                                  int chans, int drq_count,
+                                                  omap_clk iclk, omap_clk fclk)
+{
+    int i;
+    struct omap_dma_s *s = (struct omap_dma_s *)
+        qemu_mallocz(sizeof(struct omap_dma_s));
+    
     s->model = omap_dma_4;
     s->chans = chans;
     s->mpu = mpu;
     s->clk = fclk;
-
+    
     s->dma = soc_dma_init(s->chans);
     s->dma->freq = omap_clk_getrate(fclk);
     s->dma->transfer_fn = omap_dma_transfer_generic;
     s->dma->setup_fn = omap_dma_transfer_setup;
-    s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
+    s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, drq_count);
     s->dma->opaque = s;
     for (i = 0; i < s->chans; i ++) {
         s->ch[i].dma = &s->dma->ch[i];
         s->dma->ch[i].opaque = &s->ch[i];
     }
-
+    
     memcpy(&s->irq, irqs, sizeof(s->irq));
     s->intr_update = omap_dma_interrupts_4_update;
-
+    
     omap_dma_setcaps(s);
     omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
     omap_dma_reset(s->dma);
     omap_dma_clk_update(s, 0, !!s->dma->freq);
 
+    mpu->drq = s->dma->drq;
+    
+    register_savevm("omap_dma4", -1, 0,
+                    omap_dma4_save_state, omap_dma4_load_state, s);
+    return s;
+}
+    
+struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
+                struct omap_mpu_state_s *mpu, int fifo,
+                int chans, omap_clk iclk, omap_clk fclk)
+{
+    int iomemtype;
+    struct omap_dma_s *s = omap_dma4_init_internal(mpu, irqs, chans, 64,
+                                                   iclk, fclk);
+
     iomemtype = cpu_register_io_memory(0, omap_dma4_readfn,
                     omap_dma4_writefn, s);
     cpu_register_physical_memory(base, 0x1000, iomemtype);
+    
+    return s->dma;
+}
 
-    mpu->drq = s->dma->drq;
-
+struct soc_dma_s *omap3_dma4_init(struct omap_target_agent_s *ta,
+                                  struct omap_mpu_state_s *mpu,
+                                  qemu_irq *irqs, int chans,
+                                  omap_clk iclk, omap_clk fclk)
+{
+    struct omap_dma_s *s = omap_dma4_init_internal(mpu, irqs, chans, 96,
+                                                   iclk, fclk);
+    omap_l4_attach(ta, 0, cpu_register_io_memory(0, omap_dma4_readfn,
+                                                 omap_dma4_writefn, s));
     return s->dma;
 }
 
index 67b2b02..0ddd403 100644 (file)
 #include "hw.h"
 #include "console.h"
 #include "omap.h"
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "vga_int.h"
+#include "pixel_ops.h"
+
+#define OMAP_DSS_DEBUG
+//#define OMAP_DSS_DEBUG_REG
+
+#ifdef OMAP_DSS_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+#ifdef OMAP_DSS_DEBUG_REG
+#define TRACEREG(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#define LAYERNAME(n) ((!(n)) ? "GFX" : ((n)==1) ? "VID1" : "VID2")
+#else
+#define TRACEREG(...)
+#endif
+
+struct omap3_lcd_panel_s {
+    struct omap_dss_s *dss;
+    DisplayState *state;
+    omap3_lcd_panel_fn_t *line_fn_tab[2];
+    omap3_lcd_panel_fn_t line_fn;
+    uint32_t invalidate;
+};
 
 struct omap_dss_s {
     qemu_irq irq;
@@ -29,6 +58,8 @@ struct omap_dss_s {
 
     int autoidle;
     int control;
+    uint32_t sdi_control;
+    uint32_t pll_control;
     int enable;
 
     struct omap_dss_panel_s {
@@ -39,8 +70,10 @@ struct omap_dss_s {
         int x;
         int y;
     } dig, lcd;
+    struct omap3_lcd_panel_s *omap_lcd_panel[2];
 
     struct {
+        uint8_t rev;
         uint32_t idlemode;
         uint32_t irqst;
         uint32_t irqen;
@@ -51,7 +84,11 @@ struct omap_dss_s {
         int line;
         uint32_t bg[2];
         uint32_t trans[2];
-
+        uint32_t global_alpha;
+        uint32_t cpr_coef_r;
+        uint32_t cpr_coef_g;
+        uint32_t cpr_coef_b;
+        
         struct omap_dss_plane_s {
             int enable;
             int bpp;
@@ -60,6 +97,10 @@ struct omap_dss_s {
             int nx;
             int ny;
 
+            int rotation_flag;
+            int gfx_format;
+            int gfx_channel;
+            
             target_phys_addr_t addr[3];
 
             uint32_t attr;
@@ -67,8 +108,19 @@ struct omap_dss_s {
             int rowinc;
             int colinc;
             int wininc;
+            
+            uint32_t preload;
+            
+            /* following for l1 & l2 only (VID1 and VID2) */
+            uint32_t fir;
+            uint32_t fir_coef_h[8];
+            uint32_t fir_coef_hv[8];
+            uint32_t fir_coef_v[8];
+            uint32_t conv_coef[5];
+            uint32_t picture_size;
+            uint32_t accu[2];
         } l[3];
-
+        
         int invalidate;
         uint16_t palette[256];
     } dispc;
@@ -88,11 +140,229 @@ struct omap_dss_s {
         uint16_t hsync;
         struct rfbi_chip_s *chip[2];
     } rfbi;
+    
+    struct {
+        uint32_t irqst;
+        uint32_t irqen;
+    } dsi;
 };
 
-static void omap_dispc_interrupt_update(struct omap_dss_s *s)
+static void omap_dss_interrupt_update(struct omap_dss_s *s)
+{
+    qemu_set_irq(s->irq, 
+                 (s->dsi.irqst & s->dsi.irqen)
+                 | (s->dispc.irqst & s->dispc.irqen));
+}
+
+static void omap_dss_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *)opaque;
+    int i, j;
+    
+    qemu_put_sbe32(f, s->autoidle);
+    qemu_put_sbe32(f, s->control);
+    qemu_put_be32(f, s->sdi_control);
+    qemu_put_be32(f, s->pll_control);
+    qemu_put_sbe32(f, s->enable);
+    qemu_put_sbe32(f, s->dig.enable);
+    qemu_put_sbe32(f, s->dig.nx);
+    qemu_put_sbe32(f, s->dig.ny);
+    qemu_put_sbe32(f, s->dig.x);
+    qemu_put_sbe32(f, s->dig.y);
+    qemu_put_sbe32(f, s->lcd.enable);
+    qemu_put_sbe32(f, s->lcd.nx);
+    qemu_put_sbe32(f, s->lcd.ny);
+    qemu_put_sbe32(f, s->lcd.x);
+    qemu_put_sbe32(f, s->lcd.y);
+    qemu_put_be32(f, s->dispc.idlemode);
+    qemu_put_be32(f, s->dispc.irqst);
+    qemu_put_be32(f, s->dispc.irqen);
+    qemu_put_be32(f, s->dispc.control);
+    qemu_put_be32(f, s->dispc.config);
+    qemu_put_be32(f, s->dispc.capable);
+    qemu_put_be32(f, s->dispc.timing[0]);
+    qemu_put_be32(f, s->dispc.timing[1]);
+    qemu_put_be32(f, s->dispc.timing[2]);
+    qemu_put_be32(f, s->dispc.timing[3]);
+    qemu_put_sbe32(f, s->dispc.line);
+    qemu_put_be32(f, s->dispc.bg[0]);
+    qemu_put_be32(f, s->dispc.bg[1]);
+    qemu_put_be32(f, s->dispc.trans[0]);
+    qemu_put_be32(f, s->dispc.trans[1]);
+    qemu_put_be32(f, s->dispc.global_alpha);
+    qemu_put_be32(f, s->dispc.cpr_coef_r);
+    qemu_put_be32(f, s->dispc.cpr_coef_g);
+    qemu_put_be32(f, s->dispc.cpr_coef_b);
+    for (i = 0; i < 3; i++) {
+        qemu_put_sbe32(f, s->dispc.l[i].enable);
+        qemu_put_sbe32(f, s->dispc.l[i].bpp);
+        qemu_put_sbe32(f, s->dispc.l[i].posx);
+        qemu_put_sbe32(f, s->dispc.l[i].posy);
+        qemu_put_sbe32(f, s->dispc.l[i].nx);
+        qemu_put_sbe32(f, s->dispc.l[i].ny);
+        qemu_put_sbe32(f, s->dispc.l[i].rotation_flag);
+        qemu_put_sbe32(f, s->dispc.l[i].gfx_format);
+        qemu_put_sbe32(f, s->dispc.l[i].gfx_channel);
+        for (j = 0; j < 3; j++) {
+#if TARGET_PHYS_ADDR_BITS == 32
+            qemu_put_be32(f, s->dispc.l[i].addr[j]);
+#elif TARGET_PHYS_ADDR_BITS == 64
+            qemu_put_be64(f, s->dispc.l[i].addr[j]);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+        }
+        qemu_put_be32(f, s->dispc.l[i].attr);
+        qemu_put_be32(f, s->dispc.l[i].tresh);
+        qemu_put_sbe32(f, s->dispc.l[i].rowinc);
+        qemu_put_sbe32(f, s->dispc.l[i].colinc);
+        qemu_put_sbe32(f, s->dispc.l[i].wininc);
+        qemu_put_be32(f, s->dispc.l[i].preload);
+        qemu_put_be32(f, s->dispc.l[i].fir);
+        for (j = 0; j < 8; j++) {
+            qemu_put_be32(f, s->dispc.l[i].fir_coef_h[j]);
+            qemu_put_be32(f, s->dispc.l[i].fir_coef_hv[j]);
+            qemu_put_be32(f, s->dispc.l[i].fir_coef_v[j]);
+            if (j < 5)
+                qemu_put_be32(f, s->dispc.l[i].conv_coef[j]);
+        }
+        qemu_put_be32(f, s->dispc.l[i].picture_size);
+        qemu_put_be32(f, s->dispc.l[i].accu[0]);
+        qemu_put_be32(f, s->dispc.l[i].accu[1]);
+    }
+    qemu_put_sbe32(f, s->dispc.invalidate);
+    for (i = 0; i < 256; i++)
+        qemu_put_be16(f, s->dispc.palette[i]);
+    qemu_put_sbe32(f, s->rfbi.idlemode);
+    qemu_put_be32(f, s->rfbi.control);
+    qemu_put_sbe32(f, s->rfbi.enable);
+    qemu_put_sbe32(f, s->rfbi.pixels);
+    qemu_put_sbe32(f, s->rfbi.busy);
+    qemu_put_sbe32(f, s->rfbi.skiplines);
+    qemu_put_be16(f, s->rfbi.rxbuf);
+    for (i = 0; i < 6; i++) {
+        if (i < 2)
+            qemu_put_be32(f, s->rfbi.config[i]);
+        if (i < 4)
+            qemu_put_be32(f, s->rfbi.time[i]);
+        qemu_put_be32(f, s->rfbi.data[i]);
+    }
+    qemu_put_be16(f, s->rfbi.vsync);
+    qemu_put_be16(f, s->rfbi.hsync);
+    qemu_put_be32(f, s->dsi.irqst);
+    qemu_put_be32(f, s->dsi.irqen);
+}
+
+static int omap_dss_load_state(QEMUFile *f, void *opaque, int version_id)
 {
-    qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
+    struct omap_dss_s *s = (struct omap_dss_s *)opaque;
+    int i, j;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->autoidle = qemu_get_sbe32(f);
+    s->control = qemu_get_sbe32(f);
+    s->sdi_control = qemu_get_be32(f);
+    s->pll_control = qemu_get_be32(f);
+    s->enable = qemu_get_sbe32(f);
+    s->dig.enable = qemu_get_sbe32(f);
+    s->dig.nx = qemu_get_sbe32(f);
+    s->dig.ny = qemu_get_sbe32(f);
+    s->dig.x = qemu_get_sbe32(f);
+    s->dig.y = qemu_get_sbe32(f);
+    s->lcd.enable = qemu_get_sbe32(f);
+    s->lcd.nx = qemu_get_sbe32(f);
+    s->lcd.ny = qemu_get_sbe32(f);
+    s->lcd.x = qemu_get_sbe32(f);
+    s->lcd.y = qemu_get_sbe32(f);
+    s->dispc.idlemode = qemu_get_be32(f);
+    s->dispc.irqst = qemu_get_be32(f);
+    s->dispc.irqen = qemu_get_be32(f);
+    s->dispc.control = qemu_get_be32(f);
+    s->dispc.config = qemu_get_be32(f);
+    s->dispc.capable = qemu_get_be32(f);
+    s->dispc.timing[0] = qemu_get_be32(f);
+    s->dispc.timing[1] = qemu_get_be32(f);
+    s->dispc.timing[2] = qemu_get_be32(f);
+    s->dispc.timing[3] = qemu_get_be32(f);
+    s->dispc.line = qemu_get_sbe32(f);
+    s->dispc.bg[0] = qemu_get_be32(f);
+    s->dispc.bg[1] = qemu_get_be32(f);
+    s->dispc.trans[0] = qemu_get_be32(f);
+    s->dispc.trans[1] = qemu_get_be32(f);
+    s->dispc.global_alpha = qemu_get_be32(f);
+    s->dispc.cpr_coef_r = qemu_get_be32(f);
+    s->dispc.cpr_coef_g = qemu_get_be32(f);
+    s->dispc.cpr_coef_b = qemu_get_be32(f);
+    for (i = 0; i < 3; i++) {
+        s->dispc.l[i].enable = qemu_get_sbe32(f);
+        s->dispc.l[i].bpp = qemu_get_sbe32(f);
+        s->dispc.l[i].posx = qemu_get_sbe32(f);
+        s->dispc.l[i].posy = qemu_get_sbe32(f);
+        s->dispc.l[i].nx = qemu_get_sbe32(f);
+        s->dispc.l[i].ny = qemu_get_sbe32(f);
+        s->dispc.l[i].rotation_flag = qemu_get_sbe32(f);
+        s->dispc.l[i].gfx_format = qemu_get_sbe32(f);
+        s->dispc.l[i].gfx_channel = qemu_get_sbe32(f);
+        for (j = 0; j < 3; j++) {
+#if TARGET_PHYS_ADDR_BITS == 32
+            s->dispc.l[i].addr[j] = qemu_get_be32(f);
+#elif TARGET_PHYS_ADDR_BITS == 64
+            s->dispc.l[i].addr[j] = qemu_get_be64(f);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+        }
+        s->dispc.l[i].attr = qemu_get_be32(f);
+        s->dispc.l[i].tresh = qemu_get_be32(f);
+        s->dispc.l[i].rowinc = qemu_get_sbe32(f);
+        s->dispc.l[i].colinc = qemu_get_sbe32(f);
+        s->dispc.l[i].wininc = qemu_get_sbe32(f);
+        s->dispc.l[i].preload = qemu_get_be32(f);
+        s->dispc.l[i].fir = qemu_get_be32(f);
+        for (j = 0; j < 8; j++) {
+            s->dispc.l[i].fir_coef_h[j] = qemu_get_be32(f);
+            s->dispc.l[i].fir_coef_hv[j] = qemu_get_be32(f);
+            s->dispc.l[i].fir_coef_v[j] = qemu_get_be32(f);
+            if (j < 5)
+                s->dispc.l[i].conv_coef[j] = qemu_get_be32(f);
+        }
+        s->dispc.l[i].picture_size = qemu_get_be32(f);
+        s->dispc.l[i].accu[0] = qemu_get_be32(f);
+        s->dispc.l[i].accu[1] = qemu_get_be32(f);
+    }
+    s->dispc.invalidate = qemu_get_sbe32(f);
+    for (i = 0; i < 256; i++)
+        s->dispc.palette[i] = qemu_get_be16(f);
+    s->rfbi.idlemode = qemu_get_sbe32(f);
+    s->rfbi.control = qemu_get_be32(f);
+    s->rfbi.enable = qemu_get_sbe32(f);
+    s->rfbi.pixels = qemu_get_sbe32(f);
+    s->rfbi.busy = qemu_get_sbe32(f);
+    s->rfbi.skiplines = qemu_get_sbe32(f);
+    s->rfbi.rxbuf = qemu_get_be16(f);
+    for (i = 0; i < 6; i++) {
+        if (i < 2)
+            s->rfbi.config[i] = qemu_get_be32(f);
+        if (i < 4)
+            s->rfbi.time[i] = qemu_get_be32(f);
+        s->rfbi.data[i] = qemu_get_be32(f);
+    }
+    s->rfbi.vsync = qemu_get_be16(f);
+    s->rfbi.hsync = qemu_get_be16(f);
+    s->dsi.irqst = qemu_get_be32(f);
+    s->dsi.irqen = qemu_get_be32(f);
+    
+    s->dispc.invalidate = 1; /* force refresh of display parameters */
+    if (s->omap_lcd_panel[0])
+        s->omap_lcd_panel[0]->invalidate = 1;
+    if (s->omap_lcd_panel[1])
+        s->omap_lcd_panel[1]->invalidate = 1;
+    
+    omap_dss_interrupt_update(s);
+
+    return 0;
 }
 
 static void omap_rfbi_reset(struct omap_dss_s *s)
@@ -121,8 +391,12 @@ static void omap_rfbi_reset(struct omap_dss_s *s)
 
 void omap_dss_reset(struct omap_dss_s *s)
 {
-    s->autoidle = 0;
+    int i, j;
+    
+    s->autoidle = 0x10; /* was 0 for OMAP2 but bit4 must be set for OMAP3 */
     s->control = 0;
+    s->sdi_control = 0;
+    s->pll_control = 0;
     s->enable = 0;
 
     s->dig.enable = 0;
@@ -142,56 +416,100 @@ void omap_dss_reset(struct omap_dss_s *s)
     s->dispc.timing[0] = 0;
     s->dispc.timing[1] = 0;
     s->dispc.timing[2] = 0;
-    s->dispc.timing[3] = 0;
+    s->dispc.timing[3] = 0x00010002;
     s->dispc.line = 0;
     s->dispc.bg[0] = 0;
     s->dispc.bg[1] = 0;
     s->dispc.trans[0] = 0;
     s->dispc.trans[1] = 0;
-
-    s->dispc.l[0].enable = 0;
-    s->dispc.l[0].bpp = 0;
-    s->dispc.l[0].addr[0] = 0;
-    s->dispc.l[0].addr[1] = 0;
-    s->dispc.l[0].addr[2] = 0;
-    s->dispc.l[0].posx = 0;
-    s->dispc.l[0].posy = 0;
-    s->dispc.l[0].nx = 1;
-    s->dispc.l[0].ny = 1;
-    s->dispc.l[0].attr = 0;
-    s->dispc.l[0].tresh = 0;
-    s->dispc.l[0].rowinc = 1;
-    s->dispc.l[0].colinc = 1;
-    s->dispc.l[0].wininc = 0;
-
+    s->dispc.global_alpha = 0;
+    s->dispc.cpr_coef_r = 0;
+    s->dispc.cpr_coef_g = 0;
+    s->dispc.cpr_coef_b = 0;
+
+    for (i = 0; i < 3; i++) {
+        s->dispc.l[i].enable = 0;
+        s->dispc.l[i].bpp = 0;
+        s->dispc.l[i].addr[0] = 0;
+        s->dispc.l[i].addr[1] = 0;
+        s->dispc.l[i].addr[2] = 0;
+        s->dispc.l[i].posx = 0;
+        s->dispc.l[i].posy = 0;
+        s->dispc.l[i].nx = 1;
+        s->dispc.l[i].ny = 1;
+        s->dispc.l[i].attr = 0;
+        s->dispc.l[i].tresh = (s->dispc.rev < 0x30) ? 0 : 0x03ff03c0;
+        s->dispc.l[i].rowinc = 1;
+        s->dispc.l[i].colinc = 1;
+        s->dispc.l[i].wininc = 0;
+        s->dispc.l[i].preload = 0x100;
+        s->dispc.l[i].fir = 0;
+        s->dispc.l[i].picture_size = 0;
+        s->dispc.l[i].accu[0] = 0;
+        s->dispc.l[i].accu[1] = 0;
+        for (j = 0; j < 5; j++)
+            s->dispc.l[i].conv_coef[j] = 0;
+        for (j = 0; j < 8; j++) {
+            s->dispc.l[i].fir_coef_h[j] = 0;
+            s->dispc.l[i].fir_coef_hv[j] = 0;
+            s->dispc.l[i].fir_coef_v[j] = 0;
+        }
+    }
+        
+    s->dsi.irqst = 0;
+    s->dsi.irqen = 0;
+    
     omap_rfbi_reset(s);
-    omap_dispc_interrupt_update(s);
+    omap_dss_interrupt_update(s);
 }
 
 static uint32_t omap_diss_read(void *opaque, target_phys_addr_t addr)
 {
     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
 
+
     switch (addr) {
     case 0x00: /* DSS_REVISIONNUMBER */
+        TRACEREG("DSS_REVISIONNUMBER: 0x20");
         return 0x20;
 
     case 0x10: /* DSS_SYSCONFIG */
+        TRACEREG("DSS_SYSCONFIG: 0x%08x", s->autoidle);
         return s->autoidle;
 
     case 0x14: /* DSS_SYSSTATUS */
+        TRACEREG("DSS_SYSSTATUS: 0x1");
         return 1;                                              /* RESETDONE */
-
+            
+    case 0x18:  /* DSS_IRQSTATUS */
+        TRACEREG("DSS_IRQSTATUS: 0x%08x",
+                 ((s->dsi.irqst & s->dsi.irqen) ? 2 : 0) 
+                 | ((s->dispc.irqst & s->dispc.irqen) ? 1 : 0));
+        return ((s->dsi.irqst & s->dsi.irqen) ? 2 : 0) 
+            | ((s->dispc.irqst & s->dispc.irqen) ? 1 : 0);
+            
     case 0x40: /* DSS_CONTROL */
+        TRACEREG("DSS_CONTROL: 0x%08x", s->control);
         return s->control;
 
+    case 0x44:  /* DSS_SDI_CONTROL */
+        TRACEREG("DSS_SDI_CONTROL: 0x%08x", s->sdi_control);
+        return s->sdi_control;
+            
+    case 0x48: /* DSS_PLL_CONTROL */
+        TRACEREG("DSS_PLL_CONTROL: 0x%08x", s->pll_control);
+        return s->pll_control;
+
     case 0x50: /* DSS_PSA_LCD_REG_1 */
     case 0x54: /* DSS_PSA_LCD_REG_2 */
     case 0x58: /* DSS_PSA_VIDEO_REG */
+        TRACEREG("DSS_PSA_xxx: 0");
         /* TODO: fake some values when appropriate s->control bits are set */
         return 0;
 
-    case 0x5c: /* DSS_STATUS */
+    case 0x5c: /* DSS_SDI_STATUS */
+        /* TODO: check and implement missing OMAP3 bits */
+        TRACEREG("DSS_STATUS: 0x%08x", 1 + (s->control & 1));
         return 1 + (s->control & 1);
 
     default:
@@ -209,25 +527,40 @@ static void omap_diss_write(void *opaque, target_phys_addr_t addr,
     switch (addr) {
     case 0x00: /* DSS_REVISIONNUMBER */
     case 0x14: /* DSS_SYSSTATUS */
+    case 0x18:  /* DSS_IRQSTATUS */
     case 0x50: /* DSS_PSA_LCD_REG_1 */
     case 0x54: /* DSS_PSA_LCD_REG_2 */
     case 0x58: /* DSS_PSA_VIDEO_REG */
     case 0x5c: /* DSS_STATUS */
-        OMAP_RO_REG(addr);
+        /* quietly ignore */
+        /*OMAP_RO_REGV(addr, value);*/
         break;
 
     case 0x10: /* DSS_SYSCONFIG */
+        TRACEREG("DSS_SYSCONFIG = 0x%08x", value);
         if (value & 2)                                         /* SOFTRESET */
             omap_dss_reset(s);
-        s->autoidle = value & 1;
+        s->autoidle = value & 0x19; /* was 0x01 for OMAP2 */
         break;
 
     case 0x40: /* DSS_CONTROL */
-        s->control = value & 0x3dd;
+        TRACEREG("DSS_CONTROL = 0x%08x", value);
+        s->control = value & 0x3ff; /* was 0x3dd for OMAP2 */
         break;
 
+    case 0x44: /* DSS_SDI_CONTROL */
+        TRACEREG("DSS_SDI_CONTROL = 0x%08x", value);
+        s->sdi_control = value & 0x000ff80f;
+        break;
+
+    case 0x48: /* DSS_PLL_CONTROL */
+        TRACEREG("DSS_PLL_CONTROL = 0x%08x", value);
+        s->pll_control = value;
+        break;
+            
     default:
-        OMAP_BAD_REG(addr);
+        OMAP_BAD_REGV(addr, value);
+        break;
     }
 }
 
@@ -246,116 +579,223 @@ static CPUWriteMemoryFunc *omap_diss1_writefn[] = {
 static uint32_t omap_disc_read(void *opaque, target_phys_addr_t addr)
 {
     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int n = 0;
 
     switch (addr) {
     case 0x000:        /* DISPC_REVISION */
-        return 0x20;
-
+        TRACEREG("DISPC_REVISION: 0x%08x", s->dispc.rev);
+        return s->dispc.rev;
     case 0x010:        /* DISPC_SYSCONFIG */
+        TRACEREG("DISPC_SYSCONFIG: 0x%08x", s->dispc.idlemode);
         return s->dispc.idlemode;
-
     case 0x014:        /* DISPC_SYSSTATUS */
+        TRACEREG("DISPC_SYSSTATUS: 1");
         return 1;                                              /* RESETDONE */
-
     case 0x018:        /* DISPC_IRQSTATUS */
+        TRACEREG("DISPC_IRQSTATUS: 0x%08x", s->dispc.irqst);
         return s->dispc.irqst;
-
     case 0x01c:        /* DISPC_IRQENABLE */
+        TRACEREG("DISPC_IRQENABLE: 0x%08x", s->dispc.irqen);
         return s->dispc.irqen;
-
     case 0x040:        /* DISPC_CONTROL */
+        TRACEREG("DISPC_CONTROL: 0x%08x", s->dispc.control);
         return s->dispc.control;
-
     case 0x044:        /* DISPC_CONFIG */
+        TRACEREG("DISPC_CONFIG: 0x%08x", s->dispc.config);
         return s->dispc.config;
-
     case 0x048:        /* DISPC_CAPABLE */
+        TRACEREG("DISPC_CAPABLE: 0x%08x", s->dispc.capable);
         return s->dispc.capable;
-
     case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
+        TRACEREG("DISPC_DEFAULT_COLOR0: 0x%08x", s->dispc.bg[0]);
         return s->dispc.bg[0];
     case 0x050:        /* DISPC_DEFAULT_COLOR1 */
+        TRACEREG("DISPC_DEFAULT_COLOR0: 0x%08x", s->dispc.bg[1]);
         return s->dispc.bg[1];
     case 0x054:        /* DISPC_TRANS_COLOR0 */
+        TRACEREG("DISPC_TRANS_COLOR0: 0x%08x", s->dispc.trans[0]);
         return s->dispc.trans[0];
     case 0x058:        /* DISPC_TRANS_COLOR1 */
+        TRACEREG("DISPC_TRANS_COLOR0: 0x%08x", s->dispc.trans[1]);
         return s->dispc.trans[1];
-
     case 0x05c:        /* DISPC_LINE_STATUS */
+        TRACEREG("DISPC_LINE_STATUS: 0x7ff");
         return 0x7ff;
     case 0x060:        /* DISPC_LINE_NUMBER */
+        TRACEREG("DISPC_LINE_NUMBER: 0x%08x", s->dispc.line);
         return s->dispc.line;
-
     case 0x064:        /* DISPC_TIMING_H */
+        TRACEREG("DISPC_TIMING_H: 0x%08x", s->dispc.timing[0]);
         return s->dispc.timing[0];
     case 0x068:        /* DISPC_TIMING_V */
+        TRACEREG("DISPC_TIMING_H: 0x%08x", s->dispc.timing[1]);
         return s->dispc.timing[1];
     case 0x06c:        /* DISPC_POL_FREQ */
+        TRACEREG("DISPC_POL_FREQ: 0x%08x", s->dispc.timing[2]);
         return s->dispc.timing[2];
     case 0x070:        /* DISPC_DIVISOR */
+        TRACEREG("DISPC_DIVISOR: 0x%08x", s->dispc.timing[3]);
         return s->dispc.timing[3];
-
+    case 0x074: /* DISPC_GLOBAL_ALPHA */
+        TRACEREG("DISPC_GLOBAL_ALPHA: 0x%08x", s->dispc.global_alpha);
+        return s->dispc.global_alpha;
     case 0x078:        /* DISPC_SIZE_DIG */
+        TRACEREG("DISPC_SIZE_DIG: 0x%08x", ((s->dig.ny - 1) << 16) | (s->dig.nx - 1));
         return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
     case 0x07c:        /* DISPC_SIZE_LCD */
+        TRACEREG("DISPC_SIZE_LCD: 0x%08x", ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1));
         return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
-
+    case 0x14c:        /* DISPC_VID2_BA0 */
+        n++;
+    case 0x0bc:        /* DISPC_VID1_BA0 */
+        n++;
     case 0x080:        /* DISPC_GFX_BA0 */
-        return s->dispc.l[0].addr[0];
+        TRACEREG("DISPC_%s_BA0: 0x%08x", LAYERNAME(n), s->dispc.l[n].addr[0]);
+        return s->dispc.l[n].addr[0];
+    case 0x150:        /* DISPC_VID2_BA1 */
+        n++;
+    case 0x0c0:        /* DISPC_VID1_BA1 */
+        n++;
     case 0x084:        /* DISPC_GFX_BA1 */
-        return s->dispc.l[0].addr[1];
+        TRACEREG("DISPC_%s_BA1: 0x%08x", LAYERNAME(n), s->dispc.l[n].addr[1]);
+        return s->dispc.l[n].addr[1];
+    case 0x154:        /* DISPC_VID2_POSITION */
+        n++;
+    case 0x0c4:        /* DISPC_VID1_POSITION */
+        n++;
     case 0x088:        /* DISPC_GFX_POSITION */
-        return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
+        TRACEREG("DISPC_%s_POSITION: 0x%08x", LAYERNAME(n),
+                 (s->dispc.l[n].posy << 16) | s->dispc.l[n].posx);
+        return (s->dispc.l[n].posy << 16) | s->dispc.l[n].posx;
+    case 0x158:        /* DISPC_VID2_SIZE */
+        n++;
+    case 0x0c8:        /* DISPC_VID1_SIZE */
+        n++;
     case 0x08c:        /* DISPC_GFX_SIZE */
-        return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
+        TRACEREG("DISPC_%s_SIZE: 0x%08x", LAYERNAME(n),
+                 ((s->dispc.l[n].ny - 1) << 16) | (s->dispc.l[n].nx - 1));
+        return ((s->dispc.l[n].ny - 1) << 16) | (s->dispc.l[n].nx - 1);
+    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
+        n++;
+    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
+        n++;
     case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
-        return s->dispc.l[0].attr;
+        TRACEREG("DISPC_%s_ATTRIBUTES: 0x%08x", LAYERNAME(n),
+                 s->dispc.l[n].attr);
+        return s->dispc.l[n].attr;
+    case 0x160:        /* DISPC_VID2_FIFO_THRESHOLD */
+        n++;
+    case 0x0d0:        /* DISPC_VID1_FIFO_THRESHOLD */
+        n++;
     case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
-        return s->dispc.l[0].tresh;
+        TRACEREG("DISPC_%s_THRESHOLD: 0x%08x", LAYERNAME(n),
+                 s->dispc.l[n].tresh);
+        return s->dispc.l[n].tresh;
+    case 0x164:        /* DISPC_VID2_FIFO_SIZE_STATUS */
+        n++;
+    case 0x0d4:        /* DISPC_VID1_FIFO_SIZE_STATUS */
+        n++;
     case 0x0a8:        /* DISPC_GFX_FIFO_SIZE_STATUS */
-        return 256;
+        TRACEREG("DISPC_%s_FIFO_SIZE_STATUS: 0x%08x", LAYERNAME(n),
+                 s->dispc.rev < 0x30 ? 256 : 1024);
+        return s->dispc.rev < 0x30 ? 256 : 1024;
+    case 0x168:        /* DISPC_VID2_ROW_INC */
+        n++;
+    case 0x0d8:        /* DISPC_VID1_ROW_INC */
+        n++;
     case 0x0ac:        /* DISPC_GFX_ROW_INC */
-        return s->dispc.l[0].rowinc;
+        TRACEREG("DISPC_%s_ROW_INC: 0x%08x", LAYERNAME(n),
+                 s->dispc.l[n].rowinc);
+        return s->dispc.l[n].rowinc;
+    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
+        n++;
+    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
+        n++;
     case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
-        return s->dispc.l[0].colinc;
+        TRACEREG("DISPC_%s_PIXEL_INC: 0x%08x", LAYERNAME(n),
+                 s->dispc.l[n].colinc);
+        return s->dispc.l[n].colinc;
     case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
+        TRACEREG("DISPC_GFX_WINDOW_SKIP: 0x%08x", s->dispc.l[0].wininc);
         return s->dispc.l[0].wininc;
     case 0x0b8:        /* DISPC_GFX_TABLE_BA */
+        TRACEREG("DISPC_GFX_TABLE_BA: 0x%08x", s->dispc.l[0].addr[2]);
         return s->dispc.l[0].addr[2];
-
-    case 0x0bc:        /* DISPC_VID1_BA0 */
-    case 0x0c0:        /* DISPC_VID1_BA1 */
-    case 0x0c4:        /* DISPC_VID1_POSITION */
-    case 0x0c8:        /* DISPC_VID1_SIZE */
-    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
-    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
-    case 0x0d4:        /* DISPC_VID1_FIFO_SIZE_STATUS */
-    case 0x0d8:        /* DISPC_VID1_ROW_INC */
-    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
-    case 0x0e0:        /* DISPC_VID1_FIR */
-    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
-    case 0x0e8:        /* DISPC_VID1_ACCU0 */
-    case 0x0ec:        /* DISPC_VID1_ACCU1 */
-    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
-    case 0x14c:        /* DISPC_VID2_BA0 */
-    case 0x150:        /* DISPC_VID2_BA1 */
-    case 0x154:        /* DISPC_VID2_POSITION */
-    case 0x158:        /* DISPC_VID2_SIZE */
-    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
-    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
-    case 0x164:        /* DISPC_VID2_FIFO_SIZE_STATUS */
-    case 0x168:        /* DISPC_VID2_ROW_INC */
-    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
     case 0x170:        /* DISPC_VID2_FIR */
+        n++;
+    case 0x0e0:        /* DISPC_VID1_FIR */
+        n++;
+        TRACEREG("DISPC_%s_FIR: 0x%08x", LAYERNAME(n),
+                 s->dispc.l[n].fir);
+        return s->dispc.l[n].fir;
     case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
+        n++;
+    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
+        n++;
+        TRACEREG("DISPC_%s_PICTURE_SIZE: 0x%08x", LAYERNAME(n),
+                 s->dispc.l[n].picture_size);
+        return s->dispc.l[n].picture_size;
     case 0x178:        /* DISPC_VID2_ACCU0 */
     case 0x17c:        /* DISPC_VID2_ACCU1 */
-    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+        n++;
+    case 0x0e8:        /* DISPC_VID1_ACCU0 */
+    case 0x0ec:        /* DISPC_VID1_ACCU1 */
+        n++;
+        TRACEREG("DISPC_%s_ACCU%d: 0x%08x", LAYERNAME(n),
+                 (addr >> 1) & 1, s->dispc.l[n].accu[(addr >> 1 ) & 1]);
+        return s->dispc.l[n].accu[(addr >> 1) & 1];
+    case 0x180 ... 0x1bc:      /* DISPC_VID2_FIR_COEF */
+        n++;
+    case 0x0f0 ... 0x12c:      /* DISPC_VID1_FIR_COEF */
+        n++;
+        if (addr & 4) {
+            TRACEREG("DISPC_%s_FIR_COEF_HV%d: 0x%08x", LAYERNAME(n),
+                     (addr - ((n > 1) ? 0x180 : 0xf0)) / 8,
+                     s->dispc.l[n].fir_coef_hv[(addr - ((n > 1) ? 0x180 : 0xf0)) / 8]);
+            return s->dispc.l[n].fir_coef_hv[(addr - ((n > 1) ? 0x180 : 0xf0)) / 8];
+        }
+        TRACEREG("DISPC_%s_FIR_COEF_H%d: 0x%08x", LAYERNAME(n),
+                 (addr - ((n > 1) ? 0x180 : 0xf0)) / 8,
+                 s->dispc.l[n].fir_coef_h[(addr - ((n > 1) ? 0x180 : 0xf0)) / 8]);
+        return s->dispc.l[n].fir_coef_h[(addr - ((n > 1) ? 0x180 : 0xf0)) / 8];
+    case 0x1c0 ... 0x1d0: /* DISPC_VID2_CONV_COEFi */
+        n++;
+    case 0x130 ... 0x140: /* DISPC_VID1_CONV_COEFi */
+        n++;
+        TRACEREG("DISPC_%s_CONV_COEF%d: 0x%08x", LAYERNAME(n),
+                 (addr - ((n > 1) ? 0x1c0 : 0x130)) / 4,
+                 s->dispc.l[n].conv_coef[(addr - ((n > 1) ? 0x1c0 : 0x130)) / 4]);
+        return s->dispc.l[n].conv_coef[(addr - ((n > 1) ? 0x1c0 : 0x130)) / 4];
     case 0x1d4:        /* DISPC_DATA_CYCLE1 */
     case 0x1d8:        /* DISPC_DATA_CYCLE2 */
     case 0x1dc:        /* DISPC_DATA_CYCLE3 */
+        TRACEREG("DISPC_DATA_CYCLE%d: 0", (addr - 0x1d4) / 4);
         return 0;
-
+    case 0x200 ... 0x21c: /* DISPC_VID2_FIR_COEF_Vi */
+        n++;
+    case 0x1e0 ... 0x1fc: /* DISPC_VID1_FIR_COEF_Vi */
+        n++;
+        TRACEREG("DISPC_%s_FIR_COEF_V%d: 0x%08x", LAYERNAME(n),
+                 (addr & 0x01f) / 4,
+                 s->dispc.l[n].fir_coef_v[(addr & 0x01f) / 4]);
+        return s->dispc.l[n].fir_coef_v[(addr & 0x01f) / 4];
+    case 0x220: /* DISPC_CPR_COEF_R */
+        TRACEREG("DISPC_CPR_COEF_R: 0x%08x", s->dispc.cpr_coef_r);
+        return s->dispc.cpr_coef_r;
+    case 0x224: /* DISPC_CPR_COEF_G */
+        TRACEREG("DISPC_CPR_COEF_G: 0x%08x", s->dispc.cpr_coef_g);
+        return s->dispc.cpr_coef_g;
+    case 0x228: /* DISPC_CPR_COEF_B */
+        TRACEREG("DISPC_CPR_COEF_B: 0x%08x", s->dispc.cpr_coef_b);
+        return s->dispc.cpr_coef_b;
+    case 0x234: /* DISPC_VID2_PRELOAD */
+        n++;
+    case 0x230: /* DISPC_VID1_PRELOAD */
+        n++;
+    case 0x22c: /* DISPC_GFX_PRELOAD */
+        TRACEREG("DISPC_%s_PRELOAD: 0x%08x", LAYERNAME(n),
+                 s->dispc.l[n].preload);
+        return s->dispc.l[n].preload;
     default:
         break;
     }
@@ -367,26 +807,38 @@ static void omap_disc_write(void *opaque, target_phys_addr_t addr,
                 uint32_t value)
 {
     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+    int n = 0;
 
     switch (addr) {
+    case 0x000: /* DISPC_REVISION */
+    case 0x014: /* DISPC_SYSSTATUS */
+    case 0x05c: /* DISPC_LINE_STATUS */
+    case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */
+        /* quietly ignore */
+        /*OMAP_RO_REGV(addr, value);*/
+        break;
     case 0x010:        /* DISPC_SYSCONFIG */
+        TRACEREG("DISPC_SYSCONFIG = 0x%08x", value);
         if (value & 2)                                         /* SOFTRESET */
             omap_dss_reset(s);
-        s->dispc.idlemode = value & 0x301b;
+        s->dispc.idlemode = value & ((s->dispc.rev < 0x30) ? 0x301b : 0x331f);
         break;
-
     case 0x018:        /* DISPC_IRQSTATUS */
+        TRACEREG("DISPC_IRQSTATUS = 0x%08x", value);
         s->dispc.irqst &= ~value;
-        omap_dispc_interrupt_update(s);
+        omap_dss_interrupt_update(s);
         break;
-
     case 0x01c:        /* DISPC_IRQENABLE */
-        s->dispc.irqen = value & 0xffff;
-        omap_dispc_interrupt_update(s);
+        TRACEREG("DISPC_IRQENABLE = 0x%08x", value);
+        s->dispc.irqen = value & ((s->dispc.rev < 0x30) ? 0xffff : 0x1ffff);
+        omap_dss_interrupt_update(s);
         break;
-
     case 0x040:        /* DISPC_CONTROL */
-        s->dispc.control = value & 0x07ff9fff;
+        TRACEREG("DISPC_CONTROL = 0x%08x", value);
+        if (s->dispc.rev < 0x30)
+            s->dispc.control = value & 0x07ff9fff;
+        else
+            s->dispc.control = (value & 0xffff9bff) | (s->dispc.control & 0x6000);
         s->dig.enable = (value >> 1) & 1;
         s->lcd.enable = (value >> 0) & 1;
         if (value & (1 << 12))                 /* OVERLAY_OPTIMIZATION */
@@ -424,14 +876,16 @@ static void omap_disc_write(void *opaque, target_phys_addr_t addr,
              * s->dispc.l[0].wininc
              * All they need to be loaded here from their shadow registers.
              */
+            s->dispc.control &= ~(1 << 6); /* GODIGITAL finished */
         }
         if (value & (1 << 5)) {                                /* GOLCD */
              /* XXX: Likewise for LCD here.  */
+            s->dispc.control &= ~(1 << 5); /* GOLCD finished */
         }
         s->dispc.invalidate = 1;
         break;
-
     case 0x044:        /* DISPC_CONFIG */
+        TRACEREG("DISPC_CONFIG = 0x%08x", value);
         s->dispc.config = value & 0x3fff;
         /* XXX:
          * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
@@ -439,134 +893,245 @@ static void omap_disc_write(void *opaque, target_phys_addr_t addr,
          */
         s->dispc.invalidate = 1;
         break;
-
     case 0x048:        /* DISPC_CAPABLE */
+        TRACEREG("DISPC_CAPABLE = 0x%08x", value);
         s->dispc.capable = value & 0x3ff;
         break;
-
     case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
+        TRACEREG("DISPC_DEFAULT_COLOR0 = 0x%08x", value);
         s->dispc.bg[0] = value & 0xffffff;
         s->dispc.invalidate = 1;
         break;
     case 0x050:        /* DISPC_DEFAULT_COLOR1 */
+        TRACEREG("DISPC_DEFAULT_COLOR1 = 0x%08x", value);
         s->dispc.bg[1] = value & 0xffffff;
         s->dispc.invalidate = 1;
         break;
     case 0x054:        /* DISPC_TRANS_COLOR0 */
+        TRACEREG("DISPC_TRANS_COLOR0 = 0x%08x", value);
         s->dispc.trans[0] = value & 0xffffff;
         s->dispc.invalidate = 1;
         break;
     case 0x058:        /* DISPC_TRANS_COLOR1 */
+        TRACEREG("DISPC_TRANS_COLOR1 = 0x%08x", value);
         s->dispc.trans[1] = value & 0xffffff;
         s->dispc.invalidate = 1;
         break;
-
     case 0x060:        /* DISPC_LINE_NUMBER */
+        TRACEREG("DISPC_LINE_NUMBER = 0x%08x", value);
         s->dispc.line = value & 0x7ff;
         break;
-
     case 0x064:        /* DISPC_TIMING_H */
+        TRACEREG("DISPC_TIMING_H = 0x%08x", value);
         s->dispc.timing[0] = value & 0x0ff0ff3f;
         break;
     case 0x068:        /* DISPC_TIMING_V */
+        TRACEREG("DISPC_TIMING_V = 0x%08x", value);
         s->dispc.timing[1] = value & 0x0ff0ff3f;
         break;
     case 0x06c:        /* DISPC_POL_FREQ */
+        TRACEREG("DISPC_POL_FREQ = 0x%08x", value);
         s->dispc.timing[2] = value & 0x0003ffff;
         break;
     case 0x070:        /* DISPC_DIVISOR */
+        TRACEREG("DISPC_DIVISOR = 0x%08x", value);
         s->dispc.timing[3] = value & 0x00ff00ff;
         break;
-
+    case 0x074: /* DISPC_GLOBAL_ALPHA */
+        TRACEREG("DISPC_GLOBAL_ALPHA = 0x%08x", value);
+        s->dispc.global_alpha = value & 0x00ff00ff;
+        break;
     case 0x078:        /* DISPC_SIZE_DIG */
         s->dig.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
         s->dig.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
         s->dispc.invalidate = 1;
+        TRACEREG("DISPC_SIZE_DIG = 0x%08x (%dx%d)", value, s->dig.nx, s->dig.ny);
         break;
     case 0x07c:        /* DISPC_SIZE_LCD */
         s->lcd.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
         s->lcd.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
         s->dispc.invalidate = 1;
+        TRACEREG("DISPC_SIZE_LCD = 0x%08x (%dx%d)", value, s->lcd.nx, s->lcd.ny);
         break;
+    case 0x14c:        /* DISPC_VID2_BA0 */
+        n++;
+    case 0x0bc: /* DISPC_VID1_BA0 */
+        n++;
     case 0x080:        /* DISPC_GFX_BA0 */
-        s->dispc.l[0].addr[0] = (target_phys_addr_t) value;
+        TRACEREG("DISPC_%s_BA0 = 0x%08x", LAYERNAME(n), value);
+        s->dispc.l[n].addr[0] = (target_phys_addr_t) value;
         s->dispc.invalidate = 1;
         break;
+    case 0x150:        /* DISPC_VID2_BA1 */
+        n++;
+    case 0x0c0:        /* DISPC_VID1_BA1 */
+        n++;
     case 0x084:        /* DISPC_GFX_BA1 */
-        s->dispc.l[0].addr[1] = (target_phys_addr_t) value;
+        TRACEREG("DISPC_%s_BA1 = 0x%08x", LAYERNAME(n), value);
+        s->dispc.l[n].addr[1] = (target_phys_addr_t) value;
         s->dispc.invalidate = 1;
         break;
+    case 0x154:        /* DISPC_VID2_POSITION */
+        n++;
+    case 0x0c4:        /* DISPC_VID1_POSITION */
+        n++;
     case 0x088:        /* DISPC_GFX_POSITION */
-        s->dispc.l[0].posx = ((value >>  0) & 0x7ff);          /* GFXPOSX */
-        s->dispc.l[0].posy = ((value >> 16) & 0x7ff);          /* GFXPOSY */
+        s->dispc.l[n].posx = ((value >>  0) & 0x7ff);          /* GFXPOSX */
+        s->dispc.l[n].posy = ((value >> 16) & 0x7ff);          /* GFXPOSY */
         s->dispc.invalidate = 1;
+        TRACEREG("DISPC_%s_POSITION = 0x%08x (%d,%d)", LAYERNAME(n),
+                 value, s->dispc.l[n].posx, s->dispc.l[n].posy);
         break;
+    case 0x158:        /* DISPC_VID2_SIZE */
+        n++;
+    case 0x0c8:        /* DISPC_VID1_SIZE */
+        n++;
     case 0x08c:        /* DISPC_GFX_SIZE */
-        s->dispc.l[0].nx = ((value >>  0) & 0x7ff) + 1;                /* GFXSIZEX */
-        s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1;                /* GFXSIZEY */
+        s->dispc.l[n].nx = ((value >>  0) & 0x7ff) + 1;                /* GFXSIZEX */
+        s->dispc.l[n].ny = ((value >> 16) & 0x7ff) + 1;                /* GFXSIZEY */
+        TRACEREG("DISPC_%s_SIZE = 0x%08x (%dx%d)", LAYERNAME(n),
+                 value, s->dispc.l[n].nx, s->dispc.l[n].ny);
         s->dispc.invalidate = 1;
         break;
+        n++;
     case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
-        s->dispc.l[0].attr = value & 0x7ff;
+        TRACEREG("DISPC_GFX_ATTRIBUTES = 0x%08x", value);
+        s->dispc.l[0].attr = value & 0xffff;
         if (value & (3 << 9))
             fprintf(stderr, "%s: Big-endian pixel format not supported\n",
                             __FUNCTION__);
         s->dispc.l[0].enable = value & 1;
         s->dispc.l[0].bpp = (value >> 1) & 0xf;
+        s->dispc.l[0].rotation_flag = (value >> 12) & 0x3;
+        s->dispc.l[0].gfx_format = (value >> 1) & 0xf;
+        s->dispc.l[0].gfx_channel = (value >> 8) & 0x1;
         s->dispc.invalidate = 1;
         break;
-    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
-        s->dispc.l[0].tresh = value & 0x01ff01ff;
+    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
+        n++;
+    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
+        n++;
+    case 0x0a4:        /* DISPC_GFX_FIFO_THRESHOLD */
+        TRACEREG("DISPC_%s_FIFO_THRESHOLD = 0x%08x", LAYERNAME(n), value);
+        s->dispc.l[n].tresh = value & ((s->dispc.rev < 0x30) 
+                                       ? 0x01ff01ff : 0x0fff0fff);
         break;
+    case 0x168:        /* DISPC_VID2_ROW_INC */
+        n++;
+    case 0x0d8:        /* DISPC_VID1_ROW_INC */
+        n++;
     case 0x0ac:        /* DISPC_GFX_ROW_INC */
-        s->dispc.l[0].rowinc = value;
+        TRACEREG("DISPC_%s_ROW_INC = 0x%08x", LAYERNAME(n), value);
+        s->dispc.l[n].rowinc = value;
         s->dispc.invalidate = 1;
         break;
+    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
+        n++;
+    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
+        n++;
     case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
-        s->dispc.l[0].colinc = value;
+        TRACEREG("DISPC_%s_PIXEL_INC = 0x%08x", LAYERNAME(n), value);
+        s->dispc.l[n].colinc = value;
         s->dispc.invalidate = 1;
         break;
     case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
+        TRACEREG("DISPC_GFX_WINDOW_SKIP = 0x%08x", value);
         s->dispc.l[0].wininc = value;
         break;
     case 0x0b8:        /* DISPC_GFX_TABLE_BA */
+        TRACEREG("DISPC_GFX_TABLE_BA = 0x%08x", value);
         s->dispc.l[0].addr[2] = (target_phys_addr_t) value;
         s->dispc.invalidate = 1;
         break;
-
-    case 0x0bc:        /* DISPC_VID1_BA0 */
-    case 0x0c0:        /* DISPC_VID1_BA1 */
-    case 0x0c4:        /* DISPC_VID1_POSITION */
-    case 0x0c8:        /* DISPC_VID1_SIZE */
-    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
-    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
-    case 0x0d8:        /* DISPC_VID1_ROW_INC */
-    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
-    case 0x0e0:        /* DISPC_VID1_FIR */
-    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
-    case 0x0e8:        /* DISPC_VID1_ACCU0 */
-    case 0x0ec:        /* DISPC_VID1_ACCU1 */
-    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
-    case 0x14c:        /* DISPC_VID2_BA0 */
-    case 0x150:        /* DISPC_VID2_BA1 */
-    case 0x154:        /* DISPC_VID2_POSITION */
-    case 0x158:        /* DISPC_VID2_SIZE */
     case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
-    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
-    case 0x168:        /* DISPC_VID2_ROW_INC */
-    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
+        n++;
+    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
+        n++;
+        TRACEREG("DISPC_%s_ATTRIBUTES = 0x%08x", LAYERNAME(n), value);
+        s->dispc.l[n].attr = value & 0x1fffffff;
+        break;
     case 0x170:        /* DISPC_VID2_FIR */
+        n++;
+    case 0x0e0:        /* DISPC_VID1_FIR */
+        n++;
+        TRACEREG("DISPC_%s_FIR = 0x%08x", LAYERNAME(n), value);
+        s->dispc.l[n].fir = value & 0x1fff1fff;
+        break;
     case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
+        n++;
+    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
+        n++;
+        TRACEREG("DISPC_%s_PICTURE_SIZE = 0x%08x", LAYERNAME(n), value);
+        s->dispc.l[n].picture_size = value & 0x07ff07ff;
+        break;
     case 0x178:        /* DISPC_VID2_ACCU0 */
     case 0x17c:        /* DISPC_VID2_ACCU1 */
-    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+        n++;
+    case 0x0e8:        /* DISPC_VID1_ACCU0 */
+    case 0x0ec:        /* DISPC_VID1_ACCU1 */
+        n++;
+        TRACEREG("DISPC_%s_ACCU%d = 0x%08x", LAYERNAME(n),
+                 (addr >> 1) & 1, value);
+        s->dispc.l[n].accu[(addr >> 1) & 1] = value & 0x03ff03ff;
+        break;
+    case 0x180 ... 0x1bc:      /* DISPC_VID2_FIR_COEF */
+        n++;
+    case 0x0f0 ... 0x12c:      /* DISPC_VID1_FIR_COEF */
+        n++;
+        if (addr & 4) {
+            TRACEREG("DISPC_%s_FIR_COEF_HV%d = 0x%08x", LAYERNAME(n),
+                     (addr - ((n > 1) ? 0x180 : 0xf0)) / 8, value);
+            s->dispc.l[n].fir_coef_hv[(addr - ((n > 1) ? 0x180 : 0xf0)) / 8] = value;
+        } else {
+            TRACEREG("DISPC_%s_FIR_COEF_H%d = 0x%08x", LAYERNAME(n),
+                     (addr - ((n > 1) ? 0x180 : 0xf0)) / 8, value);
+            s->dispc.l[n].fir_coef_h[(addr - ((n > 1) ? 0x180 : 0xf0)) / 8] = value;
+        }
+        break;
+    case 0x1c0 ... 0x1d0: /* DISPC_VID2_CONV_COEFi */
+        n++;
+    case 0x130 ... 0x140: /* DISPC_VID1_CONV_COEFi */
+        n++;
+        TRACEREG("DISPC_%s_CONV_COEF%d = 0x%08x", LAYERNAME(n),
+                 (addr - ((n > 1) ? 0x1c0 : 0x130)) / 4, value);
+        s->dispc.l[n].conv_coef[(addr - ((n > 1) ? 0x1c0 : 0x130)) / 4] = value;
+        break;
     case 0x1d4:        /* DISPC_DATA_CYCLE1 */
     case 0x1d8:        /* DISPC_DATA_CYCLE2 */
     case 0x1dc:        /* DISPC_DATA_CYCLE3 */
+        TRACEREG("DISPC_DATA_CYCLE%d = 0x%08x (ignored)", (addr - 0x1d4) / 4, value);
+        break;
+    case 0x200 ... 0x21c: /* DISPC_VID2_FIR_COEF_Vi */
+        n++;
+    case 0x1e0 ... 0x1fc: /* DISPC_VID1_FIR_COEF_Vi */
+        n++;
+        TRACEREG("DISPC_%s_FIR_COEF_V%d = 0x%08x", LAYERNAME(n),
+                 (addr & 0x01f) / 4, value);
+        s->dispc.l[n].fir_coef_v[(addr & 0x01f) / 4] = value & 0x0000ffff;
+        break;
+    case 0x220: /* DISPC_CPR_COEF_R */
+        TRACEREG("DISPC_CPR_COEF_R = 0x%08x", value);
+        s->dispc.cpr_coef_r = value & 0xffbffbff;
+        break;
+    case 0x224: /* DISPC_CPR_COEF_G */
+        TRACEREG("DISPC_CPR_COEF_G = 0x%08x", value);
+        s->dispc.cpr_coef_g = value & 0xffbffbff;
+        break;
+    case 0x228: /* DISPC_CPR_COEF_B */
+        TRACEREG("DISPC_CPR_COEF_B = 0x%08x", value);
+        s->dispc.cpr_coef_b = value & 0xffbffbff;
+        break;
+    case 0x234: /* DISPC_VID2_PRELOAD */
+        n++;
+    case 0x230: /* DISPC_VID1_PRELOAD */
+        n++;
+    case 0x22c: /* DISPC_GFX_PRELOAD */
+        TRACEREG("DISPC_%s_PRELOAD = 0x%08x", LAYERNAME(n), value);
+        s->dispc.l[n].preload = value & 0x0fff;
         break;
-
     default:
-        OMAP_BAD_REG(addr);
+        OMAP_BAD_REGV(addr, value);
+        break;
     }
 }
 
@@ -651,7 +1216,7 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s)
 
     /* TODO */
     s->dispc.irqst |= 1;                                       /* FRAMEDONE */
-    omap_dispc_interrupt_update(s);
+    omap_dss_interrupt_update(s);
 }
 
 static uint32_t omap_rfbi_read(void *opaque, target_phys_addr_t addr)
@@ -660,56 +1225,77 @@ static uint32_t omap_rfbi_read(void *opaque, target_phys_addr_t addr)
 
     switch (addr) {
     case 0x00: /* RFBI_REVISION */
+        TRACEREG("RFBI_REVISION: 0x10");
         return 0x10;
 
     case 0x10: /* RFBI_SYSCONFIG */
+        TRACEREG("RFBI_SYSCONFIG: 0x%08x", s->rfbi.idlemode);
         return s->rfbi.idlemode;
 
     case 0x14: /* RFBI_SYSSTATUS */
+        TRACEREG("RFBI_SYSSTATUS: 0x%08x", 1 | (s->rfbi.busy << 8));
         return 1 | (s->rfbi.busy << 8);                                /* RESETDONE */
 
     case 0x40: /* RFBI_CONTROL */
+        TRACEREG("RFBI_CONTROL: 0x%08x", s->rfbi.control);
         return s->rfbi.control;
 
     case 0x44: /* RFBI_PIXELCNT */
+        TRACEREG("RFBI_PIXELCNT: 0x%08x", s->rfbi.pixels);
         return s->rfbi.pixels;
 
     case 0x48: /* RFBI_LINE_NUMBER */
+        TRACEREG("RFBI_LINE_NUMBER: 0x%08x", s->rfbi.skiplines);
         return s->rfbi.skiplines;
 
     case 0x58: /* RFBI_READ */
     case 0x5c: /* RFBI_STATUS */
+        TRACEREG("RFBI_READ/STATUS: 0x%08x", s->rfbi.rxbuf);
         return s->rfbi.rxbuf;
 
     case 0x60: /* RFBI_CONFIG0 */
+        TRACEREG("RFBI_CONFIG0: 0x%08x", s->rfbi.config[0]);
         return s->rfbi.config[0];
     case 0x64: /* RFBI_ONOFF_TIME0 */
+        TRACEREG("RFBI_ONOFF_TIME0: 0x%08x", s->rfbi.time[0]);
         return s->rfbi.time[0];
     case 0x68: /* RFBI_CYCLE_TIME0 */
+        TRACEREG("RFBI_CYCLE_TIME0: 0x%08x", s->rfbi.time[1]);
         return s->rfbi.time[1];
     case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+        TRACEREG("RFBI_DATA_CYCLE1_0: 0x%08x", s->rfbi.data[0]);
         return s->rfbi.data[0];
     case 0x70: /* RFBI_DATA_CYCLE2_0 */
+        TRACEREG("RFBI_DATA_CYCLE2_0: 0x%08x", s->rfbi.data[1]);
         return s->rfbi.data[1];
     case 0x74: /* RFBI_DATA_CYCLE3_0 */
+        TRACEREG("RFBI_DATA_CYCLE3_0: 0x%08x", s->rfbi.data[2]);
         return s->rfbi.data[2];
 
     case 0x78: /* RFBI_CONFIG1 */
+        TRACEREG("RFBI_CONFIG1: 0x%08x", s->rfbi.config[1]);
         return s->rfbi.config[1];
     case 0x7c: /* RFBI_ONOFF_TIME1 */
+        TRACEREG("RFBI_ONOFF_TIME1: 0x%08x", s->rfbi.time[2]);
         return s->rfbi.time[2];
     case 0x80: /* RFBI_CYCLE_TIME1 */
+        TRACEREG("RFBI_CYCLE_TIME1: 0x%08x", s->rfbi.time[3]);
         return s->rfbi.time[3];
     case 0x84: /* RFBI_DATA_CYCLE1_1 */
+        TRACEREG("RFBI_DATA_CYCLE1_1: 0x%08x", s->rfbi.data[3]);
         return s->rfbi.data[3];
     case 0x88: /* RFBI_DATA_CYCLE2_1 */
+        TRACEREG("RFBI_DATA_CYCLE2_1: 0x%08x", s->rfbi.data[4]);
         return s->rfbi.data[4];
     case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+        TRACEREG("RFBI_DATA_CYCLE3_1: 0x%08x", s->rfbi.data[5]);
         return s->rfbi.data[5];
 
     case 0x90: /* RFBI_VSYNC_WIDTH */
+        TRACEREG("RFBI_VSYNC_WIDTH: 0x%08x", s->rfbi.vsync);
         return s->rfbi.vsync;
     case 0x94: /* RFBI_HSYNC_WIDTH */
+        TRACEREG("RFBI_HSYNC_WIDTH: 0x%08x", s->rfbi.hsync);
         return s->rfbi.hsync;
     }
     OMAP_BAD_REG(addr);
@@ -723,12 +1309,14 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
 
     switch (addr) {
     case 0x10: /* RFBI_SYSCONFIG */
+        TRACEREG("RFBI_SYSCONFIG = 0x%08x", value);
         if (value & 2)                                         /* SOFTRESET */
             omap_rfbi_reset(s);
         s->rfbi.idlemode = value & 0x19;
         break;
 
     case 0x40: /* RFBI_CONTROL */
+        TRACEREG("RFBI_CONTROL = 0x%08x", value);
         s->rfbi.control = value & 0xf;
         s->rfbi.enable = value & 1;
         if (value & (1 << 4) &&                                        /* ITE */
@@ -737,26 +1325,31 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
         break;
 
     case 0x44: /* RFBI_PIXELCNT */
+        TRACEREG("RFBI_PIXELCNT = 0x%08x", value);
         s->rfbi.pixels = value;
         break;
 
     case 0x48: /* RFBI_LINE_NUMBER */
+        TRACEREG("RFBI_LINE_NUMBER = 0x%08x", value);
         s->rfbi.skiplines = value & 0x7ff;
         break;
 
     case 0x4c: /* RFBI_CMD */
+        TRACEREG("RFBI_CMD = 0x%08x", value);
         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
         if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
         break;
     case 0x50: /* RFBI_PARAM */
+        TRACEREG("RFBI_PARAM = 0x%08x", value);
         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
         if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
         break;
     case 0x54: /* RFBI_DATA */
+        TRACEREG("RFBI_DATA = 0x%08x", value);
         /* TODO: take into account the format set up in s->rfbi.config[?] and
          * s->rfbi.data[?], but special-case the most usual scenario so that
          * speed doesn't suffer.  */
@@ -772,6 +1365,7 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
             omap_rfbi_transfer_stop(s);
         break;
     case 0x58: /* RFBI_READ */
+        TRACEREG("RFBI_READ = 0x%08x", value);
         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
@@ -781,6 +1375,7 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
         break;
 
     case 0x5c: /* RFBI_STATUS */
+        TRACEREG("RFBI_STATUS = 0x%08x", value);
         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
@@ -790,53 +1385,68 @@ static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
         break;
 
     case 0x60: /* RFBI_CONFIG0 */
+        TRACEREG("RFBI_CONFIG0 = 0x%08x", value);
         s->rfbi.config[0] = value & 0x003f1fff;
         break;
 
     case 0x64: /* RFBI_ONOFF_TIME0 */
+        TRACEREG("RFBI_ONOFF_TIME0 = 0x%08x", value);
         s->rfbi.time[0] = value & 0x3fffffff;
         break;
     case 0x68: /* RFBI_CYCLE_TIME0 */
+        TRACEREG("RFBI_CYCLE_TIME0 = 0x%08x", value);
         s->rfbi.time[1] = value & 0x0fffffff;
         break;
     case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+        TRACEREG("RFBI_DATA_CYCLE1_0 = 0x%08x", value);
         s->rfbi.data[0] = value & 0x0f1f0f1f;
         break;
     case 0x70: /* RFBI_DATA_CYCLE2_0 */
+        TRACEREG("RFBI_DATA_CYCLE2_0 = 0x%08x", value);
         s->rfbi.data[1] = value & 0x0f1f0f1f;
         break;
     case 0x74: /* RFBI_DATA_CYCLE3_0 */
+        TRACEREG("RFBI_DATA_CYCLE3_0 = 0x%08x", value);
         s->rfbi.data[2] = value & 0x0f1f0f1f;
         break;
     case 0x78: /* RFBI_CONFIG1 */
+        TRACEREG("RFBI_CONFIG1 = 0x%08x", value);
         s->rfbi.config[1] = value & 0x003f1fff;
         break;
 
     case 0x7c: /* RFBI_ONOFF_TIME1 */
+        TRACEREG("RFBI_ONOFF_TIME1 = 0x%08x", value);
         s->rfbi.time[2] = value & 0x3fffffff;
         break;
     case 0x80: /* RFBI_CYCLE_TIME1 */
+        TRACEREG("RFBI_CYCLE_TIME1 = 0x%08x", value);
         s->rfbi.time[3] = value & 0x0fffffff;
         break;
     case 0x84: /* RFBI_DATA_CYCLE1_1 */
+        TRACEREG("RFBI_DATA_CYCLE1_1 = 0x%08x", value);
         s->rfbi.data[3] = value & 0x0f1f0f1f;
         break;
     case 0x88: /* RFBI_DATA_CYCLE2_1 */
+        TRACEREG("RFBI_DATA_CYCLE2_1 = 0x%08x", value);
         s->rfbi.data[4] = value & 0x0f1f0f1f;
         break;
     case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+        TRACEREG("RFBI_DATA_CYCLE3_1 = 0x%08x", value);
         s->rfbi.data[5] = value & 0x0f1f0f1f;
         break;
 
     case 0x90: /* RFBI_VSYNC_WIDTH */
+        TRACEREG("RFBI_VSYNC_WIDTH = 0x%08x", value);
         s->rfbi.vsync = value & 0xffff;
         break;
     case 0x94: /* RFBI_HSYNC_WIDTH */
+        TRACEREG("RFBI_HSYNC_WIDTH = 0x%08x", value);
         s->rfbi.hsync = value & 0xffff;
         break;
 
     default:
-        OMAP_BAD_REG(addr);
+        OMAP_BAD_REGV(addr, value);
+        break;
     }
 }
 
@@ -855,53 +1465,54 @@ static CPUWriteMemoryFunc *omap_rfbi1_writefn[] = {
 static uint32_t omap_venc_read(void *opaque, target_phys_addr_t addr)
 {
     switch (addr) {
-    case 0x00: /* REV_ID */
-    case 0x04: /* STATUS */
-    case 0x08: /* F_CONTROL */
-    case 0x10: /* VIDOUT_CTRL */
-    case 0x14: /* SYNC_CTRL */
-    case 0x1c: /* LLEN */
-    case 0x20: /* FLENS */
-    case 0x24: /* HFLTR_CTRL */
-    case 0x28: /* CC_CARR_WSS_CARR */
-    case 0x2c: /* C_PHASE */
-    case 0x30: /* GAIN_U */
-    case 0x34: /* GAIN_V */
-    case 0x38: /* GAIN_Y */
-    case 0x3c: /* BLACK_LEVEL */
-    case 0x40: /* BLANK_LEVEL */
-    case 0x44: /* X_COLOR */
-    case 0x48: /* M_CONTROL */
-    case 0x4c: /* BSTAMP_WSS_DATA */
-    case 0x50: /* S_CARR */
-    case 0x54: /* LINE21 */
-    case 0x58: /* LN_SEL */
-    case 0x5c: /* L21__WC_CTL */
-    case 0x60: /* HTRIGGER_VTRIGGER */
-    case 0x64: /* SAVID__EAVID */
-    case 0x68: /* FLEN__FAL */
-    case 0x6c: /* LAL__PHASE_RESET */
-    case 0x70: /* HS_INT_START_STOP_X */
-    case 0x74: /* HS_EXT_START_STOP_X */
-    case 0x78: /* VS_INT_START_X */
-    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
-    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
-    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
-    case 0x88: /* VS_EXT_STOP_Y */
-    case 0x90: /* AVID_START_STOP_X */
-    case 0x94: /* AVID_START_STOP_Y */
-    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
-    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
-    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
-    case 0xb0: /* TVDETGP_INT_START_STOP_X */
-    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
-    case 0xb8: /* GEN_CTRL */
-    case 0xc4: /* DAC_TST__DAC_A */
-    case 0xc8: /* DAC_B__DAC_C */
-        return 0;
-
-    default:
-        break;
+        case 0x00:     /* REV_ID */
+            return 0x2;
+        case 0x04:     /* STATUS */
+        case 0x08:     /* F_CONTROL */
+        case 0x10:     /* VIDOUT_CTRL */
+        case 0x14:     /* SYNC_CTRL */
+        case 0x1c:     /* LLEN */
+        case 0x20:     /* FLENS */
+        case 0x24:     /* HFLTR_CTRL */
+        case 0x28:     /* CC_CARR_WSS_CARR */
+        case 0x2c:     /* C_PHASE */
+        case 0x30:     /* GAIN_U */
+        case 0x34:     /* GAIN_V */
+        case 0x38:     /* GAIN_Y */
+        case 0x3c:     /* BLACK_LEVEL */
+        case 0x40:     /* BLANK_LEVEL */
+        case 0x44:     /* X_COLOR */
+        case 0x48:     /* M_CONTROL */
+        case 0x4c:     /* BSTAMP_WSS_DATA */
+        case 0x50:     /* S_CARR */
+        case 0x54:     /* LINE21 */
+        case 0x58:     /* LN_SEL */
+        case 0x5c:     /* L21__WC_CTL */
+        case 0x60:     /* HTRIGGER_VTRIGGER */
+        case 0x64:     /* SAVID__EAVID */
+        case 0x68:     /* FLEN__FAL */
+        case 0x6c:     /* LAL__PHASE_RESET */
+        case 0x70:     /* HS_INT_START_STOP_X */
+        case 0x74:     /* HS_EXT_START_STOP_X */
+        case 0x78:     /* VS_INT_START_X */
+        case 0x7c:     /* VS_INT_STOP_X__VS_INT_START_Y */
+        case 0x80:     /* VS_INT_STOP_Y__VS_INT_START_X */
+        case 0x84:     /* VS_EXT_STOP_X__VS_EXT_START_Y */
+        case 0x88:     /* VS_EXT_STOP_Y */
+        case 0x90:     /* AVID_START_STOP_X */
+        case 0x94:     /* AVID_START_STOP_Y */
+        case 0xa0:     /* FID_INT_START_X__FID_INT_START_Y */
+        case 0xa4:     /* FID_INT_OFFSET_Y__FID_EXT_START_X */
+        case 0xa8:     /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+        case 0xb0:     /* TVDETGP_INT_START_STOP_X */
+        case 0xb4:     /* TVDETGP_INT_START_STOP_Y */
+        case 0xb8:     /* GEN_CTRL */
+        case 0xc4:     /* DAC_TST__DAC_A */
+        case 0xc8:     /* DAC_B__DAC_C */
+            return 0;
+            
+        default:
+            break;
     }
     OMAP_BAD_REG(addr);
     return 0;
@@ -911,51 +1522,56 @@ static void omap_venc_write(void *opaque, target_phys_addr_t addr,
                 uint32_t value)
 {
     switch (addr) {
-    case 0x08: /* F_CONTROL */
-    case 0x10: /* VIDOUT_CTRL */
-    case 0x14: /* SYNC_CTRL */
-    case 0x1c: /* LLEN */
-    case 0x20: /* FLENS */
-    case 0x24: /* HFLTR_CTRL */
-    case 0x28: /* CC_CARR_WSS_CARR */
-    case 0x2c: /* C_PHASE */
-    case 0x30: /* GAIN_U */
-    case 0x34: /* GAIN_V */
-    case 0x38: /* GAIN_Y */
-    case 0x3c: /* BLACK_LEVEL */
-    case 0x40: /* BLANK_LEVEL */
-    case 0x44: /* X_COLOR */
-    case 0x48: /* M_CONTROL */
-    case 0x4c: /* BSTAMP_WSS_DATA */
-    case 0x50: /* S_CARR */
-    case 0x54: /* LINE21 */
-    case 0x58: /* LN_SEL */
-    case 0x5c: /* L21__WC_CTL */
-    case 0x60: /* HTRIGGER_VTRIGGER */
-    case 0x64: /* SAVID__EAVID */
-    case 0x68: /* FLEN__FAL */
-    case 0x6c: /* LAL__PHASE_RESET */
-    case 0x70: /* HS_INT_START_STOP_X */
-    case 0x74: /* HS_EXT_START_STOP_X */
-    case 0x78: /* VS_INT_START_X */
-    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
-    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
-    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
-    case 0x88: /* VS_EXT_STOP_Y */
-    case 0x90: /* AVID_START_STOP_X */
-    case 0x94: /* AVID_START_STOP_Y */
-    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
-    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
-    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
-    case 0xb0: /* TVDETGP_INT_START_STOP_X */
-    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
-    case 0xb8: /* GEN_CTRL */
-    case 0xc4: /* DAC_TST__DAC_A */
-    case 0xc8: /* DAC_B__DAC_C */
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
+        case 0x00: /* REV_ID */
+        case 0x04: /* STATUS */
+            /* read-only, ignore */
+            break;
+        case 0x08:     /* F_CONTROL */
+        case 0x10:     /* VIDOUT_CTRL */
+        case 0x14:     /* SYNC_CTRL */
+        case 0x1c:     /* LLEN */
+        case 0x20:     /* FLENS */
+        case 0x24:     /* HFLTR_CTRL */
+        case 0x28:     /* CC_CARR_WSS_CARR */
+        case 0x2c:     /* C_PHASE */
+        case 0x30:     /* GAIN_U */
+        case 0x34:     /* GAIN_V */
+        case 0x38:     /* GAIN_Y */
+        case 0x3c:     /* BLACK_LEVEL */
+        case 0x40:     /* BLANK_LEVEL */
+        case 0x44:     /* X_COLOR */
+        case 0x48:     /* M_CONTROL */
+        case 0x4c:     /* BSTAMP_WSS_DATA */
+        case 0x50:     /* S_CARR */
+        case 0x54:     /* LINE21 */
+        case 0x58:     /* LN_SEL */
+        case 0x5c:     /* L21__WC_CTL */
+        case 0x60:     /* HTRIGGER_VTRIGGER */
+        case 0x64:     /* SAVID__EAVID */
+        case 0x68:     /* FLEN__FAL */
+        case 0x6c:     /* LAL__PHASE_RESET */
+        case 0x70:     /* HS_INT_START_STOP_X */
+        case 0x74:     /* HS_EXT_START_STOP_X */
+        case 0x78:     /* VS_INT_START_X */
+        case 0x7c:     /* VS_INT_STOP_X__VS_INT_START_Y */
+        case 0x80:     /* VS_INT_STOP_Y__VS_INT_START_X */
+        case 0x84:     /* VS_EXT_STOP_X__VS_EXT_START_Y */
+        case 0x88:     /* VS_EXT_STOP_Y */
+        case 0x90:     /* AVID_START_STOP_X */
+        case 0x94:     /* AVID_START_STOP_Y */
+        case 0xa0:     /* FID_INT_START_X__FID_INT_START_Y */
+        case 0xa4:     /* FID_INT_OFFSET_Y__FID_EXT_START_X */
+        case 0xa8:     /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+        case 0xb0:     /* TVDETGP_INT_START_STOP_X */
+        case 0xb4:     /* TVDETGP_INT_START_STOP_Y */
+        case 0xb8:     /* GEN_CTRL */
+        case 0xc4:     /* DAC_TST__DAC_A */
+        case 0xc8:     /* DAC_B__DAC_C */
+            break;
+            
+        default:
+            OMAP_BAD_REGV(addr, value);
+            break;
     }
 }
 
@@ -1005,7 +1621,8 @@ static void omap_im3_write(void *opaque, target_phys_addr_t addr,
         break;
 
     default:
-        OMAP_BAD_REG(addr);
+        OMAP_BAD_REGV(addr, value);
+        break;
     }
 }
 
@@ -1021,41 +1638,237 @@ static CPUWriteMemoryFunc *omap_im3_writefn[] = {
     omap_im3_write,
 };
 
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
-                target_phys_addr_t l3_base,
-                qemu_irq irq, qemu_irq drq,
-                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
-                omap_clk ick1, omap_clk ick2)
+static uint32_t omap_dsi_read(void *opaque, target_phys_addr_t addr)
+{
+    switch (addr) {
+        case 0x000: /* DSI_REVISION */
+            return 0x10;
+        case 0x014: /* DSI_SYSSTATUS */
+            return 1; /* RESET_DONE */
+        case 0x010: /* DSI_SYSCONFIG */
+        case 0x018: /* DSI_IRQSTATUS */
+        case 0x01c: /* DSI_IRQENABLE */
+        case 0x040: /* DSI_CTRL */
+        case 0x048: /* DSI_COMPLEXIO_CFG_1 */
+        case 0x04c: /* DSI_COMPLEXIO_IRQ_STATUS */
+        case 0x050: /* DSI_COMPLEXIO_IRQ_ENABLE */
+        case 0x054: /* DSI_CLK_CTRL */
+        case 0x058: /* DSI_TIMING1 */
+        case 0x05c: /* DSI_TIMING2 */
+        case 0x060: /* DSI_VM_TIMING1 */
+        case 0x064: /* DSI_VM_TIMING2 */
+        case 0x068: /* DSI_VM_TIMING3 */
+        case 0x06c: /* DSI_CLK_TIMING */
+        case 0x070: /* DSI_TX_FIFO_VC_SIZE */
+        case 0x074: /* DSI_RX_FIFO_VC_SIZE */
+        case 0x078: /* DSI_COMPLEXIO_CFG_2 */
+        case 0x07c: /* DSI_RX_FIFO_VC_FULLNESS */
+        case 0x080: /* DSI_VM_TIMING4 */
+        case 0x084: /* DSI_TX_FIFO_VC_EMPTINESS */
+        case 0x088: /* DSI_VM_TIMING5 */
+        case 0x08c: /* DSI_VM_TIMING6 */
+        case 0x090: /* DSI_VM_TIMING7 */
+        case 0x094: /* DSI_STOPCLK_TIMING */
+        case 0x100: /* DSI_VC0_CTRL */
+        case 0x104: /* DSI_VC0_TE */
+        case 0x108: /* DSI_VC0_LONG_PACKET_HEADER */
+        case 0x10c: /* DSI_VC0_LONG_PACKET_PAYLOAD */
+        case 0x110: /* DSI_VC0_SHORT_PACKET_HEADER */
+        case 0x118: /* DSI_VC0_IRQSTATUS */
+        case 0x11c: /* DSI_VC0_IRQENABLE */
+        case 0x120: /* DSI_VC1_CTRL */
+        case 0x124: /* DSI_VC1_TE */
+        case 0x128: /* DSI_VC1_LONG_PACKET_HEADER */
+        case 0x12c: /* DSI_VC1_LONG_PACKET_PAYLOAD */
+        case 0x130: /* DSI_VC1_SHORT_PACKET_HEADER */
+        case 0x138: /* DSI_VC1_IRQSTATUS */
+        case 0x13c: /* DSI_VC1_IRQENABLE */
+        case 0x140: /* DSI_VC2_CTRL */
+        case 0x144: /* DSI_VC2_TE */
+        case 0x148: /* DSI_VC2_LONG_PACKET_HEADER */
+        case 0x14c: /* DSI_VC2_LONG_PACKET_PAYLOAD */
+        case 0x150: /* DSI_VC2_SHORT_PACKET_HEADER */
+        case 0x158: /* DSI_VC2_IRQSTATUS */
+        case 0x15c: /* DSI_VC2_IRQENABLE */
+        case 0x160: /* DSI_VC3_CTRL */
+        case 0x164: /* DSI_VC3_TE */
+        case 0x168: /* DSI_VC3_LONG_PACKET_HEADER */
+        case 0x16c: /* DSI_VC3_LONG_PACKET_PAYLOAD */
+        case 0x170: /* DSI_VC3_SHORT_PACKET_HEADER */
+        case 0x178: /* DSI_VC3_IRQSTATUS */
+        case 0x17c: /* DSI_VC3_IRQENABLE */
+        
+        case 0x200: /* DSI_PHY_CFG0 */
+        case 0x204: /* DSI_PHY_CFG1 */
+        case 0x208: /* DSI_PHY_CFG2 */
+        case 0x214: /* DSI_PHY_CFG5 */
+            
+        case 0x300: /* DSI_PLL_CONTROL */
+        case 0x304: /* DSI_PLL_STATUS */
+        case 0x308: /* DSI_PLL_GO */
+        case 0x30c: /* DSI_PLL_CONFIGURATION1 */
+        case 0x310: /* DSI_PLL_CONFIGURATION2 */
+            
+            fprintf(stderr,
+                    "%s: DSI register " OMAP_FMT_plx " not implemented!\n",
+                    __FUNCTION__, addr);
+            return 0;
+            
+        default:
+            break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_dsi_write(void *opaque, target_phys_addr_t addr,
+                           uint32_t value)
+{
+    switch (addr) {
+        case 0x000: /* DSI_REVISION */
+        case 0x014: /* DSI_SYSSTATUS */
+        case 0x07c: /* DSI_RX_FIFO_VC_FULLNESS */
+        case 0x084: /* DSI_RX_FIFO_VC_EMPTINESS */
+        case 0x214: /* DSI_PHY_CFG5 */
+        case 0x304: /* DSI_PLL_STATUS */
+            /* read-only, ignore */
+            break;
+        case 0x010: /* DSI_SYSCONFIG */
+        case 0x018: /* DSI_IRQSTATUS */
+        case 0x01c: /* DSI_IRQENABLE */
+        case 0x040: /* DSI_CTRL */
+        case 0x048: /* DSI_COMPLEXIO_CFG_1 */
+        case 0x04c: /* DSI_COMPLEXIO_IRQ_STATUS */
+        case 0x050: /* DSI_COMPLEXIO_IRQ_ENABLE */
+        case 0x054: /* DSI_CLK_CTRL */
+        case 0x058: /* DSI_TIMING1 */
+        case 0x05c: /* DSI_TIMING2 */
+        case 0x060: /* DSI_VM_TIMING1 */
+        case 0x064: /* DSI_VM_TIMING2 */
+        case 0x068: /* DSI_VM_TIMING3 */
+        case 0x06c: /* DSI_CLK_TIMING */
+        case 0x070: /* DSI_TX_FIFO_VC_SIZE */
+        case 0x074: /* DSI_RX_FIFO_VC_SIZE */
+        case 0x078: /* DSI_COMPLEXIO_CFG_2 */
+        case 0x080: /* DSI_VM_TIMING4 */
+        case 0x088: /* DSI_VM_TIMING5 */
+        case 0x08c: /* DSI_VM_TIMING6 */
+        case 0x090: /* DSI_VM_TIMING7 */
+        case 0x094: /* DSI_STOPCLK_TIMING */
+        case 0x100: /* DSI_VC0_CTRL */
+        case 0x104: /* DSI_VC0_TE */
+        case 0x108: /* DSI_VC0_LONG_PACKET_HEADER */
+        case 0x10c: /* DSI_VC0_LONG_PACKET_PAYLOAD */
+        case 0x110: /* DSI_VC0_SHORT_PACKET_HEADER */
+        case 0x118: /* DSI_VC0_IRQSTATUS */
+        case 0x11c: /* DSI_VC0_IRQENABLE */
+        case 0x120: /* DSI_VC1_CTRL */
+        case 0x124: /* DSI_VC1_TE */
+        case 0x128: /* DSI_VC1_LONG_PACKET_HEADER */
+        case 0x12c: /* DSI_VC1_LONG_PACKET_PAYLOAD */
+        case 0x130: /* DSI_VC1_SHORT_PACKET_HEADER */
+        case 0x138: /* DSI_VC1_IRQSTATUS */
+        case 0x13c: /* DSI_VC1_IRQENABLE */
+        case 0x140: /* DSI_VC2_CTRL */
+        case 0x144: /* DSI_VC2_TE */
+        case 0x148: /* DSI_VC2_LONG_PACKET_HEADER */
+        case 0x14c: /* DSI_VC2_LONG_PACKET_PAYLOAD */
+        case 0x150: /* DSI_VC2_SHORT_PACKET_HEADER */
+        case 0x158: /* DSI_VC2_IRQSTATUS */
+        case 0x15c: /* DSI_VC2_IRQENABLE */
+        case 0x160: /* DSI_VC3_CTRL */
+        case 0x164: /* DSI_VC3_TE */
+        case 0x168: /* DSI_VC3_LONG_PACKET_HEADER */
+        case 0x16c: /* DSI_VC3_LONG_PACKET_PAYLOAD */
+        case 0x170: /* DSI_VC3_SHORT_PACKET_HEADER */
+        case 0x178: /* DSI_VC3_IRQSTATUS */
+        case 0x17c: /* DSI_VC3_IRQENABLE */
+            
+        case 0x200: /* DSI_PHY_CFG0 */
+        case 0x204: /* DSI_PHY_CFG1 */
+        case 0x208: /* DSI_PHY_CFG2 */
+            
+        case 0x300: /* DSI_PLL_CONTROL */
+        case 0x308: /* DSI_PLL_GO */
+        case 0x30c: /* DSI_PLL_CONFIGURATION1 */
+        case 0x310: /* DSI_PLL_CONFIGURATION2 */
+            
+            fprintf(stderr,
+                    "%s: DSI register " OMAP_FMT_plx " not implemented!\n",
+                    __FUNCTION__, addr);
+            break;
+            
+        default:
+            OMAP_BAD_REGV(addr, value);
+            break;
+    }
+}
+
+static CPUReadMemoryFunc *omap_dsi_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_dsi_read,
+};
+
+static CPUWriteMemoryFunc *omap_dsi_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_dsi_write,
+};
+
+struct omap_dss_s *omap_dss_init(struct omap_mpu_state_s *mpu,
+                                 struct omap_target_agent_s *ta,
+                                 qemu_irq irq, qemu_irq drq,
+                                 omap_clk fck1, omap_clk fck2, omap_clk ck54m,
+                                 omap_clk ick1, omap_clk ick2)
 {
     int iomemtype[5];
+    int region_base = 0;
     struct omap_dss_s *s = (struct omap_dss_s *)
             qemu_mallocz(sizeof(struct omap_dss_s));
 
     s->irq = irq;
     s->drq = drq;
-    omap_dss_reset(s);
 
     iomemtype[0] = l4_register_io_memory(0, omap_diss1_readfn,
-                    omap_diss1_writefn, s);
+                                         omap_diss1_writefn, s);
     iomemtype[1] = l4_register_io_memory(0, omap_disc1_readfn,
-                    omap_disc1_writefn, s);
+                                         omap_disc1_writefn, s);
     iomemtype[2] = l4_register_io_memory(0, omap_rfbi1_readfn,
-                    omap_rfbi1_writefn, s);
+                                         omap_rfbi1_writefn, s);
     iomemtype[3] = l4_register_io_memory(0, omap_venc1_readfn,
-                    omap_venc1_writefn, s);
-    iomemtype[4] = cpu_register_io_memory(0, omap_im3_readfn,
-                    omap_im3_writefn, s);
-    omap_l4_attach(ta, 0, iomemtype[0]);
-    omap_l4_attach(ta, 1, iomemtype[1]);
-    omap_l4_attach(ta, 2, iomemtype[2]);
-    omap_l4_attach(ta, 3, iomemtype[3]);
-    cpu_register_physical_memory(l3_base, 0x1000, iomemtype[4]);
+                                         omap_venc1_writefn, s);
+
+    if (cpu_class_omap3(mpu)) {
+        s->dispc.rev = 0x30;
+        
+        iomemtype[4] = l4_register_io_memory(0, omap_dsi_readfn,
+                                             omap_dsi_writefn, s);
+        omap_l4_attach(ta, 0, iomemtype[4]);
+        region_base = 1;
+    } else {
+        s->dispc.rev = 0x20;
+        
+        iomemtype[4] = cpu_register_io_memory(0, omap_im3_readfn,
+                                              omap_im3_writefn, s);
+        cpu_register_physical_memory(0x68000800, 0x1000, iomemtype[4]);
+    }
+    
+    omap_l4_attach(ta, region_base+0, iomemtype[0]); /* DISS */
+    omap_l4_attach(ta, region_base+1, iomemtype[1]); /* DISC */
+    omap_l4_attach(ta, region_base+2, iomemtype[2]); /* RFBI */
+    omap_l4_attach(ta, region_base+3, iomemtype[3]); /* VENC */
+
+    omap_dss_reset(s);
 
 #if 0
     s->state = graphic_console_init(omap_update_display,
                                     omap_invalidate_display, omap_screen_dump, s);
 #endif
 
+    register_savevm("omap_dss", -1, 0,
+                    omap_dss_save_state, omap_dss_load_state, s);
+    
     return s;
 }
 
@@ -1065,3 +1878,171 @@ void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
         cpu_abort(cpu_single_env, "%s: wrong CS %i\n", __FUNCTION__, cs);
     s->rfbi.chip[cs] = chip;
 }
+
+void omap3_lcd_panel_attach(struct omap_dss_s *dss,
+                            int cs,
+                            struct omap3_lcd_panel_s *lcd_panel)
+{
+    if (cs < 0 || cs > 1)
+        cpu_abort(cpu_single_env, "%s: wrong CS %i\n", __FUNCTION__, cs);
+    dss->omap_lcd_panel[cs] = lcd_panel;
+       lcd_panel->dss = dss;
+}
+
+/*omap3 lcd panel stuff*/
+
+/* Bytes(!) per pixel */
+static const int omap3_lcd_panel_bpp[0x10] = {
+    0,  /* 0x0: BITMAP1 (CLUT) */
+    0,  /* 0x1: BITMAP2 (CLUT) */
+    0,  /* 0x2: BITMAP4 (CLUT) */
+    0,  /* 0x3: BITMAP8 (CLUT) */
+    2,  /* 0x4: RGB12 (unpacked 16-bit container)*/
+    2,  /* 0x5: ARGB16 */
+    2,  /* 0x6: RGB16 */
+    0,  /* 0x7: reserved */
+    4,  /* 0x8: RGB24 (unpacked in 32-bit container) */
+    3,  /* 0x9: RGB24 (packed in 24-bit container) */
+    2,  /* 0xa: YUV2 422 */
+    2,  /* 0xb: UYVY 422 */
+    4,  /* 0xc: ARGB32 */
+    4,  /* 0xd: RGBA32 */
+    4,  /* 0xe: RGBx32 (24-bit RGB aligned on MSB of the 32-bit container) */
+    0,  /* 0xf: reserved */
+};
+
+static inline void omap3_lcd_panel_invalidate_display(void *opaque) 
+{
+    struct omap3_lcd_panel_s *s = (struct omap3_lcd_panel_s *)opaque;
+    s->invalidate = 1;
+}
+
+static void omap3_lcd_panel_update_display(void *opaque)
+{
+    struct omap3_lcd_panel_s *s = (struct omap3_lcd_panel_s *)opaque;
+    struct omap_dss_s *dss = s->dss;
+    const uint32_t lcd_width = dss->lcd.nx;
+    const uint32_t lcd_height = dss->lcd.ny;
+    uint32_t graphic_width, graphic_height;
+    uint32_t start_x, start_y;
+    const uint32_t lcd_Bpp = omap3_lcd_panel_bpp[dss->dispc.l[0].gfx_format];
+    uint32_t dss_Bpp;
+    uint32_t linesize, y;
+    uint32_t copy_width, copy_height;
+    uint8_t *src, *dest;
+
+    if (!dss->lcd.enable
+        || dss->dispc.l[0].gfx_channel /* 24bit digital out */
+        || ((dss->dispc.control & (1 << 11))) /* RFBI */
+        || !lcd_Bpp)
+        return;
+    
+    /* check for setup changes since last visit only if flagged */
+    if (dss->dispc.invalidate) {
+        dss->dispc.invalidate = 0;
+        if (!(dss->dispc.l[0].rotation_flag)) {          /* rotation*/
+            s->line_fn = s->line_fn_tab[0][dss->dispc.l[0].gfx_format];
+        } else {
+            fprintf(stderr, "%s: rotation is not supported \n", __FUNCTION__);
+            exit(1);
+        }
+        if (!s->line_fn) {
+            fprintf(stderr,
+                    "%s: line_fn is NULL - unsupported gfx_format (%d)\n",
+                    __FUNCTION__, dss->dispc.l[0].gfx_format);
+            exit(1);
+        }
+        if (lcd_width != ds_get_width(s->state) 
+            || lcd_height != ds_get_height(s->state)) {
+            qemu_console_resize(s->state, lcd_width, lcd_height);
+            s->invalidate = 1;
+        }
+    }
+    
+    /* Resolution */
+    graphic_width = dss->dispc.l[0].nx;
+    graphic_height = dss->dispc.l[0].ny;
+    start_x = dss->dispc.l[0].posx;
+    start_y = dss->dispc.l[0].posy;
+
+    /*use the rfbi function*/
+    src = (uint8_t *)omap_rfbi_get_buffer(dss);
+    dest = ds_get_data(s->state);
+    linesize = ds_get_linesize(s->state);
+
+    dss_Bpp = linesize / ds_get_width(s->state);
+
+    dest += linesize * start_y;
+    dest += start_x * dss_Bpp;
+
+    if ((start_x + graphic_width) > lcd_width)
+        copy_width = lcd_width - start_x;
+    else
+       copy_width = graphic_width;
+    copy_height = lcd_height>graphic_height ? graphic_height:lcd_height;
+
+    for (y = start_y; y < copy_height; y++) {
+        s->line_fn(dest, src, copy_width * lcd_Bpp);
+        src += graphic_width * lcd_Bpp;
+        dest += linesize;
+    }
+
+    dpy_update(s->state, start_x, start_y, graphic_width, graphic_height);
+    s->invalidate = 0;
+    
+    dss->dispc.irqst |= 1; /* FRAMEDONE */
+    omap_dss_interrupt_update(dss);
+}
+
+/*omap lcd stuff*/
+#define DEPTH 8
+#include "omap3_lcd_panel_template.h"
+#define DEPTH 15
+#include "omap3_lcd_panel_template.h"
+#define DEPTH 16
+#include "omap3_lcd_panel_template.h"
+#define DEPTH 24
+#include "omap3_lcd_panel_template.h"
+#define DEPTH 32
+#include "omap3_lcd_panel_template.h"
+
+void *omap3_lcd_panel_init()
+{
+    struct omap3_lcd_panel_s *s = (struct omap3_lcd_panel_s *) qemu_mallocz(sizeof(*s));
+
+    s->state = graphic_console_init(omap3_lcd_panel_update_display,
+                                    omap3_lcd_panel_invalidate_display,
+                                    NULL, NULL, s);
+
+    switch (ds_get_bits_per_pixel(s->state)) {
+    case 0:
+        s->line_fn_tab[0] = s->line_fn_tab[1] =
+            qemu_mallocz(sizeof(omap3_lcd_panel_fn_t) * 0x10);
+        break;
+    case 8:
+        s->line_fn_tab[0] =  omap3_lcd_panel_draw_fn_8;
+        s->line_fn_tab[1] =  omap3_lcd_panel_draw_fn_r_8;
+        break;
+    case 15:
+        s->line_fn_tab[0] =  omap3_lcd_panel_draw_fn_15;
+        s->line_fn_tab[1] =  omap3_lcd_panel_draw_fn_r_15;
+        break;
+    case 16:
+        s->line_fn_tab[0] =  omap3_lcd_panel_draw_fn_16;
+        s->line_fn_tab[1] =  omap3_lcd_panel_draw_fn_r_16;
+        break;
+    case 24:
+        s->line_fn_tab[0] =  omap3_lcd_panel_draw_fn_24;
+        s->line_fn_tab[1] =  omap3_lcd_panel_draw_fn_r_24;
+        break;
+    case 32:
+        s->line_fn_tab[0] =  omap3_lcd_panel_draw_fn_32;
+        s->line_fn_tab[1] =  omap3_lcd_panel_draw_fn_r_32;
+        break;
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+
+    return s;
+}
index 258730b..96e1b4b 100644 (file)
@@ -2,6 +2,7 @@
  * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
  *
  * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (C) 2009 Nokia Corporation
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
 #include "i2c.h"
 #include "omap.h"
 
+#define I2C_MAX_FIFO_SIZE (1 << 6)
+#define I2C_FIFO_SIZE_MASK ((I2C_MAX_FIFO_SIZE) - 1)
+
 struct omap_i2c_s {
     qemu_irq irq;
     qemu_irq drq[2];
-    i2c_slave slave;
+    i2c_slave slave[4];
     i2c_bus *bus;
 
     uint8_t revision;
-    uint8_t mask;
+    uint16_t mask;
     uint16_t stat;
+    uint16_t we;
     uint16_t dma;
     uint16_t count;
     int count_cur;
-    uint32_t fifo;
-    int rxlen;
-    int txlen;
+    uint16_t sysc;
     uint16_t control;
-    uint16_t addr[2];
+    uint16_t own_addr[4];
+    uint16_t slave_addr;
+    uint8_t sblock;
     uint8_t divider;
-    uint8_t times[2];
+    uint16_t times[2];
     uint16_t test;
+    int fifostart;
+    int fifolen;
+    int fifosize;
+    uint8_t fifo[I2C_MAX_FIFO_SIZE];
 };
 
 #define OMAP2_INTR_REV 0x34
 #define OMAP2_GC_REV   0x34
+#define OMAP3_INTR_REV  0x3c
+
+//#define I2C_DEBUG
+#ifdef I2C_DEBUG
+#define TRACE(fmt, ...) fprintf(stderr, "%s " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
 
 static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
 {
+    TRACE("IRQ=%04x,RDRQ=%d,XDRQ=%d", 
+          s->stat & s->mask,
+          ((s->dma >> 15 ) & 1) & ((s->stat >> 3) & 1),
+          ((s->dma >> 7 ) & 1 )& ((s->stat >> 4 ) & 1));
     qemu_set_irq(s->irq, s->stat & s->mask);
-    if ((s->dma >> 15) & 1)                                    /* RDMA_EN */
-        qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);           /* RRDY */
-    if ((s->dma >> 7) & 1)                                     /* XDMA_EN */
-        qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);           /* XRDY */
+    if ((s->dma >> 15) & 1)                          /* RDMA_EN */
+        qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
+    if ((s->dma >> 7) & 1)                           /* XDMA_EN */
+        qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
 }
 
 /* These are only stubs now.  */
 static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event)
 {
-    struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
-
-    if ((~s->control >> 15) & 1)                               /* I2C_EN */
-        return;
-
-    switch (event) {
-    case I2C_START_SEND:
-    case I2C_START_RECV:
-        s->stat |= 1 << 9;                                     /* AAS */
-        break;
-    case I2C_FINISH:
-        s->stat |= 1 << 2;                                     /* ARDY */
-        break;
-    case I2C_NACK:
-        s->stat |= 1 << 1;                                     /* NACK */
-        break;
-    }
-
-    omap_i2c_interrupts_update(s);
+    fprintf(stderr, "%s: I^2C slave mode not supported\n", __FUNCTION__);
+    
+    /* code below is broken, i2c_slave CANNOT be cast to omap_i2c_s! */
+     
+    //struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
+    // 
+    //if ((~s->control >> 15) & 1)                             /* I2C_EN */
+    //    return;
+    //
+    //switch (event) {
+    //    case I2C_START_SEND:
+    //    case I2C_START_RECV:
+    //        s->stat |= 1 << 9;                                       /* AAS */
+    //        break;
+    //    case I2C_FINISH:
+    //        s->stat |= 1 << 2;                                       /* ARDY */
+    //        break;
+    //    case I2C_NACK:
+    //        s->stat |= 1 << 1;                                       /* NACK */
+    //        break;
+    //    default:
+    //        break;
+    //}
+    //
+    //omap_i2c_interrupts_update(s);
 }
 
 static int omap_i2c_rx(i2c_slave *i2c)
 {
-    struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
-    uint8_t ret = 0;
-
-    if ((~s->control >> 15) & 1)                               /* I2C_EN */
-        return -1;
-
-    if (s->txlen)
-        ret = s->fifo >> ((-- s->txlen) << 3) & 0xff;
-    else
-        s->stat |= 1 << 10;                                    /* XUDF */
-    s->stat |= 1 << 4;                                         /* XRDY */
-
-    omap_i2c_interrupts_update(s);
-    return ret;
+    fprintf(stderr, "%s: I^2C slave mode not supported\n", __FUNCTION__);
+    return 0;
+    
+    /* code below is broken, i2c_slave CANNOT be cast to omap_i2c_s! */
+    
+    //struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
+    //uint8_t ret = 0;
+    //
+    //if ((~s->control >> 15) & 1)                             /* I2C_EN */
+    //    return -1;
+    //
+    //if (s->rxlen < s->txlen)
+    //    ret = s->fifo[s->rxlen++];
+    //else
+    //    s->stat |= 1 << 10;                                  /* XUDF */
+    //s->stat |= 1 << 4;                                               /* XRDY */
+    //
+    //omap_i2c_interrupts_update(s);
+    //return ret;
 }
 
 static int omap_i2c_tx(i2c_slave *i2c, uint8_t data)
 {
-    struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
-
-    if ((~s->control >> 15) & 1)                               /* I2C_EN */
-        return 1;
-
-    if (s->rxlen < 4)
-        s->fifo |= data << ((s->rxlen ++) << 3);
-    else
-        s->stat |= 1 << 11;                                    /* ROVR */
-    s->stat |= 1 << 3;                                         /* RRDY */
-
-    omap_i2c_interrupts_update(s);
+    fprintf(stderr, "%s: I^2C slave mode not supported\n", __FUNCTION__);
     return 1;
+    
+    /* code below is broken, i2c_slave CANNOT be cast to omap_i2c_s! */
+    
+    //struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
+    //
+    //if ((~s->control >> 15) & 1)                             /* I2C_EN */
+    //    return 1;
+    //
+    //if (s->txlen < s->fifosize)
+    //    s->fifo[s->txlen++] = data;
+    //else
+    //    s->stat |= 1 << 11;                                  /* ROVR */
+    //s->stat |= 1 << 3;                                               /* RRDY */
+    //
+    //omap_i2c_interrupts_update(s);
+    //return 1;
 }
 
 static void omap_i2c_fifo_run(struct omap_i2c_s *s)
 {
-    int ack = 1;
+    int ack = 1, i;
 
     if (!i2c_bus_busy(s->bus))
         return;
@@ -126,60 +163,83 @@ static void omap_i2c_fifo_run(struct omap_i2c_s *s)
             i2c_end_transfer(s->bus);
             s->control &= ~(1 << 1);                           /* STP */
             s->count_cur = s->count;
-            s->txlen = 0;
+            s->fifolen = 0;
         } else if ((s->control >> 9) & 1) {                    /* TRX */
-            while (ack && s->txlen)
-                ack = (i2c_send(s->bus,
-                                        (s->fifo >> ((-- s->txlen) << 3)) &
-                                        0xff) >= 0);
+            while (ack && s->fifolen) {
+                ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
+                s->fifostart &= I2C_FIFO_SIZE_MASK;
+                s->fifolen--;
+            }
+            s->fifolen = 0;
             s->stat |= 1 << 4;                                 /* XRDY */
         } else {
-            while (s->rxlen < 4)
-                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
+            for (i = 0; i < 4; i++)
+                s->fifo[(s->fifostart + i) & I2C_FIFO_SIZE_MASK] =
+                    i2c_recv(s->bus);
+            s->fifolen = 4;
             s->stat |= 1 << 3;                                 /* RRDY */
         }
     } else {
-        if ((s->control >> 9) & 1) {                           /* TRX */
-            while (ack && s->count_cur && s->txlen) {
-                ack = (i2c_send(s->bus,
-                                        (s->fifo >> ((-- s->txlen) << 3)) &
-                                        0xff) >= 0);
-                s->count_cur --;
+        if ((s->control >> 9) & 1) {                /* TRX */
+            TRACE("master transmit, count_cur=%d, fifolen=%d",
+                  s->count_cur, s->fifolen);
+            for (; ack && s->count_cur && s->fifolen; s->count_cur--) {
+                ack = (i2c_send(s->bus, s->fifo[s->fifostart++]) >= 0);
+                s->fifostart &= I2C_FIFO_SIZE_MASK;
+                s->fifolen--;
             }
-            if (ack && s->count_cur)
-                s->stat |= 1 << 4;                             /* XRDY */
-            else
-                s->stat &= ~(1 << 4);                          /* XRDY */
-            if (!s->count_cur) {
-                s->stat |= 1 << 2;                             /* ARDY */
-                s->control &= ~(1 << 10);                      /* MST */
+            s->stat &= ~0x4410;                     /* XDR | XUDF | XRDY */
+            if (ack && s->count_cur) {              /* send more? */
+                /* we know that FIFO is empty */
+                s->stat |= 1 << 10;                 /* XUDF */
+                if (s->revision < OMAP3_INTR_REV)
+                    s->stat |= 1 << 4;              /* XRDY */
+                else {
+                    if (s->count_cur > (s->dma & 0x3f)) /* XTRSH */
+                        s->stat |= 1 << 4;          /* XRDY */
+                    else
+                        s->stat |= 1 << 14;         /* XDR */
+                }
             }
-        } else {
-            while (s->count_cur && s->rxlen < 4) {
-                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
-                s->count_cur --;
+            if (!s->count_cur)                      /* everything sent? */
+                s->stat |= 1 << 2;                  /* ARDY */
+        } else {                                    /* !TRX */
+            TRACE("master receive");
+            for (; s->count_cur && s->fifolen < s->fifosize; s->count_cur--) {
+                i = i2c_recv(s->bus);
+                if (i < 0) break; /* stop receiving if nothing to receive */
+                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
+                    (uint8_t)(i & 0xff);
+                TRACE("received fifo[%02x] = %02x", s->fifolen - 1,
+                      s->fifo[(s->fifostart + s->fifolen - 1) & I2C_FIFO_SIZE_MASK]);
             }
-            if (s->rxlen)
-                s->stat |= 1 << 3;                             /* RRDY */
-            else
-                s->stat &= ~(1 << 3);                          /* RRDY */
+            s->stat &= ~((1 << 3) | (1 << 13));            /* RRDY | RDR */
+            if (s->fifolen) {
+                if (s->revision < OMAP3_INTR_REV)
+                    s->stat |= 1 << 3;                     /* RRDY */
+                else {
+                    if (s->fifolen > ((s->dma >> 8) & 0x3f)) /* RTRSH */
+                        s->stat |= 1 << 3;                 /* RRDY */
+                    else
+                        s->stat |= 1 << 13;                /* RDR */
+                }
+            } else if (!s->count_cur && (s->control & 2))  /* STP */
+                s->stat |= 1 << 2;                         /* ARDY */
         }
         if (!s->count_cur) {
-            if ((s->control >> 1) & 1) {                       /* STP */
+            TRACE("no more data to transmit/receive");
+            if ((s->control >> 1) & 1) {   /* STP */
                 i2c_end_transfer(s->bus);
-                s->control &= ~(1 << 1);                       /* STP */
+                s->control &= ~0x0602;     /* MST | TRX | STP */
                 s->count_cur = s->count;
-                s->txlen = 0;
-            } else {
-                s->stat |= 1 << 2;                             /* ARDY */
-                s->control &= ~(1 << 10);                      /* MST */
-            }
+            } 
         }
     }
 
-    s->stat |= (!ack) << 1;                                    /* NACK */
+    s->stat |= (!ack) << 1;                  /* NACK */
     if (!ack)
-        s->control &= ~(1 << 1);                               /* STP */
+        s->control &= ~(1 << 1);          /* STP */
+    TRACE("finished, STAT = %04x, CNT = %d", s->stat, s->count_cur);
 }
 
 void omap_i2c_reset(struct omap_i2c_s *s)
@@ -189,12 +249,17 @@ void omap_i2c_reset(struct omap_i2c_s *s)
     s->dma = 0;
     s->count = 0;
     s->count_cur = 0;
-    s->fifo = 0;
-    s->rxlen = 0;
-    s->txlen = 0;
+    s->we = 0;
+    s->sysc = 0;
+    s->fifolen = 0;
+    s->fifostart = 0;
     s->control = 0;
-    s->addr[0] = 0;
-    s->addr[1] = 0;
+    s->own_addr[0] = 0;
+    s->own_addr[1] = 0;
+    s->own_addr[2] = 0;
+    s->own_addr[3] = 0;
+    s->slave_addr = 0;
+    s->sblock = 0;
     s->divider = 0;
     s->times[0] = 0;
     s->times[1] = 0;
@@ -208,91 +273,127 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
     uint16_t ret;
 
     switch (offset) {
-    case 0x00: /* I2C_REV */
-        return s->revision;                                    /* REV */
-
-    case 0x04: /* I2C_IE */
-        return s->mask;
-
-    case 0x08: /* I2C_STAT */
-        return s->stat | (i2c_bus_busy(s->bus) << 12);
-
-    case 0x0c: /* I2C_IV */
-        if (s->revision >= OMAP2_INTR_REV)
-            break;
-        ret = ffs(s->stat & s->mask);
-        if (ret)
-            s->stat ^= 1 << (ret - 1);
-        omap_i2c_interrupts_update(s);
-        return ret;
-
-    case 0x10: /* I2C_SYSS */
-        return (s->control >> 15) & 1;                         /* I2C_EN */
-
-    case 0x14: /* I2C_BUF */
-        return s->dma;
-
-    case 0x18: /* I2C_CNT */
-        return s->count_cur;                                   /* DCOUNT */
-
-    case 0x1c: /* I2C_DATA */
-        ret = 0;
-        if (s->control & (1 << 14)) {                          /* BE */
-            ret |= ((s->fifo >> 0) & 0xff) << 8;
-            ret |= ((s->fifo >> 8) & 0xff) << 0;
-        } else {
-            ret |= ((s->fifo >> 8) & 0xff) << 8;
-            ret |= ((s->fifo >> 0) & 0xff) << 0;
-        }
-        if (s->rxlen == 1) {
-            s->stat |= 1 << 15;                                        /* SBD */
-            s->rxlen = 0;
-        } else if (s->rxlen > 1) {
-            if (s->rxlen > 2)
-                s->fifo >>= 16;
-            s->rxlen -= 2;
-        } else
-            /* XXX: remote access (qualifier) error - what's that?  */;
-        if (!s->rxlen) {
-            s->stat &= ~(1 << 3);                              /* RRDY */
-            if (((s->control >> 10) & 1) &&                    /* MST */
-                            ((~s->control >> 9) & 1)) {                /* TRX */
-                s->stat |= 1 << 2;                             /* ARDY */
-                s->control &= ~(1 << 10);                      /* MST */
+        case 0x00: /* I2C_REV */
+            TRACE("REV returns %04x", s->revision);
+            return s->revision;
+        case 0x04: /* I2C_IE */
+            TRACE("IE returns %04x", s->mask);
+            return s->mask;
+        case 0x08: /* I2C_STAT */
+            TRACE("STAT returns %04x", s->stat | (i2c_bus_busy(s->bus) << 12));
+            return s->stat | (i2c_bus_busy(s->bus) << 12);
+        case 0x0c: /* I2C_IV / I2C_WE */
+            if (s->revision >= OMAP3_INTR_REV)
+                return s->we;
+            if (s->revision >= OMAP2_INTR_REV)
+                break;
+            ret = ffs(s->stat & s->mask);
+            if (ret)
+                s->stat ^= 1 << (ret - 1);
+            omap_i2c_interrupts_update(s);
+            return ret;
+        case 0x10: /* I2C_SYSS */
+            return (s->control >> 15) & 1; /* reset completed == I2C_EN */
+        case 0x14: /* I2C_BUF */
+            TRACE("BUF returns %04x", s->dma);
+            return s->dma;
+        case 0x18: /* I2C_CNT */
+            TRACE("CNT returns %04x", s->count_cur);
+            return s->count_cur; /* DCOUNT */
+        case 0x1c: /* I2C_DATA */
+            ret = 0;
+            if (s->fifolen) {
+                if (s->revision < OMAP3_INTR_REV) {
+                    if (s->control & (1 << 14)) /* BE */
+                        ret = (((uint16_t)s->fifo[s->fifostart]) << 8) 
+                            | s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK];
+                    else
+                        ret = (((uint16_t)s->fifo[(s->fifostart + 1) & I2C_FIFO_SIZE_MASK]) << 8) 
+                            | s->fifo[s->fifostart];
+                    s->fifostart = (s->fifostart + 2) & I2C_FIFO_SIZE_MASK;
+                    if (s->fifolen == 1) {
+                        s->stat |= 1 << 15; /* SBD */
+                        s->fifolen = 0;
+                    } else
+                        s->fifolen -= 2;
+                    if (!s->fifolen) {
+                        s->stat &= ~(1 << 3); /* RRDY */
+                        s->stat |= 1 << 2;    /* ARDY */
+                    }
+                } else {
+                    s->stat &= ~(1 << 7); /* AERR */
+                    ret = s->fifo[s->fifostart++];
+                    s->fifostart &= I2C_FIFO_SIZE_MASK;
+                    if (--s->fifolen) {
+                        if (s->fifolen < ((s->dma & 0x3f) >> 8)) {
+                            s->stat &= ~(1 << 3); /* RRDY */
+                            s->stat |= 1 << 13;   /* RDR */
+                        }
+                    } else {
+                        s->stat &= ~((1 << 3) | (1 << 13)); /* RRDY | RDR */
+                        s->stat |= 1 << 2;                  /* ARDY */
+                    }
+                }
+                s->stat &= ~(1 << 11); /* ROVR */
+            } else if (s->revision >= OMAP3_INTR_REV)
+                s->stat |= (1 << 7); /* AERR */
+            TRACE("DATA returns %04x", ret);
+            omap_i2c_fifo_run(s);
+            omap_i2c_interrupts_update(s);
+            return ret;
+        case 0x20: /* I2C_SYSC */
+            TRACE("SYSC returns %04x", s->sysc);
+            return s->sysc;
+        case 0x24: /* I2C_CON */
+            TRACE("CON returns %04x", s->control);
+            return s->control;
+        case 0x28: /* I2C_OA / I2C_OA0 */
+            return s->own_addr[0];
+        case 0x2c: /* I2C_SA */
+            return s->slave_addr;
+        case 0x30: /* I2C_PSC */
+            return s->divider;
+        case 0x34: /* I2C_SCLL */
+            return s->times[0];
+        case 0x38: /* I2C_SCLH */
+            return s->times[1];
+        case 0x3c: /* I2C_SYSTEST */
+            if (s->test & (1 << 15)) { /* ST_EN */
+                s->test ^= 0xa;
+                return s->test;
             }
-        }
-        s->stat &= ~(1 << 11);                                 /* ROVR */
-        omap_i2c_fifo_run(s);
-        omap_i2c_interrupts_update(s);
-        return ret;
-
-    case 0x20: /* I2C_SYSC */
-        return 0;
-
-    case 0x24: /* I2C_CON */
-        return s->control;
-
-    case 0x28: /* I2C_OA */
-        return s->addr[0];
-
-    case 0x2c: /* I2C_SA */
-        return s->addr[1];
-
-    case 0x30: /* I2C_PSC */
-        return s->divider;
-
-    case 0x34: /* I2C_SCLL */
-        return s->times[0];
-
-    case 0x38: /* I2C_SCLH */
-        return s->times[1];
-
-    case 0x3c: /* I2C_SYSTEST */
-        if (s->test & (1 << 15)) {                             /* ST_EN */
-            s->test ^= 0xa;
-            return s->test;
-        } else
             return s->test & ~0x300f;
+        case 0x40: /* I2C_BUFSTAT */
+            if (s->revision >= OMAP3_INTR_REV) {
+                switch (s->fifosize) {
+                    case 8:  ret = 0x0000; break;
+                    case 16: ret = 0x4000; break;
+                    case 32: ret = 0x8000; break;
+                    case 64: ret = 0xc000; break;
+                    default: ret = 0x0000; break;
+                }
+                ret |= ((s->fifolen) & 0x3f) << 8;  /* RXSTAT */
+                ret |= (s->count_cur) & 0x3f;       /* TXSTAT */
+                TRACE("BUFSTAT returns %04x", ret);
+                return ret;
+            }
+            break;
+        case 0x44: /* I2C_OA1 */
+        case 0x48: /* I2C_OA2 */
+        case 0x4c: /* I2C_OA3 */
+            if (s->revision >= OMAP3_INTR_REV)
+                return s->own_addr[(addr >> 2) & 3];
+            break;
+        case 0x50: /* I2C_ACTOA */
+            if (s->revision >= OMAP3_INTR_REV)
+                return 0; /* TODO: determine accessed slave own address */
+            break;
+        case 0x54: /* I2C_SBLOCK */
+            if (s->revision >= OMAP3_INTR_REV)
+                return s->sblock;
+            break;
+        default:
+            break;
     }
 
     OMAP_BAD_REG(addr);
@@ -307,138 +408,195 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
     int nack;
 
     switch (offset) {
-    case 0x00: /* I2C_REV */
-    case 0x0c: /* I2C_IV */
-    case 0x10: /* I2C_SYSS */
-        OMAP_RO_REG(addr);
-        return;
-
-    case 0x04: /* I2C_IE */
-        s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
-        break;
-
-    case 0x08: /* I2C_STAT */
-        if (s->revision < OMAP2_INTR_REV) {
+        case 0x00: /* I2C_REV */
+        case 0x10: /* I2C_SYSS */
+        case 0x40: /* I2C_BUFSTAT */
+        case 0x50: /* I2C_ACTOA */
             OMAP_RO_REG(addr);
-            return;
-        }
-
-        /* RRDY and XRDY are reset by hardware. (in all versions???) */
-        s->stat &= ~(value & 0x27);
-        omap_i2c_interrupts_update(s);
-        break;
-
-    case 0x14: /* I2C_BUF */
-        s->dma = value & 0x8080;
-        if (value & (1 << 15))                                 /* RDMA_EN */
-            s->mask &= ~(1 << 3);                              /* RRDY_IE */
-        if (value & (1 << 7))                                  /* XDMA_EN */
-            s->mask &= ~(1 << 4);                              /* XRDY_IE */
-        break;
-
-    case 0x18: /* I2C_CNT */
-        s->count = value;                                      /* DCOUNT */
-        break;
-
-    case 0x1c: /* I2C_DATA */
-        if (s->txlen > 2) {
-            /* XXX: remote access (qualifier) error - what's that?  */
             break;
-        }
-        s->fifo <<= 16;
-        s->txlen += 2;
-        if (s->control & (1 << 14)) {                          /* BE */
-            s->fifo |= ((value >> 8) & 0xff) << 8;
-            s->fifo |= ((value >> 0) & 0xff) << 0;
-        } else {
-            s->fifo |= ((value >> 0) & 0xff) << 8;
-            s->fifo |= ((value >> 8) & 0xff) << 0;
-        }
-        s->stat &= ~(1 << 10);                                 /* XUDF */
-        if (s->txlen > 2)
-            s->stat &= ~(1 << 4);                              /* XRDY */
-        omap_i2c_fifo_run(s);
-        omap_i2c_interrupts_update(s);
-        break;
-
-    case 0x20: /* I2C_SYSC */
-        if (s->revision < OMAP2_INTR_REV) {
-            OMAP_BAD_REG(addr);
-            return;
-        }
-
-        if (value & 2)
-            omap_i2c_reset(s);
-        break;
-
-    case 0x24: /* I2C_CON */
-        s->control = value & 0xcf87;
-        if (~value & (1 << 15)) {                              /* I2C_EN */
+        case 0x04: /* I2C_IE */
+            TRACE("IE = %04x", value);
+            if (s->revision >= OMAP3_INTR_REV)
+                s->mask = value & 0x63ff;
+            else
+                s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
+            omap_i2c_interrupts_update(s);
+            break;
+        case 0x08: /* I2C_STAT */
             if (s->revision < OMAP2_INTR_REV)
+                OMAP_RO_REG(addr);
+            else {
+                TRACE("STAT = %04x", value);
+                /* RRDY and XRDY are reset by hardware. (in all versions???) */
+                s->stat &= ~(value & (s->revision < OMAP3_INTR_REV ? 0x27 : 0x63e7));
+                omap_i2c_interrupts_update(s);
+            }
+            break;
+        case 0x0c: /* I2C_IV / I2C_WE */
+            if (s->revision < OMAP3_INTR_REV)
+                OMAP_RO_REG(addr);
+            else
+                s->we = value & 0x636f;
+            break;
+        case 0x14: /* I2C_BUF */
+            TRACE("BUF = %04x", value);
+            if (s->revision < OMAP3_INTR_REV)
+                s->dma = value & 0x8080;
+            else {
+                s->dma = value & 0xbfbf;
+                if ((value & (1 << 14))    /* RXFIFO_CLR */
+                    || (value & (1 << 6))) /* TXFIFO_CLR */
+                    s->fifolen = 0;
+            }
+            if (value & (1 << 15))     /* RDMA_EN */
+                s->mask &= ~(1 << 3);  /* RRDY_IE */
+            if (value & (1 << 7))      /* XDMA_EN */
+                s->mask &= ~(1 << 4);  /* XRDY_IE */
+            break;
+        case 0x18: /* I2C_CNT */
+            TRACE("CNT = %04x", value);
+            s->count = value; /* DCOUNT */
+            break;
+        case 0x1c: /* I2C_DATA */
+            TRACE("DATA = %04x", value);
+            if (s->revision < OMAP3_INTR_REV) {
+                if (s->fifolen > 2) {
+                    /* XXX: remote access (qualifier) error - what's that? */
+                    break;
+                }
+                if (s->control & (1 << 14)) { /* BE */
+                    s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
+                        (uint8_t)((value >> 8) & 0xff);
+                    s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
+                        (uint8_t)(value & 0xff);
+                } else {
+                    s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
+                        (uint8_t)(value & 0xff);
+                    s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
+                        (uint8_t)((value >> 8) & 0xff);
+                }
+            } else {
+                if (s->fifolen < s->fifosize) {
+                    s->stat &= ~(1 << 7); /* AERR */
+                    s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
+                        (uint8_t)(value & 0xff);
+                } else
+                    s->stat |= (1 << 7); /* AERR */
+            }
+            s->stat &= ~(1 << 10); /* XUDF */
+            omap_i2c_fifo_run(s);
+            omap_i2c_interrupts_update(s);
+            break;
+        case 0x20: /* I2C_SYSC */
+            if (s->revision < OMAP2_INTR_REV) {
+                OMAP_BAD_REG(addr);
+                break;
+            }
+            TRACE("SYSC = %04x", value);
+            if (value & 2)
                 omap_i2c_reset(s);
+            else if (s->revision >= OMAP3_INTR_REV)
+                s->sysc = value & 0x031d;
             break;
-        }
-        if ((value & (1 << 15)) && !(value & (1 << 10))) {     /* MST */
-            fprintf(stderr, "%s: I^2C slave mode not supported\n",
-                            __FUNCTION__);
+        case 0x24: /* I2C_CON */
+            TRACE("CON = %04x", value);
+            s->control = value & (s->revision < OMAP3_INTR_REV ? 0xcf87 : 0xbff3);
+            if (~value & (1 << 15)) { /* I2C_EN */
+                if (s->revision < OMAP2_INTR_REV)
+                    omap_i2c_reset(s);
+                break;
+            }
+            if (s->revision >= OMAP3_INTR_REV && ((value >> 12) & 3) > 1) { /* OPMODE */
+                fprintf(stderr,
+                        "%s: only FS and HS modes are supported\n",
+                        __FUNCTION__);
+                break;
+            }
+            if ((value & (1 << 10))) { /* MST */
+                if (value & 1) { /* STT */
+                    nack = !!i2c_start_transfer(s->bus, s->slave_addr, /*SA*/
+                                                (~value >> 9) & 1);    /*TRX*/
+                    s->stat |= nack << 1;        /* NACK */
+                    s->control &= ~(1 << 0);     /* STT */
+                    s->fifolen = 0;
+                    if (nack)
+                        s->control &= ~(1 << 1); /* STP */
+                    else {
+                        s->count_cur = s->count;
+                        omap_i2c_fifo_run(s);
+                    }
+                    omap_i2c_interrupts_update(s);
+                } else if (value & 2) { /* STP, but not STT */
+                    i2c_end_transfer(s->bus);
+                    s->control &= ~0x0602;     /* MST | TRX | STP */
+                    s->count_cur = s->count;
+                }
+            }
             break;
-        }
-        if ((value & (1 << 15)) && value & (1 << 8)) {         /* XA */
-            fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
-                            __FUNCTION__);
+        case 0x28: /* I2C_OA / I2C_OA0 */
+            TRACE("OA0 = %04x", value);
+            s->own_addr[0] = value & (s->revision < OMAP3_INTR_REV 
+                                      ? 0x3ff : 0xe3ff);
+            i2c_set_slave_address(&s->slave[0], 
+                                  value & (s->revision >= OMAP3_INTR_REV 
+                                           && (s->control & 0x80) 
+                                           ? 0x3ff: 0x7f));
             break;
-        }
-        if ((value & (1 << 15)) && value & (1 << 0)) {         /* STT */
-            nack = !!i2c_start_transfer(s->bus, s->addr[1],    /* SA */
-                            (~value >> 9) & 1);                        /* TRX */
-            s->stat |= nack << 1;                              /* NACK */
-            s->control &= ~(1 << 0);                           /* STT */
-            s->fifo = 0;
-            if (nack)
-                s->control &= ~(1 << 1);                       /* STP */
+        case 0x2c: /* I2C_SA */
+            TRACE("SA = %04x", value);
+            s->slave_addr = value & 0x3ff;
+            break;
+        case 0x30: /* I2C_PSC */
+            s->divider = value;
+            break;
+        case 0x34: /* I2C_SCLL */
+            s->times[0] = value & (s->revision < OMAP3_INTR_REV 
+                                   ? 0xff : 0xffff);
+            break;
+        case 0x38: /* I2C_SCLH */
+            s->times[1] = value & (s->revision < OMAP3_INTR_REV
+                                   ? 0xff : 0xffff);
+            break;
+        case 0x3c: /* I2C_SYSTEST */
+            value &= s->revision < OMAP3_INTR_REV ? 0xf805 : 0xf815;
+            if ((value & (1 << 15))) { /* ST_EN */
+                fprintf(stderr, "%s: System Test not supported\n",
+                        __FUNCTION__);
+                s->test = (s->test & 0x0a) | value;
+            } else
+                s->test = (s->test & 0x1f) | (value & 0xf800);
+            if (value & (1 << 11)) /* SBB */
+                if (s->revision >= OMAP2_INTR_REV) {
+                    s->stat |= 0x3f;
+                    if (s->revision >= OMAP3_INTR_REV)
+                        s->stat |= 0x600;
+                    omap_i2c_interrupts_update(s);
+                }
+            break;
+        case 0x44: /* I2C_OA1 */
+        case 0x48: /* I2C_OA2 */
+        case 0x4c: /* I2C_OA3 */
+            if (s->revision < OMAP3_INTR_REV)
+                OMAP_BAD_REG(addr);
             else {
-                s->count_cur = s->count;
-                omap_i2c_fifo_run(s);
+                addr = (addr >> 2) & 3;
+                TRACE("OA%d = %04x", addr, value);
+                s->own_addr[addr] = value & 0x3ff;
+                i2c_set_slave_address(&s->slave[addr], 
+                                      value & ((s->control & (0x80 >> addr)) 
+                                               ? 0x3ff: 0x7f));
             }
-            omap_i2c_interrupts_update(s);
-        }
-        break;
-
-    case 0x28: /* I2C_OA */
-        s->addr[0] = value & 0x3ff;
-        i2c_set_slave_address(&s->slave, value & 0x7f);
-        break;
-
-    case 0x2c: /* I2C_SA */
-        s->addr[1] = value & 0x3ff;
-        break;
-
-    case 0x30: /* I2C_PSC */
-        s->divider = value;
-        break;
-
-    case 0x34: /* I2C_SCLL */
-        s->times[0] = value;
-        break;
-
-    case 0x38: /* I2C_SCLH */
-        s->times[1] = value;
-        break;
-
-    case 0x3c: /* I2C_SYSTEST */
-        s->test = value & 0xf80f;
-        if (value & (1 << 11))                                 /* SBB */
-            if (s->revision >= OMAP2_INTR_REV) {
-                s->stat |= 0x3f;
-                omap_i2c_interrupts_update(s);
+            break;
+        case 0x54: /* I2C_SBLOCK */
+            if (s->revision < OMAP3_INTR_REV)
+                OMAP_BAD_REG(addr);
+            else {
+                s->sblock = value & 0x0f;
             }
-        if (value & (1 << 15))                                 /* ST_EN */
-            fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
+            break;
+        default:
+            OMAP_BAD_REG(addr);
+            break;
     }
 }
 
@@ -449,24 +607,26 @@ static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr,
     int offset = addr & OMAP_MPUI_REG_MASK;
 
     switch (offset) {
-    case 0x1c: /* I2C_DATA */
-        if (s->txlen > 2) {
-            /* XXX: remote access (qualifier) error - what's that?  */
+        case 0x1c: /* I2C_DATA */
+            TRACE("DATA = %02x", value);
+            if (s->revision < OMAP3_INTR_REV && s->fifolen > 2) {
+                /* XXX: remote access (qualifier) error - what's that? */
+                break;
+            }
+            if (s->fifolen < s->fifosize) {
+                s->fifo[(s->fifostart + s->fifolen++) & I2C_FIFO_SIZE_MASK] =
+                    (uint8_t)(value & 0xff);
+                if (s->revision >= OMAP3_INTR_REV)
+                    s->stat &= ~(1 << 7); /* AERR */
+                s->stat &= ~(1 << 10);    /* XUDF */
+                omap_i2c_fifo_run(s);
+            } else if (s->revision >= OMAP3_INTR_REV)
+                s->stat |= (1 << 7);      /* AERR */
+            omap_i2c_interrupts_update(s);
+            break;
+        default:
+            OMAP_BAD_REG(addr);
             break;
-        }
-        s->fifo <<= 8;
-        s->txlen += 1;
-        s->fifo |= value & 0xff;
-        s->stat &= ~(1 << 10);                                 /* XUDF */
-        if (s->txlen > 2)
-            s->stat &= ~(1 << 4);                              /* XRDY */
-        omap_i2c_fifo_run(s);
-        omap_i2c_interrupts_update(s);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
     }
 }
 
@@ -482,52 +642,137 @@ static CPUWriteMemoryFunc *omap_i2c_writefn[] = {
     omap_badwidth_write16,
 };
 
-struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
-                qemu_irq irq, qemu_irq *dma, omap_clk clk)
+static void omap_i2c_save_state(QEMUFile *f, void *opaque)
 {
-    int iomemtype;
-    struct omap_i2c_s *s = (struct omap_i2c_s *)
-            qemu_mallocz(sizeof(struct omap_i2c_s));
+    struct omap_i2c_s *s = (struct omap_i2c_s *)opaque;
+    
+    /* TODO: slave setup(s) */
+    qemu_put_be16(f, s->mask);
+    qemu_put_be16(f, s->stat);
+    qemu_put_be16(f, s->we);
+    qemu_put_be16(f, s->dma);
+    qemu_put_be16(f, s->count);
+    qemu_put_sbe32(f, s->count_cur);
+    qemu_put_be16(f, s->sysc);
+    qemu_put_be16(f, s->control);
+    qemu_put_be16(f, s->own_addr[0]);
+    qemu_put_be16(f, s->own_addr[1]);
+    qemu_put_be16(f, s->own_addr[2]);
+    qemu_put_be16(f, s->own_addr[3]);
+    qemu_put_be16(f, s->slave_addr);
+    qemu_put_byte(f, s->sblock);
+    qemu_put_byte(f, s->divider);
+    qemu_put_be16(f, s->times[0]);
+    qemu_put_be16(f, s->times[1]);
+    qemu_put_be16(f, s->test);
+    qemu_put_sbe32(f, s->fifostart);
+    qemu_put_sbe32(f, s->fifolen);
+    qemu_put_sbe32(f, s->fifosize);
+    qemu_put_buffer(f, s->fifo, sizeof(s->fifo));
+}
 
-    /* TODO: set a value greater or equal to real hardware */
-    s->revision = 0x11;
+static int omap_i2c_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_i2c_s *s = (struct omap_i2c_s *)opaque;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    /* TODO: slave setup(s) */
+    s->mask = qemu_get_be16(f);
+    s->stat = qemu_get_be16(f);
+    s->we = qemu_get_be16(f);
+    s->dma = qemu_get_be16(f);
+    s->count = qemu_get_be16(f);
+    s->count_cur = qemu_get_sbe32(f);
+    s->sysc = qemu_get_be16(f);
+    s->control = qemu_get_be16(f);
+    s->own_addr[0] = qemu_get_be16(f);
+    s->own_addr[1] = qemu_get_be16(f);
+    s->own_addr[2] = qemu_get_be16(f);
+    s->own_addr[3] = qemu_get_be16(f);
+    s->slave_addr = qemu_get_be16(f);
+    s->sblock = qemu_get_byte(f);
+    s->divider = qemu_get_byte(f);
+    s->times[0] = qemu_get_be16(f);
+    s->times[1] = qemu_get_be16(f);
+    s->test = qemu_get_be16(f);
+    s->fifostart = qemu_get_sbe32(f);
+    s->fifolen = qemu_get_sbe32(f);
+    s->fifosize = qemu_get_sbe32(f);
+    qemu_get_buffer(f, s->fifo, sizeof(s->fifo));
+
+    omap_i2c_interrupts_update(s);
+    
+    return 0;
+}
+
+static struct omap_i2c_s *omap_i2c_common_init(uint8_t rev, int fifosize,
+                                               qemu_irq irq, qemu_irq *dma)
+{
+    struct omap_i2c_s *s = (struct omap_i2c_s *)
+        qemu_mallocz(sizeof(struct omap_i2c_s));
+    
+    if (fifosize > I2C_MAX_FIFO_SIZE) {
+        fprintf(stderr, "%s: maximum FIFO size is %d (tried to use %d)\n",
+                __FUNCTION__, I2C_MAX_FIFO_SIZE, fifosize);
+        exit(-1);
+    }
+    s->revision = rev;
     s->irq = irq;
     s->drq[0] = dma[0];
     s->drq[1] = dma[1];
-    s->slave.event = omap_i2c_event;
-    s->slave.recv = omap_i2c_rx;
-    s->slave.send = omap_i2c_tx;
+    s->slave[0].event = s->slave[1].event = s->slave[2].event =
+        s->slave[3].event = omap_i2c_event;
+    s->slave[0].recv = s->slave[1].recv = s->slave[2].recv =
+        s->slave[3].recv = omap_i2c_rx;
+    s->slave[0].send = s->slave[1].send = s->slave[2].send =
+        s->slave[3].send = omap_i2c_tx;
     s->bus = i2c_init_bus();
+    s->fifosize = fifosize;
     omap_i2c_reset(s);
+    return s;
+}
 
-    iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
-                    omap_i2c_writefn, s);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
+                qemu_irq irq, qemu_irq *dma, omap_clk clk)
+{
+    struct omap_i2c_s *s = omap_i2c_common_init(0x11, 4, irq, dma);
 
+    cpu_register_physical_memory(base, 0x800,
+                                 cpu_register_io_memory(0, omap_i2c_readfn,
+                                                        omap_i2c_writefn, s));
     return s;
 }
 
 struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta,
                 qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk)
 {
-    int iomemtype;
-    struct omap_i2c_s *s = (struct omap_i2c_s *)
-            qemu_mallocz(sizeof(struct omap_i2c_s));
-
-    s->revision = 0x34;
-    s->irq = irq;
-    s->drq[0] = dma[0];
-    s->drq[1] = dma[1];
-    s->slave.event = omap_i2c_event;
-    s->slave.recv = omap_i2c_rx;
-    s->slave.send = omap_i2c_tx;
-    s->bus = i2c_init_bus();
-    omap_i2c_reset(s);
+    struct omap_i2c_s *s = omap_i2c_common_init(0x34, 4, irq, dma);
 
-    iomemtype = l4_register_io_memory(0, omap_i2c_readfn,
-                    omap_i2c_writefn, s);
-    omap_l4_attach(ta, 0, iomemtype);
+    omap_l4_attach(ta, 0, l4_register_io_memory(0, omap_i2c_readfn,
+                                                omap_i2c_writefn, s));
+    return s;
+}
 
+struct omap_i2c_s *omap3_i2c_init(struct omap_target_agent_s *ta,
+                                  qemu_irq irq, qemu_irq *dma,
+                                  omap_clk fclk, omap_clk iclk,
+                                  int fifosize)
+{
+    struct omap_i2c_s *s;
+    
+    if (fifosize != 8 && fifosize != 16 && fifosize != 32 && fifosize != 64) {
+        fprintf(stderr, "%s: unsupported FIFO depth specified (%d)\n",
+                __FUNCTION__, fifosize);
+        exit(-1);
+    }
+    s = omap_i2c_common_init(OMAP3_INTR_REV, fifosize, irq, dma);
+    
+    omap_l4_attach(ta, 0, l4_register_io_memory(0, omap_i2c_readfn,
+                                                omap_i2c_writefn, s));
+    register_savevm("omap3_i2c", (ta->base >> 12) & 0xff, 0,
+                    omap_i2c_save_state, omap_i2c_load_state, s);
     return s;
 }
 
diff --git a/hw/omap_spi.c b/hw/omap_spi.c
new file mode 100644 (file)
index 0000000..b24eb65
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * TI OMAP processor's Multichannel SPI emulation.
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "hw.h"
+#include "omap.h"
+
+#define SPI_FIFOSIZE 64
+#define SPI_REV_OMAP2420 0x14
+#define SPI_REV_OMAP3530 0x21
+#define IS_OMAP3_SPI(s) ((s)->revision >= SPI_REV_OMAP3530)
+
+struct omap_mcspi_s {
+    qemu_irq irq;
+    int chnum;
+    uint8_t revision;
+    
+    uint32_t sysconfig;
+    uint32_t systest;
+    uint32_t irqst;
+    uint32_t irqen;
+    uint32_t wken;
+    uint32_t control;
+    uint32_t xferlevel;
+    struct omap_mcspi_fifo_s {
+        int start;
+        int len;
+        int size;
+        uint8_t buf[SPI_FIFOSIZE];
+    } tx_fifo, rx_fifo;
+    int fifo_ch;
+    int fifo_wcnt;
+    
+    struct omap_mcspi_ch_s {
+        qemu_irq txdrq;
+        qemu_irq rxdrq;
+        uint32_t (*txrx)(void *opaque, uint32_t, int);
+        void *opaque;
+        
+        uint32_t tx;
+        uint32_t rx;
+        
+        uint32_t config;
+        uint32_t status;
+        uint32_t control;
+    } ch[0];
+};
+
+static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
+{
+    qemu_set_irq(s->irq, s->irqst & s->irqen);
+}
+
+static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_s *s,
+                                                int chnum)
+{
+    struct omap_mcspi_ch_s *ch = &s->ch[chnum];
+    if ((ch->control & 1) &&                         /* EN */
+        (ch->config & (1 << 14)) &&                  /* DMAW */
+        (ch->status & (1 << 1)) &&                   /* TXS */
+        ((ch->config >> 12) & 3) != 1) {             /* TRM */
+        if (!IS_OMAP3_SPI(s) ||
+            !(ch->config & (1 << 27)) ||             /* FFEW */
+            s->tx_fifo.len <= (s->xferlevel & 0x3f)) /* AEL */
+            qemu_irq_raise(ch->txdrq);
+        else
+            qemu_irq_lower(ch->txdrq);
+    }
+    if ((ch->control & 1) &&                                /* EN */
+        (ch->config & (1 << 15)) &&                         /* DMAW */
+        (ch->status & (1 << 0)) &&                          /* RXS */
+        ((ch->config >> 12) & 3) != 2) {                    /* TRM */
+        if (!IS_OMAP3_SPI(s) ||
+            !(ch->config & (1 << 28)) ||                    /* FFER */
+            s->rx_fifo.len >= ((s->xferlevel >> 8) & 0x3f)) /* AFL */
+            qemu_irq_raise(ch->rxdrq);
+        else
+            qemu_irq_lower(ch->rxdrq);
+    }
+}
+
+static void omap_mcspi_fifo_reset(struct omap_mcspi_s *s)
+{
+    struct omap_mcspi_ch_s *ch;
+    
+    s->tx_fifo.len = 0;
+    s->rx_fifo.len = 0;
+    s->tx_fifo.start = 0;
+    s->rx_fifo.start = 0;
+    if (s->fifo_ch < 0) {
+        s->tx_fifo.size  = s->rx_fifo.size  = 0;
+    } else {
+        ch = &s->ch[s->fifo_ch];
+        s->tx_fifo.size = ((ch->config >> 27) & 1) ? SPI_FIFOSIZE : 0;
+        s->rx_fifo.size = ((ch->config >> 28) & 1) ? SPI_FIFOSIZE : 0;
+        if (((ch->config >> 27) & 3) == 3) {
+            s->tx_fifo.size >>= 1;
+            s->rx_fifo.size >>= 1;
+        }
+    }
+}
+
+static void omap_mcspi_save_state(QEMUFile *f, void *opaque)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *)opaque;
+    int i;
+    
+    qemu_put_be32(f, s->sysconfig);
+    qemu_put_be32(f, s->systest);
+    qemu_put_be32(f, s->irqst);
+    qemu_put_be32(f, s->irqen);
+    qemu_put_be32(f, s->wken);
+    qemu_put_be32(f, s->control);
+    qemu_put_be32(f, s->xferlevel);
+    qemu_put_sbe32(f, s->tx_fifo.start);
+    qemu_put_sbe32(f, s->tx_fifo.len);
+    qemu_put_sbe32(f, s->tx_fifo.size);
+    qemu_put_buffer(f, s->tx_fifo.buf, sizeof(s->tx_fifo.buf));
+    qemu_put_sbe32(f, s->rx_fifo.start);
+    qemu_put_sbe32(f, s->rx_fifo.len);
+    qemu_put_sbe32(f, s->rx_fifo.size);
+    qemu_put_buffer(f, s->rx_fifo.buf, sizeof(s->rx_fifo.buf));
+    qemu_put_sbe32(f, s->fifo_ch);
+    qemu_put_sbe32(f, s->fifo_wcnt);
+    for (i = 0; i < s->chnum; i++) {
+        qemu_put_be32(f, s->ch[i].tx);
+        qemu_put_be32(f, s->ch[i].rx);
+        qemu_put_be32(f, s->ch[i].config);
+        qemu_put_be32(f, s->ch[i].status);
+        qemu_put_be32(f, s->ch[i].control);
+    }
+}
+
+static int omap_mcspi_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->sysconfig = qemu_get_be32(f);
+    s->systest = qemu_get_be32(f);
+    s->irqst = qemu_get_be32(f);
+    s->irqen = qemu_get_be32(f);
+    s->wken = qemu_get_be32(f);
+    s->control = qemu_get_be32(f);
+    s->xferlevel = qemu_get_be32(f);
+    s->tx_fifo.start = qemu_get_be32(f);
+    s->tx_fifo.len = qemu_get_be32(f);
+    s->tx_fifo.size = qemu_get_be32(f);
+    qemu_get_buffer(f, s->tx_fifo.buf, sizeof(s->tx_fifo.buf));
+    s->rx_fifo.start = qemu_get_be32(f);
+    s->rx_fifo.len = qemu_get_be32(f);
+    s->rx_fifo.size = qemu_get_be32(f);
+    qemu_get_buffer(f, s->rx_fifo.buf, sizeof(s->rx_fifo.buf));
+    s->fifo_ch = qemu_get_sbe32(f);
+    s->fifo_wcnt = qemu_get_sbe32(f);
+    for (i = 0; i < s->chnum; i++) {
+        s->ch[i].tx = qemu_get_be32(f);
+        s->ch[i].rx = qemu_get_be32(f);
+        s->ch[i].config = qemu_get_be32(f);
+        s->ch[i].status = qemu_get_be32(f);
+        s->ch[i].control = qemu_get_be32(f);
+        omap_mcspi_dmarequest_update(s, i);
+    }
+    omap_mcspi_interrupt_update(s);
+    
+    return 0;
+}
+
+/* returns next word in FIFO or the n first bytes if there is not
+ * enough data in FIFO */
+static uint32_t omap_mcspi_fifo_get(struct omap_mcspi_fifo_s *s, int wl)
+{
+    uint32_t v, sh;
+    
+    for (v = 0, sh = 0; wl > 0 && s->len; wl -= 8, s->len--, sh += 8) {
+        v |= ((uint32_t)s->buf[s->start++]) << sh;
+        if (s->start >= s->size)
+            s->start = 0;
+    }
+    return v;
+}
+
+/* pushes a word to FIFO or the first n bytes of the word if the FIFO
+ * is too full to hold the full word */
+static void omap_mcspi_fifo_put(struct omap_mcspi_fifo_s *s, int wl,
+                                uint32_t v)
+{
+    int p = s->start + s->len;
+
+    for (; wl > 0 && s->len < s->size; wl -=8, v >>= 8, s->len++) {
+        if (p >= s->size)
+            p -= s->size;
+        s->buf[p++] = (uint8_t)(v & 0xff);
+    }
+}
+
+static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
+{
+    struct omap_mcspi_ch_s *ch = s->ch + chnum;
+    int trm = (ch->config >> 12) & 3;
+    int wl;
+    
+    if (!(ch->control & 1))                  /* EN */
+        return;
+    if ((ch->status & 1) && trm != 2 &&      /* RXS */
+        !(ch->config & (1 << 19)))           /* TURBO */
+        goto intr_update;
+    if ((ch->status & (1 << 1)) && trm != 1) /* TXS */
+        goto intr_update;
+    
+    if (!(s->control & 1) ||        /* SINGLE */
+        (ch->config & (1 << 20))) { /* FORCE */
+        if (ch->txrx) {
+            wl = 1 + (0x1f & (ch->config >> 7)); /* WL */
+            if (!IS_OMAP3_SPI(s) || s->fifo_ch != chnum ||
+                !((ch->config >> 27) & 3))       /* FFER | FFEW */
+                ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
+            else {
+                switch ((ch->config >> 27) & 3) {
+                    case 1: /* !FFER, FFEW */
+                        if (trm != 1)
+                            ch->tx = omap_mcspi_fifo_get(&s->tx_fifo, wl);
+                        ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
+                        s->fifo_wcnt--;
+                        break;
+                    case 2: /* FFER, !FFEW */
+                        ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
+                        if (trm != 2)
+                            omap_mcspi_fifo_put(&s->rx_fifo, wl, ch->rx);
+                        s->fifo_wcnt--;
+                        break;
+                    case 3: /* FFER, FFEW */
+                        while (s->rx_fifo.len < s->rx_fifo.size &&
+                               s->tx_fifo.len && s->fifo_wcnt) {
+                            if (trm != 1)
+                                ch->tx = omap_mcspi_fifo_get(&s->tx_fifo, wl);
+                            ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
+                            if (trm != 2)
+                                omap_mcspi_fifo_put(&s->rx_fifo, wl, ch->rx);
+                            s->fifo_wcnt--;
+                        }
+                        break;
+                    default:
+                        break;
+                }
+                if ((ch->config & (1 << 28)) &&        /* FFER */
+                    s->rx_fifo.len >= s->rx_fifo.size)
+                    ch->status |= 1 << 6;              /* RXFFF */
+                ch->status &= ~(1 << 5);               /* RXFFE */
+                ch->status &= ~(1 << 4);               /* TXFFF */
+                if ((ch->config & (1 << 27)) &&        /* FFEW */
+                    !s->tx_fifo.len)
+                    ch->status |= 1 << 3;              /* TXFFE */
+                if (!s->fifo_wcnt &&
+                    ((s->xferlevel >> 16) & 0xffff))   /* WCNT */
+                    s->irqst |= 1 << 17;               /* EOW */
+            }
+        }
+    }
+    
+    ch->tx = 0;
+    ch->status |= 1 << 2;               /* EOT */
+    ch->status |= 1 << 1;               /* TXS */
+    if (trm != 2)
+        ch->status |= 1;                /* RXS */
+        
+intr_update:
+    if ((ch->status & 1) &&    trm != 2 &&                     /* RXS */
+        !(ch->config & (1 << 19)))                          /* TURBO */
+        if (!IS_OMAP3_SPI(s) || s->fifo_ch != chnum ||
+            !((ch->config >> 28) & 1) ||                    /* FFER */
+            s->rx_fifo.len >= ((s->xferlevel >> 8) & 0x3f)) /* AFL */
+            s->irqst |= 1 << (2 + 4 * chnum);               /* RX_FULL */
+    if ((ch->status & (1 << 1)) && trm != 1)                /* TXS */
+        if (!IS_OMAP3_SPI(s) || s->fifo_ch != chnum ||
+            !((ch->config >> 27) & 1) ||                    /* FFEW */
+            s->tx_fifo.len <= (s->xferlevel & 0x3f))        /* AEL */
+            s->irqst |= 1 << (4 * chnum);                   /* TX_EMPTY */
+    omap_mcspi_interrupt_update(s);
+    omap_mcspi_dmarequest_update(s, chnum);
+}
+
+void omap_mcspi_reset(struct omap_mcspi_s *s)
+{
+    int ch;
+    
+    s->sysconfig = 0;
+    s->systest = 0;
+    s->irqst = 0;
+    s->irqen = 0;
+    s->wken = 0;
+    s->control = 4;
+    
+    s->fifo_ch = -1;
+    omap_mcspi_fifo_reset(s);
+    
+    for (ch = 0; ch < s->chnum; ch ++) {
+        s->ch[ch].config = 0x060000;
+        s->ch[ch].status = 2;                          /* TXS */
+        s->ch[ch].control = 0;
+        
+        omap_mcspi_dmarequest_update(s, ch);
+    }
+    
+    omap_mcspi_interrupt_update(s);
+}
+
+static uint32_t omap_mcspi_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    int ch = 0;
+    uint32_t ret;
+    
+    switch (addr) {
+        case 0x00:     /* MCSPI_REVISION */
+            return s->revision;
+            
+        case 0x10:     /* MCSPI_SYSCONFIG */
+            return s->sysconfig;
+            
+        case 0x14:     /* MCSPI_SYSSTATUS */
+            return 1;                                  /* RESETDONE */
+            
+        case 0x18:     /* MCSPI_IRQSTATUS */
+            return s->irqst;
+            
+        case 0x1c:     /* MCSPI_IRQENABLE */
+            return s->irqen;
+            
+        case 0x20:     /* MCSPI_WAKEUPENABLE */
+            return s->wken;
+            
+        case 0x24:     /* MCSPI_SYST */
+            return s->systest;
+            
+        case 0x28:     /* MCSPI_MODULCTRL */
+            return s->control;
+            
+        case 0x68: ch ++;
+        case 0x54: ch ++;
+        case 0x40: ch ++;
+        case 0x2c:     /* MCSPI_CHCONF */
+            return (ch < s->chnum) ? s->ch[ch].config : 0;
+            
+        case 0x6c: ch ++;
+        case 0x58: ch ++;
+        case 0x44: ch ++;
+        case 0x30:     /* MCSPI_CHSTAT */
+            return (ch < s->chnum) ? s->ch[ch].status : 0;
+            
+        case 0x70: ch ++;
+        case 0x5c: ch ++;
+        case 0x48: ch ++;
+        case 0x34:     /* MCSPI_CHCTRL */
+            return (ch < s->chnum) ? s->ch[ch].control : 0;
+            
+        case 0x74: ch ++;
+        case 0x60: ch ++;
+        case 0x4c: ch ++;
+        case 0x38:     /* MCSPI_TX */
+            if (ch < s->chnum)
+                return s->ch[ch].tx;
+            break;
+            
+        case 0x78: ch ++;
+        case 0x64: ch ++;
+        case 0x50: ch ++;
+        case 0x3c:     /* MCSPI_RX */
+            if (ch < s->chnum) {
+                if (!IS_OMAP3_SPI(s) || ch != s->fifo_ch ||
+                    !(s->ch[ch].config & (1 << 28))) { /* FFER */
+                    s->ch[ch].status &= ~1;            /* RXS */
+                    ret = s->ch[ch].rx;
+                    omap_mcspi_transfer_run(s, ch);
+                    return ret;
+                }
+                if (!s->rx_fifo.len)
+                    fprintf(stderr, "%s: rxfifo underflow!\n", __FUNCTION__);
+                else {
+                    qemu_irq_lower(s->ch[ch].rxdrq);
+                    s->ch[ch].status &= ~(1 << 6);                 /* RXFFF */
+                    if (((s->ch[ch].config >> 12) & 3) != 2)        /* TRM */
+                        ret = omap_mcspi_fifo_get(&s->rx_fifo,
+                            1 + ((s->ch[ch].config >> 7) & 0x1f)); /* WL */
+                    else
+                        ret = s->ch[ch].rx;
+                    if (!s->rx_fifo.len) {
+                        s->ch[ch].status &= ~1;     /* RXS */
+                        s->ch[ch].status |= 1 << 5; /* RXFFE */
+                        omap_mcspi_transfer_run(s, ch);
+                    }
+                    return ret;
+                }
+            }
+            return 0;
+        
+        case 0x7c: /* MCSPI_XFERLEVEL */
+            if (IS_OMAP3_SPI(s)) {
+                if ((s->xferlevel >> 16) & 0xffff) /* WCNT */
+                    ret = ((s->xferlevel & 0xffff0000) - (s->fifo_wcnt << 16));
+                else
+                    ret = ((-s->fifo_wcnt) & 0xffff) << 16;
+                return (s->xferlevel & 0xffff) | ret;
+            }
+            break;
+            
+        default:
+            break;
+    }
+    
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mcspi_write(void *opaque, target_phys_addr_t addr,
+                             uint32_t value)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    uint32_t old;
+    int ch = 0;
+    
+    switch (addr) {
+        case 0x00:     /* MCSPI_REVISION */
+        case 0x14:     /* MCSPI_SYSSTATUS */
+        case 0x30:     /* MCSPI_CHSTAT0 */
+        case 0x3c:     /* MCSPI_RX0 */
+        case 0x44:     /* MCSPI_CHSTAT1 */
+        case 0x50:     /* MCSPI_RX1 */
+        case 0x58:     /* MCSPI_CHSTAT2 */
+        case 0x64:     /* MCSPI_RX2 */
+        case 0x6c:     /* MCSPI_CHSTAT3 */
+        case 0x78:     /* MCSPI_RX3 */
+            OMAP_RO_REGV(addr, value);
+            return;
+            
+        case 0x10:     /* MCSPI_SYSCONFIG */
+            if (value & (1 << 1))                              /* SOFTRESET */
+                omap_mcspi_reset(s);
+            s->sysconfig = value & 0x31d;
+            break;
+            
+        case 0x18:     /* MCSPI_IRQSTATUS */
+            if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
+                s->irqst &= ~value;
+                omap_mcspi_interrupt_update(s);
+            }
+            break;
+            
+        case 0x1c:     /* MCSPI_IRQENABLE */
+            s->irqen = value & (IS_OMAP3_SPI(s) ? 0x3777f : 0x1777f);
+            omap_mcspi_interrupt_update(s);
+            break;
+            
+        case 0x20:     /* MCSPI_WAKEUPENABLE */
+            s->wken = value & 1;
+            break;
+            
+        case 0x24:     /* MCSPI_SYST */
+            if (s->control & (1 << 3))                 /* SYSTEM_TEST */
+                if (value & (1 << 11)) {                       /* SSB */
+                    s->irqst |= 0x1777f;
+                    omap_mcspi_interrupt_update(s);
+                }
+            s->systest = value & 0xfff;
+            break;
+            
+        case 0x28:     /* MCSPI_MODULCTRL */
+            if (value & (1 << 3))                              /* SYSTEM_TEST */
+                if (s->systest & (1 << 11)) {          /* SSB */
+                    s->irqst |= IS_OMAP3_SPI(s) ? 0x3777f : 0x1777f;
+                    omap_mcspi_interrupt_update(s);
+                }
+            s->control = value & 0xf;
+            break;
+            
+        case 0x68: ch ++;
+        case 0x54: ch ++;
+        case 0x40: ch ++;
+        case 0x2c:     /* MCSPI_CHCONF */
+            if (ch < s->chnum) {
+                old = s->ch[ch].config;
+                s->ch[ch].config = value & (IS_OMAP3_SPI(s)
+                                            ? 0x3fffffff : 0x7fffff);
+                if (IS_OMAP3_SPI(s) &&
+                    ((value ^ old) & (3 << 27))) { /* FFER | FFEW */
+                    s->fifo_ch = ((value & (3 << 27))) ? ch : -1;
+                    omap_mcspi_fifo_reset(s);
+                }
+                if (((value ^ old) & (3 << 14)) || /* DMAR | DMAW */
+                    (IS_OMAP3_SPI(s) &&
+                     ((value ^ old) & (3 << 27)))) /* FFER | FFEW */
+                    omap_mcspi_dmarequest_update(s, ch);
+                if (((value >> 12) & 3) == 3)                  /* TRM */
+                    fprintf(stderr, "%s: invalid TRM value (3)\n",
+                            __FUNCTION__);
+                if (((value >> 7) & 0x1f) < 3)                 /* WL */
+                    fprintf(stderr, "%s: invalid WL value (%i)\n",
+                            __FUNCTION__, (value >> 7) & 0x1f);
+                if (IS_OMAP3_SPI(s) &&
+                    ((value >> 23) & 1))               /* SBE */
+                    fprintf(stderr, "%s: start-bit mode is not supported\n",
+                            __FUNCTION__);
+            }
+            break;
+            
+        case 0x70: ch ++;
+        case 0x5c: ch ++;
+        case 0x48: ch ++;
+        case 0x34:     /* MCSPI_CHCTRL */
+            if (ch < s->chnum) {
+                old = s->ch[ch].control;
+                s->ch[ch].control = value & (IS_OMAP3_SPI(s) ? 0xff01 : 1);
+                if (value & ~old & 1) { /* EN */
+                    if (IS_OMAP3_SPI(s) && s->fifo_ch == ch)
+                        omap_mcspi_fifo_reset(s);
+                    omap_mcspi_transfer_run(s, ch);
+                }
+            }
+            break;
+            
+        case 0x74: ch ++;
+        case 0x60: ch ++;
+        case 0x4c: ch ++;
+        case 0x38:     /* MCSPI_TX */
+            if (ch < s->chnum) {
+                if (!IS_OMAP3_SPI(s) || s->fifo_ch != ch ||
+                    !(s->ch[ch].config & (1 << 27))) { /* FFEW */
+                    s->ch[ch].tx = value;
+                    s->ch[ch].status &= ~(1 << 1);     /* TXS */
+                    omap_mcspi_transfer_run(s, ch);
+                } else {
+                    if (s->tx_fifo.len >= s->tx_fifo.size)
+                        fprintf(stderr, "%s: txfifo overflow!\n",
+                                __FUNCTION__);
+                    else {
+                        qemu_irq_lower(s->ch[ch].txdrq);
+                        s->ch[ch].status &= ~0x0a;            /* TXFFE | TXS */
+                        if (((s->ch[ch].config >> 12) & 3) != 1) {    /* TRM */
+                            omap_mcspi_fifo_put(
+                                &s->tx_fifo,
+                                1 + ((s->ch[ch].config >> 7) & 0x1f), /* WL */
+                                value);
+                            if (s->tx_fifo.len >= s->tx_fifo.size)
+                                s->ch[ch].status |= 1 << 4;        /* TXFFF */
+                            if (s->tx_fifo.len >= (s->xferlevel & 0x3f))
+                                omap_mcspi_transfer_run(s, ch);
+                        } else {
+                            s->ch[ch].tx = value;
+                            omap_mcspi_transfer_run(s, ch);
+                        }
+                    }
+                }
+            }
+            break;
+            
+        case 0x7c:
+            if (IS_OMAP3_SPI(s)) {
+                if (value != s->xferlevel) {
+                    s->fifo_wcnt = (value >> 16) & 0xffff;
+                    s->xferlevel = value & 0xffff3f3f;
+                    omap_mcspi_fifo_reset(s);
+                }
+            } else
+                OMAP_BAD_REGV(addr, value);
+            break;
+            
+        default:
+            OMAP_BAD_REGV(addr, value);
+            return;
+    }
+}
+
+static CPUReadMemoryFunc *omap_mcspi_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_mcspi_read,
+};
+
+static CPUWriteMemoryFunc *omap_mcspi_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_mcspi_write,
+};
+
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta,
+                                     struct omap_mpu_state_s *mpu,
+                                     int chnum, qemu_irq irq, qemu_irq *drq,
+                                     omap_clk fclk, omap_clk iclk)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
+        qemu_mallocz(sizeof(struct omap_mcspi_s) +
+                     chnum * sizeof(struct omap_mcspi_ch_s));
+    struct omap_mcspi_ch_s *ch = s->ch;
+    
+    s->irq = irq;
+    s->chnum = chnum;
+    /* revision was hardcoded as 0x91 in original code -- odd */
+    s->revision = cpu_class_omap3(mpu) ? SPI_REV_OMAP3530 : SPI_REV_OMAP2420;
+    while (chnum --) {
+        ch->txdrq = *drq ++;
+        ch->rxdrq = *drq ++;
+        ch ++;
+    }
+    omap_mcspi_reset(s);
+    
+    omap_l4_attach(ta, 0, l4_register_io_memory(0, omap_mcspi_readfn,
+                                                omap_mcspi_writefn, s));
+    register_savevm("omap_mcspi", (ta->base >> 8), 0,
+                    omap_mcspi_save_state, omap_mcspi_load_state, s);
+    return s;
+}
+
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+                       uint32_t (*txrx)(void *opaque, uint32_t, int),
+                       void *opaque,
+                       int chipselect)
+{
+    if (chipselect < 0 || chipselect >= s->chnum)
+        cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n",
+                  __FUNCTION__, chipselect);
+    
+    s->ch[chipselect].txrx = txrx;
+    s->ch[chipselect].opaque = opaque;
+}
index 510119f..694d03a 100644 (file)
@@ -24,6 +24,7 @@
 #include "irq.h"
 #include "sysemu.h"
 #include "block.h"
+#include "hw.h"
 
 /* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
 #define PAGE_SHIFT     11
@@ -129,6 +130,85 @@ static void onenand_intr_update(struct onenand_s *s)
     qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
 }
 
+static void onenand_save_state(QEMUFile *f, void *opaque)
+{
+    struct onenand_s *s = (struct onenand_s *)opaque;
+    int i;
+    
+    if (s->current == s->otp)
+        qemu_put_byte(f, 1);
+    else if (s->current == s->image)
+        qemu_put_byte(f, 2);
+    else
+        qemu_put_byte(f, 0);
+    qemu_put_sbe32(f, s->cycle);
+    qemu_put_sbe32(f, s->otpmode);
+    for (i = 0; i < 8; i++) {
+        qemu_put_be16(f, s->addr[i]);
+        qemu_put_be16(f, s->unladdr[i]);
+    }
+    qemu_put_sbe32(f, s->bufaddr);
+    qemu_put_sbe32(f, s->count);
+    qemu_put_be16(f, s->command);
+    qemu_put_be16(f, s->config[0]);
+    qemu_put_be16(f, s->config[1]);
+    qemu_put_be16(f, s->status);
+    qemu_put_be16(f, s->intstatus);
+    qemu_put_be16(f, s->wpstatus);
+    qemu_put_sbe32(f, s->secs_cur);
+    qemu_put_buffer(f, s->blockwp, s->blocks);
+    qemu_put_byte(f, s->ecc.cp);
+    qemu_put_be16(f, s->ecc.lp[0]);
+    qemu_put_be16(f, s->ecc.lp[1]);
+    qemu_put_be16(f, s->ecc.count);
+    qemu_put_buffer(f, s->otp, (64 + 2) << PAGE_SHIFT);
+}
+
+static int onenand_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct onenand_s *s = (struct onenand_s *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    switch (qemu_get_byte(f)) {
+        case 1:
+            s->current = s->otp;
+            break;
+        case 2:
+            s->current = s->image;
+            break;
+        default:
+            break;
+    }
+    s->cycle = qemu_get_sbe32(f);
+    s->otpmode = qemu_get_sbe32(f);
+    for (i = 0; i < 8; i++) {
+        s->addr[i] = qemu_get_be16(f);
+        s->unladdr[i] = qemu_get_be16(f);
+    }
+    s->bufaddr = qemu_get_sbe32(f);
+    s->count = qemu_get_sbe32(f);
+    s->command = qemu_get_be16(f);
+    s->config[0] = qemu_get_be16(f);
+    s->config[1] = qemu_get_be16(f);
+    s->status = qemu_get_be16(f);
+    s->intstatus = qemu_get_be16(f);
+    s->wpstatus = qemu_get_be16(f);
+    s->secs_cur = qemu_get_sbe32(f);
+    qemu_get_buffer(f, s->blockwp, s->blocks);
+    s->ecc.cp = qemu_get_byte(f);
+    s->ecc.lp[0] = qemu_get_be16(f);
+    s->ecc.lp[1] = qemu_get_be16(f);
+    s->ecc.count = qemu_get_be16(f);
+    qemu_get_buffer(f, s->otp, (64 + 2) << PAGE_SHIFT);
+    
+    onenand_intr_update(s);
+    
+    return 0;
+}
+
 /* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
 static void onenand_reset(struct onenand_s *s, int cold)
 {
@@ -651,6 +731,9 @@ void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
     s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
 
     onenand_reset(s, 1);
+    
+    register_savevm("onenand", id | ((regshift & 0x7f) << 24), 0,
+                    onenand_save_state, onenand_load_state, s);
 
     return s;
 }
index aae4b86..aa67c4f 100644 (file)
@@ -123,7 +123,7 @@ static void realview_init(ram_addr_t ram_size, int vga_ram_size,
         nd = &nd_table[n];
 
         if ((!nd->model && !done_smc) || strcmp(nd->model, "smc91c111") == 0) {
-            smc91c111_init(nd, 0x4e000000, pic[28]);
+            smc91c111_init(nd, 0x4e000000, pic[28], 1);
             done_smc = 1;
         } else {
             pci_nic_init(pci_bus, nd, -1, "rtl8139");
diff --git a/hw/sd.c b/hw/sd.c
index 4618883..5f496cd 100644 (file)
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -37,7 +37,7 @@
 
 #ifdef DEBUG_SD
 #define DPRINTF(fmt, args...) \
-do { fprintf(stderr, "SD: " fmt , ##args); } while (0)
+do { fprintf(stderr, "%s: " fmt , __FUNCTION__, ##args); } while (0)
 #else
 #define DPRINTF(fmt, args...) do {} while(0)
 #endif
@@ -200,8 +200,8 @@ static void sd_set_ocr(SDState *sd)
 
 static void sd_set_scr(SDState *sd)
 {
-    sd->scr[0] = 0x00;         /* SCR Structure */
-    sd->scr[1] = 0x2f;         /* SD Security Support */
+    sd->scr[0] = 0x00; /* SCR v1.0, SD spec v1.0/1.01 */
+    sd->scr[1] = 0x25; /* erase=0, SD security v1.01, 1bit/4bit bus width */
     sd->scr[2] = 0x00;
     sd->scr[3] = 0x00;
     sd->scr[4] = 0x00;
@@ -367,14 +367,14 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
 
     bdrv_get_geometry(bdrv, &sect);
     sect <<= 9;
-
+    
     if (sect > 0x40000000)
         size = 0x40000000;     /* 1 gig */
     else
         size = sect + 1;
-
+    
     sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
-
+    
     sd->state = sd_idle_state;
     sd->rca = 0x0000;
     sd_set_ocr(sd);
@@ -408,6 +408,95 @@ static void sd_cardchange(void *opaque)
     }
 }
 
+static void sd_save_state(QEMUFile *f, void *opaque)
+{
+    struct SDState *s = (struct SDState *)opaque;
+    int i;
+    uint32_t wpgc = (s->size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+    char *filename;
+    
+    filename = qemu_mallocz(1024);
+    bdrv_get_backing_filename(s->bdrv, filename, 1024);
+    qemu_put_buffer(f, (uint8_t *)filename, 1024);
+    free(filename);
+    
+    qemu_put_sbe32(f, s->mode);
+    qemu_put_sbe32(f, s->state);
+    qemu_put_be32(f, s->ocr);
+    qemu_put_buffer(f, s->scr, sizeof(s->scr));
+    qemu_put_buffer(f, s->cid, sizeof(s->cid));
+    qemu_put_buffer(f, s->csd, sizeof(s->csd));
+    qemu_put_be16(f, s->rca);
+    qemu_put_be32(f, s->card_status);
+    qemu_put_buffer(f, s->sd_status, sizeof(s->sd_status));
+    qemu_put_be32(f, s->vhs);
+    for (i = 0; i < wpgc; i++)
+        qemu_put_sbe32(f, s->wp_groups[i]);
+    qemu_put_sbe32(f, s->blk_len);
+    qemu_put_be32(f, s->erase_start);
+    qemu_put_be32(f, s->erase_end);
+    qemu_put_buffer(f, s->pwd, sizeof(s->pwd));
+    qemu_put_sbe32(f, s->pwd_len);
+    for (i = 0; i < 6; i++)
+        qemu_put_sbe32(f, s->function_group[i]);
+    qemu_put_sbe32(f, s->current_cmd);
+    qemu_put_sbe32(f, s->blk_written);
+    qemu_put_be32(f, s->data_start);
+    qemu_put_be32(f, s->data_offset);
+    qemu_put_buffer(f, s->data, sizeof(s->data));
+    qemu_put_buffer(f, s->buf, 512);
+    qemu_put_sbe32(f, s->enable);
+}
+
+static int sd_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct SDState *s = (struct SDState *)opaque;
+    int i;
+    uint32_t wpgc = (s->size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+    char *filename1, *filename2;
+    int result = 0;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    filename1 = qemu_mallocz(1024);
+    filename2 = qemu_mallocz(1024);
+    bdrv_get_backing_filename(s->bdrv, filename1, 1024);
+    qemu_get_buffer(f, (uint8_t *)filename2, 1024);
+    if (!strcmp(filename1, filename2)) {
+        s->mode = qemu_get_sbe32(f);
+        s->state = qemu_get_sbe32(f);
+        s->ocr = qemu_get_be32(f);
+        qemu_get_buffer(f, s->scr, sizeof(s->scr));
+        qemu_get_buffer(f, s->cid, sizeof(s->cid));
+        qemu_get_buffer(f, s->csd, sizeof(s->csd));
+        s->rca = qemu_get_be16(f);
+        s->card_status = qemu_get_be32(f);
+        qemu_get_buffer(f, s->sd_status, sizeof(s->sd_status));
+        s->vhs = qemu_get_be32(f);
+        for (i = 0; i < wpgc; i++)
+            s->wp_groups[i] = qemu_get_sbe32(f);
+        s->blk_len = qemu_get_sbe32(f);
+        s->erase_start = qemu_get_be32(f);
+        s->erase_end = qemu_get_be32(f);
+        qemu_get_buffer(f, s->pwd, sizeof(s->pwd));
+        s->pwd_len = qemu_get_sbe32(f);
+        for (i = 0; i < 6; i++)
+            s->function_group[i] = qemu_get_sbe32(f);
+        s->current_cmd = qemu_get_sbe32(f);
+        s->blk_written = qemu_get_sbe32(f);
+        s->data_start = qemu_get_be32(f);
+        s->data_offset = qemu_get_be32(f);
+        qemu_get_buffer(f, s->data, sizeof(s->data));
+        qemu_get_buffer(f, s->buf, 512);
+        s->enable = qemu_get_sbe32(f);
+    } else 
+        result = -EINVAL;
+    free(filename2);
+    free(filename1);
+    return result;
+}
+
 /* We do not model the chip select pin, so allow the board to select
    whether card should be in SSI or MMC/SD mode.  It is also up to the
    board to ensure that ssi transfers only occur when the chip select
@@ -415,6 +504,7 @@ static void sd_cardchange(void *opaque)
 SDState *sd_init(BlockDriverState *bs, int is_spi)
 {
     SDState *sd;
+    static int instance_number = 1;
 
     sd = (SDState *) qemu_mallocz(sizeof(SDState));
     sd->buf = qemu_memalign(512, 512);
@@ -422,6 +512,8 @@ SDState *sd_init(BlockDriverState *bs, int is_spi)
     sd->enable = 1;
     sd_reset(sd, bs);
     bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
+    register_savevm("sd", instance_number++, 0,
+                    sd_save_state, sd_load_state, sd);
     return sd;
 }
 
@@ -636,7 +728,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
             goto bad_cmd;
         switch (sd->state) {
         case sd_standby_state:
-            break;
+            return sd_r0;
 
         default:
             break;
@@ -1228,7 +1320,7 @@ int sd_do_command(SDState *sd, struct sd_request_s *req,
     sd_rsp_type_t rtype;
     int rsplen;
 
-    if (!bdrv_is_inserted(sd->bdrv) || !sd->enable) {
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable) {
         return 0;
     }
 
@@ -1306,8 +1398,8 @@ int sd_do_command(SDState *sd, struct sd_request_s *req,
         int i;
         DPRINTF("Response:");
         for (i = 0; i < rsplen; i++)
-            printf(" %02x", response[i]);
-        printf(" state %d\n", sd->state);
+            fprintf(stderr, " %02x", response[i]);
+        fprintf(stderr, " state %d\n", sd->state);
     } else {
         DPRINTF("No response %d\n", sd->state);
     }
@@ -1504,7 +1596,7 @@ uint8_t sd_read_data(SDState *sd)
         return 0x00;
 
     if (sd->state != sd_sendingdata_state) {
-        fprintf(stderr, "sd_read_data: not in Sending-Data state\n");
+        fprintf(stderr, "sd_read_data: not in Sending-Data state (state=%d)\n", sd->state);
         return 0x00;
     }
 
index f5b29a7..50160ad 100644 (file)
@@ -37,6 +37,7 @@ typedef struct {
     int rx_fifo[NUM_PACKETS];
     int tx_fifo_done_len;
     int tx_fifo_done[NUM_PACKETS];
+    int iomemtype;
     /* Packet buffer memory.  */
     uint8_t data[NUM_PACKETS][2048];
     uint8_t int_level;
@@ -690,17 +691,22 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = {
     smc91c111_writel
 };
 
-void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+int smc91c111_iomemtype(void *opaque) {
+    smc91c111_state *s=(smc91c111_state *) opaque;
+    return s->iomemtype;
+}
+
+void *smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq, int phys_alloc)
 {
     smc91c111_state *s;
-    int iomemtype;
 
     qemu_check_nic_model(nd, "smc91c111");
 
     s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state));
-    iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
-                                       smc91c111_writefn, s);
-    cpu_register_physical_memory(base, 16, iomemtype);
+    s->iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
+                                          smc91c111_writefn, s);
+    if (phys_alloc)
+        cpu_register_physical_memory(base, 16, s->iomemtype);
     s->irq = irq;
     memcpy(s->macaddr, nd->macaddr, 6);
 
@@ -710,4 +716,5 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
                                  smc91c111_receive, smc91c111_can_receive, s);
     qemu_format_nic_info_str(s->vc, s->macaddr);
     /* ??? Save/restore.  */
+    return s;
 }
index 2967b52..c66cf7b 100644 (file)
@@ -21,6 +21,7 @@
 #include "qemu-common.h"
 #include "qemu-timer.h"
 #include "soc_dma.h"
+#include "hw.h"
 
 static void transfer_mem2mem(struct soc_dma_ch_s *ch)
 {
@@ -229,12 +230,79 @@ void soc_dma_reset(struct soc_dma_s *soc)
 {
     struct dma_s *s = (struct dma_s *) soc;
 
-    s->soc.drqbmp = 0;
+    memset(s->soc.drqst, 0, sizeof(s->soc.drqst));
     s->ch_enable_mask = 0;
     s->enabled_count = 0;
     soc_dma_ch_freq_update(s);
 }
 
+static void soc_dma_save_state(QEMUFile *f, void *opaque)
+{
+    struct dma_s *s = (struct dma_s *)opaque;
+    int i;
+    
+    qemu_put_buffer(f, s->soc.drqst, sizeof(s->soc.drqst));
+    qemu_put_sbe64(f, s->soc.freq);
+    qemu_put_be64(f, s->ch_enable_mask);
+    qemu_put_sbe64(f, s->channel_freq);
+    qemu_put_sbe32(f, s->enabled_count);
+    for (i = 0; i < s->chnum; i++) {
+        qemu_put_timer(f, s->ch[i].timer);
+        qemu_put_sbe32(f, s->ch[i].enable);
+        qemu_put_sbe32(f, s->ch[i].update);
+        qemu_put_sbe32(f, s->ch[i].bytes);
+        qemu_put_sbe32(f, s->ch[i].type[0]);
+        qemu_put_sbe32(f, s->ch[i].type[1]);
+#if TARGET_PHYS_ADDR_BITS == 32
+        qemu_put_be32(f, s->ch[i].vaddr[0]);
+        qemu_put_be32(f, s->ch[i].vaddr[1]);
+#elif TARGET_PHYS_ADDR_BITS == 64
+        qemu_put_be64(f, s->ch[i].vaddr[0]);
+        qemu_put_be64(f, s->ch[i].vaddr[1]);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+        qemu_put_sbe32(f, s->ch[i].running);
+    }
+}
+
+static int soc_dma_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct dma_s *s = (struct dma_s *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    qemu_get_buffer(f, s->soc.drqst, sizeof(s->soc.drqst));
+    s->soc.freq = qemu_get_sbe64(f);
+    s->ch_enable_mask = qemu_get_be64(f);
+    s->channel_freq = qemu_get_sbe64(f);
+    s->enabled_count = qemu_get_sbe32(f);
+    for (i = 0; i < s->chnum; i++) {
+        qemu_get_timer(f, s->ch[i].timer);
+        s->ch[i].enable = qemu_get_sbe32(f);
+        s->ch[i].update = qemu_get_sbe32(f);
+        s->ch[i].bytes = qemu_get_sbe32(f);
+        s->ch[i].type[0] = qemu_get_sbe32(f);
+        s->ch[i].type[1] = qemu_get_sbe32(f);
+#if TARGET_PHYS_ADDR_BITS == 32
+        s->ch[i].vaddr[0] = qemu_get_be32(f);
+        s->ch[i].vaddr[1] = qemu_get_be32(f);
+#elif TARGET_PHYS_ADDR_BITS == 64
+        s->ch[i].vaddr[0] = qemu_get_be64(f);
+        s->ch[i].vaddr[1] = qemu_get_be64(f);
+#else
+#error TARGET_PHYS_ADDR_BITS undefined
+#endif
+        s->ch[i].running = qemu_get_sbe32(f);
+        
+        soc_dma_ch_update(&s->ch[i]);
+    }
+    
+    return 0;
+}
+
 /* TODO: take a functional-clock argument */
 struct soc_dma_s *soc_dma_init(int n)
 {
@@ -252,6 +320,8 @@ struct soc_dma_s *soc_dma_init(int n)
     soc_dma_reset(&s->soc);
     fifo_size = 0;
 
+    register_savevm("soc_dma", -1, 0,
+                    soc_dma_save_state, soc_dma_load_state, s);
     return &s->soc;
 }
 
index 47bc4ea..1977773 100644 (file)
@@ -19,6 +19,8 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#define DMA_MAX_DRQ 96
+
 struct soc_dma_s;
 struct soc_dma_ch_s;
 typedef void (*soc_dma_io_t)(void *opaque, uint8_t *buf, int len);
@@ -66,7 +68,7 @@ struct soc_dma_ch_s {
 struct soc_dma_s {
     /* Following fields are set by the SoC DMA module and can be used
      * by anybody.  */
-    uint64_t drqbmp;   /* Is zeroed by soc_dma_reset() */
+    uint8_t drqst[DMA_MAX_DRQ]; /* Is zeroed by soc_dma_reset() */
     qemu_irq *drq;
     void *opaque;
     int64_t freq;
index e8d4a85..68b18c4 100644 (file)
@@ -229,25 +229,6 @@ static void tsc2005_write(struct tsc2005_state_s *s, int reg, uint16_t data)
 static void tsc2005_pin_update(struct tsc2005_state_s *s)
 {
     int64_t expires;
-    int pin_state;
-
-    switch (s->pin_func) {
-    case 0:
-        pin_state = !s->pressure && !!s->dav;
-        break;
-    case 1:
-    case 3:
-    default:
-        pin_state = !s->dav;
-        break;
-    case 2:
-        pin_state = !s->pressure;
-    }
-
-    if (pin_state != s->irq) {
-        s->irq = pin_state;
-        qemu_set_irq(s->pint, s->irq);
-    }
 
     switch (s->nextfunction) {
     case TSC_MODE_XYZ_SCAN:
@@ -400,16 +381,35 @@ uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
 static void tsc2005_timer_tick(void *opaque)
 {
     struct tsc2005_state_s *s = opaque;
+       int pin_state;
 
     /* Timer ticked -- a set of conversions has been finished.  */
 
     if (!s->busy)
         return;
 
-    s->busy = 0;
-    s->dav |= mode_regs[s->function];
-    s->function = -1;
-    tsc2005_pin_update(s);
+       switch (s->pin_func) {
+               case 0:
+                       pin_state = !s->pressure && !!s->dav;
+                       break;
+               case 1:
+               case 3:
+               default:
+                       pin_state = !s->dav;
+                       break;
+               case 2:
+                       pin_state = !s->pressure;
+    }
+       
+       s->busy = 0;
+       if (pin_state && !s->irq) s->dav |= mode_regs[s->function];
+       s->function = -1;
+       tsc2005_pin_update(s);
+
+    if (pin_state != s->irq) {
+        s->irq = pin_state;
+        qemu_set_irq(s->pint, s->irq);
+    }
 }
 
 static void tsc2005_touchscreen_event(void *opaque,
index d6847d0..dfd2824 100644 (file)
 #include "irq.h"
 #include "devices.h"
 
+#define OMAP3_HSUSB_DEBUG
+
+#ifdef OMAP3_HSUSB_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+
 struct tusb_s {
     int iomemtype[2];
     qemu_irq irq;
@@ -686,9 +695,11 @@ static void tusb_musb_core_intr(void *opaque, int source, int level)
 {
     struct tusb_s *s = (struct tusb_s *) opaque;
     uint16_t otg_status = s->otg_status;
+    TRACE("intr 0x%08x, 0x%08x, 0x%08x", source, level, musb_core_intr_get(s->musb));
 
     switch (source) {
     case musb_set_vbus:
+        TRACE("dealing with VBUS");
         if (level)
             otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
         else
@@ -704,6 +715,7 @@ static void tusb_musb_core_intr(void *opaque, int source, int level)
         break;
 
     case musb_set_session:
+        TRACE("dealing with SESSION");
         /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set?  */
         /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set?  */
         if (level) {
@@ -719,6 +731,7 @@ static void tusb_musb_core_intr(void *opaque, int source, int level)
 
     case musb_irq_tx:
     case musb_irq_rx:
+        TRACE("rxtx");
         s->usbip_intr = musb_core_intr_get(s->musb);
         /* Fall through.  */
     default:
diff --git a/hw/twl4030.c b/hw/twl4030.c
new file mode 100644 (file)
index 0000000..b4dc11e
--- /dev/null
@@ -0,0 +1,1146 @@
+/*
+ * TI TWL4030 for beagle board
+ *
+ * Copyright (C) 2008 yajin<yajin@vm-kernel.org>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Register implementation based on TPS65950 ES1.0 specification.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "i2c.h"
+#include "sysemu.h"
+#include "console.h"
+#include "cpu-all.h"
+
+//#define VERBOSE 1
+
+#ifdef VERBOSE
+#define TRACE(fmt, ...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, __##VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+struct twl4030_i2c_s {
+    i2c_slave i2c;
+    int firstbyte;
+    uint8_t reg;
+    qemu_irq irq;
+    uint8 reg_data[256];
+    struct twl4030_s *twl4030;
+};
+
+struct twl4030_s {
+    struct twl4030_i2c_s *i2c[5];
+    
+    int key_cfg;
+    int key_tst;
+    
+    uint8_t seq_mem[64][4]; /* power-management sequencing memory */
+};
+
+static const uint8_t addr_48_reset_values[256] = {
+    0x51, 0x04, 0x02, 0xc0, 0x41, 0x41, 0x41, 0x10, /* 0x00...0x07 */
+    0x10, 0x10, 0x06, 0x06, 0x06, 0x1f, 0x1f, 0x1f, /* 0x08...0x0f */
+    0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+    0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, /* 0x18...0x1f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x03, /* 0x20...0x27 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+    0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, /* 0x30...0x37 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
+    0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, /* 0x80...0x87 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90...0x97 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
+    0x00, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8...0xb8 */
+    0xa0, 0xa0, 0x64, 0x7f, 0x6c, 0x75, 0x64, 0x20, /* 0xc0...0xc7 */
+    0x01, 0x17, 0x01, 0x02, 0x00, 0x36, 0x44, 0x07, /* 0xc8...0xcf */
+    0x3b, 0x17, 0x6b, 0x04, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
+    0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00  /* 0xf8...0xff */
+};
+
+static const uint8_t addr_49_reset_values[256] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
+    0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, /* 0x08...0x0f */
+    0x3f, 0x3f, 0x3f, 0x3f, 0x25, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+    0x00, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x55, /* 0x18...0x1f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
+    0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+    0x13, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x00, /* 0x30...0x37 */
+    0x00, 0x00, 0x06, 0x00, 0x44, 0x69, 0x00, 0x00, /* 0x38...0x3f */
+    0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80...0x87 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
+    0x00, 0x90, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, /* 0x90...0x97 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
+    0x00, 0x00, 0x04, 0x00, 0x55, 0x01, 0x55, 0x05, /* 0xa8...0xaf */
+    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, /* 0xb0...0xb7 */
+    0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, /* 0xb8...0xbf */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* 0xc0...0xc7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8...0xff */
+};
+
+static const uint8_t addr_4a_reset_values[256] = {
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
+    0xc0, 0x8c, 0xde, 0xde, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18...0x1f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30...0x37 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+    0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x55, 0x07, /* 0x60...0x67 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
+    0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, /* 0x80...0x87 */
+    0x00, 0x68, 0x9b, 0x86, 0x48, 0x2a, 0x07, 0x28, /* 0x88...0x8f */
+    0x09, 0x69, 0x90, 0x00, 0x2a, 0x00, 0x02, 0x00, /* 0x90...0x97 */
+    0x10, 0xcd, 0x02, 0x68, 0x03, 0x00, 0x00, 0x00, /* 0x98...0x9f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
+    0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, /* 0xb8...0xbf */
+    0x0f, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x01, 0x00, /* 0xc0...0xc7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
+    0x00, 0x00, 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, /* 0xd0...0xd7 */
+    0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
+    0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, /* 0xe0...0xe7 */
+    0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* 0xf8...0xff */
+};
+
+static const uint8_t addr_4b_reset_values[256] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x18...0x1f */
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, /* 0x20...0x27 */
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+    0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0xbf, 0xbf, /* 0x30...0x37 */
+    0xbf, 0xab, 0x00, 0x08, 0x3f, 0x15, 0x40, 0x0e, /* 0x38...0x3f */
+    0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+    0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+    0x00, 0x02, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+    0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+    0x00, 0x00, 0x2f, 0x18, 0x0f, 0x08, 0x0f, 0x08, /* 0x60...0x67 */
+    0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+    0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x80, 0x03, /* 0x70...0x77 */
+    0x08, 0x09, 0x00, 0x00, 0x08, 0x03, 0x80, 0x03, /* 0x78...0x7f */
+    0x08, 0x02, 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, /* 0x80...0x87 */
+    0x08, 0x08, 0x20, 0x00, 0x00, 0x02, 0x80, 0x04, /* 0x88...0x8f */
+    0x08, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, /* 0x90...0x97 */
+    0x08, 0x02, 0xe0, 0x01, 0x08, 0x00, 0xe0, 0x00, /* 0x98...0x9f */
+    0x08, 0x01, 0xe0, 0x01, 0x08, 0x04, 0xe0, 0x03, /* 0xa0...0xa7 */
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
+    0x20, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
+    0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, /* 0xb8...0xbf */
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, /* 0xc0...0xc7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, /* 0xc8...0xcf */
+    0x00, 0x08, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
+    0x14, 0x08, 0xe0, 0x02, 0x08, 0xe0, 0x00, 0x08, /* 0xd8...0xdf */
+    0xe0, 0x05, 0x08, 0xe0, 0x06, 0x08, 0xe0, 0x00, /* 0xe0...0xe7 */
+    0x08, 0xe0, 0x00, 0x08, 0xe0, 0x06, 0x06, 0xe0, /* 0xe8...0xef */
+    0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* 0xf8...0xff */
+};
+
+static uint8_t twl4030_48_read(void *opaque, uint8_t addr)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+       
+    TRACE("addr=0x%02x", addr);
+    switch (addr) {
+        case 0x00: /* VENDOR_ID_LO */
+        case 0x01: /* VENDOR_ID_HI */
+        case 0x02: /* PRODUCT_ID_LO */
+        case 0x03: /* PRODUCT_ID_HI */
+            return s->reg_data[addr];
+        case 0x04: /* FUNC_CTRL */
+        case 0x05: /* FUNC_CRTL_SET */
+        case 0x06: /* FUNC_CRTL_CLR */
+            return s->reg_data[0x04];
+        case 0x07: /* IFC_CTRL */
+        case 0x08: /* IFC_CRTL_SET */
+        case 0x09: /* IFC_CRTL_CLR */
+            return s->reg_data[0x07];
+        case 0xac: /* POWER_CTRL */
+        case 0xad: /* POWER_SET */
+        case 0xae: /* POWER_CLR */
+            return s->reg_data[0xac];
+        case 0xfd: /* PHY_PWR_CTRL */
+        case 0xfe: /* PHY_CLK_CTRL */
+            return s->reg_data[addr];
+        case 0xff: /* PHY_CLK_CTRL */
+            return s->reg_data[0xfe] & 0x1;
+        default:
+            fprintf(stderr, "%s: unknown register 0x%02x pc %x\n",
+                    __FUNCTION__, addr, cpu_single_env->regs[15]);
+            break;
+    }
+    return 0;
+}
+
+static void twl4030_48_write(void *opaque, uint8_t addr, uint8_t value)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+       
+    TRACE("addr=0x%02x, value=0x%02x", addr, value);
+    switch (addr) {
+        case 0x04: /* IFC_CTRL */
+            s->reg_data[0x04] = value & 0x80;
+            break;
+        case 0x05: /* IFC_CRTL_SET */
+            s->reg_data[0x04] =  (s->reg_data[0x04] | value) & 0x80;
+            break;
+        case 0x06: /* IFC_CRTL_CLEAR */
+            s->reg_data[0x04] =  (s->reg_data[0x04] & ~value) & 0x80;
+            break;
+        case 0x07: /* IFC_CTRL */
+            s->reg_data[0x07] = value & 0x61;
+            break;
+        case 0x08: /* IFC_CRTL_SET */
+            s->reg_data[0x07] =  (s->reg_data[0x07] | value) & 0x61;
+            break;
+        case 0x09: /* IFC_CRTL_CLEAR */
+            s->reg_data[0x07] =  (s->reg_data[0x07] & ~value) & 0x61;
+            break;
+        case 0xac: /* POWER_CTRL */
+            s->reg_data[0xac] = value & 0x20;
+            break;
+        case 0xad: /* POWER_SET */
+            s->reg_data[0xac] =  (s->reg_data[0xac] | value) & 0x20;
+            break;
+        case 0xae: /* POWER_CLEAR */
+            s->reg_data[0xac] =  (s->reg_data[0xac] & ~value) & 0x20;
+            break;
+        case 0xfd: /* PHY_PWR_CTRL */
+            s->reg_data[addr] = value & 0x1;
+            break;
+        case 0xfe: /* PHY_CLK_CTRL */
+            s->reg_data[addr] = value & 0x7;
+            break;
+        default:
+            fprintf(stderr, "%s: unknown register 0x%02x pc %x\n",
+                    __FUNCTION__, addr, cpu_single_env->regs[15]);
+                       break;
+    }
+}
+
+static int twl4030_48_tx(i2c_slave *i2c, uint8_t data)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+    /* Interpret register address byte */
+    if (s->firstbyte) {
+        s->reg = data;
+        s->firstbyte = 0;
+    } else
+        twl4030_48_write(s, s->reg++, data);
+       
+    return 0;
+}
+
+static int twl4030_48_rx(i2c_slave *i2c)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+       
+    return twl4030_48_read(s, s->reg++);
+}
+
+static void twl4030_48_reset(i2c_slave *i2c)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+    s->reg = 0x00;
+    memcpy(s->reg_data, addr_48_reset_values, 256);
+}
+
+static void twl4030_48_event(i2c_slave *i2c, enum i2c_event event)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+    
+    if (event == I2C_START_SEND)
+        s->firstbyte = 1;
+}
+
+static uint8_t twl4030_49_read(void *opaque, uint8_t addr)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+    TRACE("addr=0x%02x", addr);
+    switch (addr) {
+        /* AUDIO_VOICE region */
+        case 0x01: /* CODEC_MODE */
+        case 0x02: /* OPTION */
+        case 0x04: /* MICBIAS_CTL */
+        case 0x05: /* ANAMICL */
+        case 0x06: /* ANAMICR */
+        case 0x07: /* AVADC_CTL */
+        case 0x08: /* ADCMICSEL */
+        case 0x09: /* DIGMIXING */
+        case 0x0a: /* ATXL1PGA */
+        case 0x0b: /* ATXR1PGA */
+        case 0x0c: /* AVTXL2PGA */
+        case 0x0d: /* AVTXR2PGA */
+        case 0x0e: /* AUDIO_IF */
+        case 0x0f: /* VOICE_IF */
+        case 0x10: /* ARXR1PGA */
+        case 0x11: /* ARXL1PGA */
+        case 0x12: /* ARXR2PGA */
+        case 0x13: /* ARXL2PGA */
+        case 0x14: /* VRXPGA */
+        case 0x15: /* VSTPGA */
+        case 0x16: /* VRX2ARXPGA */
+        case 0x17: /* AVDAC_CTL */
+        case 0x18: /* ARX2VTXPGA */
+        case 0x19: /* ARXL1_APGA_CTL */
+        case 0x1a: /* ARXR1_APGA_CTL */
+        case 0x1b: /* ARXL2_APGA_CTL */
+        case 0x1c: /* ARXR2_APGA_CTL */
+        case 0x1d: /* ATX2ARXPGA */
+        case 0x1e: /* BT_IF */
+        case 0x1f: /* BTPGA */
+        case 0x20: /* BTSTPGA */
+        case 0x21: /* EAR_CTL */
+        case 0x22: /* HS_SEL */
+        case 0x23: /* HS_GAIN_SET */
+        case 0x24: /* HS_POPN_SET */
+        case 0x25: /* PREDL_CTL */
+        case 0x26: /* PREDR_CTL */
+        case 0x27: /* PRECKL_CTL */
+        case 0x28: /* PRECKR_CTL */
+        case 0x29: /* HFL_CTL */
+        case 0x2a: /* HFR_CTL */
+        case 0x2b: /* ALC_CTL */
+        case 0x2c: /* ALC_SET1 */
+        case 0x2d: /* ALC_SET2 */
+        case 0x2e: /* BOOST_CTL */
+        case 0x2f: /* SOFTVOL_CTL */
+        case 0x30: /* DTMF_FREQSEL */
+        case 0x31: /* DTMF_TONEXT1H */
+        case 0x32: /* DTMF_TONEXT1L */
+        case 0x33: /* DTMF_TONEXT2H */
+        case 0x34: /* DTMF_TONEXT2L */
+        case 0x35: /* DTMF_TONOFF */
+        case 0x36: /* DTMF_WANONOFF */
+        case 0x37: /* CODEC_RX_SCRAMBLE_H */
+        case 0x38: /* CODEC_RX_SCRAMBLE_M */
+        case 0x39: /* CODEC_RX_SCRAMBLE_L */
+        case 0x3a: /* APLL_CTL */
+        case 0x3b: /* DTMF_CTL */
+        case 0x3c: /* DTMF_PGA_CTL2 */
+        case 0x3d: /* DTMF_PGA_CTL1 */
+        case 0x3e: /* MISC_SET_1 */
+        case 0x3f: /* PCMBTMUX */
+        case 0x43: /* RX_PATH_SEL */
+        case 0x44: /* VDL_APGA_CTL */
+        case 0x45: /* VIBRA_CTL */
+        case 0x46: /* VIBRA_SET */
+        case 0x48: /* ANAMIC_GAIN */
+        case 0x49: /* MISC_SET_2 */
+        /* Test region */
+        case 0x4c: /* AUDIO_TEST_CTL */
+        case 0x4d: /* INT_TEST_CTL */
+        case 0x4e: /* DAC_ADC_TEST_CTL */
+        case 0x4f: /* RXTX_TRIM_IB */
+        case 0x50: /* CLD_CONTROL */
+        case 0x51: /* CLD_MODE_TIMING */
+        case 0x52: /* CLD_TRIM_RAMP */
+        case 0x53: /* CLD_TESTV_CTL */
+        case 0x54: /* APLL_TEST_CTL */
+        case 0x55: /* APLL_TEST_DIV */
+        case 0x56: /* APLL_TEST_CTL2 */
+        case 0x57: /* APLL_TEST_CUR */
+        case 0x58: /* DIGIMIC_BIAS1_CTL */
+        case 0x59: /* DIGIMIC_BIAS2_CTL */
+        case 0x5a: /* RX_OFFSET_VOICE */
+        case 0x5b: /* RX_OFFSET_AL1 */
+        case 0x5c: /* RX_OFFSET_AR1 */
+        case 0x5d: /* RX_OFFSET_AL2 */
+        case 0x5e: /* RX_OFFSET_AR2 */
+        case 0x5f: /* OFFSET1 */
+        case 0x60: /* OFFSET2 */
+        /* PIH region */
+        case 0x81: /* PIH_ISR_P1 */
+        case 0x82: /* PIH_ISR_P2 */
+        case 0x83: /* PIH_SIR */
+        /* INTBR region */
+        case 0x85: /* IDCODE_7_0 */
+        case 0x86: /* IDCODE_15_8 */
+        case 0x87: /* IDCODE_23_16 */
+        case 0x88: /* IDCODE_31_24 */
+        case 0x89: /* DIEID_7_0 */
+        case 0x8a: /* DIEID_15_8 */
+        case 0x8b: /* DIEID_23_16 */
+        case 0x8c: /* DIEID_31_24 */
+        case 0x8d: /* DIEID_39_32 */
+        case 0x8e: /* DIEID_47_40 */
+        case 0x8f: /* DIEID_55_48 */
+        case 0x90: /* DIEID_63_56 */
+        case 0x91: /* GPBR1 */
+        case 0x92: /* PMBR1 */
+        case 0x93: /* PMBR2 */
+        case 0x94: /* GPPUPDCTR1 */
+        case 0x95: /* GPPUPDCTR2 */
+        case 0x96: /* GPPUPDCTR3 */
+        case 0x97: /* UNLOCK_TEST_REG */
+        /* GPIO region */
+        case 0x98: /* GPIO_DATAIN1 */
+        case 0x99: /* GPIO_DATAIN2 */
+        case 0x9a: /* GPIO_DATAIN3 */
+        case 0x9b: /* GPIO_DATADIR1 */
+        case 0x9c: /* GPIO_DATADIR2 */
+        case 0x9d: /* GPIO_DATADIR3 */
+        case 0x9e: /* GPIO_DATAOUT1 */
+        case 0x9f: /* GPIO_DATAOUT2 */
+        case 0xa0: /* GPIO_DATAOUT3 */
+        case 0xa1: /* GPIO_CLEARGPIODATAOUT1 */
+        case 0xa2: /* GPIO_CLEARGPIODATAOUT2 */
+        case 0xa3: /* GPIO_CLEARGPIODATAOUT3 */
+        case 0xa4: /* GPIO_SETGPIODATAOUT1 */
+        case 0xa5: /* GPIO_SETGPIODATAOUT2 */
+        case 0xa6: /* GPIO_SETGPIODATAOUT3 */
+        case 0xa7: /* GPIO_DEBEN1 */
+        case 0xa8: /* GPIO_DEBEN2 */
+        case 0xa9: /* GPIO_DEBEN3 */
+        case 0xaa: /* GPIO_CTRL */
+        case 0xab: /* GPIO_PUPDCTR1 */
+        case 0xac: /* GPIO_PUPDCTR2 */
+        case 0xad: /* GPIO_PUPDCTR3 */
+        case 0xae: /* GPIO_PUPDCTR4 */
+        case 0xaf: /* GPIO_PUPDCTR5 */
+        case 0xb0: /* GPIO_TEST */
+        case 0xb1: /* GPIO_ISR1A */
+        case 0xb2: /* GPIO_ISR2A */
+        case 0xb3: /* GPIO_ISR3A */
+        case 0xb4: /* GPIO_IMR1A */
+        case 0xb5: /* GPIO_IMR2A */
+        case 0xb6: /* GPIO_IMR3A */
+        case 0xb7: /* GPIO_ISR1B */
+        case 0xb8: /* GPIO_ISR2B */
+        case 0xb9: /* GPIO_ISR3B */
+        case 0xba: /* GPIO_IMR1B */
+        case 0xbb: /* GPIO_IMR2B */
+        case 0xbc: /* GPIO_IMR3B */
+        case 0xbd: /* GPIO_SIR1 */
+        case 0xbe: /* GPIO_SIR2 */
+        case 0xbf: /* GPIO_SIR3 */
+        case 0xc0: /* GPIO_EDR1 */
+        case 0xc1: /* GPIO_EDR2 */
+        case 0xc2: /* GPIO_EDR3 */
+        case 0xc3: /* GPIO_EDR4 */
+        case 0xc4: /* GPIO_EDR5 */
+        case 0xc5: /* GPIO_SIH_CTRL */
+            return s->reg_data[addr];
+        default:
+            fprintf(stderr, "%s: unknown register 0x%02x pc %x\n",
+                    __FUNCTION__, addr, cpu_single_env->regs[15]);
+                       break;
+    }
+    return 0;
+}
+
+static void twl4030_49_write(void *opaque, uint8_t addr, uint8_t value)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+       
+    TRACE("addr=0x%02x, value=0x%02x", addr, value);
+    switch (addr) {
+        /* AUDIO_VOICE region */
+        case 0x01: /* CODEC_MODE */
+        case 0x02: /* OPTION */
+        case 0x04: /* MICBIAS_CTL */
+        case 0x05: /* ANAMICL */
+        case 0x06: /* ANAMICR */
+        case 0x07: /* AVADC_CTL */
+        case 0x08: /* ADCMICSEL */
+        case 0x09: /* DIGMIXING */
+        case 0x0a: /* ATXL1PGA */
+        case 0x0b: /* ATXR1PGA */
+        case 0x0c: /* AVTXL2PGA */
+        case 0x0d: /* AVTXR2PGA */
+        case 0x0e: /* AUDIO_IF */
+        case 0x0f: /* VOICE_IF */
+        case 0x10: /* ARXR1PGA */
+        case 0x11: /* ARXL1PGA */
+        case 0x12: /* ARXR2PGA */
+        case 0x13: /* ARXL2PGA */
+        case 0x14: /* VRXPGA */
+        case 0x15: /* VSTPGA */
+        case 0x16: /* VRX2ARXPGA */
+        case 0x17: /* AVDAC_CTL */
+        case 0x18: /* ARX2VTXPGA */
+        case 0x19: /* ARXL1_APGA_CTL */
+        case 0x1a: /* ARXR1_APGA_CTL */
+        case 0x1b: /* ARXL2_APGA_CTL */
+        case 0x1c: /* ARXR2_APGA_CTL */
+        case 0x1d: /* ATX2ARXPGA */
+        case 0x1e: /* BT_IF */
+        case 0x1f: /* BTPGA */
+        case 0x20: /* BTSTPGA */
+        case 0x21: /* EAR_CTL */
+        case 0x22: /* HS_SEL */
+        case 0x23: /* HS_GAIN_SET */
+        case 0x24: /* HS_POPN_SET */
+        case 0x25: /* PREDL_CTL */
+        case 0x26: /* PREDR_CTL */
+        case 0x27: /* PRECKL_CTL */
+        case 0x28: /* PRECKR_CTL */
+        case 0x29: /* HFL_CTL */
+        case 0x2a: /* HFR_CTL */
+        case 0x2b: /* ALC_CTL */
+        case 0x2c: /* ALC_SET1 */
+        case 0x2d: /* ALC_SET2 */
+        case 0x2e: /* BOOST_CTL */
+        case 0x2f: /* SOFTVOL_CTL */
+        case 0x30: /* DTMF_FREQSEL */
+        case 0x31: /* DTMF_TONEXT1H */
+        case 0x32: /* DTMF_TONEXT1L */
+        case 0x33: /* DTMF_TONEXT2H */
+        case 0x34: /* DTMF_TONEXT2L */
+        case 0x35: /* DTMF_TONOFF */
+        case 0x36: /* DTMF_WANONOFF */
+        case 0x37: /* CODEC_RX_SCRAMBLE_H */
+        case 0x38: /* CODEC_RX_SCRAMBLE_M */
+        case 0x39: /* CODEC_RX_SCRAMBLE_L */
+        case 0x3a: /* APLL_CTL */
+        case 0x3b: /* DTMF_CTL */
+        case 0x3c: /* DTMF_PGA_CTL2 */
+        case 0x3d: /* DTMF_PGA_CTL1 */
+        case 0x3e: /* MISC_SET_1 */
+        case 0x3f: /* PCMBTMUX */
+        case 0x43: /* RX_PATH_SEL */
+        case 0x44: /* VDL_APGA_CTL */
+        case 0x45: /* VIBRA_CTL */
+        case 0x46: /* VIBRA_SET */
+        case 0x48: /* ANAMIC_GAIN */
+        case 0x49: /* MISC_SET_2 */
+            s->reg_data[addr] = value;
+            break;
+        /* Test region */
+        case 0x4c: /* AUDIO_TEST_CTL */
+        case 0x4d: /* INT_TEST_CTL */
+        case 0x4e: /* DAC_ADC_TEST_CTL */
+        case 0x4f: /* RXTX_TRIM_IB */
+        case 0x50: /* CLD_CONTROL */
+        case 0x51: /* CLD_MODE_TIMING */
+        case 0x52: /* CLD_TRIM_RAMP */
+        case 0x53: /* CLD_TESTV_CTL */
+        case 0x54: /* APLL_TEST_CTL */
+        case 0x55: /* APLL_TEST_DIV */
+        case 0x56: /* APLL_TEST_CTL2 */
+        case 0x57: /* APLL_TEST_CUR */
+        case 0x58: /* DIGIMIC_BIAS1_CTL */
+        case 0x59: /* DIGIMIC_BIAS2_CTL */
+            s->reg_data[addr] = value;
+            break;
+        case 0x5a: /* RX_OFFSET_VOICE */
+        case 0x5b: /* RX_OFFSET_AL1 */
+        case 0x5c: /* RX_OFFSET_AR1 */
+        case 0x5d: /* RX_OFFSET_AL2 */
+        case 0x5e: /* RX_OFFSET_AR2 */
+        case 0x5f: /* OFFSET1 */
+        case 0x60: /* OFFSET2 */
+            /* read-only, ignore */
+            break;
+        /* PIH region */
+        case 0x81: /* PIH_ISR_P1 */
+        case 0x82: /* PIH_ISR_P2 */
+        case 0x83: /* PIH_SIR */
+            s->reg_data[addr] = value;
+            break;
+        /* INTBR region */
+        case 0x85: /* IDCODE_7_0 */
+        case 0x86: /* IDCODE_15_8 */
+        case 0x87: /* IDCODE_23_16 */
+        case 0x88: /* IDCODE_31_24 */
+        case 0x89: /* DIEID_7_0 */
+        case 0x8a: /* DIEID_15_8 */
+        case 0x8b: /* DIEID_23_16 */
+        case 0x8c: /* DIEID_31_24 */
+        case 0x8d: /* DIEID_39_32 */
+        case 0x8e: /* DIEID_47_40 */
+        case 0x8f: /* DIEID_55_48 */
+        case 0x90: /* DIEID_63_56 */
+            /* read-only, ignore */
+            break;
+        case 0x91: /* GPBR1 */
+        case 0x92: /* PMBR1 */
+        case 0x93: /* PMBR2 */
+        case 0x94: /* GPPUPDCTR1 */
+        case 0x95: /* GPPUPDCTR2 */
+        case 0x96: /* GPPUPDCTR3 */
+        case 0x97: /* UNLOCK_TEST_REG */
+            s->reg_data[addr] = value;
+            break;
+        /* GPIO region */
+        case 0x98: /* GPIODATAIN1 */
+        case 0x99: /* GPIODATAIN2 */
+        case 0x9a: /* GPIODATAIN3 */
+            /* read-only, ignore */
+            break;
+        case 0x9b: /* GPIODATADIR1 */
+        case 0x9c: /* GPIODATADIR2 */
+        case 0x9d: /* GPIODATADIR3 */
+        case 0x9e: /* GPIODATAOUT1 */
+        case 0x9f: /* GPIODATAOUT2 */
+        case 0xa0: /* GPIODATAOUT3 */
+        case 0xa1: /* CLEARGPIODATAOUT1 */
+        case 0xa2: /* CLEARGPIODATAOUT2 */
+        case 0xa3: /* CLEARGPIODATAOUT3 */
+        case 0xa4: /* SETGPIODATAOUT1 */
+        case 0xa5: /* SETGPIODATAOUT2 */
+        case 0xa6: /* SETGPIODATAOUT3 */
+        case 0xa7: /* GPIO_DEBEN1 */
+        case 0xa8: /* GPIO_DEBEN2 */
+        case 0xa9: /* GPIO_DEBEN3 */
+        case 0xaa: /* GPIO_CTRL */
+        case 0xab: /* GPIOPUPDCTR1 */
+        case 0xac: /* GPIOPUPDCTR2 */
+        case 0xad: /* GPIOPUPDCTR3 */
+        case 0xae: /* GPIOPUPDCTR4 */
+            s->reg_data[addr] = value;
+            break;
+        case 0xaf: /* GPIOPUPDCTR5 */
+            s->reg_data[addr] = value & 0x0f;
+            break;
+        case 0xb0: /* GPIO_TEST */
+        case 0xb1: /* GPIO_ISR1A */
+        case 0xb2: /* GPIO_ISR2A */
+        case 0xb3: /* GPIO_ISR3A */
+           case 0xb4: /* GPIO_IMR1A */
+           case 0xb5: /* GPIO_IMR2A */
+            s->reg_data[addr] = value;
+            break;
+           case 0xb6: /* GPIO_IMR3A */
+            s->reg_data[addr] = value & 0x03;
+            break;
+        case 0xb7: /* GPIO_ISR1B */
+        case 0xb8: /* GPIO_ISR2B */
+        case 0xb9: /* GPIO_ISR3B */
+        case 0xba: /* GPIO_IMR1B */
+        case 0xbb: /* GPIO_IMR2B */
+        case 0xbc: /* GPIO_IMR3B */
+        case 0xbd: /* GPIO_SIR1 */
+        case 0xbe: /* GPIO_SIR2 */
+        case 0xbf: /* GPIO_SIR3 */
+           case 0xc0: /* GPIO_EDR1 */
+           case 0xc1: /* GPIO_EDR2 */
+           case 0xc2: /* GPIO_EDR3 */
+           case 0xc3: /* GPIO_EDR4 */
+           case 0xc4: /* GPIO_EDR5 */
+            s->reg_data[addr] = value;
+            break;
+           case 0xc5: /* GPIO_SIH_CTRL */
+            s->reg_data[addr] = value & 0x07;
+            break;
+        default:
+            fprintf(stderr, "%s: unknown register 0x%02x pc %x\n",
+                    __FUNCTION__, addr, cpu_single_env->regs[15]);
+            break;
+    }
+}
+
+
+static int twl4030_49_tx(i2c_slave *i2c, uint8_t data)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+    /* Interpret register address byte */
+    if (s->firstbyte) {
+        s->reg = data;
+        s->firstbyte = 0;
+    } else
+        twl4030_49_write(s, s->reg++, data);
+       
+    return 0;
+}
+
+static int twl4030_49_rx(i2c_slave *i2c)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+       
+    return twl4030_49_read(s, s->reg++);
+}
+
+static void twl4030_49_reset(i2c_slave *i2c)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+    s->reg = 0x00;
+    memcpy(s->reg_data, addr_49_reset_values, 256);
+}
+
+static void twl4030_49_event(i2c_slave *i2c, enum i2c_event event)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+       
+    if (event == I2C_START_SEND)
+        s->firstbyte = 1;
+}
+
+static uint8_t twl4030_4a_read(void *opaque, uint8_t addr)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+       
+    TRACE("addr=0x%02x", addr);
+    switch (addr) {
+        case 0x61: /* MADC_ISR1 */
+        case 0xb9: /* BCIISR1A */
+        case 0xba: /* BCIISR2A */
+        case 0xe3: /* KEYP_ISR1 */
+        case 0xee: /* LEDEN */
+            return s->reg_data[addr];
+        default:
+               fprintf(stderr, "%s: unknown register %02x pc %x\n",
+                    __FUNCTION__, addr, cpu_single_env->regs[15] );
+            break;
+    }
+    return 0;
+}
+
+static void twl4030_4a_write(void *opaque, uint8_t addr, uint8_t value)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+    TRACE("addr=0x%02x, value=0x%02x", addr, value);
+    switch (addr) {
+        case 0x61: /* MADC_ISR1 */
+            s->reg_data[value] &= ~(value & 0x0f);
+            break;
+        case 0x62: /* MADC_IMR1 */
+            s->reg_data[value] = value & 0x0f;
+            break;
+        case 0xb9: /* BCIISR1A */
+            s->reg_data[value] &= ~value;
+            break;
+        case 0xba: /* BCIISR2A */
+            s->reg_data[value] &= ~(value & 0x0f);
+            break;
+        case 0xbb: /* BCIIMR1A */
+            s->reg_data[addr] = value;
+            break;
+        case 0xbc: /* BCIIMR2A */
+            s->reg_data[addr] = value & 0x0f;
+            break;
+        case 0xe4: /* KEYP_IMR1 */
+            s->reg_data[addr] = value & 0x0f;
+            break;
+        case 0xe9: /* KEYP_SIH_CTRL */
+            s->reg_data[addr] = value & 0x07;
+            break;
+        case 0xee: /* LEDEN */
+            s->reg_data[addr] = value;
+            TRACE("LEDA power=%s/enable=%s, LEDB power=%s/enable=%s",
+                    value & 0x10 ? "on" : "off", value & 0x01 ? "yes" : "no",
+                    value & 0x20 ? "on" : "off", value & 0x02 ? "yes" : "no");
+            break;
+        case 0xef: /* PWMAON */
+            s->reg_data[addr] = value;
+            break;
+        case 0xf0: /* PWMAOFF */
+            s->reg_data[addr] = value & 0x7f;
+            break;
+        default:
+               fprintf(stderr, "%s: unknown register %02x pc %x\n",
+                    __FUNCTION__, addr, cpu_single_env->regs[15]);
+            break;
+    }
+}
+
+static int twl4030_4a_tx(i2c_slave *i2c, uint8_t data)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+    /* Interpret register address byte */
+    if (s->firstbyte) {
+        s->reg = data;
+        s->firstbyte = 0;
+    } else
+        twl4030_4a_write(s, s->reg++, data);
+       
+    return 0;
+}
+
+static int twl4030_4a_rx(i2c_slave *i2c)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+       
+    return twl4030_4a_read(s, s->reg++);
+}
+
+static void twl4030_4a_reset(i2c_slave *i2c)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+    s->reg = 0x00;
+    memcpy(s->reg_data, addr_4a_reset_values, 256);
+}
+
+static void twl4030_4a_event(i2c_slave *i2c, enum i2c_event event)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+       
+    if (event == I2C_START_SEND)
+        s->firstbyte = 1;
+}
+
+static uint8_t twl4030_4b_read(void *opaque, uint8_t addr)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+       TRACE("addr=0x%02x", addr);
+    switch (addr) {
+        case 0x1c: /* RTC */
+        case 0x1d:
+        case 0x1e:
+        case 0x1f:
+        case 0x20:
+        case 0x21:
+        case 0x22:
+        case 0x23:
+        case 0x24:
+        case 0x25:
+        case 0x26:
+        case 0x27:
+        case 0x28:
+        case 0x29:
+        case 0x2a:
+        case 0x2b:
+        case 0x2c:
+        case 0x2d: /*RTC end */
+        case 0x2e: /* PWR_ISR1 */
+        case 0x33: /* PWR_EDR1 */
+        case 0x34: /* PWR_EDR2 */
+            return s->reg_data[addr];
+        case 0x45: /* STS_HW_CONDITIONS - USB plugged, no VBUS -> host usb */
+            return 0x4;
+        default:
+               fprintf(stderr, "%s: unknown register %02x pc %x \n",
+                    __FUNCTION__, addr, cpu_single_env->regs[15] );
+            break;
+    }
+    return 0;
+}
+
+
+static void twl4030_4b_write(void *opaque, uint8_t addr, uint8_t value)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+    uint8_t seq_addr, seq_sub;
+
+       TRACE("addr=0x%02x, value=0x%02x", addr, value);
+    switch (addr) {
+        case 0x1c: /* SECONDS_REG */
+        case 0x1d: /* MINUTES_REG */
+        case 0x23: /* ALARM_SECONDS_REG */
+        case 0x24: /* ALARM_MINUTES_REG */
+            s->reg_data[addr] = value & 0x7f;
+            break;
+        case 0x1e: /* HOURS_REG */
+        case 0x25: /* ALARM_HOURS_REG */
+            s->reg_data[addr] = value & 0xbf;
+            break;
+        case 0x1f: /* DAYS_REG */
+        case 0x26: /* ALARM_DAYS_REG */
+            s->reg_data[addr] = value & 0x3f;
+            break;
+        case 0x20: /* MONTHS_REG */
+        case 0x27: /* ALARM_MONTHS_REG */
+            s->reg_data[addr] = value & 0x1f;
+            break;
+        case 0x21: /* YEARS_REG */
+        case 0x28: /* ALARM_YEARS_REG */
+            s->reg_data[addr] = value;
+            break;
+        case 0x22: /* WEEKS_REG */
+            s->reg_data[addr] = value & 0x07;
+            break;
+        case 0x29: /* RTC_CTRL_REG */
+            s->reg_data[addr] = value & 0x7f;
+            break;
+        case 0x2a: /* RTC_STATUS_REG */
+            s->reg_data[addr] = value & 0xfe;
+            break;
+        case 0x2b: /* RTC_INTERRUPTS_REG */
+            s->reg_data[addr] = value & 0x0f;
+            break;
+        case 0x2c: /* RTC_COMP_LSB_REG */
+        case 0x2d: /* RTC_COMP_MSB_REG */
+            s->reg_data[addr] = value;
+            break;
+        case 0x33: /* PWR_EDR1 */
+        case 0x34: /* PWR_EDR2 */
+            s->reg_data[addr] = value;
+            break;
+        case 0x46: /* P1_SW_EVENTS */
+        case 0x47: /* P2_SW_EVENTS */
+        case 0x48: /* P3_SW_EVENTS */
+            s->reg_data[addr] = value & 0x78;
+            break;
+        case 0x52: /* SEQ_ADD_W2P */
+        case 0x53: /* SEQ_ADD_P2A */
+        case 0x54: /* SEQ_ADD_A2W */
+        case 0x55: /* SEQ_ADD_A2S */
+        case 0x56: /* SEQ_ADD_S2A12 */
+        case 0x57: /* SEQ_ADD_S2A3 */
+        case 0x58: /* SEQ_ADD_WARM */
+            if (s->twl4030->key_cfg)
+                s->reg_data[addr] = value & 0x3f;
+            break;
+        case 0x59: /* MEMORY_ADDRESS */
+            if (s->twl4030->key_cfg)
+                s->reg_data[addr] = value;
+            break;
+        case 0x5a: /* MEMORY_DATA */
+            if (s->twl4030->key_cfg) {
+                s->reg_data[addr] = value;
+                seq_addr = s->reg_data[0x59];
+                seq_sub = seq_addr & 3;
+                seq_addr >>= 2;
+                if ((seq_addr >= 0x2b && seq_addr <= 0x3e) || (seq_addr <= 0x0e && seq_sub == 3))
+                    s->twl4030->seq_mem[seq_addr][seq_sub] = value;
+            }
+            s->reg_data[0x59]++; /* TODO: check if autoincrement is write-protected as well */
+            break;
+        case 0x7a: /* VAUX3_DEV_GRP */
+        case 0x82: /* VMMC1_DEV_GRP */
+        case 0x8e: /* VPLL2_DEV_GRP */
+        case 0x96: /* VDAC_DEV_GRP */
+        case 0xcc: /* VUSB1V5_DEV_GRP */
+        case 0xcf: /* VUSB1V8_DEV_GRP */
+        case 0xd2: /* VUSB3V1_DEV_GRP */
+        case 0xe6: /* HFCLKOUT_DEV_GRP */
+            s->reg_data[addr] = (s->reg_data[addr] & 0x0f) | (value & 0xf0); 
+            break;
+        case 0x2f: /* PWR_IMR1 */
+            s->reg_data[addr] = value;
+            break;
+        case 0x35: /* PWR_SIH_CTRL */
+            s->reg_data[addr] = value & 0x07;
+            break;
+        case 0x3b: /* CFG_BOOT */
+            if (s->twl4030->key_cfg)
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);
+            break;
+        case 0x44: /* PROTECT_KEY */
+            s->twl4030->key_cfg = 0;
+            s->twl4030->key_tst = 0;
+            switch (value) {
+                case 0x0C: 
+                    if (s->reg_data[addr] == 0xC0)
+                        s->twl4030->key_cfg = 1;
+                    break;
+                case 0xE0:
+                    if (s->reg_data[addr] == 0x0E)
+                        s->twl4030->key_tst = 1;
+                    break;
+                case 0xEC:
+                    if (s->reg_data[addr] == 0xCE) {
+                        s->twl4030->key_cfg = 1;
+                        s->twl4030->key_tst = 1;
+                    }
+                    break;
+                default:
+                    break;
+            }
+            s->reg_data[addr] = value;
+            break;
+        case 0x7d: /* VAUX3_DEDICATED */
+            if (s->twl4030->key_tst)
+                s->reg_data[addr] = value & 0x77;
+            else
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);
+            break;
+        case 0x85: /* VMMC1_DEDICATED */
+        case 0x99: /* VDAC_DEDICATED */
+            if (s->twl4030->key_tst) 
+                s->reg_data[addr] = value & 0x73;
+            else
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);
+            break;
+        case 0x91: /* VPLL2_DEDICATED */
+            if (s->twl4030->key_tst)
+                s->reg_data[addr] = value & 0x7f;
+            else
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
+            break;
+        case 0xcd: /* VUSB1V5_TYPE */
+        case 0xd0: /* VUSB1V8_TYPE */
+        case 0xd3: /* VUSB3V1_TYPE */
+            s->reg_data[addr] = value & 0x1f;
+            break;
+        case 0xd8: /* VUSB_DEDICATED1 */
+            s->reg_data[addr] = value & 0x1f;
+            break;
+        case 0xd9: /* VUSB_DEDICATED2 */
+            s->reg_data[addr] = value & 0x08;
+            break;
+            
+        default:
+               fprintf(stderr, "%s: unknown register %02x value %0x pc %x\n",
+                    __FUNCTION__, addr, value, cpu_single_env->regs[15]);
+            break;
+    }
+}
+
+static int twl4030_4b_tx(i2c_slave *i2c, uint8_t data)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+    /* Interpret register address byte */
+    if (s->firstbyte) {
+        s->reg = data;
+        s->firstbyte = 0;
+    } else
+        twl4030_4b_write(s, s->reg++, data);
+       
+    return 1;
+}
+
+static int twl4030_4b_rx(i2c_slave *i2c)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+       
+    return twl4030_4b_read(s, s->reg++);
+}
+
+static void twl4030_4b_reset(i2c_slave *i2c)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+    s->reg = 0x00;
+    memcpy(s->reg_data, addr_4b_reset_values, 256);
+    s->twl4030->key_cfg = 0;
+    s->twl4030->key_tst = 0;
+}
+
+static void twl4030_4b_event(i2c_slave *i2c, enum i2c_event event)
+{
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+       
+    if (event == I2C_START_SEND)
+        s->firstbyte = 1;
+}
+
+static void twl4030_save_state(QEMUFile *f, void *opaque)
+{
+    struct twl4030_s *s = (struct twl4030_s *)opaque;
+    int i;
+    
+    qemu_put_sbe32(f, s->key_cfg);
+    qemu_put_sbe32(f, s->key_tst);
+    for (i = 0; i < 64; i++)
+        qemu_put_buffer(f, s->seq_mem[i], 4);
+    for (i = 0; i < 5; i++) {
+        qemu_put_sbe32(f, s->i2c[i]->firstbyte);
+        qemu_put_byte(f, s->i2c[i]->reg);
+        qemu_put_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
+    }
+}
+
+static int twl4030_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct twl4030_s *s = (struct twl4030_s *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->key_cfg = qemu_get_sbe32(f);
+    s->key_tst = qemu_get_sbe32(f);
+    for (i = 0; i < 64; i++)
+        qemu_get_buffer(f, s->seq_mem[i], 4);
+    for (i = 0; i < 5; i++) {
+        s->i2c[i]->firstbyte = qemu_get_sbe32(f);
+        s->i2c[i]->reg = qemu_get_byte(f);
+        qemu_get_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
+    }
+    
+    return 0;
+}
+
+struct twl4030_s *twl4030_init(i2c_bus *bus, qemu_irq irq)
+{
+    int i;
+       
+    struct twl4030_s *s = (struct twl4030_s *) qemu_mallocz(sizeof(*s));
+       
+    for (i = 0; i < 5; i++) {
+        s->i2c[i]=(struct twl4030_i2c_s *)i2c_slave_init(
+            bus, 0, sizeof(struct twl4030_i2c_s));
+        s->i2c[i]->irq = irq;
+        s->i2c[i]->twl4030 = s;
+    }
+    s->i2c[0]->i2c.event = twl4030_48_event;
+    s->i2c[0]->i2c.recv = twl4030_48_rx;
+    s->i2c[0]->i2c.send = twl4030_48_tx;
+    twl4030_48_reset(&s->i2c[0]->i2c);
+    i2c_set_slave_address((i2c_slave *)&s->i2c[0]->i2c,0x48);
+       
+    s->i2c[1]->i2c.event = twl4030_49_event;
+    s->i2c[1]->i2c.recv = twl4030_49_rx;
+    s->i2c[1]->i2c.send = twl4030_49_tx;
+    twl4030_49_reset(&s->i2c[1]->i2c);
+    i2c_set_slave_address((i2c_slave *)&s->i2c[1]->i2c,0x49);
+       
+    s->i2c[2]->i2c.event = twl4030_4a_event;
+    s->i2c[2]->i2c.recv = twl4030_4a_rx;
+    s->i2c[2]->i2c.send = twl4030_4a_tx;
+    twl4030_4a_reset(&s->i2c[2]->i2c);
+    i2c_set_slave_address((i2c_slave *)&s->i2c[2]->i2c,0x4a);
+       
+    s->i2c[3]->i2c.event = twl4030_4b_event;
+    s->i2c[3]->i2c.recv = twl4030_4b_rx;
+    s->i2c[3]->i2c.send = twl4030_4b_tx;
+    twl4030_4b_reset(&s->i2c[3]->i2c);
+    i2c_set_slave_address((i2c_slave *)&s->i2c[3]->i2c,0x4b);
+       
+    register_savevm("twl4030", -1, 0,
+                    twl4030_save_state, twl4030_load_state, s);
+
+    return s;
+}
index c850a91..8a6661d 100644 (file)
@@ -100,7 +100,7 @@ static const uint8_t qemu_mouse_config_descriptor[] = {
        0x01,       /*  u8  bNumInterfaces; (1) */
        0x01,       /*  u8  bConfigurationValue; */
        0x04,       /*  u8  iConfiguration; */
-       0xa0,       /*  u8  bmAttributes;
+       0xe0,       /*  u8  bmAttributes;
                                 Bit 7: must be set,
                                     6: Self-powered,
                                     5: Remote wakeup,
index 9f26bbe..f7cebed 100644 (file)
@@ -23,6 +23,7 @@
  */
 #include "qemu-common.h"
 #include "usb.h"
+#include "hw.h"
 
 //#define DEBUG
 
@@ -40,6 +41,37 @@ typedef struct USBHubState {
     USBHubPort ports[MAX_PORTS];
 } USBHubState;
 
+static void usb_hub_save_state(QEMUFile *f, void *opaque)
+{
+    USBHubState *s = (USBHubState *)opaque;
+    int i;
+    
+    qemu_put_sbe32(f, s->nb_ports);
+    for (i = 0; i < s->nb_ports; i++) {
+        qemu_put_be16(f, s->ports[i].wPortStatus);
+        qemu_put_be16(f, s->ports[i].wPortChange);
+    }
+}
+
+static int usb_hub_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    USBHubState *s = (USBHubState *)opaque;
+    int i;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    if (qemu_get_sbe32(f) != s->nb_ports)
+        return -EINVAL;
+    
+    for (i = 0; i < s->nb_ports; i++) {
+        s->ports[i].wPortStatus = qemu_get_be16(f);
+        s->ports[i].wPortChange = qemu_get_be16(f);
+    }
+    
+    return 0;
+}
+
 #define ClearHubFeature                (0x2000 | USB_REQ_CLEAR_FEATURE)
 #define ClearPortFeature       (0x2300 | USB_REQ_CLEAR_FEATURE)
 #define GetHubDescriptor       (0xa000 | USB_REQ_GET_DESCRIPTOR)
@@ -113,7 +145,7 @@ static const uint8_t qemu_hub_config_descriptor[] = {
        0x01,       /*  u8  bNumInterfaces; (1) */
        0x01,       /*  u8  bConfigurationValue; */
        0x00,       /*  u8  iConfiguration; */
-       0xc0,       /*  u8  bmAttributes;
+       0xe0,       /*  u8  bmAttributes;
                                 Bit 7: must be set,
                                     6: Self-powered,
                                     5: Remote wakeup,
@@ -548,5 +580,9 @@ USBDevice *usb_hub_init(int nb_ports)
         port->wPortStatus = PORT_STAT_POWER;
         port->wPortChange = 0;
     }
+    
+    register_savevm("usb hub", -1, 0,
+                    usb_hub_save_state, usb_hub_load_state, s);
+    
     return (USBDevice *)s;
 }
index 8e1e6eb..5d91973 100644 (file)
@@ -25,6 +25,7 @@
 #include "qemu-timer.h"
 #include "usb.h"
 #include "irq.h"
+#include "hw.h"
 
 /* Common USB registers */
 #define MUSB_HDRC_FADDR                0x00    /* 8-bit */
@@ -32,8 +33,8 @@
 
 #define MUSB_HDRC_INTRTX       0x02    /* 16-bit */
 #define MUSB_HDRC_INTRRX       0x04
-#define MUSB_HDRC_INTRTXE      0x06  
-#define MUSB_HDRC_INTRRXE      0x08  
+#define MUSB_HDRC_INTRTXE      0x06
+#define MUSB_HDRC_INTRRXE      0x08
 #define MUSB_HDRC_INTRUSB      0x0a    /* 8 bit */
 #define MUSB_HDRC_INTRUSBE     0x0b    /* 8 bit */
 #define MUSB_HDRC_FRAME                0x0c    /* 16-bit */
  */
 
 /* POWER */
-#define MGC_M_POWER_ISOUPDATE          0x80 
+#define MGC_M_POWER_ISOUPDATE          0x80
 #define        MGC_M_POWER_SOFTCONN            0x40
 #define        MGC_M_POWER_HSENAB              0x20
 #define        MGC_M_POWER_HSMODE              0x10
 #define MGC_M_INTR_RESUME              0x02
 #define MGC_M_INTR_RESET               0x04
 #define MGC_M_INTR_BABBLE              0x04
-#define MGC_M_INTR_SOF                 0x08 
+#define MGC_M_INTR_SOF                 0x08
 #define MGC_M_INTR_CONNECT             0x10
 #define MGC_M_INTR_DISCONNECT          0x20
 #define MGC_M_INTR_SESSREQ             0x40
 #define MGC_M_INTR_EP0                 0x01    /* FOR EP0 INTERRUPT */
 
 /* DEVCTL */
-#define MGC_M_DEVCTL_BDEVICE           0x80   
+#define MGC_M_DEVCTL_BDEVICE           0x80
 #define MGC_M_DEVCTL_FSDEV             0x40
 #define MGC_M_DEVCTL_LSDEV             0x20
 #define MGC_M_DEVCTL_VBUS              0x18
 #define MGC_M_ULPI_REGCTL_COMPLETE     0x02
 #define MGC_M_ULPI_REGCTL_REG          0x01
 
+/* #define MUSB_DEBUG */
+
+#ifdef MUSB_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+
 static void musb_attach(USBPort *port, USBDevice *dev);
 
 struct musb_s {
@@ -270,7 +280,7 @@ struct musb_s {
     int setup_len;
     int session;
 
-    uint32_t buf[0x2000];
+    uint8_t buf[0x8000];
 
     struct musb_ep_s {
         uint16_t faddr[2];
@@ -285,7 +295,7 @@ struct musb_s {
         uint8_t fifosize;
         int timeout[2];        /* Always in microframes */
 
-        uint32_t *buf[2];
+        uint8_t *buf[2];
         int fifolen[2];
         int fifostart[2];
         int fifoaddr[2];
@@ -302,37 +312,7 @@ struct musb_s {
         /* Duplicating the world since 2008!...  probably we should have 32
          * logical, single endpoints instead.  */
     } ep[16];
-} *musb_init(qemu_irq *irqs)
-{
-    struct musb_s *s = qemu_mallocz(sizeof(*s));
-    int i;
-
-    s->irqs = irqs;
-
-    s->faddr = 0x00;
-    s->power = MGC_M_POWER_HSENAB;
-    s->tx_intr = 0x0000;
-    s->rx_intr = 0x0000;
-    s->tx_mask = 0xffff;
-    s->rx_mask = 0xffff;
-    s->intr = 0x00;
-    s->mask = 0x06;
-    s->idx = 0;
-
-    /* TODO: _DW */
-    s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
-    for (i = 0; i < 16; i ++) {
-        s->ep[i].fifosize = 64;
-        s->ep[i].maxp[0] = 0x40;
-        s->ep[i].maxp[1] = 0x40;
-        s->ep[i].musb = s;
-        s->ep[i].epnum = i;
-    }
-
-    qemu_register_usb_port(&s->port, s, 0, musb_attach);
-
-    return s;
-}
+};
 
 static void musb_vbus_set(struct musb_s *s, int level)
 {
@@ -771,7 +751,7 @@ static void musb_tx_rdy(struct musb_s *s, int epnum)
     struct musb_ep_s *ep = s->ep + epnum;
     int pid;
     int total, valid = 0;
-
+    TRACE("start %d, len %d",  ep->fifostart[0], ep->fifolen[0] );
     ep->fifostart[0] += ep->fifolen[0];
     ep->fifolen[0] = 0;
 
@@ -786,11 +766,11 @@ static void musb_tx_rdy(struct musb_s *s, int epnum)
     }
 
     /* If the packet is not fully ready yet, wait for a next segment.  */
-    if (epnum && (ep->fifostart[0] << 2) < total)
+    if (epnum && (ep->fifostart[0]) < total)
         return;
 
     if (!valid)
-        total = ep->fifostart[0] << 2;
+        total = ep->fifostart[0];
 
     pid = USB_TOKEN_OUT;
     if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {
@@ -814,12 +794,13 @@ static void musb_rx_req(struct musb_s *s, int epnum)
     /* If we already have a packet, which didn't fit into the
      * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
     if (ep->packey[1].pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
-                    (ep->fifostart[1] << 2) + ep->rxcount <
+                    (ep->fifostart[1]) + ep->rxcount <
                     ep->packey[1].len) {
-        ep->fifostart[1] += ep->rxcount >> 2;
+        TRACE("0x%08x, %d",  ep->fifostart[1], ep->rxcount );
+        ep->fifostart[1] += ep->rxcount;
         ep->fifolen[1] = 0;
 
-        ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1] << 2),
+        ep->rxcount = MIN(ep->packey[0].len - (ep->fifostart[1]),
                         ep->maxp[1]);
 
         ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
@@ -869,6 +850,38 @@ static void musb_rx_req(struct musb_s *s, int epnum)
                     total, musb_rx_packet_complete, 1);
 }
 
+static uint8_t musb_read_fifo(struct musb_ep_s *ep)
+{
+    uint8_t value;
+    if (ep->fifolen[1] >= 64) {
+        /* We have a FIFO underrun */
+        printf("%s: EP%d FIFO is now empty, stop reading\n",
+                __FUNCTION__, ep->epnum);
+        return 0x00000000;
+    }
+    /* In DMA mode clear RXPKTRDY and set REQPKT automatically
+     * (if AUTOREQ is set) */
+
+    ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
+    value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
+    TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] );
+    return value;
+}
+
+static void musb_write_fifo(struct musb_ep_s *ep, uint8_t value)
+{
+    TRACE("EP%d = %02x", ep->epnum, value);
+    if (ep->fifolen[0] >= 64) {
+        /* We have a FIFO overrun */
+        printf("%s: EP%d FIFO exceeded 64 bytes, stop feeding data\n",
+                __FUNCTION__, ep->epnum);
+        return;
+     }
+
+     ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
+     ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
+}
+
 static void musb_ep_frame_cancel(struct musb_ep_s *ep, int dir)
 {
     if (ep->intv_timer[dir])
@@ -879,6 +892,7 @@ static void musb_ep_frame_cancel(struct musb_ep_s *ep, int dir)
 static uint8_t musb_busctl_readb(void *opaque, int ep, int addr)
 {
     struct musb_s *s = (struct musb_s *) opaque;
+//    TRACE("ADDR = 0x%08x", addr);
 
     switch (addr) {
     /* For USB2.0 HS hubs only */
@@ -902,6 +916,12 @@ static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value)
     struct musb_s *s = (struct musb_s *) opaque;
 
     switch (addr) {
+    case MUSB_HDRC_TXFUNCADDR:
+        s->ep[ep].faddr[0] = value;
+        break;
+    case MUSB_HDRC_RXFUNCADDR:
+        s->ep[ep].faddr[1] = value;
+        break;
     case MUSB_HDRC_TXHUBADDR:
         s->ep[ep].haddr[0] = value;
         break;
@@ -972,6 +992,8 @@ static uint8_t musb_ep_readb(void *opaque, int ep, int addr)
         return 0x00;
     case MUSB_HDRC_FIFOSIZE:
         return ep ? s->ep[ep].fifosize : s->ep[ep].config;
+    case MUSB_HDRC_RXCOUNT:
+        return s->ep[ep].rxcount;
 
     default:
         printf("%s: unknown register at %02x\n", __FUNCTION__, addr);
@@ -1005,7 +1027,6 @@ static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value)
                         __FUNCTION__, value);
         s->ep[ep].fifosize = value;
         break;
-
     default:
         printf("%s: unknown register at %02x\n", __FUNCTION__, addr);
     };
@@ -1144,6 +1165,7 @@ static uint32_t musb_readb(void *opaque, target_phys_addr_t addr)
     struct musb_s *s = (struct musb_s *) opaque;
     int ep, i;
     uint8_t ret;
+//    TRACE("ADDR = 0x%08x", addr);
 
     switch (addr) {
     case MUSB_HDRC_FADDR:
@@ -1191,6 +1213,10 @@ static uint32_t musb_readb(void *opaque, target_phys_addr_t addr)
         ep = (addr >> 4) & 0xf;
         return musb_ep_readb(s, ep, addr & 0xf);
 
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        return musb_read_fifo(s->ep + ep);
+
     default:
         printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
         return 0x00;
@@ -1201,6 +1227,7 @@ static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
 {
     struct musb_s *s = (struct musb_s *) opaque;
     int ep;
+//    TRACE("ADDR = 0x%08x = %08x", addr, value);
 
     switch (addr) {
     case MUSB_HDRC_FADDR:
@@ -1273,6 +1300,11 @@ static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
         musb_ep_writeb(s, ep, addr & 0xf, value);
         break;
 
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        musb_write_fifo(s->ep + ep, value & 0xff);
+        break;
+
     default:
         printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
     };
@@ -1283,6 +1315,7 @@ static uint32_t musb_readh(void *opaque, target_phys_addr_t addr)
     struct musb_s *s = (struct musb_s *) opaque;
     int ep, i;
     uint16_t ret;
+//    TRACE("ADDR = 0x%08x", addr);
 
     switch (addr) {
     case MUSB_HDRC_INTRTX:
@@ -1323,6 +1356,10 @@ static uint32_t musb_readh(void *opaque, target_phys_addr_t addr)
         ep = (addr >> 4) & 0xf;
         return musb_ep_readh(s, ep, addr & 0xf);
 
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8);
+
     default:
         return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8);
     };
@@ -1332,6 +1369,7 @@ static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value)
 {
     struct musb_s *s = (struct musb_s *) opaque;
     int ep;
+    //TRACE("ADDR = 0x%08x = %08x", addr, value);
 
     switch (addr) {
     case MUSB_HDRC_INTRTXE:
@@ -1350,12 +1388,14 @@ static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value)
     case MUSB_HDRC_TXFIFOADDR:
         s->ep[s->idx].fifoaddr[0] = value;
         s->ep[s->idx].buf[0] =
-                s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1));
+                s->buf + ((value << 3) & 0x7ff );
+       //TRACE("TXFIFOADDR = 0x%08x, BUF %08x", value, s->ep[s->idx].buf[0]);
         break;
     case MUSB_HDRC_RXFIFOADDR:
         s->ep[s->idx].fifoaddr[1] = value;
         s->ep[s->idx].buf[1] =
-                s->buf + ((value << 1) & (sizeof(s->buf) / 4 - 1));
+                s->buf + ((value << 3) & 0x7ff);
+       //TRACE("RXFIFOADDR = 0x%08x, BUF %08x", value, s->ep[s->idx].buf[1]);
         break;
 
     case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
@@ -1372,6 +1412,12 @@ static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value)
         musb_ep_writeh(s, ep, addr & 0xf, value);
         break;
 
+    case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        musb_write_fifo(s->ep + ep, value & 0xff);
+        musb_write_fifo(s->ep + ep, (value >> 8) & 0xff);
+        break;
+
     default:
         musb_writeb(s, addr, value & 0xff);
         musb_writeb(s, addr | 1, value >> 8);
@@ -1381,26 +1427,15 @@ static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value)
 static uint32_t musb_readw(void *opaque, target_phys_addr_t addr)
 {
     struct musb_s *s = (struct musb_s *) opaque;
-    struct musb_ep_s *ep;
-    int epnum;
+    int ep;
 
     switch (addr) {
     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
-        epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
-        ep = s->ep + epnum;
-
-        if (ep->fifolen[1] >= 16) {
-            /* We have a FIFO underrun */
-            printf("%s: EP%i FIFO is now empty, stop reading\n",
-                            __FUNCTION__, epnum);
-            return 0x00000000;
-        }
-        /* In DMA mode clear RXPKTRDY and set REQPKT automatically
-         * (if AUTOREQ is set) */
-
-        ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
-        return ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
-
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        return ( musb_read_fifo(s->ep + ep)       |
+                 musb_read_fifo(s->ep + ep) << 8  |
+                 musb_read_fifo(s->ep + ep) << 16 |
+                 musb_read_fifo(s->ep + ep) << 24 );
     default:
         printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
         return 0x00000000;
@@ -1410,26 +1445,17 @@ static uint32_t musb_readw(void *opaque, target_phys_addr_t addr)
 static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
 {
     struct musb_s *s = (struct musb_s *) opaque;
-    struct musb_ep_s *ep;
-    int epnum;
+    int ep;
+//    TRACE("ADDR = 0x%08x = %08x", addr, value);
 
     switch (addr) {
     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
-        epnum = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
-        ep = s->ep + epnum;
-
-        if (ep->fifolen[0] >= 16) {
-            /* We have a FIFO overrun */
-            printf("%s: EP%i FIFO exceeded 64 bytes, stop feeding data\n",
-                            __FUNCTION__, epnum);
-            break;
-        }
-
-        ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
-        if (epnum)
-            ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
+        ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
+        musb_write_fifo(s->ep + ep, value & 0xff);
+        musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
+        musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
+        musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
         break;
-
     default:
         printf("%s: unknown register at %02x\n", __FUNCTION__, (int) addr);
     };
@@ -1446,3 +1472,182 @@ CPUWriteMemoryFunc *musb_write[] = {
     musb_writeh,
     musb_writew,
 };
+
+static void musb_save_state(QEMUFile *f, void *opaque)
+{
+    struct musb_s *s = (struct musb_s *)opaque;
+    int i, j;
+    
+    qemu_put_sbe32(f, s->idx);
+    qemu_put_byte(f, s->devctl);
+    qemu_put_byte(f, s->power);
+    qemu_put_byte(f, s->faddr);
+    qemu_put_byte(f, s->intr);
+    qemu_put_byte(f, s->mask);
+    qemu_put_be16(f, s->tx_intr);
+    qemu_put_be16(f, s->tx_mask);
+    qemu_put_be16(f, s->rx_intr);
+    qemu_put_be16(f, s->rx_mask);
+    qemu_put_sbe32(f, s->setup_len);
+    qemu_put_sbe32(f, s->session);
+    qemu_put_buffer(f, s->buf, sizeof(s->buf));
+    for (i = 0; i < 16; i++) {
+        qemu_put_be16(f, s->ep[i].rxcount);
+        qemu_put_byte(f, s->ep[i].config);
+        qemu_put_byte(f, s->ep[i].fifosize);
+        for (j = 0; j < 2; j++) {
+            qemu_put_be16(f, s->ep[i].faddr[j]);
+            qemu_put_byte(f, s->ep[i].haddr[j]);
+            qemu_put_byte(f, s->ep[i].hport[j]);
+            qemu_put_be16(f, s->ep[i].csr[j]);
+            qemu_put_be16(f, s->ep[i].maxp[j]);
+            qemu_put_byte(f, s->ep[i].type[j]);
+            qemu_put_byte(f, s->ep[i].interval[j]);
+            qemu_put_sbe32(f, s->ep[i].timeout[j]);
+            if (s->ep[i].buf[j])
+                qemu_put_be32(f, s->ep[i].buf[j] - s->buf);
+            else
+                qemu_put_be32(f, 0xffffffff);
+            qemu_put_sbe32(f, s->ep[i].fifolen[j]);
+            qemu_put_sbe32(f, s->ep[i].fifostart[j]);
+            qemu_put_sbe32(f, s->ep[i].fifoaddr[j]);
+            qemu_put_sbe32(f, s->ep[i].packey[j].pid);
+            qemu_put_byte(f, s->ep[i].packey[j].devaddr);
+            qemu_put_byte(f, s->ep[i].packey[j].devep);
+            qemu_put_sbe32(f, s->ep[i].packey[j].len);
+            qemu_put_sbe32(f, s->ep[i].status[j]);
+            qemu_put_sbe32(f, s->ep[i].ext_size[j]);
+            qemu_put_sbe32(f, s->ep[i].interrupt[j]);
+            if (s->ep[i].delayed_cb[j] == musb_rx_packet_complete)
+                qemu_put_byte(f, 1);
+            else if (s->ep[i].delayed_cb[j] == musb_tx_packet_complete)
+                qemu_put_byte(f, 2);
+            else
+                qemu_put_byte(f, 0);
+            if (s->ep[i].intv_timer[j]) {
+                qemu_put_byte(f, 1);
+                qemu_put_timer(f, s->ep[i].intv_timer[j]);
+            } else
+                qemu_put_byte(f, 0);
+        }
+    }
+}
+
+static int musb_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+    struct musb_s *s = (struct musb_s *)opaque;
+    int i, j;
+    uint32_t x;
+    
+    if (version_id)
+        return -EINVAL;
+    
+    s->idx = qemu_get_sbe32(f);
+    s->devctl = qemu_get_byte(f);
+    s->power = qemu_get_byte(f);
+    s->faddr = qemu_get_byte(f);
+    s->intr = qemu_get_byte(f);
+    s->mask = qemu_get_byte(f);
+    s->tx_intr = qemu_get_be16(f);
+    s->tx_mask = qemu_get_be16(f);
+    s->rx_intr = qemu_get_be16(f);
+    s->rx_mask = qemu_get_be16(f);
+    s->setup_len = qemu_get_sbe32(f);
+    s->session = qemu_get_sbe32(f);
+    qemu_get_buffer(f, s->buf, sizeof(s->buf));
+    for (i = 0; i < 16; i++) {
+        s->ep[i].rxcount = qemu_get_be16(f);
+        s->ep[i].config = qemu_get_byte(f);
+        s->ep[i].fifosize = qemu_get_byte(f);
+        for (j = 0; j < 2; j++) {
+            s->ep[i].faddr[j] = qemu_get_be16(f);
+            s->ep[i].haddr[j] = qemu_get_byte(f);
+            s->ep[i].hport[j] = qemu_get_byte(f);
+            s->ep[i].csr[j] = qemu_get_be16(f);
+            s->ep[i].maxp[j] = qemu_get_be16(f);
+            s->ep[i].type[j] = qemu_get_byte(f);
+            s->ep[i].interval[j] = qemu_get_byte(f);
+            s->ep[i].timeout[j] = qemu_get_sbe32(f);
+            x = qemu_get_be32(f);
+            if (x != 0xffffffff)
+                s->ep[i].buf[j] = s->buf + x;
+            else
+                s->ep[i].buf[j] = 0;
+            s->ep[i].fifolen[j] = qemu_get_sbe32(f);
+            s->ep[i].fifostart[j] = qemu_get_sbe32(f);
+            s->ep[i].fifoaddr[j] = qemu_get_sbe32(f);
+            s->ep[i].packey[j].pid = qemu_get_sbe32(f);
+            s->ep[i].packey[j].devaddr = qemu_get_byte(f);
+            s->ep[i].packey[j].devep = qemu_get_byte(f);
+            s->ep[i].packey[j].data = s->ep[i].buf[j];
+            s->ep[i].packey[j].len = qemu_get_sbe32(f);
+            s->ep[i].packey[j].complete_opaque = &s->ep[i];
+            s->ep[i].status[j] = qemu_get_sbe32(f);
+            s->ep[i].ext_size[j] = qemu_get_sbe32(f);
+            s->ep[i].interrupt[j] = qemu_get_sbe32(f);
+            switch (qemu_get_byte(f)) {
+                case 0:
+                    s->ep[i].delayed_cb[j] = 0;
+                    s->ep[i].packey[j].complete_cb = 0;
+                    break;
+                case 1:
+                    s->ep[i].delayed_cb[j] = musb_rx_packet_complete;
+                    s->ep[i].packey[j].complete_cb = musb_rx_packet_complete;
+                    break;
+                case 2:
+                    s->ep[i].delayed_cb[j] = musb_tx_packet_complete;
+                    s->ep[i].packey[j].complete_cb = musb_tx_packet_complete;
+                    break;
+                default:
+                    fprintf(stderr, "%s: unknown delayed_cb\n", __FUNCTION__);
+                    exit(-1);
+                    break;
+            }
+            if (qemu_get_byte(f)) {
+                if (!s->ep[i].intv_timer[j]) {
+                    s->ep[i].intv_timer[j] =
+                        qemu_new_timer(vm_clock,
+                                       j ? musb_cb_tick1 : musb_cb_tick0,
+                                       &s->ep[i]);
+                }
+                qemu_get_timer(f, s->ep[i].intv_timer[j]);
+            }
+        }
+    }
+    
+    /* TODO: restore interrupt status */
+    
+    return 0;
+}
+
+struct musb_s *musb_init(qemu_irq *irqs)
+{
+    struct musb_s *s = qemu_mallocz(sizeof(*s));
+    int i;
+    
+    s->irqs = irqs;
+    
+    s->faddr = 0x00;
+    s->power = MGC_M_POWER_HSENAB;
+    s->tx_intr = 0x0000;
+    s->rx_intr = 0x0000;
+    s->tx_mask = 0xffff;
+    s->rx_mask = 0xffff;
+    s->intr = 0x00;
+    s->mask = 0x06;
+    s->idx = 0;
+    
+    /* TODO: _DW */
+    s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
+    for (i = 0; i < 16; i ++) {
+        s->ep[i].fifosize = 64;
+        s->ep[i].maxp[0] = 0x40;
+        s->ep[i].maxp[1] = 0x40;
+        s->ep[i].musb = s;
+        s->ep[i].epnum = i;
+    }
+    
+    qemu_register_usb_port(&s->port, s, 0, musb_attach);
+    register_savevm("musb", -1, 0, musb_save_state, musb_load_state, s);
+    return s;
+}
index e59bc8a..3766a76 100644 (file)
@@ -32,6 +32,7 @@
 #include "usb.h"
 #include "pci.h"
 #include "pxa.h"
+#include "omap.h"
 
 //#define DEBUG_OHCI
 /* Dump packet contents.  */
@@ -60,7 +61,8 @@ typedef struct OHCIPort {
 
 enum ohci_type {
     OHCI_TYPE_PCI,
-    OHCI_TYPE_PXA
+    OHCI_TYPE_PXA,
+    OHCI_TYPE_OMAP
 };
 
 typedef struct {
@@ -1703,3 +1705,12 @@ void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
 
     cpu_register_physical_memory(base, 0x1000, ohci->mem);
 }
+
+int usb_ohci_init_omap(target_phys_addr_t base, uint32_t region_size,
+                       int num_ports, qemu_irq irq)
+{
+    OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
+    
+    usb_ohci_init(ohci, num_ports, -1, irq, OHCI_TYPE_OMAP, "OHCI USB");
+    return ohci->mem;
+}
index d80e2f2..ca34619 100644 (file)
@@ -194,7 +194,7 @@ static void versatile_init(ram_addr_t ram_size, int vga_ram_size,
         nd = &nd_table[n];
 
         if ((!nd->model && !done_smc) || strcmp(nd->model, "smc91c111") == 0) {
-            smc91c111_init(nd, 0x10010000, sic[25]);
+            smc91c111_init(nd, 0x10010000, sic[25], 1);
             done_smc = 1;
         } else {
             pci_nic_init(pci_bus, nd, -1, "rtl8139");
index 6de30f4..706c8e2 100644 (file)
@@ -1,4 +1,6 @@
 /* This is the Linux kernel elf-loading code, ported into user space */
+#include <sys/time.h>
+#include <sys/param.h>
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -8,6 +10,7 @@
 #include <sys/mman.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 
 #include "qemu.h"
 #include "disas.h"
@@ -21,6 +24,8 @@
 #undef ELF_ARCH
 #endif
 
+#define ELF_OSABI      ELFOSABI_SYSV
+
 /* from personality.h */
 
 /*
@@ -128,7 +133,45 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
     regs->rip = infop->entry;
 }
 
-#else
+#define USE_ELF_CORE_DUMP
+
+typedef struct target_pt_regs elf_gregset_t;
+
+/*
+ * For register format that gdb uses, see <sys/reg.h>.  These
+ * should be in same format (which is usually same as target_pt_regs).
+ */
+static void elf_core_copy_regs(elf_gregset_t *elfregs, const CPUState *env)
+{
+    (void) memset(elfregs, 0, sizeof (*elfregs));
+
+    /* GPRs */
+    elfregs->r15 = env->regs[15];
+    elfregs->r14 = env->regs[14];
+    elfregs->r13 = env->regs[13];
+    elfregs->r12 = env->regs[12];
+    elfregs->rbp = env->regs[R_EBP];
+    elfregs->rbx = env->regs[R_EBX];
+    elfregs->r11 = env->regs[11];
+    elfregs->r10 = env->regs[10];
+    elfregs->r9 = env->regs[9];
+    elfregs->r8 = env->regs[8];
+    elfregs->rax = env->regs[R_EAX];
+    elfregs->rcx = env->regs[R_ECX];
+    elfregs->rdx = env->regs[R_EDX];
+    elfregs->rsi = env->regs[R_ESI];
+    elfregs->rdi = env->regs[R_EDI];
+    elfregs->orig_rax = env->regs[R_EAX];
+    elfregs->rip = env->eip;
+    elfregs->rsp = env->regs[R_ESP];
+    elfregs->eflags = env->eflags;
+
+    /* segment registers */
+    elfregs->cs = env->segs[R_CS].selector;
+    elfregs->ss = env->segs[R_SS].selector;
+}
+
+#else /* !TARGET_X86_64 */
 
 #define ELF_START_MMAP 0x80000000
 
@@ -158,9 +201,39 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
        A value of 0 tells we have no such handler.  */
     regs->edx = 0;
 }
-#endif
 
 #define USE_ELF_CORE_DUMP
+
+typedef struct target_pt_regs elf_gregset_t;
+
+static void elf_core_copy_regs(elf_gregset_t *elfregs, const CPUState *env)
+{
+    (void) memset(elfregs, 0, sizeof (*elfregs));
+
+    /* GPRs */
+    elfregs->ebx = env->regs[R_EBX];
+    elfregs->ecx = env->regs[R_ECX];
+    elfregs->edx = env->regs[R_EDX];
+    elfregs->esi = env->regs[R_ESI];
+    elfregs->edi = env->regs[R_EDI];
+    elfregs->ebp = env->regs[R_EBP];
+    elfregs->eax = env->regs[R_EAX];
+    elfregs->orig_eax = env->regs[R_EAX]; /* XXX */
+    elfregs->esp = env->regs[R_ESP];
+    elfregs->eip = env->eip;
+    elfregs->eflags = env->eflags;
+
+    /* segment registers */
+    elfregs->xds = env->segs[R_DS].selector;
+    elfregs->xes = env->segs[R_ES].selector;
+    elfregs->xcs = env->segs[R_CS].selector;
+    elfregs->xss = env->segs[R_SS].selector;
+    elfregs->xfs = env->segs[R_FS].selector;
+    elfregs->xgs = env->segs[R_GS].selector;
+}
+
+#endif /* TARGET_i386 */
+
 #define ELF_EXEC_PAGESIZE      4096
 
 #endif
@@ -199,6 +272,34 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
 }
 
 #define USE_ELF_CORE_DUMP
+
+typedef struct target_pt_regs elf_gregset_t;
+
+static void elf_core_copy_regs(elf_gregset_t *elfregs, const CPUState *env)
+{
+    (void) memset(elfregs, 0, sizeof (*elfregs));
+
+    elfregs->ARM_r0 = env->regs[0];
+    elfregs->ARM_r1 = env->regs[1];
+    elfregs->ARM_r2 = env->regs[2];
+    elfregs->ARM_r3 = env->regs[3];
+    elfregs->ARM_r4 = env->regs[4];
+    elfregs->ARM_r5 = env->regs[5];
+    elfregs->ARM_r6 = env->regs[6];
+    elfregs->ARM_r7 = env->regs[7];
+    elfregs->ARM_r8 = env->regs[8];
+    elfregs->ARM_r9 = env->regs[9];
+    elfregs->ARM_r10 = env->regs[10];
+    elfregs->ARM_fp = env->regs[11];
+    elfregs->ARM_ip = env->regs[12];
+    elfregs->ARM_sp = env->regs[13];
+    elfregs->ARM_lr = env->regs[14];
+    elfregs->ARM_pc = env->regs[15];
+
+    elfregs->ARM_cpsr = cpsr_read((CPUState *)env);
+    elfregs->ARM_ORIG_r0 = env->regs[0]; /* XXX */
+}
+
 #define ELF_EXEC_PAGESIZE      4096
 
 enum
@@ -360,7 +461,6 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
     _regs->gpr[5] = pos;
 }
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
 #endif
@@ -390,7 +490,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
     regs->regs[29] = infop->start_stack;
 }
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE        4096
 
 #endif /* TARGET_MIPS */
@@ -412,7 +511,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
   regs->regs[15] = infop->start_stack;
 }
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE        4096
 
 #endif
@@ -432,7 +530,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
   regs->erp = infop->entry;
 }
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE        8192
 
 #endif
@@ -457,7 +554,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
     regs->pc = infop->entry;
 }
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      8192
 
 #endif
@@ -482,7 +578,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
            regs->unique, infop->start_data);
 }
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE        8192
 
 #endif /* TARGET_ALPHA */
@@ -598,8 +693,23 @@ static void bswap_sym(struct elf_sym *sym)
     bswaptls(&sym->st_size);
     bswap16s(&sym->st_shndx);
 }
+
 #endif
 
+#ifdef USE_ELF_CORE_DUMP
+static int elf_core_dump(int, const CPUState *);
+
+#ifdef BSWAP_NEEDED
+static void bswap_note(struct elf_note *en)
+{
+    bswaptls(&en->n_namesz);
+    bswaptls(&en->n_descsz);
+    bswaptls(&en->n_type);
+}
+#endif /* BSWAP_NEEDED */
+
+#endif /* USE_ELF_CORE_DUMP */
+
 /*
  * 'copy_elf_strings()' copies argument/envelope strings from user
  * memory to free pages in kernel mem. These are in a format ready
@@ -824,6 +934,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
 #endif
 #undef NEW_AUX_ENT
 
+        info->saved_auxv = sp;
+
         sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
         return sp;
 }
@@ -1337,6 +1449,30 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
     info->mmap = 0;
     elf_entry = (abi_ulong) elf_ex.e_entry;
 
+#if defined(CONFIG_USE_GUEST_BASE)
+    /*
+     * In case where user has not explicitly set the guest_base, we
+     * probe here that should we set it automatically.
+     */
+    if (guest_base == 0) {
+        /*
+         * Go through ELF program header table and find out whether
+        * any of the segments drop below our current mmap_min_addr and
+         * in that case set guest_base to corresponding address.
+         */
+        for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
+            i++, elf_ppnt++) {
+            if (elf_ppnt->p_type != PT_LOAD)
+                continue;
+            if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
+                guest_base = HOST_PAGE_ALIGN(mmap_min_addr);
+                qemu_log("setting guest_base=0x%lx\n", guest_base);
+                break;
+            }
+        }
+    }
+#endif /* CONFIG_USE_GUEST_BASE */
+
     /* Do this so that we can load the interpreter, if need be.  We will
        change some of these later */
     info->rss = 0;
@@ -1506,9 +1642,828 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
 
     info->entry = elf_entry;
 
+#ifdef USE_ELF_CORE_DUMP
+    bprm->core_dump = &elf_core_dump;
+#endif
+
+
     return 0;
 }
 
+#ifdef USE_ELF_CORE_DUMP
+
+/*
+ * Definitions to generate Intel SVR4-like core files.
+ * These mostly have the same names as the SVR4 types with "elf_"
+ * tacked on the front to prevent clashes with linux definitions,
+ * and the typedef forms have been avoided.  This is mostly like
+ * the SVR4 structure, but more Linuxy, with things that Linux does
+ * not support and which gdb doesn't really use excluded.
+ *
+ * Fields we don't dump (their contents is zero) in linux-user qemu
+ * are marked with XXX.
+ *
+ * TODO: check that dumped field types are correct (e.g should we
+ * use abi_long or something else).
+ *
+ * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
+ */
+
+/* An ELF note in memory */
+struct memelfnote {
+    const char *name;
+    size_t     namesz;
+    size_t     namesz_rounded;
+    int        type;
+    size_t     datasz;
+    void       *data;
+    size_t     notesz;
+};
+
+struct elf_siginfo {
+    int  si_signo; /* signal number */
+    int  si_code;  /* extra code */
+    int  si_errno; /* errno */
+};
+
+struct elf_prstatus {
+    struct elf_siginfo pr_info;      /* Info associated with signal */
+    short              pr_cursig;    /* Current signal */
+    target_ulong       pr_sigpend;   /* XXX */
+    target_ulong       pr_sighold;   /* XXX */
+    int                pr_pid;
+    int                pr_ppid;
+    int                pr_pgrp;
+    int                pr_sid;
+    struct target_timeval pr_utime;  /* XXX User time */
+    struct target_timeval pr_stime;  /* XXX System time */
+    struct target_timeval pr_cutime; /* XXX Cumulative user time */
+    struct target_timeval pr_cstime; /* XXX Cumulative system time */
+    elf_gregset_t      pr_reg;       /* GP registers */
+    abi_long           pr_fpvalid;   /* XXX */
+};
+
+#define ELF_PRARGSZ     (80) /* Number of chars for args */
+
+struct elf_prpsinfo {
+    char         pr_state;       /* numeric process state */
+    char         pr_sname;       /* char for pr_state */
+    char         pr_zomb;        /* zombie */
+    char         pr_nice;        /* nice val */
+    target_ulong pr_flag;        /* flags */
+    short        pr_uid;
+    short        pr_gid;
+    abi_long     pr_pid, pr_ppid, pr_pgrp, pr_sid;
+    /* Lots missing */
+    char    pr_fname[16];           /* filename of executable */
+    char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+/* Here is the structure in which status of each thread is captured. */
+struct elf_thread_status {
+    TAILQ_ENTRY(elf_thread_status)  ets_link;
+    struct elf_prstatus prstatus;   /* NT_PRSTATUS */
+#if 0
+    elf_fpregset_t fpu;             /* NT_PRFPREG */
+    struct task_struct *thread;
+    elf_fpxregset_t xfpu;           /* ELF_CORE_XFPREG_TYPE */
+#endif
+    struct memelfnote notes[1];
+    int num_notes;
+};
+
+struct elf_note_info {
+    struct memelfnote   *notes;
+    struct elf_prstatus *prstatus;  /* NT_PRSTATUS */
+    struct elf_prpsinfo *psinfo;    /* NT_PRPSINFO */
+
+    TAILQ_HEAD(thread_list_head, elf_thread_status) thread_list;
+#if 0
+    /*
+     * Current version of ELF coredump doesn't support
+     * dumping fp regs etc.
+     */
+    elf_fpregset_t *fpu;
+    elf_fpxregset_t *xfpu;
+    int thread_status_size;
+#endif
+    int notes_size;
+    int numnote;
+};
+
+struct vm_area_struct {
+    abi_ulong   vma_start;  /* start vaddr of memory region */
+    abi_ulong   vma_end;    /* end vaddr of memory region */
+    abi_ulong   vma_flags;  /* protection etc. flags for the region */
+    TAILQ_ENTRY(vm_area_struct) vma_link;
+};
+
+struct mm_struct {
+    TAILQ_HEAD(, vm_area_struct) mm_mmap;
+    int mm_count;           /* number of mappings */
+};
+
+static struct mm_struct *vma_init(void);
+static void vma_delete(struct mm_struct *);
+static int vma_add_mapping(struct mm_struct *, abi_ulong,
+    abi_ulong, abi_ulong);
+static int vma_get_mapping_count(const struct mm_struct *);
+static struct vm_area_struct *vma_first(const struct mm_struct *);
+static struct vm_area_struct *vma_next(struct vm_area_struct *);
+static abi_ulong vma_dump_size(const struct vm_area_struct *);
+static int vma_walker(void *priv, unsigned long start, unsigned long end,
+    unsigned long flags);
+
+static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
+static void fill_note(struct memelfnote *, const char *, int,
+    unsigned int, void *);
+static void fill_prstatus(struct elf_prstatus *, const TaskState *, int);
+static int fill_psinfo(struct elf_prpsinfo *, const TaskState *);
+static void fill_auxv_note(struct memelfnote *, const TaskState *);
+static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
+static size_t note_size(const struct memelfnote *);
+static void free_note_info(struct elf_note_info *);
+static int fill_note_info(struct elf_note_info *, long, const CPUState *);
+static void fill_thread_info(struct elf_note_info *, const CPUState *);
+static int core_dump_filename(const TaskState *, char *, size_t);
+
+static int dump_write(int, const void *, size_t);
+static int write_note(struct memelfnote *, int);
+static int write_note_info(struct elf_note_info *, int);
+
+#ifdef BSWAP_NEEDED
+static void bswap_prstatus(struct elf_prstatus *);
+static void bswap_psinfo(struct elf_prpsinfo *);
+
+static void bswap_prstatus(struct elf_prstatus *prstatus)
+{
+    prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo);
+    prstatus->pr_info.si_code = tswapl(prstatus->pr_info.si_code);
+    prstatus->pr_info.si_errno = tswapl(prstatus->pr_info.si_errno);
+    prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
+    prstatus->pr_sigpend = tswapl(prstatus->pr_sigpend);
+    prstatus->pr_sighold = tswapl(prstatus->pr_sighold);
+    prstatus->pr_pid = tswapl(prstatus->pr_pid);
+    prstatus->pr_ppid = tswapl(prstatus->pr_ppid);
+    prstatus->pr_pgrp = tswapl(prstatus->pr_pgrp);
+    prstatus->pr_sid = tswapl(prstatus->pr_sid);
+    /* cpu times are not filled, so we skip them */
+    /* regs should be in correct format already */
+    prstatus->pr_fpvalid = tswapl(prstatus->pr_fpvalid);
+}
+
+static void bswap_psinfo(struct elf_prpsinfo *psinfo)
+{
+    psinfo->pr_flag = tswapl(psinfo->pr_flag);
+    psinfo->pr_uid = tswap16(psinfo->pr_uid);
+    psinfo->pr_gid = tswap16(psinfo->pr_gid);
+    psinfo->pr_pid = tswapl(psinfo->pr_pid);
+    psinfo->pr_ppid = tswapl(psinfo->pr_ppid);
+    psinfo->pr_pgrp = tswapl(psinfo->pr_pgrp);
+    psinfo->pr_sid = tswapl(psinfo->pr_sid);
+}
+#endif /* BSWAP_NEEDED */
+
+/*
+ * Minimal support for linux memory regions.  These are needed
+ * when we are finding out what memory exactly belongs to
+ * emulated process.  No locks needed here, as long as
+ * thread that received the signal is stopped.
+ */
+
+static struct mm_struct *vma_init(void)
+{
+    struct mm_struct *mm;
+
+    if ((mm = qemu_malloc(sizeof (*mm))) == NULL)
+        return (NULL);
+
+    mm->mm_count = 0;
+    TAILQ_INIT(&mm->mm_mmap);
+
+    return (mm);
+}
+
+static void vma_delete(struct mm_struct *mm)
+{
+    struct vm_area_struct *vma;
+
+    while ((vma = vma_first(mm)) != NULL) {
+        TAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
+        qemu_free(vma);
+    }
+    qemu_free(mm);
+}
+
+static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
+    abi_ulong end, abi_ulong flags)
+{
+    struct vm_area_struct *vma;
+
+    if ((vma = qemu_mallocz(sizeof (*vma))) == NULL)
+        return (-1);
+
+    vma->vma_start = start;
+    vma->vma_end = end;
+    vma->vma_flags = flags;
+
+    TAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
+    mm->mm_count++;
+
+    return (0);
+}
+
+static struct vm_area_struct *vma_first(const struct mm_struct *mm)
+{
+    return (TAILQ_FIRST(&mm->mm_mmap));
+}
+
+static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
+{
+    return (TAILQ_NEXT(vma, vma_link));
+}
+
+static int vma_get_mapping_count(const struct mm_struct *mm)
+{
+    return (mm->mm_count);
+}
+
+/*
+ * Calculate file (dump) size of given memory region.
+ */
+static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
+{
+    /* if we cannot even read the first page, skip it */
+    if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
+        return (0);
+
+    /*
+     * Usually we don't dump executable pages as they contain
+     * non-writable code that debugger can read directly from
+     * target library etc.  However, thread stacks are marked
+     * also executable so we read in first page of given region
+     * and check whether it contains elf header.  If there is
+     * no elf header, we dump it.
+     */
+    if (vma->vma_flags & PROT_EXEC) {
+        char page[TARGET_PAGE_SIZE];
+
+        copy_from_user(page, vma->vma_start, sizeof (page));
+        if ((page[EI_MAG0] == ELFMAG0) &&
+            (page[EI_MAG1] == ELFMAG1) &&
+            (page[EI_MAG2] == ELFMAG2) &&
+            (page[EI_MAG3] == ELFMAG3)) {
+            /*
+             * Mappings are possibly from ELF binary.  Don't dump
+             * them.
+             */
+            return (0);
+        }
+    }
+
+    return (vma->vma_end - vma->vma_start);
+}
+
+static int vma_walker(void *priv, unsigned long start, unsigned long end,
+    unsigned long flags)
+{
+    struct mm_struct *mm = (struct mm_struct *)priv;
+
+    /*
+     * Don't dump anything that qemu has reserved for internal use.
+     */
+    if (flags & PAGE_RESERVED)
+        return (0);
+
+    vma_add_mapping(mm, start, end, flags);
+    return (0);
+}
+
+static void fill_note(struct memelfnote *note, const char *name, int type,
+    unsigned int sz, void *data)
+{
+    unsigned int namesz;
+
+    namesz = strlen(name) + 1;
+    note->name = name;
+    note->namesz = namesz;
+    note->namesz_rounded = roundup(namesz, sizeof (int32_t));
+    note->type = type;
+    note->datasz = roundup(sz, sizeof (int32_t));;
+    note->data = data;
+
+    note->notesz = sizeof (struct elf_note) +
+        note->namesz_rounded + note->datasz;
+}
+
+static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
+    uint32_t flags)
+{
+    (void) memset(elf, 0, sizeof(*elf));
+
+    (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
+    elf->e_ident[EI_CLASS] = ELF_CLASS;
+    elf->e_ident[EI_DATA] = ELF_DATA;
+    elf->e_ident[EI_VERSION] = EV_CURRENT;
+    elf->e_ident[EI_OSABI] = ELF_OSABI;
+
+    elf->e_type = ET_CORE;
+    elf->e_machine = machine;
+    elf->e_version = EV_CURRENT;
+    elf->e_phoff = sizeof(struct elfhdr);
+    elf->e_flags = flags;
+    elf->e_ehsize = sizeof(struct elfhdr);
+    elf->e_phentsize = sizeof(struct elf_phdr);
+    elf->e_phnum = segs;
+
+#ifdef BSWAP_NEEDED
+    bswap_ehdr(elf);
+#endif
+}
+
+static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
+{
+    phdr->p_type = PT_NOTE;
+    phdr->p_offset = offset;
+    phdr->p_vaddr = 0;
+    phdr->p_paddr = 0;
+    phdr->p_filesz = sz;
+    phdr->p_memsz = 0;
+    phdr->p_flags = 0;
+    phdr->p_align = 0;
+
+#ifdef BSWAP_NEEDED
+    bswap_phdr(phdr);
+#endif
+}
+
+static size_t note_size(const struct memelfnote *note)
+{
+    return (note->notesz);
+}
+
+static void fill_prstatus(struct elf_prstatus *prstatus,
+    const TaskState *ts, int signr)
+{
+    (void) memset(prstatus, 0, sizeof (*prstatus));
+    prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
+    prstatus->pr_pid = ts->ts_tid;
+    prstatus->pr_ppid = getppid();
+    prstatus->pr_pgrp = getpgrp();
+    prstatus->pr_sid = getsid(0);
+
+#ifdef BSWAP_NEEDED
+    bswap_prstatus(prstatus);
+#endif
+}
+
+static int fill_psinfo(struct elf_prpsinfo *psinfo, const TaskState *ts)
+{
+    char *filename, *base_filename;
+    unsigned int i, len;
+
+    (void) memset(psinfo, 0, sizeof (*psinfo));
+
+    len = ts->info->arg_end - ts->info->arg_start;
+    if (len >= ELF_PRARGSZ)
+        len = ELF_PRARGSZ-1;
+    if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len))
+        return -EFAULT;
+    for(i = 0; i < len; i++)
+        if (psinfo->pr_psargs[i] == 0)
+            psinfo->pr_psargs[i] = ' ';
+    psinfo->pr_psargs[len] = 0;
+
+    psinfo->pr_pid = getpid();
+    psinfo->pr_ppid = getppid();
+    psinfo->pr_pgrp = getpgrp();
+    psinfo->pr_sid = getsid(0);
+    psinfo->pr_uid = getuid();
+    psinfo->pr_gid = getgid();
+
+    filename = strdup(ts->bprm->filename);
+    base_filename = strdup(basename(filename));
+    (void) strncpy(psinfo->pr_fname, base_filename,
+        sizeof(psinfo->pr_fname));
+
+    free(base_filename);
+    free(filename);
+
+#ifdef BSWAP_NEEDED
+    bswap_psinfo(psinfo);
+#endif
+    return (0);
+}
+
+static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
+{
+    elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
+    elf_addr_t orig_auxv = auxv;
+    abi_ulong val;
+    void *ptr;
+    int i, len;
+
+    /*
+     * Auxiliary vector is stored in target process stack.  It contains
+     * {type, value} pairs that we need to dump into note.  This is not
+     * strictly necessary but we do it here for sake of completeness.
+     */
+
+    /* find out lenght of the vector, AT_NULL is terminator */
+    i = len = 0;
+    do {
+        get_user_ual(val, auxv);
+        i += 2;
+        auxv += 2 * sizeof (elf_addr_t);
+    } while (val != AT_NULL);
+    len = i * sizeof (elf_addr_t);
+
+    /* read in whole auxv vector and copy it to memelfnote */
+    ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
+    if (ptr != NULL) {
+        fill_note(note, "CORE", NT_AUXV, len, ptr);
+        unlock_user(ptr, auxv, len);
+    }
+}
+
+/*
+ * Constructs name of coredump file.  We have following convention
+ * for the name:
+ *     qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
+ *
+ * Returns 0 in case of success, -1 otherwise (errno is set).
+ */
+static int core_dump_filename(const TaskState *ts, char *buf,
+    size_t bufsize)
+{
+    char timestamp[64];
+    char *filename = NULL;
+    char *base_filename = NULL;
+    struct timeval tv;
+    struct tm tm;
+
+    assert(bufsize >= PATH_MAX);
+
+    if (gettimeofday(&tv, NULL) < 0) {
+        (void) fprintf(stderr, "unable to get current timestamp: %s",
+            strerror(errno));
+        return (-1);
+    }
+
+    /* XXX: use qemu_malloc() */
+    filename = strdup(ts->bprm->filename);
+    base_filename = strdup(basename(filename));
+
+    (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
+        localtime_r(&tv.tv_sec, &tm));
+    (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
+        base_filename, timestamp, (int)getpid());
+
+    free(base_filename);
+    free(filename);
+
+    return (0);
+}
+
+static int dump_write(int fd, const void *ptr, size_t size)
+{
+    const char *bufp = (const char *)ptr;
+    ssize_t bytes_written, bytes_left;
+
+    bytes_written = 0;
+    bytes_left = size;
+
+    /*
+     * In normal conditions, single write(2) should do but
+     * in case of socket etc. this mechanism is more portable.
+     */
+    do {
+        bytes_written = write(fd, bufp, bytes_left);
+        if (bytes_written < 0) {
+            if (errno == EINTR)
+                continue;
+            return (-1);
+        } else if (bytes_written == 0) { /* eof */
+            return (-1);
+        }
+        bufp += bytes_written;
+        bytes_left -= bytes_written;
+    } while (bytes_left > 0);
+
+    return (0);
+}
+
+static int write_note(struct memelfnote *men, int fd)
+{
+    struct elf_note en;
+
+    en.n_namesz = men->namesz;
+    en.n_type = men->type;
+    en.n_descsz = men->datasz;
+
+#ifdef BSWAP_NEEDED
+    bswap_note(&en);
+#endif
+
+    if (dump_write(fd, &en, sizeof(en)) != 0)
+        return (-1);
+    if (dump_write(fd, men->name, men->namesz_rounded) != 0)
+        return (-1);
+    if (dump_write(fd, men->data, men->datasz) != 0)
+        return (-1);
+
+    return (0);
+}
+
+static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
+{
+    TaskState *ts = (TaskState *)env->opaque;
+    struct elf_thread_status *ets;
+
+    ets = qemu_mallocz(sizeof (*ets));
+    ets->num_notes = 1; /* only prstatus is dumped */
+    fill_prstatus(&ets->prstatus, ts, 0);
+    elf_core_copy_regs(&ets->prstatus.pr_reg, env);
+    fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
+        &ets->prstatus);
+
+    TAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
+
+    /* increase size of the note segment */
+    info->notes_size += note_size(&ets->notes[0]);
+}
+
+static int fill_note_info(struct elf_note_info *info,
+    long signr, const CPUState *env)
+{
+#define NUMNOTES 3
+    CPUState *cpu = NULL;
+    TaskState *ts = (TaskState *)env->opaque;
+    int i;
+
+    (void) memset(info, 0, sizeof (*info));
+
+    TAILQ_INIT(&info->thread_list);
+
+    info->notes = qemu_mallocz(NUMNOTES * sizeof (struct memelfnote));
+    if (info->notes == NULL)
+        return (-ENOMEM);
+    info->prstatus = qemu_mallocz(sizeof (*info->prstatus));
+    if (info->prstatus == NULL)
+        return (-ENOMEM);
+    info->psinfo = qemu_mallocz(sizeof (*info->psinfo));
+    if (info->prstatus == NULL)
+        return (-ENOMEM);
+
+    /*
+     * First fill in status (and registers) of current thread
+     * including process info & aux vector.
+     */
+    fill_prstatus(info->prstatus, ts, signr);
+    elf_core_copy_regs(&info->prstatus->pr_reg, env);
+    fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
+        sizeof (*info->prstatus), info->prstatus);
+    fill_psinfo(info->psinfo, ts);
+    fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
+        sizeof (*info->psinfo), info->psinfo);
+    fill_auxv_note(&info->notes[2], ts);
+    info->numnote = 3;
+
+    info->notes_size = 0;
+    for (i = 0; i < info->numnote; i++)
+        info->notes_size += note_size(&info->notes[i]);
+
+    /* read and fill status of all threads */
+    cpu_list_lock();
+    for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+        if (cpu == thread_env)
+            continue;
+        fill_thread_info(info, cpu);
+    }
+    cpu_list_unlock();
+
+    return (0);
+}
+
+static void free_note_info(struct elf_note_info *info)
+{
+    struct elf_thread_status *ets;
+
+    while (!TAILQ_EMPTY(&info->thread_list)) {
+        ets = TAILQ_FIRST(&info->thread_list);
+        TAILQ_REMOVE(&info->thread_list, ets, ets_link);
+        qemu_free(ets);
+    }
+
+    qemu_free(info->prstatus);
+    qemu_free(info->psinfo);
+    qemu_free(info->notes);
+}
+
+static int write_note_info(struct elf_note_info *info, int fd)
+{
+    struct elf_thread_status *ets;
+    int i, error = 0;
+
+    /* write prstatus, psinfo and auxv for current thread */
+    for (i = 0; i < info->numnote; i++)
+        if ((error = write_note(&info->notes[i], fd)) != 0)
+            return (error);
+
+    /* write prstatus for each thread */
+    for (ets = info->thread_list.tqh_first; ets != NULL;
+        ets = ets->ets_link.tqe_next) {
+        if ((error = write_note(&ets->notes[0], fd)) != 0)
+            return (error);
+    }
+
+    return (0);
+}
+
+/*
+ * Write out ELF coredump.
+ *
+ * See documentation of ELF object file format in:
+ * http://www.caldera.com/developers/devspecs/gabi41.pdf
+ *
+ * Coredump format in linux is following:
+ *
+ * 0   +----------------------+         \
+ *     | ELF header           | ET_CORE  |
+ *     +----------------------+          |
+ *     | ELF program headers  |          |--- headers
+ *     | - NOTE section       |          |
+ *     | - PT_LOAD sections   |          |
+ *     +----------------------+         /
+ *     | NOTEs:               |
+ *     | - NT_PRSTATUS        |
+ *     | - NT_PRSINFO         |
+ *     | - NT_AUXV            |
+ *     +----------------------+ <-- aligned to target page
+ *     | Process memory dump  |
+ *     :                      :
+ *     .                      .
+ *     :                      :
+ *     |                      |
+ *     +----------------------+
+ *
+ * NT_PRSTATUS -> struct elf_prstatus (per thread)
+ * NT_PRSINFO  -> struct elf_prpsinfo
+ * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
+ *
+ * Format follows System V format as close as possible.  Current
+ * version limitations are as follows:
+ *     - no floating point registers are dumped
+ *
+ * Function returns 0 in case of success, negative errno otherwise.
+ *
+ * TODO: make this work also during runtime: it should be
+ * possible to force coredump from running process and then
+ * continue processing.  For example qemu could set up SIGUSR2
+ * handler (provided that target process haven't registered
+ * handler for that) that does the dump when signal is received.
+ */
+static int elf_core_dump(int signr, const CPUState *env)
+{
+    const TaskState *ts = (const TaskState *)env->opaque;
+    struct vm_area_struct *vma = NULL;
+    char corefile[PATH_MAX];
+    struct elf_note_info info;
+    struct elfhdr elf;
+    struct elf_phdr phdr;
+    struct mm_struct *mm = NULL;
+    off_t offset = 0, data_offset = 0;
+    int segs = 0;
+    int fd = -1;
+
+    errno = 0;
+
+    if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
+        return (-errno);
+
+    if ((fd = open(corefile, O_WRONLY | O_CREAT,
+        S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
+        return (-errno);
+
+    /*
+     * Walk through target process memory mappings and
+     * set up structure containing this information.  After
+     * this point vma_xxx functions can be used.
+     */
+    if ((mm = vma_init()) == NULL)
+        goto out;
+
+    walk_memory_regions(mm, vma_walker);
+    segs = vma_get_mapping_count(mm);
+
+    /*
+     * Construct valid coredump ELF header.  We also
+     * add one more segment for notes.
+     */
+    fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
+    if (dump_write(fd, &elf, sizeof (elf)) != 0)
+        goto out;
+
+    /* fill in in-memory version of notes */
+    if (fill_note_info(&info, signr, env) < 0)
+        goto out;
+
+    offset += sizeof (elf);                             /* elf header */
+    offset += (segs + 1) * sizeof (struct elf_phdr);    /* program headers */
+
+    /* write out notes program header */
+    fill_elf_note_phdr(&phdr, info.notes_size, offset);
+
+    offset += info.notes_size;
+    if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
+        goto out;
+
+    /*
+     * ELF specification wants data to start at page boundary so
+     * we align it here.
+     */
+    offset = roundup(offset, ELF_EXEC_PAGESIZE);
+
+    /*
+     * Write program headers for memory regions mapped in
+     * the target process.
+     */
+    for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
+        (void) memset(&phdr, 0, sizeof (phdr));
+
+        phdr.p_type = PT_LOAD;
+        phdr.p_offset = offset;
+        phdr.p_vaddr = vma->vma_start;
+        phdr.p_paddr = 0;
+        phdr.p_filesz = vma_dump_size(vma);
+        offset += phdr.p_filesz;
+        phdr.p_memsz = vma->vma_end - vma->vma_start;
+        phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
+        if (vma->vma_flags & PROT_WRITE)
+            phdr.p_flags |= PF_W;
+        if (vma->vma_flags & PROT_EXEC)
+            phdr.p_flags |= PF_X;
+        phdr.p_align = ELF_EXEC_PAGESIZE;
+
+        dump_write(fd, &phdr, sizeof (phdr));
+    }
+
+    /*
+     * Next we write notes just after program headers.  No
+     * alignment needed here.
+     */
+    if (write_note_info(&info, fd) < 0)
+        goto out;
+
+    /* align data to page boundary */
+    data_offset = lseek(fd, 0, SEEK_CUR);
+    data_offset = TARGET_PAGE_ALIGN(data_offset);
+    if (lseek(fd, data_offset, SEEK_SET) != data_offset)
+        goto out;
+
+    /*
+     * Finally we can dump process memory into corefile as well.
+     */
+    for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
+        abi_ulong addr;
+        abi_ulong end;
+
+        end = vma->vma_start + vma_dump_size(vma);
+
+        for (addr = vma->vma_start; addr < end;
+            addr += TARGET_PAGE_SIZE) {
+            char page[TARGET_PAGE_SIZE];
+            int error;
+
+            /*
+             *  Read in page from target process memory and
+             *  write it to coredump file.
+             */
+            error = copy_from_user(page, addr, sizeof (page));
+            if (error != 0) {
+                (void) fprintf(stderr, "unable to dump " TARGET_FMT_lx "\n",
+                    addr);
+                errno = -error;
+                goto out;
+            }
+            if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
+                goto out;
+        }
+    }
+
+out:
+    free_note_info(&info);
+    if (mm != NULL)
+        vma_delete(mm);
+    (void) close(fd);
+
+    if (errno != 0)
+        return (-errno);
+    return (0);
+}
+
+#endif /* USE_ELF_CORE_DUMP */
+
 static int load_aout_interp(void * exptr, int interp_fd)
 {
     printf("a.out interpreter not yet supported\n");
index 266e2c4..90405ea 100644 (file)
@@ -3,21 +3,23 @@
 #define __USER_DS      (0x2B)
 
 struct target_pt_regs {
-       long ebx;
-       long ecx;
-       long edx;
-       long esi;
-       long edi;
-       long ebp;
-       long eax;
-       int  xds;
-       int  xes;
-       long orig_eax;
-       long eip;
-       int  xcs;
-       long eflags;
-       long esp;
-       int  xss;
+    abi_ulong ebx;
+    abi_ulong ecx;
+    abi_ulong edx;
+    abi_ulong esi;
+    abi_ulong edi;
+    abi_ulong ebp;
+    abi_ulong eax;
+    abi_ulong xds;
+    abi_ulong xes;
+    abi_ulong xfs;
+    abi_ulong xgs;
+    abi_ulong orig_eax;
+    abi_ulong eip;
+    abi_ulong xcs;
+    abi_ulong eflags;
+    abi_ulong esp;
+    abi_ulong xss;
 };
 
 /* ioctls */
index ada7c69..14c433e 100644 (file)
@@ -115,6 +115,7 @@ static int prepare_binprm(struct linux_binprm *bprm)
 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
                               abi_ulong stringp, int push_ptr)
 {
+    TaskState *ts = (TaskState *)thread_env->opaque;
     int n = sizeof(abi_ulong);
     abi_ulong envp;
     abi_ulong argv;
@@ -133,13 +134,14 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
     sp -= n;
     /* FIXME - handle put_user() failures */
     put_user_ual(argc, sp);
-
+    ts->info->arg_start = stringp;
     while (argc-- > 0) {
         /* FIXME - handle put_user() failures */
         put_user_ual(stringp, argv);
         argv += n;
         stringp += target_strlen(stringp) + 1;
     }
+    ts->info->arg_end = stringp;
     /* FIXME - handle put_user() failures */
     put_user_ual(0, argv);
     while (envc-- > 0) {
@@ -155,45 +157,45 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
 }
 
 int loader_exec(const char * filename, char ** argv, char ** envp,
-             struct target_pt_regs * regs, struct image_info *infop)
+             struct target_pt_regs * regs, struct image_info *infop,
+             struct linux_binprm *bprm)
 {
-    struct linux_binprm bprm;
     int retval;
     int i;
 
-    bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
+    bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
     for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
-            bprm.page[i] = 0;
+            bprm->page[i] = 0;
     retval = open(filename, O_RDONLY);
     if (retval < 0)
         return retval;
-    bprm.fd = retval;
-    bprm.filename = (char *)filename;
-    bprm.argc = count(argv);
-    bprm.argv = argv;
-    bprm.envc = count(envp);
-    bprm.envp = envp;
+    bprm->fd = retval;
+    bprm->filename = (char *)filename;
+    bprm->argc = count(argv);
+    bprm->argv = argv;
+    bprm->envc = count(envp);
+    bprm->envp = envp;
 
-    retval = prepare_binprm(&bprm);
+    retval = prepare_binprm(bprm);
 
     infop->host_argv = argv;
 
     if(retval>=0) {
-        if (bprm.buf[0] == 0x7f
-                && bprm.buf[1] == 'E'
-                && bprm.buf[2] == 'L'
-                && bprm.buf[3] == 'F') {
+        if (bprm->buf[0] == 0x7f
+                && bprm->buf[1] == 'E'
+                && bprm->buf[2] == 'L'
+                && bprm->buf[3] == 'F') {
 #ifndef TARGET_HAS_ELFLOAD32
-            retval = load_elf_binary(&bprm,regs,infop);
+            retval = load_elf_binary(bprm,regs,infop);
 #else
-            retval = load_elf_binary_multi(&bprm, regs, infop);
+            retval = load_elf_binary_multi(bprm, regs, infop);
 #endif
 #if defined(TARGET_HAS_BFLT)
-        } else if (bprm.buf[0] == 'b'
-                && bprm.buf[1] == 'F'
-                && bprm.buf[2] == 'L'
-                && bprm.buf[3] == 'T') {
-            retval = load_flt_binary(&bprm,regs,infop);
+        } else if (bprm->buf[0] == 'b'
+                && bprm->buf[1] == 'F'
+                && bprm->buf[2] == 'L'
+                && bprm->buf[3] == 'T') {
+            retval = load_flt_binary(bprm,regs,infop);
 #endif
         } else {
             fprintf(stderr, "Unknown binary format\n");
@@ -209,7 +211,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
 
     /* Something went wrong, return the inode and free the argument pages*/
     for (i=0 ; i<MAX_ARG_PAGES ; i++) {
-        free(bprm.page[i]);
+        free(bprm->page[i]);
     }
     return(retval);
 }
index feb3036..d637395 100644 (file)
@@ -25,6 +25,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <sys/syscall.h>
 
 #include "qemu.h"
 #include "qemu-common.h"
 
 #define DEBUG_LOGFILE "/tmp/qemu.log"
 
-char *exec_path;
+const char *exec_path;
+
+#if defined(CONFIG_USE_GUEST_BASE)
+unsigned long mmap_min_addr = 0;
+unsigned long guest_base = 0;
+#endif
 
 static const char *interp_prefix = CONFIG_QEMU_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
@@ -1024,7 +1030,7 @@ void cpu_loop (CPUSPARCState *env)
         default:
             printf ("Unhandled trap: 0x%x\n", trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
-            exit (1);
+            _exit (1);
         }
         process_pending_signals (env);
     }
@@ -1953,7 +1959,7 @@ void cpu_loop (CPUState *env)
         default:
             printf ("Unhandled trap: 0x%x\n", trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
-            exit (1);
+            _exit (1);
         }
         process_pending_signals (env);
     }
@@ -2213,6 +2219,10 @@ static void usage(void)
            "-drop-ld-preload  drop LD_PRELOAD for target process\n"
            "-E var=value      sets/modifies targets environment variable(s)\n"
            "-U var            unsets targets environment variable(s)\n"
+           "-0 argv0          forces target process argv[0] to be argv0\n"
+#if defined(CONFIG_USE_GUEST_BASE)
+           "-B address        set guest_base address to address\n"
+#endif
            "\n"
            "Debug options:\n"
            "-d options   activate log (logfile=%s)\n"
@@ -2222,12 +2232,22 @@ static void usage(void)
            "Environment variables:\n"
            "QEMU_STRACE       Print system calls and arguments similar to the\n"
            "                  'strace' program.  Enable by setting to any value.\n"
+           "\n"
            "You can use -E and -U options to set/unset environment variables\n"
            "for target process.  It is possible to provide several variables\n"
            "by repeating the option.  For example:\n"
            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
            "Note that if you provide several changes to single variable\n"
            "last change will stay in effect.\n"
+#if defined(CONFIG_USE_GUEST_BASE)
+           "\n"
+           "You can use -B option to load target binary into different\n"
+           "address that is specified in elf headers.  This can be useful\n"
+           "when target binary would be loaded to low addresses and\n"
+           "/proc/sys/vm/mmap_min_addr is set to higher.  For example\n"
+           "     qemu-" TARGET_ARCH " -B 0x100000 ...\n"
+           "loads target binary starting from the first meg.\n"
+#endif
            ,
            TARGET_ARCH,
            interp_prefix,
@@ -2238,6 +2258,29 @@ static void usage(void)
 
 THREAD CPUState *thread_env;
 
+void task_settid(TaskState *ts)
+{
+    if (ts->ts_tid == 0) {
+#ifdef USE_NPTL
+        ts->ts_tid = (pid_t)syscall(SYS_gettid);
+#else
+        /* when no threads are used, tid becomes pid */
+        ts->ts_tid = getpid();
+#endif
+    }
+}
+
+void stop_all_tasks(void)
+{
+    /*
+     * We trust that when using NPTL, start_exclusive()
+     * handles thread stopping correctly.  Note that there
+     * is no way out of this state as we don't provide
+     * any suspend routine.
+     */
+    start_exclusive();
+}
+
 /* Assumes contents are already zeroed.  */
 void init_task_state(TaskState *ts)
 {
@@ -2253,17 +2296,24 @@ void init_task_state(TaskState *ts)
  
 int main(int argc, char **argv, char **envp)
 {
-    const char *filename;
+    const char *filename = NULL;
     const char *cpu_model;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
+    struct linux_binprm bprm;
     TaskState ts1, *ts = &ts1;
     CPUState *env;
     int optind;
     const char *r;
     int gdbstub_port = 0;
     char **target_environ, **wrk;
+    char **target_argv;
+    int target_argc;
+    int drop_ld_preload = 0;
     envlist_t *envlist = NULL;
+    const char *argv0 = NULL;
+    int argskip = 0;
+    int i;
 
     if (argc <= 1)
         usage();
@@ -2309,7 +2359,7 @@ int main(int argc, char **argv, char **envp)
                 for(item = cpu_log_items; item->mask != 0; item++) {
                     printf("%-10s %s\n", item->name, item->help);
                 }
-                exit(1);
+                _exit(1);
             }
             cpu_set_log(mask);
         } else if (!strcmp(r, "E")) {
@@ -2320,6 +2370,11 @@ int main(int argc, char **argv, char **envp)
             r = argv[optind++];
             if (envlist_unsetenv(envlist, r) != 0)
                 usage();
+        } else if (!strcmp(r, "0")) {
+            r = argv[optind++];
+            argv0 = r;
+        } else if (!strcmp(r,"-sbox-call")) {
+            argskip++;
         } else if (!strcmp(r, "s")) {
             if (optind >= argc)
                 break;
@@ -2340,7 +2395,7 @@ int main(int argc, char **argv, char **envp)
             if (qemu_host_page_size == 0 ||
                 (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
                 fprintf(stderr, "page size must be a power of two\n");
-                exit(1);
+                _exit(1);
             }
         } else if (!strcmp(r, "g")) {
             if (optind >= argc)
@@ -2357,8 +2412,14 @@ int main(int argc, char **argv, char **envp)
 #endif
                 exit(1);
             }
+#if defined(CONFIG_USE_GUEST_BASE)
+        } else if (!strcmp(r, "B")) {
+           guest_base = strtol(argv[optind++], NULL, 0);
+#endif
         } else if (!strcmp(r, "drop-ld-preload")) {
-            (void) envlist_unsetenv(envlist, "LD_PRELOAD");
+            drop_ld_preload = 1;
+        } else if (!strcmp(r, "keep-ld-preload")) {
+            drop_ld_preload = 0;
         } else if (!strcmp(r, "strace")) {
             do_strace = 1;
         } else
@@ -2368,8 +2429,15 @@ int main(int argc, char **argv, char **envp)
     }
     if (optind >= argc)
         usage();
-    filename = argv[optind];
-    exec_path = argv[optind];
+    if (filename == NULL) {
+        filename = argv[optind];
+        exec_path = argv[optind];
+    } else {
+        argv0 = argv[optind];
+    }
+    if (drop_ld_preload) {
+        (void) envlist_unsetenv(envlist, "LD_PRELOAD");
+    }
 
     /* Zero out regs */
     memset(regs, 0, sizeof(struct target_pt_regs));
@@ -2377,6 +2445,8 @@ int main(int argc, char **argv, char **envp)
     /* Zero out image_info */
     memset(info, 0, sizeof(struct image_info));
 
+    memset(&bprm, 0, sizeof (bprm));
+
     /* Scan interp_prefix dir for replacement files. */
     init_paths(interp_prefix);
 
@@ -2388,7 +2458,7 @@ int main(int argc, char **argv, char **envp)
         cpu_model = "qemu32";
 #endif
 #elif defined(TARGET_ARM)
-        cpu_model = "arm926";
+        cpu_model = "any";
 #elif defined(TARGET_M68K)
         cpu_model = "any";
 #elif defined(TARGET_SPARC)
@@ -2430,11 +2500,78 @@ int main(int argc, char **argv, char **envp)
     target_environ = envlist_to_environ(envlist, NULL);
     envlist_free(envlist);
 
-    if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+#if defined(CONFIG_USE_GUEST_BASE)
+    /*
+     * Now that page sizes are configured in cpu_init() we can do
+     * proper page alignment for guest_base.
+     */
+    guest_base = HOST_PAGE_ALIGN(guest_base);
+
+    /*
+     * Read in mmap_min_addr kernel parameter and check
+     * whether it is set to some value > 0.  This value is used
+     * later on when doing mmap(2)s to calculate where guest_base
+     * is to set, if needed.
+     *
+     * When user has explicitly set the quest base, we skip this
+     * test.
+     */
+    if (guest_base == 0) {
+        FILE *fp;
+
+        if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
+            unsigned long tmp;
+            if (fscanf(fp, "%lu", &tmp) == 1) {
+                mmap_min_addr = tmp;
+                qemu_log("kernel mmap_min_addr=%lu\n", mmap_min_addr);
+            }
+            fclose(fp);
+        }
+    }
+#endif /* CONFIG_USE_GUEST_BASE */
+
+    /*
+     * Prepare copy of argv vector for target.
+     */
+    target_argc = argc - optind;
+    target_argv = calloc(target_argc + 1, sizeof (char *));
+    if (target_argv == NULL) {
+       (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
+       exit(1);
+    }
+
+    /*
+     * If argv0 is specified (using '-0' switch) we replace
+     * argv[0] pointer with the given one.
+     */
+    i = 0;
+    if (argv0 != NULL) {
+        target_argv[i++] = strdup(argv0);
+    }
+    for (; i < target_argc; i++) {
+        target_argv[i] = strdup(argv[optind + i]);
+    }
+    target_argv[target_argc] = NULL;
+
+    memset(ts, 0, sizeof(TaskState));
+    init_task_state(ts);
+    /* build Task State */
+    env->opaque = ts;
+    ts->bprm = &bprm;
+    ts->info = info;
+    task_settid(ts);
+
+    if (loader_exec(filename, target_argv+argskip, target_environ, regs,
+        info, &bprm) != 0) {
         printf("Error loading %s\n", filename);
         _exit(1);
     }
 
+    for (i = 0; i < target_argc; i++) {
+        free(target_argv[i]);
+    }
+    free(target_argv);
+
     for (wrk = target_environ; *wrk; wrk++) {
         free(*wrk);
     }
@@ -2442,6 +2579,18 @@ int main(int argc, char **argv, char **envp)
     free(target_environ);
 
     if (qemu_log_enabled()) {
+#if defined(CONFIG_USE_GUEST_BASE)
+        if (guest_base > 0) {
+            qemu_log("guest_base is set to 0x%lx\n", guest_base);
+            qemu_log(
+                "==========================================================\n"
+                "Note that all target addresses below are given in target\n"
+                "address space which is different from host by guest_base.\n"
+                "For example: target address 0x%x becomes 0x%x and so on.\n"
+                "==========================================================\n",
+                (uintptr_t)0x8000, (uintptr_t)g2h(0x8000));
+        }
+#endif
         log_page_dump();
 
         qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
@@ -2461,12 +2610,6 @@ int main(int argc, char **argv, char **envp)
     syscall_init();
     signal_init();
 
-    /* build Task State */
-    memset(ts, 0, sizeof(TaskState));
-    init_task_state(ts);
-    ts->info = info;
-    env->opaque = ts;
-
 #if defined(TARGET_I386)
     cpu_x86_set_cpl(env, 3);
 
index 6f300a0..8cec230 100644 (file)
@@ -275,52 +275,59 @@ static abi_ulong mmap_next_start = 0x40000000;
 
 unsigned long last_brk;
 
-/* find a free memory area of size 'size'. The search starts at
-   'start'. If 'start' == 0, then a default start address is used.
-   Return -1 if error.
-*/
-/* page_init() marks pages used by the host as reserved to be sure not
-   to use them. */
-static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+/*
+ * Find and reserve a free memory area of size 'size'. The search
+ * starts at 'start'.
+ * It must be called with mmap_lock() held.
+ * Return -1 if error.
+ */
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
 {
-    abi_ulong addr, addr1, addr_start;
-    int prot;
-    unsigned long new_brk;
-
-    new_brk = (unsigned long)sbrk(0);
-    if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
-        /* This is a hack to catch the host allocating memory with brk().
-           If it uses mmap then we loose.
-           FIXME: We really want to avoid the host allocating memory in
-           the first place, and maybe leave some slack to avoid switching
-           to mmap.  */
-        page_set_flags(last_brk & TARGET_PAGE_MASK,
-                       TARGET_PAGE_ALIGN(new_brk),
-                       PAGE_RESERVED); 
-    }
-    last_brk = new_brk;
+    void *ptr;
+    abi_ulong addr;
 
     size = HOST_PAGE_ALIGN(size);
-    start = start & qemu_host_page_mask;
+    start &= qemu_host_page_mask;
+
+    /* If 'start' == 0, then a default start address is used. */
+    if (start == 0)
+        start = mmap_next_start;
+
     addr = start;
-    if (addr == 0)
-        addr = mmap_next_start;
-    addr_start = addr;
+
     for(;;) {
-        prot = 0;
-        for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
-            prot |= page_get_flags(addr1);
-        }
-        if (prot == 0)
+        /*
+         * Reserve needed memory area to avoid a race.
+         * It should be discarded using:
+         *  - mmap() with MAP_FIXED flag
+         *  - mremap() with MREMAP_FIXED flag
+         *  - shmat() with SHM_REMAP flag
+         */
+        ptr = mmap((void *)(unsigned long)addr, size, PROT_NONE,
+                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+
+        /* ENOMEM, if host address space has no memory */
+        if (ptr == MAP_FAILED)
+            return (abi_ulong)-1;
+
+        /* If address fits target address space we've found what we need */
+        if ((unsigned long)ptr + size - 1 <= (abi_ulong)-1)
             break;
+
+        /* Unmap and try again with new page */
+        munmap(ptr, size);
         addr += qemu_host_page_size;
-        /* we found nothing */
-        if (addr == addr_start)
+
+        /* ENOMEM if we check whole of target address space */
+        if (addr == start)
             return (abi_ulong)-1;
     }
-    if (start == 0)
-        mmap_next_start = addr + size;
-    return addr;
+
+    /* Update default start address */
+    if (start == mmap_next_start)
+        mmap_next_start = (unsigned long)ptr + size;
+
+    return h2g(ptr);
 }
 
 /* NOTE: all the constants are the HOST ones */
index 06b1f5f..b991af0 100644 (file)
@@ -4,6 +4,7 @@
    The assumption is that this area does not change.
 */
 #include <sys/types.h>
+#include <assert.h>
 #include <dirent.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -52,6 +53,38 @@ static struct pathelem *new_entry(const char *root,
 
 #define streq(a,b) (strcmp((a), (b)) == 0)
 
+/*
+ * Checks whether directory entry (dent) is valid.  This
+ * means that symlinks pointing to '.' and '..' should
+ * be skipped by main recursion code.  Returns 1 when
+ * entry is valid.
+ */
+static int
+is_dentry_valid(const char *path, const struct dirent *dent)
+{
+    char fullpath[PATH_MAX];
+    char linkbuf[PATH_MAX];
+    ssize_t len;
+
+    assert(path != NULL);
+    assert(dent != NULL);
+
+    if (dent->d_type != DT_LNK)
+        return (1);
+
+    (void) snprintf(fullpath, sizeof (fullpath), "%s/%s",
+       path, dent->d_name);
+
+    if ((len = readlink(fullpath, linkbuf, sizeof (linkbuf) - 1)) != -1) {
+        linkbuf[len] = '\0';
+        if (streq(linkbuf, ".") || streq(linkbuf, ".."))
+            return (0);
+    }
+
+    return (1);
+}
+
+/* TODO: add recursion count check */
 static struct pathelem *add_dir_maybe(struct pathelem *path)
 {
     DIR *dir;
@@ -61,7 +94,9 @@ static struct pathelem *add_dir_maybe(struct pathelem *path)
 
        while ((dirent = readdir(dir)) != NULL) {
            if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
-               path = add_entry(path, dirent->d_name);
+               if (is_dentry_valid(path->pathname, dirent)) {
+                   path = add_entry(path, dirent->d_name);
+               }
            }
        }
         closedir(dir);
index 94ae333..bef99ea 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef QEMU_H
 #define QEMU_H
 
+#include <sys/queue.h>
+
 #include <signal.h>
 #include <string.h>
 
@@ -44,6 +46,9 @@ struct image_info {
         abi_ulong       entry;
         abi_ulong       code_offset;
         abi_ulong       data_offset;
+        abi_ulong       saved_auxv;
+        abi_ulong       arg_start;
+        abi_ulong       arg_end;
         char            **host_argv;
        int             personality;
 };
@@ -84,10 +89,12 @@ struct emulated_sigtable {
                              first signal, we put it here */
 };
 
+struct process;
+
 /* NOTE: we force a big alignment so that the stack stored after is
    aligned too */
 typedef struct TaskState {
-    struct TaskState *next;
+    pid_t ts_tid;     /* tid (or pid) of this task */
 #ifdef TARGET_ARM
     /* FPA state */
     FPA11 fpa;
@@ -114,18 +121,24 @@ typedef struct TaskState {
 #endif
     int used; /* non zero if used */
     struct image_info *info;
+    struct linux_binprm *bprm;
 
     struct emulated_sigtable sigtab[TARGET_NSIG];
     struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
     struct sigqueue *first_free; /* first free siginfo queue entry */
     int signal_pending; /* non zero if a signal may be pending */
 
-    uint8_t stack[0];
+    uint8_t stack[];
 } __attribute__((aligned(16))) TaskState;
 
-extern char *exec_path;
+extern const char *exec_path;
 void init_task_state(TaskState *ts);
+extern void task_settid(TaskState *);
+extern void stop_all_tasks(void);
 extern const char *qemu_uname_release;
+#if defined(CONFIG_USE_GUEST_BASE)
+extern unsigned long mmap_min_addr;
+#endif
 
 /* ??? See if we can avoid exposing so much of the loader internals.  */
 /*
@@ -149,13 +162,15 @@ struct linux_binprm {
         char **argv;
         char **envp;
         char * filename;        /* Name of binary */
+        int (*core_dump)(int, const CPUState *); /* coredump routine */
 };
 
 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
                               abi_ulong stringp, int push_ptr);
 int loader_exec(const char * filename, char ** argv, char ** envp,
-             struct target_pt_regs * regs, struct image_info *infop);
+             struct target_pt_regs * regs, struct image_info *infop,
+             struct linux_binprm *);
 
 int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
                     struct image_info * info);
index fc37dc1..64918a6 100644 (file)
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
+#include <assert.h>
 #include <sys/ucontext.h>
 
 #include "qemu.h"
@@ -286,6 +287,23 @@ static int fatal_signal (int sig)
     }
 }
 
+/* returns 1 if given signal should dump core if not handled */
+static int core_dump_signal(int sig)
+{
+    switch (sig) {
+    case TARGET_SIGABRT:
+    case TARGET_SIGFPE:
+    case TARGET_SIGILL:
+    case TARGET_SIGQUIT:
+    case TARGET_SIGSEGV:
+    case TARGET_SIGTRAP:
+    case TARGET_SIGBUS:
+        return (1);
+    default:
+        return (0);
+    }
+}
+
 void signal_init(void)
 {
     struct sigaction act;
@@ -351,23 +369,45 @@ static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
 /* abort execution with signal */
 static void QEMU_NORETURN force_sig(int sig)
 {
-    int host_sig;
+    TaskState *ts = (TaskState *)thread_env->opaque;
+    int host_sig, core_dumped = 0;
+    struct sigaction act;
     host_sig = target_to_host_signal(sig);
-    fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
-            sig, strsignal(host_sig));
-#if 1
     gdb_signalled(thread_env, sig);
-    _exit(-host_sig);
-#else
-    {
-        struct sigaction act;
-        sigemptyset(&act.sa_mask);
-        act.sa_flags = SA_SIGINFO;
-        act.sa_sigaction = SIG_DFL;
-        sigaction(SIGABRT, &act, NULL);
-        abort();
+
+    /* dump core if supported by target binary format */
+    if (core_dump_signal(sig) && (ts->bprm->core_dump != NULL)) {
+        stop_all_tasks();
+        core_dumped =
+            ((*ts->bprm->core_dump)(sig, thread_env) == 0);
     }
-#endif
+
+    (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
+        sig, strsignal(host_sig),
+        ((core_dumped) ? "core dumped" : "exiting"));
+
+    /* The proper exit code for dieing from an uncaught signal is
+     * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
+     * a negative value.  To get the proper exit code we need to
+     * actually die from an uncaught signal.  Here the default signal
+     * handler is installed, we send ourself a signal and we wait for
+     * it to arrive. */
+    sigfillset(&act.sa_mask);
+    act.sa_handler = SIG_DFL;
+    sigaction(host_sig, &act, NULL);
+
+    /* For some reason raise(host_sig) doesn't send the signal when
+     * statically linked on x86-64. */
+    kill(getpid(), host_sig);
+
+    /* Make sure the signal isn't masked (just reuse the mask inside
+    of act) */
+    sigdelset(&act.sa_mask, host_sig);
+    sigsuspend(&act.sa_mask);
+
+    /* unreachable */
+    assert(0);
+
 }
 
 /* queue a signal so that it will be send to the virtual CPU as soon
index b4caffe..2ec1030 100644 (file)
@@ -255,6 +255,172 @@ print_syscall_ret_newselect(const struct syscallname *name, abi_long ret)
 }
 #endif
 
+#define LOCKED_ARG0    (1 << 0)
+#define LOCKED_ARG1    (1 << 1)
+#define LOCKED_ARG2    (1 << 2)
+#define LOCKED_ARG3    (1 << 3)
+#define LOCKED_ARG4    (1 << 4)
+#define LOCKED_ARG5    (1 << 5)
+
+struct args {
+    abi_long   arg_guest;      /* guest argument */
+    uintptr_t  arg_host;       /* host argument */
+    int                arg_locked;     /* is this argument locked? */
+};
+
+/*
+ * This function locks strings from guest memory and prints
+ * strace output according to format specified in strace.list.
+ *
+ * First parameter specifies, which guest arguments should be
+ * locked (LOCKED_ARG0 - LOCKED_ARG5).
+ */
+static void
+print_locked(unsigned int locked, const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    struct args args[6] = {
+        { arg0, 0, (locked & LOCKED_ARG0) },
+        { arg1, 0, (locked & LOCKED_ARG1) },
+        { arg2, 0, (locked & LOCKED_ARG2) },
+        { arg3, 0, (locked & LOCKED_ARG3) },
+        { arg4, 0, (locked & LOCKED_ARG4) },
+        { arg5, 0, (locked & LOCKED_ARG5) },
+    };
+    struct args *a;
+    int i;
+
+    for (i = 0; i < 6; i++) {
+        a = &args[i];
+        if (a->arg_locked) {
+            a->arg_host = (uintptr_t)lock_user_string(a->arg_guest);
+            if (a->arg_host == 0)
+                goto out;
+        } else {
+            a->arg_host = (uintptr_t)a->arg_guest;
+        }
+    }
+
+    /*
+     * Now we can have all strings locked and converted into host
+     * addresses.
+     */
+    gemu_log(name->format,
+        name->name,
+        args[0].arg_host,
+        args[1].arg_host,
+        args[2].arg_host,
+        args[3].arg_host,
+        args[4].arg_host,
+        args[5].arg_host);
+
+out:
+    for (i = 0; i < 6; i++) {
+        a = &args[i];
+        if (a->arg_locked)
+            unlock_user((void *)a->arg_host, a->arg_guest, 0);
+    }
+}
+
+static void
+print_1st_locked(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_locked(LOCKED_ARG0, name, arg0, arg1, arg2, arg3, arg4, arg5);
+}
+
+static void
+print_2nd_locked(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_locked(LOCKED_ARG1, name, arg0, arg1, arg2, arg3, arg4, arg5);
+}
+
+static void
+print_1st_and_2nd_locked(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_locked(LOCKED_ARG0 | LOCKED_ARG1, name, arg0, arg1, arg2,
+        arg3, arg4, arg5);
+}
+
+static void
+print_1st_and_3rd_locked(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_locked(LOCKED_ARG0 | LOCKED_ARG2, name, arg0, arg1, arg2,
+        arg3, arg4, arg5);
+}
+
+static void
+print_1st_2nd_and_3rd_locked(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_locked(LOCKED_ARG0 | LOCKED_ARG1 | LOCKED_ARG2, name,
+        arg0, arg1, arg2, arg3, arg4, arg5);
+}
+
+static void
+print_2nd_and_4th_locked(const struct syscallname *name,
+    abi_long arg0, abi_long arg1, abi_long arg2,
+    abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    print_locked(LOCKED_ARG1 | LOCKED_ARG3, name, arg0, arg1, arg2,
+        arg3, arg4, arg5);
+}
+
+/*
+ * Here is list of syscalls that we support reading in (locking)
+ * strings from guest addresses.  Every syscall that has "%s" in its
+ * parameter list and doesn't have specific print function, should
+ * be defined here.
+ */
+#define print_access   print_1st_locked
+#define print_chdir    print_1st_locked
+#define print_chmod    print_1st_locked
+#define print_creat    print_1st_locked
+#define print_execv    print_1st_locked
+#define print_faccessat print_2nd_locked
+#define print_fchmodat print_2nd_locked
+#define print_fchown   print_1st_locked
+#define print_fchownat print_2nd_locked
+#define print_futimesat        print_2nd_locked
+#define print_link     print_1st_and_2nd_locked
+#define print_linkat   print_2nd_and_4th_locked
+#define print_lstat    print_1st_locked
+#define print_lstat64  print_1st_locked
+#define print_mkdir    print_1st_locked
+#define print_mkdirat  print_2nd_locked
+#define print_mknod    print_1st_locked
+#define print_mknodat  print_2nd_locked
+#define print_mq_open  print_1st_locked
+#define print_mq_unlink        print_1st_locked
+#define print_fstatat64        print_2nd_locked
+#define print_newfstatat print_2nd_locked
+#define print_open     print_1st_locked
+#define print_openat   print_2nd_locked
+#define print_readlink print_1st_locked
+#define print_readlinkat print_2nd_locked
+#define print_rename   print_1st_and_2nd_locked
+#define print_renameat print_2nd_and_4th_locked
+#define print_stat     print_1st_locked
+#define print_stat64   print_1st_locked
+#define print_statfs   print_1st_locked
+#define print_statfs64 print_1st_locked
+#define print_symlink  print_1st_and_2nd_locked
+#define print_symlinkat        print_1st_and_3rd_locked
+#define print_umount   print_1st_2nd_and_3rd_locked
+#define print_unlink   print_1st_locked
+#define print_unlinkat print_2nd_locked
+#define print_utime    print_1st_locked
+#define print_utimensat        print_2nd_locked
+
 /*
  * An array of all of the syscalls we know about
  */
@@ -285,6 +451,10 @@ print_syscall(int num,
             } else {
                 /* XXX: this format system is broken because it uses
                    host types and host pointers for strings */
+                /*
+                 * It now works when it has print_xxx_locked function
+                 * as its printing function.
+                 */
                 if( scnames[i].format != NULL )
                     format = scnames[i].format;
                 gemu_log(format,scnames[i].name, arg1,arg2,arg3,arg4,arg5,arg6);
index 09a801f..5f59115 100644 (file)
@@ -1,8 +1,13 @@
+/*
+ * Note that if you change format strings in these, check also
+ * that corresponding print functions are able to handle string
+ * locking correctly (see strace.c).
+ */
 #ifdef TARGET_NR_accept
 { TARGET_NR_accept, "accept" , "%s(%d,%#x,%#x)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_access
-{ TARGET_NR_access, "access" , "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_access, "access" , "%s(\"%s\",%#o)", print_access, NULL },
 #endif
 #ifdef TARGET_NR_acct
 { TARGET_NR_acct, "acct" , NULL, NULL, NULL },
 { TARGET_NR_capset, "capset" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_chdir
-{ TARGET_NR_chdir, "chdir" , "%s(\"%s\")", NULL, NULL },
+{ TARGET_NR_chdir, "chdir" , "%s(\"%s\")", print_chdir, NULL },
 #endif
 #ifdef TARGET_NR_chmod
-{ TARGET_NR_chmod, "chmod" , "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_chmod, "chmod" , "%s(\"%s\",%#o)", print_chmod, NULL },
 #endif
 #ifdef TARGET_NR_chown
 { TARGET_NR_chown, "chown" , NULL, NULL, NULL },
@@ -89,7 +94,7 @@
 { TARGET_NR_connect, "connect" , "%s(%d,%#x,%d)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_creat
-{ TARGET_NR_creat, "creat" , "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_creat, "creat" , "%s(\"%s\",%#o)", print_creat, NULL },
 #endif
 #ifdef TARGET_NR_create_module
 { TARGET_NR_create_module, "create_module" , NULL, NULL, NULL },
 { TARGET_NR_epoll_wait_old, "epoll_wait_old" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_execv
-{ TARGET_NR_execv, "execv" , "%s(\"%s\",%ld,%ld,%ld,%ld,%ld)\n", NULL, NULL },
+{ TARGET_NR_execv, "execv" , "%s(\"%s\",%ld,%ld,%ld,%ld,%ld)\n",
+    print_execv, NULL },
 #endif
 #ifdef TARGET_NR_execve
 { TARGET_NR_execve, "execve" , NULL, print_execve, NULL },
 { TARGET_NR_exit_group, "exit_group" , "%s(%d)\n", NULL, NULL },
 #endif
 #ifdef TARGET_NR_faccessat
-{ TARGET_NR_faccessat, "faccessat" , "%s(%d,\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_NR_faccessat, "faccessat" , "%s(%d,\"%s\",%#o,%#x)",
+    print_faccessat, NULL },
 #endif
 #ifdef TARGET_NR_fadvise64
 { TARGET_NR_fadvise64, "fadvise64" , NULL, NULL, NULL },
 { TARGET_NR_fchmod, "fchmod" , "%s(%d,%#o)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_fchmodat
-{ TARGET_NR_fchmodat, "fchmodat" , "%s(%d,\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_NR_fchmodat, "fchmodat" , "%s(%d,\"%s\",%#o,%#x)",
+    print_fchmodat, NULL },
 #endif
 #ifdef TARGET_NR_fchown
-{ TARGET_NR_fchown, "fchown" , "%s(\"%s\",%d,%d)", NULL, NULL },
+{ TARGET_NR_fchown, "fchown" , "%s(\"%s\",%d,%d)", print_fchown, NULL },
 #endif
 #ifdef TARGET_NR_fchown32
 { TARGET_NR_fchown32, "fchown32" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_fchownat
-{ TARGET_NR_fchownat, "fchownat" , "%s(%d,\"%s\",%d,%d,%#x)", NULL, NULL },
+{ TARGET_NR_fchownat, "fchownat" , "%s(%d,\"%s\",%d,%d,%#x)",
+    print_fchownat, NULL },
 #endif
 #ifdef TARGET_NR_fcntl
 { TARGET_NR_fcntl, "fcntl" , NULL, NULL, NULL },
 { TARGET_NR_futex, "futex" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_futimesat
-{ TARGET_NR_futimesat, "futimesat" , "%s(%d,\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_futimesat, "futimesat" , "%s(%d,\"%s\",%p)",
+    print_futimesat, NULL },
 #endif
 #ifdef TARGET_NR_getcwd
 { TARGET_NR_getcwd, "getcwd" , "%s(%p,%d)", NULL, NULL },
 { TARGET_NR_lgetxattr, "lgetxattr" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_link
-{ TARGET_NR_link, "link" , "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_NR_link, "link" , "%s(\"%s\",\"%s\")", print_link, NULL },
 #endif
 #ifdef TARGET_NR_linkat
-{ TARGET_NR_linkat, "linkat" , "%s(%d,\"%s\",%d,\"%s\",%#x)", NULL, NULL },
+{ TARGET_NR_linkat, "linkat" , "%s(%d,\"%s\",%d,\"%s\",%#x)",
+    print_linkat, NULL },
 #endif
 #ifdef TARGET_NR_Linux
 { TARGET_NR_Linux, "Linux" , NULL, NULL, NULL },
 { TARGET_NR_lsetxattr, "lsetxattr" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_lstat
-{ TARGET_NR_lstat, "lstat" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_lstat, "lstat" , "%s(\"%s\",%p)", print_lstat, NULL },
 #endif
 #ifdef TARGET_NR_lstat64
-{ TARGET_NR_lstat64, "lstat64" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_lstat64, "lstat64" , "%s(\"%s\",%p)", print_lstat64, NULL },
 #endif
 #ifdef TARGET_NR_madvise
 { TARGET_NR_madvise, "madvise" , NULL, NULL, NULL },
 { TARGET_NR_mincore, "mincore" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_mkdir
-{ TARGET_NR_mkdir, "mkdir" , "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_mkdir, "mkdir" , "%s(\"%s\",%#o)", print_mkdir, NULL },
 #endif
 #ifdef TARGET_NR_mkdirat
-{ TARGET_NR_mkdirat, "mkdirat" , "%s(%d,\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_mkdirat, "mkdirat" , "%s(%d,\"%s\",%#o)", print_mkdirat, NULL },
 #endif
 #ifdef TARGET_NR_mknod
-{ TARGET_NR_mknod, "mknod" , "%s(\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_NR_mknod, "mknod" , "%s(\"%s\",%#o,%#x)", print_mknod, NULL },
 #endif
 #ifdef TARGET_NR_mknodat
-{ TARGET_NR_mknodat, "mknodat" , "%s(%d,\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_NR_mknodat, "mknodat" , "%s(%d,\"%s\",%#o,%#x)",
+    print_mknodat, NULL },
 #endif
 #ifdef TARGET_NR_mlock
 { TARGET_NR_mlock, "mlock" , NULL, NULL, NULL },
 { TARGET_NR_mpx, "mpx" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_getsetattr
-{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , NULL, NULL, NULL },
+{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , "%s(%d,%p,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_notify
-{ TARGET_NR_mq_notify, "mq_notify" , NULL, NULL, NULL },
+{ TARGET_NR_mq_notify, "mq_notify" , "%s(%d,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_open
-{ TARGET_NR_mq_open, "mq_open" , NULL, NULL, NULL },
+{ TARGET_NR_mq_open, "mq_open" , "%s(\"/%s\",%#x,%#o,%p)",
+    print_mq_open, NULL },
 #endif
 #ifdef TARGET_NR_mq_timedreceive
-{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , NULL, NULL, NULL },
+{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_timedsend
-{ TARGET_NR_mq_timedsend, "mq_timedsend" , NULL, NULL, NULL },
+{ TARGET_NR_mq_timedsend, "mq_timedsend" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_unlink
-{ TARGET_NR_mq_unlink, "mq_unlink" , NULL, NULL, NULL },
+{ TARGET_NR_mq_unlink, "mq_unlink" , "%s(%s)", print_mq_unlink, NULL },
 #endif
 #ifdef TARGET_NR_mremap
 { TARGET_NR_mremap, "mremap" , NULL, NULL, NULL },
 { TARGET_NR_nanosleep, "nanosleep" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_fstatat64
-{ TARGET_NR_fstatat64, "fstatat64" , "%s(%d,\"%s\",%p,%#x)", NULL, NULL },
+{ TARGET_NR_fstatat64, "fstatat64" , "%s(%d,\"%s\",%p,%#x)",
+    print_fstatat64, NULL },
 #endif
 #ifdef TARGET_NR_newfstatat
-{ TARGET_NR_newfstatat, "newfstatat" , "%s(%d,\"%s\",%p,%#x)", NULL, NULL },
+{ TARGET_NR_newfstatat, "newfstatat" , "%s(%d,\"%s\",%p,%#x)",
+    print_newfstatat, NULL },
 #endif
 #ifdef TARGET_NR__newselect
 { TARGET_NR__newselect, "_newselect" , NULL, print_newselect, print_syscall_ret_newselect },
 { TARGET_NR_olduname, "olduname" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_open
-{ TARGET_NR_open, "open" , "%s(\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_NR_open, "open" , "%s(\"%s\",%#x,%#o)", print_open, NULL },
 #endif
 #ifdef TARGET_NR_openat
-{ TARGET_NR_openat, "openat" , "%s(%d,\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_NR_openat, "openat" , "%s(%d,\"%s\",%#x,%#o)",
+    print_openat, NULL },
 #endif
 #ifdef TARGET_NR_osf_adjtime
 { TARGET_NR_osf_adjtime, "osf_adjtime" , NULL, NULL, NULL },
 { TARGET_NR_readdir, "readdir" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_readlink
-{ TARGET_NR_readlink, "readlink" , "%s(\"%s\",%p,%d)", NULL, NULL },
+{ TARGET_NR_readlink, "readlink" , "%s(\"%s\",%p,%d)",
+    print_readlink, NULL },
 #endif
 #ifdef TARGET_NR_readlinkat
-{ TARGET_NR_readlinkat, "readlinkat" , "%s(%d,\"%s\",%p,%d)", NULL, NULL },
+{ TARGET_NR_readlinkat, "readlinkat" , "%s(%d,\"%s\",%p,%d)",
+    print_readlinkat, NULL },
 #endif
 #ifdef TARGET_NR_readv
 { TARGET_NR_readv, "readv" , NULL, NULL, NULL },
 { TARGET_NR_removexattr, "removexattr" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_rename
-{ TARGET_NR_rename, "rename" , "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_NR_rename, "rename" , "%s(\"%s\",\"%s\")", print_rename, NULL },
 #endif
 #ifdef TARGET_NR_renameat
-{ TARGET_NR_renameat, "renameat" , "%s(%d,\"%s\",%d,\"%s\")", NULL, NULL },
+{ TARGET_NR_renameat, "renameat" , "%s(%d,\"%s\",%d,\"%s\")",
+    print_renameat, NULL },
 #endif
 #ifdef TARGET_NR_request_key
 { TARGET_NR_request_key, "request_key" , NULL, NULL, NULL },
 { TARGET_NR_ssetmask, "ssetmask" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_stat
-{ TARGET_NR_stat, "stat" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_stat, "stat" , "%s(\"%s\",%p)", print_stat, NULL },
 #endif
 #ifdef TARGET_NR_stat64
-{ TARGET_NR_stat64, "stat64" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_stat64, "stat64" , "%s(\"%s\",%p)", print_stat64, NULL },
 #endif
 #ifdef TARGET_NR_statfs
-{ TARGET_NR_statfs, "statfs" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_statfs, "statfs" , "%s(\"%s\",%p)", print_statfs, NULL },
 #endif
 #ifdef TARGET_NR_statfs64
-{ TARGET_NR_statfs64, "statfs64" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_statfs64, "statfs64" , "%s(\"%s\",%p)", print_statfs64, NULL },
 #endif
 #ifdef TARGET_NR_stime
 { TARGET_NR_stime, "stime" , NULL, NULL, NULL },
 { TARGET_NR_swapon, "swapon" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_symlink
-{ TARGET_NR_symlink, "symlink" , "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_NR_symlink, "symlink" , "%s(\"%s\",\"%s\")",
+    print_symlink, NULL },
 #endif
 #ifdef TARGET_NR_symlinkat
-{ TARGET_NR_symlinkat, "symlinkat" , "%s(\"%s\",%d,\"%s\")", NULL, NULL },
+{ TARGET_NR_symlinkat, "symlinkat" , "%s(\"%s\",%d,\"%s\")",
+    print_symlinkat, NULL },
 #endif
 #ifdef TARGET_NR_sync
 { TARGET_NR_sync, "sync" , NULL, NULL, NULL },
 { TARGET_NR_umask, "umask" , "%s(%#o)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_umount
-{ TARGET_NR_umount, "umount" , "%s(\"%s\",\"%s\",\"%s\",%#x,%p)", NULL, NULL },
+{ TARGET_NR_umount, "umount" , "%s(\"%s\",\"%s\",\"%s\",%#x,%p)",
+    print_umount, NULL },
 #endif
 #ifdef TARGET_NR_umount2
 { TARGET_NR_umount2, "umount2" , NULL, NULL, NULL },
 { TARGET_NR_uname, "uname" , "%s(%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_unlink
-{ TARGET_NR_unlink, "unlink" , "%s(\"%s\")", NULL, NULL },
+{ TARGET_NR_unlink, "unlink" , "%s(\"%s\")", print_unlink, NULL },
 #endif
 #ifdef TARGET_NR_unlinkat
-{ TARGET_NR_unlinkat, "unlinkat" , "%s(%d,\"%s\",%#x)", NULL, NULL },
+{ TARGET_NR_unlinkat, "unlinkat" , "%s(%d,\"%s\",%#x)", print_unlinkat, NULL },
 #endif
 #ifdef TARGET_NR_unshare
 { TARGET_NR_unshare, "unshare" , NULL, NULL, NULL },
 { TARGET_NR_ustat, "ustat" , "%s(%#x,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_utime
-{ TARGET_NR_utime, "utime" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_utime, "utime" , "%s(\"%s\",%p)", print_utime, NULL },
 #endif
 #ifdef TARGET_NR_utimes
 { TARGET_NR_utimes, "utimes" , NULL, NULL, NULL },
 { TARGET_NR_writev, "writev" , "%s(%d,%p,%#x)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_utimensat
-{ TARGET_NR_utimensat, "utimensat", "%s(%d,\"%s\",%p,%#x)", NULL, NULL },
+{ TARGET_NR_utimensat, "utimensat", "%s(%d,\"%s\",%p,%#x)",
+    print_utimensat, NULL },
 #endif
index 226ee6c..209fa7c 100644 (file)
@@ -29,6 +29,7 @@
 #include <fcntl.h>
 #include <time.h>
 #include <limits.h>
+#include <mqueue.h>
 #include <sys/types.h>
 #include <sys/ipc.h>
 #include <sys/msg.h>
@@ -43,6 +44,7 @@
 #include <signal.h>
 #include <sched.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/uio.h>
 #include <sys/poll.h>
 #include <sys/times.h>
@@ -51,6 +53,7 @@
 #include <sys/statfs.h>
 #include <utime.h>
 #include <sys/sysinfo.h>
+#include <sys/utsname.h>
 //#include <sys/user.h>
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
@@ -169,6 +172,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,   \
 #define __NR_sys_linkat __NR_linkat
 #define __NR_sys_mkdirat __NR_mkdirat
 #define __NR_sys_mknodat __NR_mknodat
+#define __NR_sys_newfstatat __NR_newfstatat
 #define __NR_sys_openat __NR_openat
 #define __NR_sys_readlinkat __NR_readlinkat
 #define __NR_sys_renameat __NR_renameat
@@ -197,19 +201,8 @@ static int gettid(void) {
     return -ENOSYS;
 }
 #endif
-_syscall1(int,sys_uname,struct new_utsname *,buf)
-#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
-_syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags)
-#endif
-#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
-_syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname,
-          mode_t,mode,int,flags)
-#endif
-#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16)
-_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
-          uid_t,owner,gid_t,group,int,flags)
-#endif
-#if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64)
+#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
+        defined(__NR_fstatat64)
 _syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
           struct stat *,buf,int,flags)
 #endif
@@ -217,7 +210,6 @@ _syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
 _syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
          const struct timeval *,times)
 #endif
-_syscall2(int,sys_getcwd1,char *,buf,size_t,size)
 #if TARGET_ABI_BITS == 32
 _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
 #endif
@@ -229,33 +221,12 @@ _syscall2(int, sys_getpriority, int, which, int, who);
 _syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
           loff_t *, res, uint, wh);
 #endif
-#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
-_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
-         int,newdirfd,const char *,newpath,int,flags)
-#endif
-#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
-_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
-#endif
-#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
-_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
-          mode_t,mode,dev_t,dev)
-#endif
-#if defined(TARGET_NR_openat) && defined(__NR_openat)
-_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
-#endif
-#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
-_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
-          char *,buf,size_t,bufsize)
-#endif
-#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
-_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
-          int,newdirfd,const char *,newpath)
+#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
+        defined(__NR_newfstatat)
+_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
+          struct stat *,buf,int,flags)
 #endif
 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
-#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
-_syscall3(int,sys_symlinkat,const char *,oldpath,
-          int,newdirfd,const char *,newpath)
-#endif
 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
 #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
 _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
@@ -269,13 +240,6 @@ _syscall1(int,exit_group,int,error_code)
 #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
 _syscall1(int,set_tid_address,int *,tidptr)
 #endif
-#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
-_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
-#endif
-#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
-_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
-          const struct timespec *,tsp,int,flags)
-#endif
 #if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
 _syscall0(int,sys_inotify_init)
 #endif
@@ -292,6 +256,230 @@ _syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
 #endif
 #endif
 
+static bitmask_transtbl fcntl_flags_tbl[] = {
+  { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
+  { TARGET_O_ACCMODE,   TARGET_O_RDWR,      O_ACCMODE,   O_RDWR,      },
+  { TARGET_O_CREAT,     TARGET_O_CREAT,     O_CREAT,     O_CREAT,     },
+  { TARGET_O_EXCL,      TARGET_O_EXCL,      O_EXCL,      O_EXCL,      },
+  { TARGET_O_NOCTTY,    TARGET_O_NOCTTY,    O_NOCTTY,    O_NOCTTY,    },
+  { TARGET_O_TRUNC,     TARGET_O_TRUNC,     O_TRUNC,     O_TRUNC,     },
+  { TARGET_O_APPEND,    TARGET_O_APPEND,    O_APPEND,    O_APPEND,    },
+  { TARGET_O_NONBLOCK,  TARGET_O_NONBLOCK,  O_NONBLOCK,  O_NONBLOCK,  },
+  { TARGET_O_SYNC,      TARGET_O_SYNC,      O_SYNC,      O_SYNC,      },
+  { TARGET_FASYNC,      TARGET_FASYNC,      FASYNC,      FASYNC,      },
+  { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
+  { TARGET_O_NOFOLLOW,  TARGET_O_NOFOLLOW,  O_NOFOLLOW,  O_NOFOLLOW,  },
+  { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
+#if defined(O_DIRECT)
+  { TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
+#endif
+  { 0, 0, 0, 0 }
+};
+
+static int
+sys_uname(struct new_utsname *buf)
+{
+  struct utsname uts_buf;
+
+  if (uname(&uts_buf) < 0)
+      return (-1);
+
+  /*
+   * Just in case these have some differences, we
+   * translate utsname to new_utsname (which is the
+   * struct linux kernel uses).
+   */
+
+#define COPY_UTSNAME_FIELD(dest, src) \
+  do { \
+      /* __NEW_UTS_LEN doesn't include terminating null */ \
+      (void) strncpy((dest), (src), __NEW_UTS_LEN); \
+      (dest)[__NEW_UTS_LEN] = '\0'; \
+  } while (0)
+
+  bzero(buf, sizeof (*buf));
+  COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
+  COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
+  COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
+  COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
+  COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
+#ifdef _GNU_SOURCE
+  COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
+#endif
+  return (0);
+
+#undef COPY_UTSNAME_FIELD
+}
+
+static int
+sys_getcwd1(char *buf, size_t size)
+{
+  if (getcwd(buf, size) == NULL) {
+      /* getcwd() sets errno */
+      return (-1);
+  }
+  return (0);
+}
+
+#ifdef CONFIG_ATFILE
+
+/*
+ * Host system seems to have atfile syscall stubs available.  We
+ * now enable them one by one as specified by target syscall_nr.h.
+ */
+
+#ifdef TARGET_NR_openat
+static int
+sys_openat(int dirfd, const char *pathname, int flags, ...)
+{
+  /*
+   * open(2) has extra parameter 'mode' when called with
+   * flag O_CREAT.
+   */
+  if ((flags & O_CREAT) != 0) {
+      va_list ap;
+      mode_t mode;
+
+      /*
+       * Get the 'mode' parameter and translate it to
+       * host bits.
+       */
+      va_start(ap, flags);
+      mode = va_arg(ap, mode_t);
+      mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
+      va_end(ap);
+
+      return (openat(dirfd, pathname, flags, mode));
+  }
+  return (openat(dirfd, pathname, flags));
+}
+#endif
+
+#ifdef TARGET_NR_mkdirat
+static int
+sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
+{
+  return (mkdirat(dirfd, pathname, mode));
+}
+#endif
+
+#ifdef TARGET_NR_mknodat
+static int
+sys_mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev)
+{
+  return (mknodat(dirfd, pathname, mode, dev));
+}
+#endif
+
+#ifdef TARGET_NR_fchownat
+static int
+sys_fchownat(int dirfd, const char *pathname, uid_t owner,
+    gid_t group, int flags)
+{
+  return (fchownat(dirfd, pathname, owner, group, flags));
+}
+#endif
+
+#ifdef TARGET_NR_fstatat
+static int
+sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
+    int flags)
+{
+  return (fstatat64(dirfd, pathname, buf, flags));
+}
+#endif
+
+#ifdef TARGET_NR_unlinkat
+static int
+sys_unlinkat(int dirfd, const char *pathname, int flags)
+{
+  return (unlinkat(dirfd, pathname, flags));
+}
+#endif
+
+#ifdef TARGET_NR_renameat
+static int
+sys_renameat(int olddirfd, const char *oldpath,
+    int newdirfd, const char *newpath)
+{
+  return (renameat(olddirfd, oldpath, newdirfd, newpath));
+}
+#endif
+
+#ifdef TARGET_NR_linkat
+static int
+sys_linkat(int olddirfd, const char *oldpath,
+    int newdirfd, const char *newpath, int flags)
+{
+  return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
+}
+#endif
+
+#ifdef TARGET_NR_symlinkat
+static int
+sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
+{
+  return (symlinkat(oldpath, newdirfd, newpath));
+}
+#endif
+
+#ifdef TARGET_NR_readlinkat
+static int
+sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
+{
+  return (readlinkat(dirfd, pathname, buf, bufsiz));
+}
+#endif
+
+#ifdef TARGET_NR_fchmodat
+static int
+sys_fchmodat(int dirfd, const char *pathname, mode_t mode, int flags)
+{
+  return (fchmodat(dirfd, pathname, mode, flags));
+}
+#endif
+
+#ifdef TARGET_NR_faccessat
+static int
+sys_faccessat(int dirfd, const char *pathname, int mode, int flags)
+{
+  return (faccessat(dirfd, pathname, mode, flags));
+}
+#endif
+
+#ifdef TARGET_NR_utimensat
+static int
+sys_utimensat(int dirfd, const char *pathname,
+    const struct timespec times[2], int flags)
+{
+  return (utimensat(dirfd, pathname, times, flags));
+}
+#endif
+
+#else /* !CONFIG_ATFILE */
+
+/*
+ * Host system doesn't have these available so we don't try
+ * to implement them.
+ */
+
+#undef TARGET_NR_openat
+#undef TARGET_NR_mkdirat
+#undef TARGET_NR_mknodat
+#undef TARGET_NR_fchownat
+#undef TARGET_NR_fstatat
+#undef TARGET_NR_unlinkat
+#undef TARGET_NR_renameat
+#undef TARGET_NR_linkat
+#undef TARGET_NR_symlinkat
+#undef TARGET_NR_readlinkat
+#undef TARGET_NR_fchmodat
+#undef TARGET_NR_faccessat
+#undef TARGET_NR_utimensat
+
+#endif /* CONFIG_ATFILE */
+
+
 extern int personality(int);
 extern int flock(int, int);
 extern int setfsuid(int);
@@ -628,6 +816,43 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
     return 0;
 }
 
+static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
+                                              abi_ulong target_mq_attr_addr)
+{
+    struct target_mq_attr *target_mq_attr;
+
+    if (!lock_user_struct(VERIFY_READ, target_mq_attr,
+                          target_mq_attr_addr, 1))
+        return -TARGET_EFAULT;
+
+    __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
+    __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+    __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+    __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
+                                            const struct mq_attr *attr)
+{
+    struct target_mq_attr *target_mq_attr;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
+                          target_mq_attr_addr, 0))
+        return -TARGET_EFAULT;
+
+    __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
+    __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+    __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+    __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
+
+    return 0;
+}
 
 /* do_select() must return target values and target errnos. */
 static abi_long do_select(int n,
@@ -690,13 +915,37 @@ static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
                                                abi_ulong target_addr,
                                                socklen_t len)
 {
+    const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
+    sa_family_t sa_family;
     struct target_sockaddr *target_saddr;
 
     target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
     if (!target_saddr)
         return -TARGET_EFAULT;
+
+    sa_family = tswap16(target_saddr->sa_family);
+
+    /* Oops. The caller might send a incomplete sun_path; sun_path
+     * must be terminated by \0 (see the manual page), but
+     * unfortunately it is quite common to specify sockaddr_un
+     * length as "strlen(x->sun_path)" while it should be
+     * "strlen(...) + 1". We'll fix that here if needed.
+     * Linux kernel has a similar feature.
+     */
+
+    if (sa_family == AF_UNIX) {
+        if (len < unix_maxlen) {
+            char *cp = (char*)target_saddr;
+
+            if ( cp[len-1] && !cp[len] )
+                len++;
+        }
+        if (len > unix_maxlen)
+            len = unix_maxlen;
+    }
+
     memcpy(addr, target_saddr, len);
-    addr->sa_family = tswap16(target_saddr->sa_family);
+    addr->sa_family = sa_family;
     unlock_user(target_saddr, target_addr, 0);
 
     return 0;
@@ -1138,19 +1387,16 @@ static abi_long do_socket(int domain, int type, int protocol)
     return get_errno(socket(domain, type, protocol));
 }
 
-/* MAX_SOCK_ADDR from linux/net/socket.c */
-#define MAX_SOCK_ADDR  128
-
 /* do_bind() Must return target values and target errnos. */
 static abi_long do_bind(int sockfd, abi_ulong target_addr,
                         socklen_t addrlen)
 {
     void *addr;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
-    addr = alloca(addrlen);
+    addr = alloca(addrlen+1);
 
     target_to_host_sockaddr(addr, target_addr, addrlen);
     return get_errno(bind(sockfd, addr, addrlen));
@@ -1162,7 +1408,7 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr,
 {
     void *addr;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     addr = alloca(addrlen);
@@ -1234,10 +1480,13 @@ static abi_long do_accept(int fd, abi_ulong target_addr,
     void *addr;
     abi_long ret;
 
+    if (target_addr == 0)
+       return get_errno(accept(fd, NULL, NULL));
+
     if (get_user_u32(addrlen, target_addrlen_addr))
         return -TARGET_EFAULT;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     addr = alloca(addrlen);
@@ -1262,7 +1511,7 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr,
     if (get_user_u32(addrlen, target_addrlen_addr))
         return -TARGET_EFAULT;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     addr = alloca(addrlen);
@@ -1290,7 +1539,7 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr,
     if (get_user_u32(addrlen, target_addrlen_addr))
         return -TARGET_EFAULT;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     addr = alloca(addrlen);
@@ -1328,7 +1577,7 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
     void *host_msg;
     abi_long ret;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     host_msg = lock_user(VERIFY_READ, msg, len, 1);
@@ -1363,7 +1612,7 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
             ret = -TARGET_EFAULT;
             goto fail;
         }
-        if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) {
+        if (addrlen < 0) {
             ret = -TARGET_EINVAL;
             goto fail;
         }
@@ -1645,14 +1894,12 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
 }
 #endif
 
-#ifdef TARGET_NR_ipc
 #define N_SHM_REGIONS  32
 
 static struct shm_region {
     abi_ulong  start;
     abi_ulong  size;
 } shm_regions[N_SHM_REGIONS];
-#endif
 
 struct target_ipc_perm
 {
@@ -1671,14 +1918,14 @@ struct target_ipc_perm
 
 struct target_semid_ds
 {
-  struct target_ipc_perm sem_perm;
-  abi_ulong sem_otime;
-  abi_ulong __unused1;
-  abi_ulong sem_ctime;
-  abi_ulong __unused2;
-  abi_ulong sem_nsems;
-  abi_ulong __unused3;
-  abi_ulong __unused4;
+    struct target_ipc_perm sem_perm;
+    abi_ulong sem_otime;
+    abi_ulong __unused1;
+    abi_ulong sem_ctime;
+    abi_ulong __unused2;
+    abi_ulong sem_nsems;
+    abi_ulong __unused3;
+    abi_ulong __unused4;
 };
 
 static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
@@ -1726,7 +1973,8 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
 
     if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
         return -TARGET_EFAULT;
-    target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
+    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
+        return -TARGET_EFAULT;
     host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
     host_sd->sem_otime = tswapl(target_sd->sem_otime);
     host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
@@ -1741,7 +1989,8 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
 
     if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
         return -TARGET_EFAULT;
-    host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
+    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
+        return -TARGET_EFAULT;;
     target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
     target_sd->sem_otime = tswapl(host_sd->sem_otime);
     target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
@@ -1749,135 +1998,215 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
     return 0;
 }
 
+struct target_seminfo {
+    int semmap;
+    int semmni;
+    int semmns;
+    int semmnu;
+    int semmsl;
+    int semopm;
+    int semume;
+    int semusz;
+    int semvmx;
+    int semaem;
+};
+
+static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
+                                              struct seminfo *host_seminfo)
+{
+    struct target_seminfo *target_seminfo;
+    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
+    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
+    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
+    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
+    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
+    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
+    __put_user(host_seminfo->semume, &target_seminfo->semume);
+    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
+    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
+    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
+    unlock_user_struct(target_seminfo, target_addr, 1);
+    return 0;
+}
+
 union semun {
-       int val;
-       struct semid_ds *buf;
-       unsigned short *array;
+    int val;
+    struct semid_ds *buf;
+    unsigned short *array;
+    struct seminfo *__buf;
 };
 
 union target_semun {
-       int val;
-       abi_long buf;
-       unsigned short int *array;
+    int val;
+    abi_ulong buf;
+    abi_ulong array;
+    abi_ulong __buf;
 };
 
-static inline abi_long target_to_host_semun(int cmd,
-                                            union semun *host_su,
-                                            abi_ulong target_addr,
-                                            struct semid_ds *ds)
+static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+                                               abi_ulong target_addr)
 {
-    union target_semun *target_su;
-
-    switch( cmd ) {
-       case IPC_STAT:
-       case IPC_SET:
-           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
-               return -TARGET_EFAULT;
-          target_to_host_semid_ds(ds,target_su->buf);
-          host_su->buf = ds;
-           unlock_user_struct(target_su, target_addr, 0);
-          break;
-       case GETVAL:
-       case SETVAL:
-           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
-               return -TARGET_EFAULT;
-          host_su->val = tswapl(target_su->val);
-           unlock_user_struct(target_su, target_addr, 0);
-          break;
-       case GETALL:
-       case SETALL:
-           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
-               return -TARGET_EFAULT;
-          *host_su->array = tswap16(*target_su->array);
-           unlock_user_struct(target_su, target_addr, 0);
-          break;
-       default:
-           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1)
+        return get_errno(ret);
+
+    nsems = semid_ds.sem_nsems;
+
+    *host_array = malloc(nsems*sizeof(unsigned short));
+    array = lock_user(VERIFY_READ, target_addr,
+                      nsems*sizeof(unsigned short), 1);
+    if (!array)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsems; i++) {
+        __get_user((*host_array)[i], &array[i]);
     }
+    unlock_user(array, target_addr, 0);
+
     return 0;
 }
 
-static inline abi_long host_to_target_semun(int cmd,
-                                            abi_ulong target_addr,
-                                            union semun *host_su,
-                                            struct semid_ds *ds)
+static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+                                               unsigned short **host_array)
 {
-    union target_semun *target_su;
-
-    switch( cmd ) {
-       case IPC_STAT:
-       case IPC_SET:
-           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
-               return -TARGET_EFAULT;
-          host_to_target_semid_ds(target_su->buf,ds);
-           unlock_user_struct(target_su, target_addr, 1);
-          break;
-       case GETVAL:
-       case SETVAL:
-           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
-               return -TARGET_EFAULT;
-          target_su->val = tswapl(host_su->val);
-           unlock_user_struct(target_su, target_addr, 1);
-          break;
-       case GETALL:
-       case SETALL:
-           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
-               return -TARGET_EFAULT;
-          *target_su->array = tswap16(*host_su->array);
-           unlock_user_struct(target_su, target_addr, 1);
-          break;
-        default:
-           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
+
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1)
+        return get_errno(ret);
+
+    nsems = semid_ds.sem_nsems;
+
+    array = lock_user(VERIFY_WRITE, target_addr,
+                      nsems*sizeof(unsigned short), 0);
+    if (!array)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsems; i++) {
+        __put_user((*host_array)[i], &array[i]);
     }
+    free(*host_array);
+    unlock_user(array, target_addr, 1);
+
     return 0;
 }
 
-static inline abi_long do_semctl(int first, int second, int third,
-                                 abi_long ptr)
+static inline abi_long do_semctl(int semid, int semnum, int cmd,
+                                 union target_semun target_su)
 {
     union semun arg;
     struct semid_ds dsarg;
-    int cmd = third&0xff;
-    abi_long ret = 0;
+    unsigned short *array;
+    struct seminfo seminfo;
+    abi_long ret = -TARGET_EINVAL;
+    abi_long err;
 
-    switch( cmd ) {
-       case GETVAL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
-       case SETVAL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
-       case GETALL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
-       case SETALL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
-       case IPC_STAT:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
-       case IPC_SET:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
-    default:
-            ret = get_errno(semctl(first, second, cmd, arg));
+    cmd &= 0xff;
+
+    switch (cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+    case SEM_STAT:
+        err = target_to_host_semid_ds(&dsarg, target_su.buf);
+        if (err)
+            return err;
+        arg.buf = &dsarg;
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        err = host_to_target_semid_ds(target_su.buf, &dsarg);
+        if (err)
+            return err;
+        break;
+    case GETVAL:
+    case SETVAL:
+        arg.val = tswapl(target_su.val);
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        target_su.val = tswapl(arg.val);
+        break;
+    case GETALL:
+    case SETALL:
+        err = target_to_host_semarray(semid, &array, target_su.array);
+        if (err)
+            return err;
+        arg.array = array;
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        err = host_to_target_semarray(semid, target_su.array, &array);
+        if (err)
+            return err;
+        break;
+    case IPC_INFO:
+    case SEM_INFO:
+        arg.__buf = &seminfo;
+        ret = get_errno(semctl(semid, semnum, cmd, arg));
+        err = host_to_target_seminfo(target_su.__buf, &seminfo);
+        if (err)
+            return err;
+        break;
+    case IPC_RMID:
+    case GETPID:
+    case GETNCNT:
+    case GETZCNT:
+        ret = get_errno(semctl(semid, semnum, cmd, NULL));
+        break;
     }
 
     return ret;
 }
 
+struct target_sembuf {
+    unsigned short sem_num;
+    short sem_op;
+    short sem_flg;
+};
+
+static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
+                                             abi_ulong target_addr,
+                                             unsigned nsops)
+{
+    struct target_sembuf *target_sembuf;
+    int i;
+
+    target_sembuf = lock_user(VERIFY_READ, target_addr,
+                              nsops*sizeof(struct target_sembuf), 1);
+    if (!target_sembuf)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsops; i++) {
+        __put_user(target_sembuf[i].sem_num, &host_sembuf[i].sem_num);
+        __put_user(target_sembuf[i].sem_op, &host_sembuf[i].sem_op);
+        __put_user(target_sembuf[i].sem_flg, &host_sembuf[i].sem_flg);
+    }
+
+    unlock_user(target_sembuf, target_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
+{
+    struct sembuf sops[nsops];
+
+    if (target_to_host_sembuf(sops, ptr, nsops))
+        return -TARGET_EFAULT;
+
+    return semop(semid, sops, nsops);
+}
+
 struct target_msqid_ds
 {
     struct target_ipc_perm msg_perm;
@@ -2064,6 +2393,226 @@ end:
     return ret;
 }
 
+struct target_shmid_ds
+{
+    struct target_ipc_perm shm_perm;
+    abi_ulong shm_segsz;
+    abi_ulong shm_atime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused1;
+#endif
+    abi_ulong shm_dtime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused2;
+#endif
+    abi_ulong shm_ctime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused3;
+#endif
+    int shm_cpid;
+    int shm_lpid;
+    abi_ulong shm_nattch;
+    unsigned long int __unused4;
+    unsigned long int __unused5;
+};
+
+static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+                                               abi_ulong target_addr)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
+        return -TARGET_EFAULT;
+    if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
+        return -TARGET_EFAULT;
+    __put_user(target_sd->shm_segsz, &host_sd->shm_segsz);
+    __put_user(target_sd->shm_atime, &host_sd->shm_atime);
+    __put_user(target_sd->shm_dtime, &host_sd->shm_dtime);
+    __put_user(target_sd->shm_ctime, &host_sd->shm_ctime);
+    __put_user(target_sd->shm_cpid, &host_sd->shm_cpid);
+    __put_user(target_sd->shm_lpid, &host_sd->shm_lpid);
+    __put_user(target_sd->shm_nattch, &host_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+                                               struct shmid_ds *host_sd)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
+        return -TARGET_EFAULT;
+    if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
+        return -TARGET_EFAULT;
+    __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+    __put_user(host_sd->shm_atime, &target_sd->shm_atime);
+    __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+    __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+struct  target_shminfo {
+    abi_ulong shmmax;
+    abi_ulong shmmin;
+    abi_ulong shmmni;
+    abi_ulong shmseg;
+    abi_ulong shmall;
+};
+
+static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
+                                              struct shminfo *host_shminfo)
+{
+    struct target_shminfo *target_shminfo;
+    if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
+    __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
+    __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
+    __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
+    __put_user(host_shminfo->shmall, &target_shminfo->shmall);
+    unlock_user_struct(target_shminfo, target_addr, 1);
+    return 0;
+}
+
+struct target_shm_info {
+    int used_ids;
+    abi_ulong shm_tot;
+    abi_ulong shm_rss;
+    abi_ulong shm_swp;
+    abi_ulong swap_attempts;
+    abi_ulong swap_successes;
+};
+
+static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
+                                               struct shm_info *host_shm_info)
+{
+    struct target_shm_info *target_shm_info;
+    if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
+    __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
+    __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
+    __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
+    __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
+    __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
+    unlock_user_struct(target_shm_info, target_addr, 1);
+    return 0;
+}
+
+static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
+{
+    struct shmid_ds dsarg;
+    struct shminfo shminfo;
+    struct shm_info shm_info;
+    abi_long ret = -TARGET_EINVAL;
+
+    cmd &= 0xff;
+
+    switch(cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+    case SHM_STAT:
+        if (target_to_host_shmid_ds(&dsarg, buf))
+            return -TARGET_EFAULT;
+        ret = get_errno(shmctl(shmid, cmd, &dsarg));
+        if (host_to_target_shmid_ds(buf, &dsarg))
+            return -TARGET_EFAULT;
+        break;
+    case IPC_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
+        if (host_to_target_shminfo(buf, &shminfo))
+            return -TARGET_EFAULT;
+        break;
+    case SHM_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
+        if (host_to_target_shm_info(buf, &shm_info))
+            return -TARGET_EFAULT;
+        break;
+    case IPC_RMID:
+    case SHM_LOCK:
+    case SHM_UNLOCK:
+        ret = get_errno(shmctl(shmid, cmd, NULL));
+        break;
+    }
+
+    return ret;
+}
+
+static inline abi_long do_shmat(int shmid, abi_ulong shmaddr, int shmflg,
+                                unsigned long *raddr)
+{
+    abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
+    abi_long ret;
+    struct shmid_ds shm_info;
+    int i;
+
+    /* find out the length of the shared memory segment */
+    ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
+    if (is_error(ret)) {
+        /* can't get length, bail out */
+        return get_errno(ret);
+    }
+
+    mmap_lock();
+
+    if (shmaddr)
+        *raddr = (unsigned long) shmat(shmid, g2h(shmaddr), shmflg);
+    else {
+        abi_ulong mmap_start;
+
+        mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
+
+        if (mmap_start == -1) {
+            errno = ENOMEM;
+            *raddr = -1;
+        } else
+            *raddr = (unsigned long) shmat(shmid, g2h(mmap_start),
+                                           shmflg | SHM_REMAP);
+    }
+
+    if (*raddr == -1) {
+        mmap_unlock();
+        return get_errno(*raddr);
+    }
+
+    page_set_flags(h2g(*raddr), h2g(*raddr) + shm_info.shm_segsz,
+                   PAGE_VALID | PAGE_READ |
+                   ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
+
+    for (i = 0; i < N_SHM_REGIONS; i++) {
+        if (shm_regions[i].start == 0) {
+            shm_regions[i].start = h2g(*raddr);
+            shm_regions[i].size = shm_info.shm_segsz;
+            break;
+        }
+    }
+
+    *raddr = h2g(*raddr);
+
+    mmap_unlock();
+    return 0;
+}
+
+static inline abi_long do_shmdt(abi_ulong shmaddr)
+{
+    int i;
+
+    for (i = 0; i < N_SHM_REGIONS; ++i) {
+        if (shm_regions[i].start == shmaddr) {
+            shm_regions[i].start = 0;
+            page_set_flags(shmaddr, shm_regions[i].size, 0);
+            break;
+        }
+    }
+
+    return get_errno(shmdt(g2h(shmaddr)));
+}
+
 #ifdef TARGET_NR_ipc
 /* ??? This only works with linear mappings.  */
 /* do_ipc() must return target values and target errnos. */
@@ -2073,15 +2622,13 @@ static abi_long do_ipc(unsigned int call, int first,
 {
     int version;
     abi_long ret = 0;
-    struct shmid_ds shm_info;
-    int i;
 
     version = call >> 16;
     call &= 0xffff;
 
     switch (call) {
     case IPCOP_semop:
-        ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second));
+        ret = do_semop(first, ptr, second);
         break;
 
     case IPCOP_semget:
@@ -2089,12 +2636,7 @@ static abi_long do_ipc(unsigned int call, int first,
         break;
 
     case IPCOP_semctl:
-        ret = do_semctl(first, second, third, ptr);
-        break;
-
-    case IPCOP_semtimedop:
-        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
-        ret = -TARGET_ENOSYS;
+        ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
         break;
 
     case IPCOP_msgget:
@@ -2134,72 +2676,40 @@ static abi_long do_ipc(unsigned int call, int first,
         break;
 
     case IPCOP_shmat:
-        {
-            abi_ulong raddr;
-            void *host_addr;
-            /* SHM_* flags are the same on all linux platforms */
-            host_addr = shmat(first, (void *)g2h(ptr), second);
-            if (host_addr == (void *)-1) {
-                ret = get_errno((long)host_addr);
-                break;
-            }
-            raddr = h2g((unsigned long)host_addr);
-            /* find out the length of the shared memory segment */
-            
-            ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
-            if (is_error(ret)) {
-                /* can't get length, bail out */
-                shmdt(host_addr);
-                break;
-            }
-            page_set_flags(raddr, raddr + shm_info.shm_segsz,
-                           PAGE_VALID | PAGE_READ |
-                           ((second & SHM_RDONLY)? 0: PAGE_WRITE));
-            for (i = 0; i < N_SHM_REGIONS; ++i) {
-                if (shm_regions[i].start == 0) {
-                    shm_regions[i].start = raddr;
-                    shm_regions[i].size = shm_info.shm_segsz;
+        switch (version) {
+        default:
+            {
+                unsigned long raddr;
+
+                ret = do_shmat(first, ptr, second, &raddr);
+                if (ret)
                     break;
-                }
+
+                ret = put_user_ual(raddr, third);
+                break;
             }
-            if (put_user_ual(raddr, third))
-                return -TARGET_EFAULT;
-            ret = 0;
+        case 1:
+            ret = -TARGET_EINVAL;
+            break;
         }
-       break;
+        break;
+
     case IPCOP_shmdt:
-       for (i = 0; i < N_SHM_REGIONS; ++i) {
-           if (shm_regions[i].start == ptr) {
-               shm_regions[i].start = 0;
-               page_set_flags(ptr, shm_regions[i].size, 0);
-               break;
-           }
-       }
-       ret = get_errno(shmdt((void *)g2h(ptr)));
-       break;
+        ret = do_shmdt(ptr);
+        break;
 
     case IPCOP_shmget:
-       /* IPC_* flag values are the same on all linux platforms */
-       ret = get_errno(shmget(first, second, third));
-       break;
+        ret = get_errno(shmget(first, second, third));
+        break;
 
-       /* IPC_* and SHM_* command values are the same on all linux platforms */
     case IPCOP_shmctl:
-        switch(second) {
-        case IPC_RMID:
-        case SHM_LOCK:
-        case SHM_UNLOCK:
-            ret = get_errno(shmctl(first, second, NULL));
-            break;
-        default:
-            goto unimplemented;
-        }
+        ret = do_shmctl(first, second, third);
         break;
+
     default:
-    unimplemented:
-       gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
-       ret = -TARGET_ENOSYS;
-       break;
+        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
+        ret = -TARGET_ENOSYS;
+        break;
     }
     return ret;
 }
@@ -2513,26 +3023,6 @@ static bitmask_transtbl mmap_flags_tbl[] = {
        { 0, 0, 0, 0 }
 };
 
-static bitmask_transtbl fcntl_flags_tbl[] = {
-       { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
-       { TARGET_O_ACCMODE,   TARGET_O_RDWR,      O_ACCMODE,   O_RDWR,      },
-       { TARGET_O_CREAT,     TARGET_O_CREAT,     O_CREAT,     O_CREAT,     },
-       { TARGET_O_EXCL,      TARGET_O_EXCL,      O_EXCL,      O_EXCL,      },
-       { TARGET_O_NOCTTY,    TARGET_O_NOCTTY,    O_NOCTTY,    O_NOCTTY,    },
-       { TARGET_O_TRUNC,     TARGET_O_TRUNC,     O_TRUNC,     O_TRUNC,     },
-       { TARGET_O_APPEND,    TARGET_O_APPEND,    O_APPEND,    O_APPEND,    },
-       { TARGET_O_NONBLOCK,  TARGET_O_NONBLOCK,  O_NONBLOCK,  O_NONBLOCK,  },
-       { TARGET_O_SYNC,      TARGET_O_SYNC,      O_SYNC,      O_SYNC,      },
-       { TARGET_FASYNC,      TARGET_FASYNC,      FASYNC,      FASYNC,      },
-       { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
-       { TARGET_O_NOFOLLOW,  TARGET_O_NOFOLLOW,  O_NOFOLLOW,  O_NOFOLLOW,  },
-       { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
-#if defined(O_DIRECT)
-       { TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
-#endif
-       { 0, 0, 0, 0 }
-};
-
 #if defined(TARGET_I386)
 
 /* NOTE: there is really one LDT for all the threads */
@@ -2854,6 +3344,7 @@ typedef struct {
     pthread_cond_t cond;
     pthread_t thread;
     uint32_t tid;
+    unsigned int flags;
     abi_ulong child_tidptr;
     abi_ulong parent_tidptr;
     sigset_t sigmask;
@@ -2863,10 +3354,13 @@ static void *clone_func(void *arg)
 {
     new_thread_info *info = arg;
     CPUState *env;
+    TaskState *ts;
 
     env = info->env;
     thread_env = env;
+    ts = (TaskState *)thread_env->opaque;
     info->tid = gettid();
+    task_settid(ts);
     if (info->child_tidptr)
         put_user_u32(info->tid, info->child_tidptr);
     if (info->parent_tidptr)
@@ -2918,6 +3412,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         flags &= ~(CLONE_VFORK | CLONE_VM);
 
     if (flags & CLONE_VM) {
+        TaskState *parent_ts = (TaskState *)env->opaque;
 #if defined(USE_NPTL)
         new_thread_info info;
         pthread_attr_t attr;
@@ -2930,6 +3425,8 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         /* Init regs that differ from the parent.  */
         cpu_clone_regs(new_env, newsp);
         new_env->opaque = ts;
+        ts->bprm = parent_ts->bprm;
+        ts->info = parent_ts->info;
 #if defined(USE_NPTL)
         nptl_flags = flags;
         flags &= ~CLONE_NPTL_FLAGS2;
@@ -3280,7 +3777,7 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr,
     return 0;
 }
 
-#ifdef TARGET_NR_stat64
+#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
 static inline abi_long host_to_target_stat64(void *cpu_env,
                                              abi_ulong target_addr,
                                              struct stat *host_st)
@@ -3312,11 +3809,15 @@ static inline abi_long host_to_target_stat64(void *cpu_env,
     } else
 #endif
     {
+#if TARGET_LONG_BITS == 64
+        struct target_stat *target_st;
+#else
         struct target_stat64 *target_st;
+#endif
 
         if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
             return -TARGET_EFAULT;
-        memset(target_st, 0, sizeof(struct target_stat64));
+        memset(target_st, 0, sizeof(*target_st));
         __put_user(host_st->st_dev, &target_st->st_dev);
         __put_user(host_st->st_ino, &target_st->st_ino);
 #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
@@ -4921,7 +5422,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
        ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
        break;
 #endif
-
+#ifdef TARGET_NR_semget
+    case TARGET_NR_semget:
+        ret = get_errno(semget(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_semop
+    case TARGET_NR_semop:
+        ret = get_errno(do_semop(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_semctl
+    case TARGET_NR_semctl:
+        ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
+        break;
+#endif
 #ifdef TARGET_NR_msgctl
     case TARGET_NR_msgctl:
         ret = do_msgctl(arg1, arg2, arg3);
@@ -4942,6 +5457,32 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_msgsnd(arg1, arg2, arg3, arg4);
         break;
 #endif
+#ifdef TARGET_NR_shmget
+    case TARGET_NR_shmget:
+        ret = get_errno(shmget(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_shmctl
+    case TARGET_NR_shmctl:
+        ret = do_shmctl(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_shmat
+    case TARGET_NR_shmat:
+        {
+            abi_long err;
+            unsigned long _ret;
+
+            err = do_shmat(arg1, arg2, arg3, &_ret);
+            ret = err ? err : _ret;
+        }
+        break;
+#endif
+#ifdef TARGET_NR_shmdt
+    case TARGET_NR_shmdt:
+        ret = do_shmdt(arg1);
+        break;
+#endif
     case TARGET_NR_fsync:
         ret = get_errno(fsync(arg1));
         break;
@@ -5459,11 +6000,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             ret = host_to_target_stat64(cpu_env, arg2, &st);
         break;
 #endif
-#if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64)
+#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
+        (defined(__NR_fstatat64) || defined(__NR_newfstatat))
+#ifdef TARGET_NR_fstatat64
     case TARGET_NR_fstatat64:
+#endif
+#ifdef TARGET_NR_newfstatat
+    case TARGET_NR_newfstatat:
+#endif
         if (!(p = lock_user_string(arg2)))
             goto efault;
+#ifdef __NR_fstatat64
         ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
+#else
+        ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
+#endif
         if (!is_error(ret))
             ret = host_to_target_stat64(cpu_env, arg3, &st);
         break;
@@ -6127,6 +6678,81 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 #endif
 
+#ifdef TARGET_NR_mq_open
+    case TARGET_NR_mq_open:
+    {
+        struct mq_attr posix_mq_attr;
+
+        p = lock_user_string(arg1 - 1);
+        if (arg4 != 0)
+            copy_from_user_mq_attr (&posix_mq_attr, arg4);
+        ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
+        unlock_user (p, arg1, 0);
+        break;
+    }
+
+    case TARGET_NR_mq_unlink:
+        p = lock_user_string(arg1 - 1);
+        ret = get_errno(mq_unlink(p));
+        unlock_user (p, arg1, 0);
+        break;
+
+    case TARGET_NR_mq_timedsend:
+    {
+        struct timespec ts;
+
+        p = lock_user (VERIFY_READ, arg2, arg3, 1);
+        if (arg5 != 0) {
+            target_to_host_timespec(&ts, arg5);
+            ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
+            host_to_target_timespec(arg5, &ts);
+        }
+        else
+            ret = get_errno(mq_send(arg1, p, arg3, arg4));
+        unlock_user (p, arg2, arg3);
+        break;
+    }
+
+    case TARGET_NR_mq_timedreceive:
+    {
+        struct timespec ts;
+        unsigned int prio;
+
+        p = lock_user (VERIFY_READ, arg2, arg3, 1);
+        if (arg5 != 0) {
+            target_to_host_timespec(&ts, arg5);
+            ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
+            host_to_target_timespec(arg5, &ts);
+        }
+        else
+            ret = get_errno(mq_receive(arg1, p, arg3, &prio));
+        unlock_user (p, arg2, arg3);
+        if (arg4 != 0)
+            put_user_u32(prio, arg4);
+        break;
+    }
+
+    /* Not implemented for now... */
+/*     case TARGET_NR_mq_notify: */
+/*         break; */
+
+    case TARGET_NR_mq_getsetattr:
+    {
+        struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
+        ret = 0;
+        if (arg3 != 0) {
+            ret = mq_getattr(arg1, &posix_mq_attr_out);
+            copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
+        }
+        if (arg2 != 0) {
+            copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
+            ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
+        }
+
+        break;
+    }
+#endif
+
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);
index 7db7a8c..a373690 100644 (file)
@@ -1998,6 +1998,13 @@ struct linux_dirent64 {
     char            d_name[256];
 };
 
+struct target_mq_attr {
+    abi_long mq_flags;
+    abi_long mq_maxmsg;
+    abi_long mq_msgsize;
+    abi_long mq_curmsgs;
+};
+
 #include "socket.h"
 
 #include "errno_defs.h"
index 2a8d696..ab82ce0 100644 (file)
@@ -2,30 +2,36 @@
 #define __USER_DS      (0x2B)
 
 struct target_pt_regs {
-       abi_ulong r15;
-       abi_ulong r14;
-       abi_ulong r13;
-       abi_ulong r12;
-       abi_ulong rbp;
-       abi_ulong rbx;
+    abi_ulong r15;
+    abi_ulong r14;
+    abi_ulong r13;
+    abi_ulong r12;
+    abi_ulong rbp;
+    abi_ulong rbx;
 /* arguments: non interrupts/non tracing syscalls only save upto here*/
-       abi_ulong r11;
-       abi_ulong r10;
-       abi_ulong r9;
-       abi_ulong r8;
-       abi_ulong rax;
-       abi_ulong rcx;
-       abi_ulong rdx;
-       abi_ulong rsi;
-       abi_ulong rdi;
-       abi_ulong orig_rax;
+    abi_ulong r11;
+    abi_ulong r10;
+    abi_ulong r9;
+    abi_ulong r8;
+    abi_ulong rax;
+    abi_ulong rcx;
+    abi_ulong rdx;
+    abi_ulong rsi;
+    abi_ulong rdi;
+    abi_ulong orig_rax;
 /* end of arguments */
 /* cpu exception frame or undefined */
-       abi_ulong rip;
-       abi_ulong cs;
-       abi_ulong eflags;
-       abi_ulong rsp;
-       abi_ulong ss;
+    abi_ulong rip;
+    abi_ulong cs;
+    abi_ulong eflags;
+    abi_ulong rsp;
+    abi_ulong ss;
+    abi_ulong fs_base;
+    abi_ulong gs_base;
+    abi_ulong ds;
+    abi_ulong es;
+    abi_ulong fs;
+    abi_ulong gs;
 /* top of stack page */
 };
 
index f98655f..587f56d 100644 (file)
@@ -110,6 +110,9 @@ typedef struct CPUARMState {
         uint32_t c1_sys; /* System control register.  */
         uint32_t c1_coproc; /* Coprocessor access register.  */
         uint32_t c1_xscaleauxcr; /* XScale auxiliary control register.  */
+        uint32_t c1_secfg; /* Secure configuration register. */
+        uint32_t c1_sedbg; /* Secure debug enable register. */
+        uint32_t c1_nseac; /* Non-secure access control register. */
         uint32_t c2_base0; /* MMU translation table base 0.  */
         uint32_t c2_base1; /* MMU translation table base 1.  */
         uint32_t c2_control; /* MMU translation table base control.  */
@@ -341,7 +344,8 @@ enum arm_features {
     ARM_FEATURE_DIV,
     ARM_FEATURE_M, /* Microcontroller profile.  */
     ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
-    ARM_FEATURE_THUMB2EE
+    ARM_FEATURE_THUMB2EE,
+       ARM_FEATURE_TRUSTZONE /* TrustZone Security Extensions. */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -367,29 +371,30 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define IS_M(env) arm_feature(env, ARM_FEATURE_M)
 #define ARM_CPUID(env) (env->cp15.c0_cpuid)
 
-#define ARM_CPUID_ARM1026     0x4106a262
-#define ARM_CPUID_ARM926      0x41069265
-#define ARM_CPUID_ARM946      0x41059461
-#define ARM_CPUID_TI915T      0x54029152
-#define ARM_CPUID_TI925T      0x54029252
-#define ARM_CPUID_PXA250      0x69052100
-#define ARM_CPUID_PXA255      0x69052d00
-#define ARM_CPUID_PXA260      0x69052903
-#define ARM_CPUID_PXA261      0x69052d05
-#define ARM_CPUID_PXA262      0x69052d06
-#define ARM_CPUID_PXA270      0x69054110
-#define ARM_CPUID_PXA270_A0   0x69054110
-#define ARM_CPUID_PXA270_A1   0x69054111
-#define ARM_CPUID_PXA270_B0   0x69054112
-#define ARM_CPUID_PXA270_B1   0x69054113
-#define ARM_CPUID_PXA270_C0   0x69054114
-#define ARM_CPUID_PXA270_C5   0x69054117
-#define ARM_CPUID_ARM1136     0x4117b363
-#define ARM_CPUID_ARM1136_R2  0x4107b362
-#define ARM_CPUID_ARM11MPCORE 0x410fb022
-#define ARM_CPUID_CORTEXA8    0x410fc080
-#define ARM_CPUID_CORTEXM3    0x410fc231
-#define ARM_CPUID_ANY         0xffffffff
+#define ARM_CPUID_ARM1026       0x4106a262
+#define ARM_CPUID_ARM926        0x41069265
+#define ARM_CPUID_ARM946        0x41059461
+#define ARM_CPUID_TI915T        0x54029152
+#define ARM_CPUID_TI925T        0x54029252
+#define ARM_CPUID_PXA250        0x69052100
+#define ARM_CPUID_PXA255        0x69052d00
+#define ARM_CPUID_PXA260        0x69052903
+#define ARM_CPUID_PXA261        0x69052d05
+#define ARM_CPUID_PXA262        0x69052d06
+#define ARM_CPUID_PXA270        0x69054110
+#define ARM_CPUID_PXA270_A0     0x69054110
+#define ARM_CPUID_PXA270_A1     0x69054111
+#define ARM_CPUID_PXA270_B0     0x69054112
+#define ARM_CPUID_PXA270_B1     0x69054113
+#define ARM_CPUID_PXA270_C0     0x69054114
+#define ARM_CPUID_PXA270_C5     0x69054117
+#define ARM_CPUID_ARM1136       0x4117b363
+#define ARM_CPUID_ARM1136_R2    0x4107b362
+#define ARM_CPUID_ARM11MPCORE   0x410fb022
+#define ARM_CPUID_CORTEXA8      0x411fc081
+#define ARM_CPUID_CORTEXA8_R2   0x412fc083
+#define ARM_CPUID_CORTEXM3      0x410fc231
+#define ARM_CPUID_ANY           0xffffffff
 
 #if defined(CONFIG_USER_ONLY)
 #define TARGET_PAGE_BITS 12
index 3464142..8a91602 100644 (file)
@@ -14,6 +14,9 @@ static uint32_t cortexa8_cp15_c0_c1[8] =
 static uint32_t cortexa8_cp15_c0_c2[8] =
 { 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 };
 
+static uint32_t cortexa8r2_cp16_c0_c2[8] =
+{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00011142, 0, 0, 0 };
+
 static uint32_t mpcore_cp15_c0_c1[8] =
 { 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 };
 
@@ -89,6 +92,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_VFP3);
         set_feature(env, ARM_FEATURE_NEON);
         set_feature(env, ARM_FEATURE_THUMB2EE);
+        set_feature(env, ARM_FEATURE_TRUSTZONE);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
@@ -100,6 +104,28 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
         env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
         break;
+    case ARM_CPUID_CORTEXA8_R2:
+        set_feature(env, ARM_FEATURE_V6);
+        set_feature(env, ARM_FEATURE_V6K);
+        set_feature(env, ARM_FEATURE_V7);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_THUMB2);
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_VFP3);
+        set_feature(env, ARM_FEATURE_NEON);
+        set_feature(env, ARM_FEATURE_THUMB2EE);
+        set_feature(env, ARM_FEATURE_TRUSTZONE);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c2;
+        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
+        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100; /* should be 0x00011111 */
+        memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, cortexa8r2_cp16_c0_c2, 8 * sizeof(uint32_t));
+        env->cp15.c0_cachetype = 0x82048004;
+        env->cp15.c0_clid = (1 << 27) | (2 << 24) | (4 << 3) | 3;
+        env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
+        env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
+        env->cp15.c0_ccsid[2] = 0xf03fe03a; /* 256k L2 cache. */
+        break;
     case ARM_CPUID_CORTEXM3:
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_THUMB2);
@@ -284,6 +310,7 @@ static const struct arm_cpu_t arm_cpu_names[] = {
     { ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
     { ARM_CPUID_CORTEXM3, "cortex-m3"},
     { ARM_CPUID_CORTEXA8, "cortex-a8"},
+    { ARM_CPUID_CORTEXA8_R2, "cortex-a8-r2"},
     { ARM_CPUID_TI925T, "ti925t" },
     { ARM_CPUID_PXA250, "pxa250" },
     { ARM_CPUID_PXA255, "pxa255" },
@@ -1339,30 +1366,60 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
         }
         goto bad_reg;
     case 1: /* System configuration.  */
-        if (arm_feature(env, ARM_FEATURE_OMAPCP))
-            op2 = 0;
-        switch (op2) {
+        switch (crm) {
         case 0:
-            if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0)
-                env->cp15.c1_sys = val;
-            /* ??? Lots of these bits are not implemented.  */
-            /* This may enable/disable the MMU, so do a TLB flush.  */
-            tlb_flush(env, 1);
-            break;
-        case 1: /* Auxiliary cotrol register.  */
-            if (arm_feature(env, ARM_FEATURE_XSCALE)) {
-                env->cp15.c1_xscaleauxcr = val;
+            if (arm_feature(env, ARM_FEATURE_OMAPCP))
+                op2 = 0;
+            switch (op2) {
+            case 0:
+                if (!arm_feature(env, ARM_FEATURE_XSCALE))
+                    env->cp15.c1_sys = val;
+                /* ??? Lots of these bits are not implemented.  */
+                /* This may enable/disable the MMU, so do a TLB flush.  */
+                tlb_flush(env, 1);
+                break;
+            case 1: /* Auxiliary cotrol register.  */
+                if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+                    env->cp15.c1_xscaleauxcr = val;
+                    break;
+                }
+                /* Not implemented.  */
                 break;
+            case 2:
+                if (arm_feature(env, ARM_FEATURE_XSCALE))
+                    goto bad_reg;
+                if (env->cp15.c1_coproc != val) {
+                    env->cp15.c1_coproc = val;
+                    /* ??? Is this safe when called from within a TB?  */
+                    tb_flush(env);
+                }
+                break;
+            default:
+                goto bad_reg;
             }
-            /* Not implemented.  */
             break;
-        case 2:
-            if (arm_feature(env, ARM_FEATURE_XSCALE))
+        case 1:
+            if (!arm_feature(env, ARM_FEATURE_TRUSTZONE)
+                || (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
+                goto bad_reg;
+            switch (op2) {
+            case 0: /* Secure configuration register. */
+                if (env->cp15.c1_secfg & 1)
+                    goto bad_reg;
+                env->cp15.c1_secfg = val;
+                break;
+            case 1: /* Secure debug enable register. */
+                if (env->cp15.c1_secfg & 1)
+                    goto bad_reg;
+                env->cp15.c1_sedbg = val;
+                break;
+            case 2: /* Nonsecure access control register. */
+                if (env->cp15.c1_secfg & 1)
+                    goto bad_reg;
+                env->cp15.c1_nseac = val;
+                break;
+            default:
                 goto bad_reg;
-            if (env->cp15.c1_coproc != val) {
-                env->cp15.c1_coproc = val;
-                /* ??? Is this safe when called from within a TB?  */
-                tb_flush(env);
             }
             break;
         default:
@@ -1382,22 +1439,22 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
                 goto bad_reg;
             }
         } else {
-           switch (op2) {
-           case 0:
-               env->cp15.c2_base0 = val;
-               break;
-           case 1:
-               env->cp15.c2_base1 = val;
-               break;
-           case 2:
+            switch (op2) {
+            case 0:
+                env->cp15.c2_base0 = val;
+                break;
+            case 1:
+                env->cp15.c2_base1 = val;
+                break;
+            case 2:
                 val &= 7;
                 env->cp15.c2_control = val;
-               env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val);
+                env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val);
                 env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val);
-               break;
-           default:
-               goto bad_reg;
-           }
+                break;
+            default:
+                goto bad_reg;
+            }
         }
         break;
     case 3: /* MMU Domain access control / MPU write buffer control.  */
@@ -1496,26 +1553,26 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
             break;
         switch (crm) {
         case 0: /* Cache lockdown.  */
-           switch (op1) {
-           case 0: /* L1 cache.  */
-               switch (op2) {
-               case 0:
-                   env->cp15.c9_data = val;
-                   break;
-               case 1:
-                   env->cp15.c9_insn = val;
-                   break;
-               default:
-                   goto bad_reg;
-               }
-               break;
-           case 1: /* L2 cache.  */
-               /* Ignore writes to L2 lockdown/auxiliary registers.  */
-               break;
-           default:
-               goto bad_reg;
-           }
-           break;
+            switch (op1) {
+            case 0: /* L1 cache.  */
+                switch (op2) {
+                case 0:
+                    env->cp15.c9_data = val;
+                    break;
+                case 1:
+                    env->cp15.c9_insn = val;
+                    break;
+                default:
+                    goto bad_reg;
+                }
+                break;
+            case 1: /* L2 cache.  */
+                /* Ignore writes to L2 lockdown/auxiliary registers.  */
+                break;
+            default:
+                goto bad_reg;
+            }
+            break;
         case 1: /* TCM memory region registers.  */
             /* Not implemented.  */
             goto bad_reg;
@@ -1625,7 +1682,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
                 case 0: /* Device ID.  */
                     return env->cp15.c0_cpuid;
                 case 1: /* Cache Type.  */
-                   return env->cp15.c0_cachetype;
+                    return env->cp15.c0_cachetype;
                 case 2: /* TCM status.  */
                     return 0;
                 case 3: /* TLB type register.  */
@@ -1648,6 +1705,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
             default:
                 goto bad_reg;
             }
+            break;
         case 1:
             /* These registers aren't documented on arm11 cores.  However
                Linux looks at them anyway.  */
@@ -1674,37 +1732,66 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
         default:
             goto bad_reg;
         }
+        break;
     case 1: /* System configuration.  */
-        if (arm_feature(env, ARM_FEATURE_OMAPCP))
-            op2 = 0;
-        switch (op2) {
-        case 0: /* Control register.  */
-            return env->cp15.c1_sys;
-        case 1: /* Auxiliary control register.  */
-            if (arm_feature(env, ARM_FEATURE_XSCALE))
-                return env->cp15.c1_xscaleauxcr;
-            if (!arm_feature(env, ARM_FEATURE_AUXCR))
-                goto bad_reg;
-            switch (ARM_CPUID(env)) {
-            case ARM_CPUID_ARM1026:
-                return 1;
-            case ARM_CPUID_ARM1136:
-            case ARM_CPUID_ARM1136_R2:
-                return 7;
-            case ARM_CPUID_ARM11MPCORE:
-                return 1;
-            case ARM_CPUID_CORTEXA8:
-                return 2;
+        switch (crm) {
+        case 0:
+            if (arm_feature(env, ARM_FEATURE_OMAPCP))
+                op2 = 0;
+            switch (op2) {
+            case 0: /* Control register.  */
+                return env->cp15.c1_sys;
+            case 1: /* Auxiliary control register.  */
+                if (arm_feature(env, ARM_FEATURE_XSCALE))
+                    return env->cp15.c1_xscaleauxcr;
+                if (!arm_feature(env, ARM_FEATURE_AUXCR))
+                    goto bad_reg;
+                switch (ARM_CPUID(env)) {
+                case ARM_CPUID_ARM1026:
+                    return 1;
+                case ARM_CPUID_ARM1136:
+                case ARM_CPUID_ARM1136_R2:
+                    return 7;
+                case ARM_CPUID_ARM11MPCORE:
+                    return 1;
+                case ARM_CPUID_CORTEXA8:
+                case ARM_CPUID_CORTEXA8_R2:
+                    return 2;
+                default:
+                    goto bad_reg;
+                }
+                break;
+            case 2: /* Coprocessor access register.  */
+                if (arm_feature(env, ARM_FEATURE_XSCALE))
+                    goto bad_reg;
+                return env->cp15.c1_coproc;
             default:
                 goto bad_reg;
             }
-        case 2: /* Coprocessor access register.  */
-            if (arm_feature(env, ARM_FEATURE_XSCALE))
+            break;
+        case 1:
+            if (!arm_feature(env, ARM_FEATURE_TRUSTZONE)
+                || (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
+                goto bad_reg;
+            switch (op2) {
+            case 0: /* Secure configuration register. */
+                if (env->cp15.c1_secfg & 1)
+                    goto bad_reg;
+                return env->cp15.c1_secfg;
+            case 1: /* Secure debug enable register. */
+                if (env->cp15.c1_secfg & 1)
+                    goto bad_reg;
+                return env->cp15.c1_sedbg;
+            case 2: /* Nonsecure access control register. */
+                return env->cp15.c1_nseac;
+            default:
                 goto bad_reg;
-            return env->cp15.c1_coproc;
+            }
+            break;
         default:
             goto bad_reg;
         }
+        break;
     case 2: /* MMU Page table control / MPU cache control.  */
         if (arm_feature(env, ARM_FEATURE_MPU)) {
             switch (op2) {
@@ -1718,17 +1805,17 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
                 goto bad_reg;
             }
         } else {
-           switch (op2) {
-           case 0:
-               return env->cp15.c2_base0;
-           case 1:
-               return env->cp15.c2_base1;
-           case 2:
+            switch (op2) {
+            case 0:
+                return env->cp15.c2_base0;
+            case 1:
+                return env->cp15.c2_base1;
+            case 2:
                 return env->cp15.c2_control;
-           default:
-               goto bad_reg;
-           }
-       }
+            default:
+                goto bad_reg;
+            }
+        }
     case 3: /* MMU Domain access control / MPU write buffer control.  */
         return env->cp15.c3;
     case 4: /* Reserved.  */
@@ -1764,41 +1851,39 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
         } else {
             if (arm_feature(env, ARM_FEATURE_OMAPCP))
                 op2 = 0;
-           switch (op2) {
-           case 0:
-               return env->cp15.c6_data;
-           case 1:
-               if (arm_feature(env, ARM_FEATURE_V6)) {
-                   /* Watchpoint Fault Adrress.  */
-                   return 0; /* Not implemented.  */
-               } else {
-                   /* Instruction Fault Adrress.  */
-                   /* Arm9 doesn't have an IFAR, but implementing it anyway
-                      shouldn't do any harm.  */
-                   return env->cp15.c6_insn;
-               }
-           case 2:
-               if (arm_feature(env, ARM_FEATURE_V6)) {
-                   /* Instruction Fault Adrress.  */
-                   return env->cp15.c6_insn;
-               } else {
-                   goto bad_reg;
-               }
-           default:
-               goto bad_reg;
-           }
+            switch (op2) {
+            case 0:
+                return env->cp15.c6_data;
+            case 1:
+                if (arm_feature(env, ARM_FEATURE_V6)) {
+                    /* Watchpoint Fault Adrress.  */
+                    return 0; /* Not implemented.  */
+                }
+                /* Instruction Fault Adrress.  */
+                /* Arm9 doesn't have an IFAR, but implementing it anyway
+                   shouldn't do any harm.  */
+                return env->cp15.c6_insn;
+            case 2:
+                if (arm_feature(env, ARM_FEATURE_V6)) {
+                    /* Instruction Fault Adrress.  */
+                    return env->cp15.c6_insn;
+                }
+                goto bad_reg;
+            default:
+                goto bad_reg;
+            }
         }
     case 7: /* Cache control.  */
-        /* FIXME: Should only clear Z flag if destination is r15.  */
-        env->ZF = 0;
+        if (((insn >> 12) & 0xf) == 0xf) /* clear ZF only if destination is r15 */
+            env->ZF = 0;
         return 0;
     case 8: /* MMU TLB control.  */
         goto bad_reg;
     case 9: /* Cache lockdown.  */
         switch (op1) {
         case 0: /* L1 cache.  */
-           if (arm_feature(env, ARM_FEATURE_OMAPCP))
-               return 0;
+            if (arm_feature(env, ARM_FEATURE_OMAPCP))
+                return 0;
             switch (op2) {
             case 0:
                 return env->cp15.c9_data;
index 323bace..3b3b1b2 100644 (file)
@@ -23,6 +23,7 @@ void register_machines(void)
     qemu_register_machine(&mainstone2_machine);
     qemu_register_machine(&musicpal_machine);
     qemu_register_machine(&tosapda_machine);
+    qemu_register_machine(&beagle_machine);
 }
 
 void cpu_save(QEMUFile *f, void *opaque)
@@ -49,6 +50,9 @@ void cpu_save(QEMUFile *f, void *opaque)
     qemu_put_be32(f, env->cp15.c1_sys);
     qemu_put_be32(f, env->cp15.c1_coproc);
     qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
+    qemu_put_be32(f, env->cp15.c1_secfg);
+    qemu_put_be32(f, env->cp15.c1_sedbg);
+    qemu_put_be32(f, env->cp15.c1_nseac);
     qemu_put_be32(f, env->cp15.c2_base0);
     qemu_put_be32(f, env->cp15.c2_base1);
     qemu_put_be32(f, env->cp15.c2_mask);
@@ -144,6 +148,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     env->cp15.c1_sys = qemu_get_be32(f);
     env->cp15.c1_coproc = qemu_get_be32(f);
     env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
+    env->cp15.c1_secfg = qemu_get_be32(f);
+    env->cp15.c1_sedbg = qemu_get_be32(f);
+    env->cp15.c1_nseac = qemu_get_be32(f);
     env->cp15.c2_base0 = qemu_get_be32(f);
     env->cp15.c2_base1 = qemu_get_be32(f);
     env->cp15.c2_mask = qemu_get_be32(f);
index 9e51464..f71162b 100644 (file)
@@ -307,7 +307,7 @@ void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
 uint32_t HELPER (add_cc)(uint32_t a, uint32_t b)
 {
     uint32_t result;
-    result = T0 + T1;
+    result = a + b;
     env->NF = env->ZF = result;
     env->CF = result < a;
     env->VF = (a ^ b ^ -1) & (a ^ result);
index f7f2a8d..d846b9c 100644 (file)
@@ -191,6 +191,14 @@ static void store_reg(DisasContext *s, int reg, TCGv var)
     dead_tmp(var);
 }
 
+/* Variant of store_reg which uses branch&exchange logic when storing
+   to r15 in ARM architecture v7 and above. The source must be a temporary
+   and will be marked as dead. */
+#define store_reg_bx(dc, reg, var) \
+    if ((reg) == 15 && ENABLE_ARCH_7) \
+        gen_bx((dc), (var)); \
+    else \
+        store_reg((dc), (reg), (var));
 
 /* Basic operations.  */
 #define gen_op_movl_T0_T1() tcg_gen_mov_i32(cpu_T[0], cpu_T[1])
@@ -436,6 +444,16 @@ static void gen_adc_T0_T1(void)
     dead_tmp(tmp);
 }
 
+/* dest = T0 + T1 + CF. */
+static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
+{
+    TCGv tmp;
+    tcg_gen_add_i32(dest, t0, t1);
+    tmp = load_cpu_field(CF);
+    tcg_gen_add_i32(dest, dest, tmp);
+    dead_tmp(tmp);
+}
+
 /* dest = T0 - T1 + CF - 1.  */
 static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
 {
@@ -3446,11 +3464,11 @@ static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr)
     return 0;
 }
 
-/* Generate an old-style exception return.  */
-static void gen_exception_return(DisasContext *s)
+/* Generate an old-style exception return. Marks pc as dead. */
+static void gen_exception_return(DisasContext *s, TCGv pc)
 {
     TCGv tmp;
-    gen_movl_reg_T0(s, 15);
+    store_reg(s, 15, pc);
     tmp = load_cpu_field(spsr);
     gen_set_cpsr(tmp, 0xffffffff);
     dead_tmp(tmp);
@@ -6017,11 +6035,22 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             dead_tmp(tmp2);
             store_reg(s, rd, tmp);
             break;
-        case 7: /* bkpt */
-            gen_set_condexec(s);
-            gen_set_pc_im(s->pc - 4);
-            gen_exception(EXCP_BKPT);
-            s->is_jmp = DISAS_JUMP;
+        case 7:
+            if (op1 == 1) {
+                /* bkpt */
+                gen_set_condexec(s);
+                gen_set_pc_im(s->pc - 4);
+                gen_exception(EXCP_BKPT);
+                s->is_jmp = DISAS_JUMP;
+            } else if (op1 == 3) {
+                /* smi/smc */
+                if (!(env->cp15.c0_c2[4] & 0xf000) || IS_USER(s))
+                    goto illegal_op;
+                /* TODO: real implementation; execute as NOP for now */
+                /*fprintf(stderr, "smc [0x%08x] pc=0x%08x\n", insn, s->pc);*/
+            } else {
+                goto illegal_op;
+            }
             break;
         case 0x8: /* signed multiply */
         case 0xa:
@@ -6089,146 +6118,151 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             shift = ((insn >> 8) & 0xf) * 2;
             if (shift)
                 val = (val >> shift) | (val << (32 - shift));
-            gen_op_movl_T1_im(val);
+            tmp2 = new_tmp();
+            tcg_gen_movi_i32(tmp2, val);
             if (logic_cc && shift)
-                gen_set_CF_bit31(cpu_T[1]);
+                gen_set_CF_bit31(tmp2);
         } else {
             /* register */
             rm = (insn) & 0xf;
-            gen_movl_T1_reg(s, rm);
+            tmp2 = load_reg(s, rm);
             shiftop = (insn >> 5) & 3;
             if (!(insn & (1 << 4))) {
                 shift = (insn >> 7) & 0x1f;
-                gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
+                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
             } else {
                 rs = (insn >> 8) & 0xf;
                 tmp = load_reg(s, rs);
-                gen_arm_shift_reg(cpu_T[1], shiftop, tmp, logic_cc);
+                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
             }
         }
         if (op1 != 0x0f && op1 != 0x0d) {
             rn = (insn >> 16) & 0xf;
-            gen_movl_T0_reg(s, rn);
-        }
+            tmp = load_reg(s, rn);
+        } else
+            tmp = new_tmp();
         rd = (insn >> 12) & 0xf;
         switch(op1) {
         case 0x00:
-            gen_op_andl_T0_T1();
-            gen_movl_reg_T0(s, rd);
+            tcg_gen_and_i32(tmp, tmp, tmp2);
             if (logic_cc)
-                gen_op_logic_T0_cc();
+                gen_logic_CC(tmp);
+            store_reg_bx(s, rd, tmp);
             break;
         case 0x01:
-            gen_op_xorl_T0_T1();
-            gen_movl_reg_T0(s, rd);
+            tcg_gen_xor_i32(tmp, tmp, tmp2);
             if (logic_cc)
-                gen_op_logic_T0_cc();
+                gen_logic_CC(tmp);
+            store_reg_bx(s, rd, tmp);
             break;
         case 0x02:
             if (set_cc && rd == 15) {
                 /* SUBS r15, ... is used for exception return.  */
                 if (IS_USER(s))
                     goto illegal_op;
-                gen_op_subl_T0_T1_cc();
-                gen_exception_return(s);
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+                gen_exception_return(s, tmp);
             } else {
                 if (set_cc)
-                    gen_op_subl_T0_T1_cc();
+                    gen_helper_sub_cc(tmp, tmp, tmp2);
                 else
-                    gen_op_subl_T0_T1();
-                gen_movl_reg_T0(s, rd);
+                    tcg_gen_sub_i32(tmp, tmp, tmp2);
+                store_reg_bx(s, rd, tmp);
             }
             break;
         case 0x03:
             if (set_cc)
-                gen_op_rsbl_T0_T1_cc();
+                gen_helper_sub_cc(tmp, tmp2, tmp);
             else
-                gen_op_rsbl_T0_T1();
-            gen_movl_reg_T0(s, rd);
+                tcg_gen_sub_i32(tmp, tmp2, tmp);
+            store_reg_bx(s, rd, tmp);
             break;
         case 0x04:
             if (set_cc)
-                gen_op_addl_T0_T1_cc();
+                gen_helper_add_cc(tmp, tmp, tmp2);
             else
-                gen_op_addl_T0_T1();
-            gen_movl_reg_T0(s, rd);
+                tcg_gen_add_i32(tmp, tmp, tmp2);
+            store_reg_bx(s, rd, tmp);
             break;
         case 0x05:
             if (set_cc)
-                gen_op_adcl_T0_T1_cc();
+                gen_helper_adc_cc(tmp, tmp, tmp2);
             else
-                gen_adc_T0_T1();
-            gen_movl_reg_T0(s, rd);
+                gen_add_carry(tmp, tmp, tmp2);
+            store_reg_bx(s, rd, tmp);
             break;
         case 0x06:
             if (set_cc)
-                gen_op_sbcl_T0_T1_cc();
+                gen_helper_sbc_cc(tmp, tmp, tmp2);
             else
-                gen_sbc_T0_T1();
-            gen_movl_reg_T0(s, rd);
+                gen_sub_carry(tmp, tmp, tmp2);
+            store_reg_bx(s, rd, tmp);
             break;
         case 0x07:
             if (set_cc)
-                gen_op_rscl_T0_T1_cc();
+                gen_helper_sbc_cc(tmp, tmp2, tmp);
             else
-                gen_rsc_T0_T1();
-            gen_movl_reg_T0(s, rd);
+                gen_sub_carry(tmp, tmp2, tmp);
+            store_reg_bx(s, rd, tmp);
             break;
         case 0x08:
             if (set_cc) {
-                gen_op_andl_T0_T1();
-                gen_op_logic_T0_cc();
+                tcg_gen_and_i32(tmp, tmp, tmp2);
+                gen_logic_CC(tmp);
             }
+            dead_tmp(tmp);
             break;
         case 0x09:
             if (set_cc) {
-                gen_op_xorl_T0_T1();
-                gen_op_logic_T0_cc();
+                tcg_gen_xor_i32(tmp, tmp, tmp2);
+                gen_logic_CC(tmp);
             }
+            dead_tmp(tmp);
             break;
         case 0x0a:
-            if (set_cc) {
-                gen_op_subl_T0_T1_cc();
-            }
+            if (set_cc)
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+            dead_tmp(tmp);
             break;
         case 0x0b:
-            if (set_cc) {
-                gen_op_addl_T0_T1_cc();
-            }
+            if (set_cc)
+                gen_helper_add_cc(tmp, tmp, tmp2);
+            dead_tmp(tmp);
             break;
         case 0x0c:
-            gen_op_orl_T0_T1();
-            gen_movl_reg_T0(s, rd);
+            tcg_gen_or_i32(tmp, tmp, tmp2);
             if (logic_cc)
-                gen_op_logic_T0_cc();
+                gen_logic_CC(tmp);
+            store_reg_bx(s, rd, tmp);
             break;
         case 0x0d:
+            tcg_gen_mov_i32(tmp, tmp2);
             if (logic_cc && rd == 15) {
                 /* MOVS r15, ... is used for exception return.  */
                 if (IS_USER(s))
                     goto illegal_op;
-                gen_op_movl_T0_T1();
-                gen_exception_return(s);
+                gen_exception_return(s, tmp);
             } else {
-                gen_movl_reg_T1(s, rd);
+                store_reg_bx(s, rd, tmp);
                 if (logic_cc)
-                    gen_op_logic_T1_cc();
+                    gen_logic_CC(tmp2);
             }
             break;
         case 0x0e:
-            gen_op_bicl_T0_T1();
-            gen_movl_reg_T0(s, rd);
+            tcg_gen_bic_i32(tmp, tmp, tmp2);
             if (logic_cc)
-                gen_op_logic_T0_cc();
+                gen_logic_CC(tmp);
+            store_reg_bx(s, rd, tmp);
             break;
         default:
         case 0x0f:
-            gen_op_notl_T1();
-            gen_movl_reg_T1(s, rd);
+            tcg_gen_not_i32(tmp, tmp2);
             if (logic_cc)
-                gen_op_logic_T1_cc();
+                gen_logic_CC(tmp);
+            store_reg_bx(s, rd, tmp);
             break;
         }
+        dead_tmp(tmp2);
     } else {
         /* other instructions */
         op1 = (insn >> 24) & 0xf;
index e0fd434..7cb51b5 100644 (file)
@@ -560,6 +560,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
     /* add x(r1), r0 */
     tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) - 
                          offsetof(CPUTLBEntry, addr_read));
+#elif defined(CONFIG_USE_GUEST_BASE)
+    /*
+     * Add guest_base to all loads.
+     */
+    tcg_out_mov(s, r0, addr_reg);    /* movl addr_reg, r0 */
+    tcg_out_addi(s, r0, GUEST_BASE); /* addl $GUEST_BASE, r0 */
 #else
     r0 = addr_reg;
 #endif
@@ -794,6 +800,12 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
     /* add x(r1), r0 */
     tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) - 
                          offsetof(CPUTLBEntry, addr_write));
+#elif defined(CONFIG_USE_GUEST_BASE)
+    /*
+     * Add guest_base to all stores.
+     */
+    tcg_out_mov(s, r0, addr_reg);    /* movl addr_reg, r0 */
+    tcg_out_addi(s, r0, GUEST_BASE); /* addl $GUEST_BASE, r0 */
 #else
     r0 = addr_reg;
 #endif
index 92f0733..204ab2a 100644 (file)
@@ -605,6 +605,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
     /* add x(r1), r0 */
     tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - 
                          offsetof(CPUTLBEntry, addr_read));
+#elif defined(CONFIG_USE_GUEST_BASE)
+    /*
+     * Add guest_base to all loads.
+     */
+    tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); /* movq addr_reg, r0 */
+    tcg_out_addi(s, r0, GUEST_BASE);             /* addq $GUEST_BASE, r0 */
 #else
     r0 = addr_reg;
 #endif    
@@ -776,6 +782,12 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
     /* add x(r1), r0 */
     tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - 
                          offsetof(CPUTLBEntry, addr_write));
+#elif defined(CONFIG_USE_GUEST_BASE)
+    /*
+     * Add guest_base to all stores.
+     */
+    tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); /* movq addr_reg, r0 */
+    tcg_out_addi(s, r0, GUEST_BASE);             /* addq $GUEST_BASE, r0 */
 #else
     r0 = addr_reg;
 #endif