From: Juha Riihimäki Date: Thu, 2 Apr 2009 09:11:11 +0000 (+0300) Subject: Merge commit 'origin/upstream' into juha-devel X-Git-Tag: 0.10.0-0maemo4~1^2~1 X-Git-Url: http://git.maemo.org/git/?a=commitdiff_plain;h=8fe7f96b91bc06948da02d0592d57bd5ced75020;hp=714fa308a3f86e1dc55021ff1282c1afe6954d3d;p=qemu Merge commit 'origin/upstream' into juha-devel --- diff --git a/Makefile b/Makefile index 2bee52c..ce78d78 100644 --- 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.* diff --git a/Makefile.target b/Makefile.target index 046427d..35250b7 100644 --- a/Makefile.target +++ b/Makefile.target @@ -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 diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 9671429..c865775 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -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 index 0000000..1852eff --- /dev/null +++ b/block-vmstate.c @@ -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 --- 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 --- 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 --- 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]) { diff --git a/configure b/configure index 5c62c59..63e7ad9 100755 --- 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 +#include +#include + +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 diff --git a/cpu-all.h b/cpu-all.h index 366f47e..04f436b 100644 --- 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 index 0000000..de0b0ab --- /dev/null +++ b/debian/README.Debian @@ -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 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 , Sun May 15 09:49:11 2005 + diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..1552399 --- /dev/null +++ b/debian/changelog @@ -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 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 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 Mon, 09 Mar 2009 14:53:44 +0200 + +qemu (0.10.0-0maemo1) unstable; urgency=low + + * New upstream version + * merge maemo patches + + -- Riku Voipio Thu, 05 Mar 2009 11:50:07 +0200 + +qemu (0.9.1+svn20090113-0maemo1) unstable; urgency=low + + * maemo patched version + + -- Riku Voipio 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 . + - 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 . + - 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 . + - 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 . + - 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 . + - debian/patches/35_syscall_sockaddr.patch: Updated. + * Fix semctl() for 32 bit targets on 64 bit hosts. (Closes: #414809) + Thanks to Stuart Anderson . + - debian/patches/38_syscall_semctl.patch: New file. + * Remove Elrond from Uploaders with consent, always welcome to join + back anytime. + + -- Guillem Jover 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 . + * 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 . + + -- Guillem Jover 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 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 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 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 . + * On install use DESTDIR instead of specifying all paths. (Closes: #396139) + Thanks to Anderson Lizardo . + * 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 . + * 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 . + * Add experimental ncurses ui support. (Closes: #369462) + - debian/patches/80_ui_curses.patch: New file. + Thanks to Andrzej Zaborowski . + * 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 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 . + * 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 . + * Document the binary blob removals from the original upstream tarball in + README.Debian. (Closes: #388740) + + -- Guillem Jover 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 . (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 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 . + * Remove now default '--enable-slirp' build option. (Closes: #356284) + Thanks to Anderson Lizardo . + * Remove unused sharedir to 'make install'. (Closes: #356418) + Thanks to Anderson Lizardo . + * Fix package not cleaning properly. (Closes: #356279) + Thanks to Anderson Lizardo 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 . + * Remove obsolete Build-Dependency xlibs-dev. + + -- Guillem Jover 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 . + * 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 . + + -- Guillem Jover 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 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 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 . + * 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 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 . + * 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 . + * Change documentation menu section to "Apps/Emulators". (Closes: #335062) + Thanks to Frans Pop . + * 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 + and Paul Brook . + * 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 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 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 . + * Link against librt, needed by the new clock_gettime syscall. + - debian/patches/31_syscalls.patch: Update. (Closes: #315388) + Thanks to Timo Savola 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 . + * Include 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 . + * Fix powerpc linker script. + - debian/patches/50_ppc_ldscript.patch: New file. + Thanks to Octavian Cerna . + + -- Guillem Jover 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 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 . + + [ 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 . + + [ 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 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 . + * Added Elrond 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: + + * 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 , 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 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 . + * 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 . + * 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 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 . + * 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 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 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 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 . + * 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 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 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 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 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 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 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 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 Fri, 12 Mar 2004 05:43:00 +0100 + +qemu (0.5.2-1) unstable; urgency=low + + * Initial Release. (Closes: #187407) + + -- Paul Russell Wed, 3 Mar 2004 02:18:54 +0100 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..49163b6 --- /dev/null +++ b/debian/control @@ -0,0 +1,34 @@ +Source: qemu +Section: misc +Priority: optional +Maintainer: Maemo Integration +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 index 0000000..35348bd --- /dev/null +++ b/debian/copyright @@ -0,0 +1,53 @@ +This package was debianized by Paul Russell on +Wed, 3 Mar 2004 02:18:54 +0100. + +Then maintained as part of the team by: + + Guilherme de S. Pastore + Elrond + Guillem Jover + +Now maintained as a team by: + + Aurelien Jarno + Josh Triplett + Riku Voipio + +The upstream source was downloaded from: + + + + 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 + +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 index 0000000..164f458 --- /dev/null +++ b/debian/cputransp-methods @@ -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 index 0000000..5e81b13 --- /dev/null +++ b/debian/overrides/qemu @@ -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 index 0000000..c9e1e9e --- /dev/null +++ b/debian/qemu-user.1 @@ -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\fP" +Set the elf interpreter prefix (default=\fI/usr/gnemul/qemu\-arm\fP). +.TP +.BR \-s " \fI\fP" +Set the stack size in bytes (default=\fI524288\fP). +.TP +.BR \-d " \fI\fP" +Activate log (logfile=\fI/tmp/qemu.log\fP) +.TP +.BR \-p " \fI\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 . diff --git a/debian/qemu.dirs b/debian/qemu.dirs new file mode 100644 index 0000000..58660d4 --- /dev/null +++ b/debian/qemu.dirs @@ -0,0 +1 @@ +usr/share/qemu/ diff --git a/debian/qemu.doc-base b/debian/qemu.doc-base new file mode 100644 index 0000000..d3b0f8a --- /dev/null +++ b/debian/qemu.doc-base @@ -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 index 0000000..d227b95 --- /dev/null +++ b/debian/qemu.docs @@ -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 index 0000000..f3da625 --- /dev/null +++ b/debian/qemu.install @@ -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 index 0000000..8f0732b --- /dev/null +++ b/debian/qemu.links @@ -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 index 0000000..ae4f28d --- /dev/null +++ b/debian/qemu.manpages @@ -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 index 0000000..b0743d8 --- /dev/null +++ b/debian/rules @@ -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 index 0000000..43ed62a --- /dev/null +++ b/debian/tundev.c @@ -0,0 +1,90 @@ +/* + * $Id: tundev.c 325 2008-08-09 21:39:16Z aurel32 $ + */ + +#define _GNU_SOURCE /* asprintf */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 ...\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 index 0000000..b33ee8e --- /dev/null +++ b/debian/watch @@ -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 --- 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 --- 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 index 0000000..613d1c2 --- /dev/null +++ b/hw/beagle.c @@ -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, +}; + diff --git a/hw/boards.h b/hw/boards.h index 1e18ba6..8dfe2fd 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -127,4 +127,7 @@ extern QEMUMachine musicpal_machine; /* tosa.c */ extern QEMUMachine tosapda_machine; +/* beagle.c */ +extern QEMUMachine beagle_machine; + #endif diff --git a/hw/devices.h b/hw/devices.h index a8afa94..92518c5 100644 --- a/hw/devices.h +++ b/hw/devices.h @@ -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); diff --git a/hw/flash.h b/hw/flash.h index faba93d..8cbd9e0 100644 --- a/hw/flash.h +++ b/hw/flash.h @@ -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 diff --git a/hw/gumstix.c b/hw/gumstix.c index 70abbdc..dfa239b 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -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 = { diff --git a/hw/i2c.h b/hw/i2c.h index 396c562..7a80bcb 100644 --- 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 diff --git a/hw/integratorcp.c b/hw/integratorcp.c index f990afe..145ae4d 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -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; diff --git a/hw/mainstone.c b/hw/mainstone.c index 5f4cc91..36c6f4b 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -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; diff --git a/hw/nand.c b/hw/nand.c index e73a1b8..2cadbe4 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -6,6 +6,10 @@ * Copyright (c) 2006 Openedhand Ltd. * Written by Andrzej Zaborowski * + * 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; } diff --git a/hw/nseries.c b/hw/nseries.c index 0c7da77..2d12705 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -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); diff --git a/hw/omap.h b/hw/omap.h index e940474..41fef42 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -35,18 +35,26 @@ # 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) */ diff --git a/hw/omap1.c b/hw/omap1.c index c32d3f7..e38b918 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -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 */ diff --git a/hw/omap2.c b/hw/omap2.c index 20b3811..895a1c7 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -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 index 0000000..5e0d89d --- /dev/null +++ b/hw/omap3.c @@ -0,0 +1,4778 @@ +/* + * TI OMAP3 processors emulation. + * + * Copyright (C) 2008 yajin + * 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 index 0000000..e0c61a9 --- /dev/null +++ b/hw/omap3_boot.c @@ -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 index 0000000..dc56f03 --- /dev/null +++ b/hw/omap3_lcd_panel_template.h @@ -0,0 +1,150 @@ +/* + * QEMU Epson S1D13744/S1D13745 templates + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski + * + * QEMU OMAP3 LCD Panel Emulation templates + * + * Copyright (c) 2008 yajin + * + * 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 index 0000000..402db19 --- /dev/null +++ b/hw/omap3_mmc.c @@ -0,0 +1,793 @@ +/* + * OMAP3 Multimedia Card/Secure Digital/Secure Digital I/O (MMC/SD/SDIO) Card Interface emulation + * + * Copyright (C) 2008 yajin + * 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 index 0000000..ebb0eef --- /dev/null +++ b/hw/omap3_usb.c @@ -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; +} + diff --git a/hw/omap_clk.c b/hw/omap_clk.c index d7a5a57..f4d20bc 100644 --- a/hw/omap_clk.c +++ b/hw/omap_clk.c @@ -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; diff --git a/hw/omap_dma.c b/hw/omap_dma.c index 6df3800..0497988 100644 --- a/hw/omap_dma.c +++ b/hw/omap_dma.c @@ -23,6 +23,15 @@ #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; } diff --git a/hw/omap_dss.c b/hw/omap_dss.c index 67b2b02..0ddd403 100644 --- a/hw/omap_dss.c +++ b/hw/omap_dss.c @@ -21,6 +21,35 @@ #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; +} diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index 258730b..96e1b4b 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -2,6 +2,7 @@ * TI OMAP on-chip I2C controller. Only "new I2C" mode supported. * * Copyright (C) 2007 Andrzej Zaborowski + * 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 @@ -21,102 +22,138 @@ #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 index 0000000..b24eb65 --- /dev/null +++ b/hw/omap_spi.c @@ -0,0 +1,644 @@ +/* + * TI OMAP processor's Multichannel SPI emulation. + * + * Copyright (C) 2007-2009 Nokia Corporation + * + * Original code for OMAP2 by Andrzej Zaborowski + * + * 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; +} diff --git a/hw/onenand.c b/hw/onenand.c index 510119f..694d03a 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -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; } diff --git a/hw/realview.c b/hw/realview.c index aae4b86..aa67c4f 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -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 --- 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 <<= 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; } diff --git a/hw/smc91c111.c b/hw/smc91c111.c index f5b29a7..50160ad 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -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; } diff --git a/hw/soc_dma.c b/hw/soc_dma.c index 2967b52..c66cf7b 100644 --- a/hw/soc_dma.c +++ b/hw/soc_dma.c @@ -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; } diff --git a/hw/soc_dma.h b/hw/soc_dma.h index 47bc4ea..1977773 100644 --- a/hw/soc_dma.h +++ b/hw/soc_dma.h @@ -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; diff --git a/hw/tsc2005.c b/hw/tsc2005.c index e8d4a85..68b18c4 100644 --- a/hw/tsc2005.c +++ b/hw/tsc2005.c @@ -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, diff --git a/hw/tusb6010.c b/hw/tusb6010.c index d6847d0..dfd2824 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -26,6 +26,15 @@ #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 index 0000000..b4dc11e --- /dev/null +++ b/hw/twl4030.c @@ -0,0 +1,1146 @@ +/* + * TI TWL4030 for beagle board + * + * Copyright (C) 2008 yajin + * 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; +} diff --git a/hw/usb-hid.c b/hw/usb-hid.c index c850a91..8a6661d 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -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, diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 9f26bbe..f7cebed 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -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; } diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 8e1e6eb..5d91973 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -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 */ @@ -112,7 +113,7 @@ */ /* 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 @@ -126,7 +127,7 @@ #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 @@ -134,7 +135,7 @@ #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 @@ -249,6 +250,15 @@ #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; +} diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index e59bc8a..3766a76 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -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; +} diff --git a/hw/versatilepb.c b/hw/versatilepb.c index d80e2f2..ca34619 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -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"); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 6de30f4..706c8e2 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1,4 +1,6 @@ /* This is the Linux kernel elf-loading code, ported into user space */ +#include +#include #include #include @@ -8,6 +10,7 @@ #include #include #include +#include #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 . 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__-