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
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 \
TAGS:
etags *.[ch] tests/*.[ch]
+tags:
+ find . -name "*.[ch]" -print | xargs ctags
cscope:
rm -f ./cscope.*
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)
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
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;
static void coreaudio_logstatus (OSStatus status)
{
- char *str = "BUG";
+ const char *str = "BUG";
switch(status) {
case kAudioHardwareNoError:
break;
default:
- AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
+ AUD_log (AUDIO_CAP, "Reason: status code %d\n", status);
return;
}
&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;
}
}
/* 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;
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;
}
}
/* 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");
}
--- /dev/null
+/*
+ * 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
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,
extern BlockDriver bdrv_qcow2;
extern BlockDriver bdrv_parallels;
extern BlockDriver bdrv_nbd;
+extern BlockDriver bdrv_vmstate;
typedef struct BlockDriverInfo {
/* in bytes, 0 if irrelevant */
NSWindow *normalWindow;
id cocoaView;
static DisplayChangeListener *dcl;
+static int last_vm_running;
int gArgc;
char **gArgv;
*/
};
-int cocoa_keycode_to_qemu(int keycode)
+static int cocoa_keycode_to_qemu(int keycode)
{
if((sizeof(keymap)/sizeof(int)) <= keycode)
{
- (float) cdx;
- (float) cdy;
- (QEMUScreen) gscreen;
+- (void) updateCaption;
@end
@implementation QemuCocoaView
[super dealloc];
}
+- (BOOL) isOpaque
+{
+ return YES;
+}
+
- (void) drawRect:(NSRect) rect
{
COCOA_DEBUG("QemuCocoaView: drawRect\n");
} 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;
[[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];
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;
}
}
- (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;}
[normalWindow setContentView:cocoaView];
[normalWindow makeKeyAndOrderFront:self];
[normalWindow center];
-
+ [cocoaView updateCaption];
}
return self;
}
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 );
w * [cocoaView cdx],
h * [cocoaView cdy]);
}
- [cocoaView displayRect:rect];
+ [cocoaView setNeedsDisplayInRect:rect];
}
static void cocoa_resize(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]) {
linux_user="no"
darwin_user="no"
bsd_user="no"
+guest_base="no"
build_docs="no"
uname_release=""
curses="yes"
;;
--enable-bsd-user) bsd_user="yes"
;;
+ --enable-guest-base) guest_base="yes"
+ ;;
--enable-uname-release=*) uname_release="$optarg"
;;
--sparc_cpu=*)
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"
fi
fi
+##########################################
+# Check for xxxat() functions when we are building linux-user
+# emulator. This is done because older glibc versions don't
+# have syscall stubs for these implemented. In that case we
+# don't provide them even if kernel supports them.
+#
+atfile=no
+if [ "$linux_user" = "yes" ] ; then
+ cat > $TMPC << EOF
+#define _ATFILE_SOURCE
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+ /* try to unlink nonexisting file */
+ return (unlinkat(AT_FDCWD, "nonexistent_file", 0));
+}
+EOF
+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+ atfile=yes
+ fi
+fi
+
# Check if tools are available to build documentation.
if [ -x "`which texi2html 2>/dev/null`" ] && \
[ -x "`which pod2man 2>/dev/null`" ]; then
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
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"
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
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
/* 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))
#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);
--- /dev/null
+qemu for Debian
+---------------
+
+The qemu debian package does not include the video.x file, which is
+needed by qemu-system-ppc for some systems. The file is available from
+the mac-on-linux project, and the sources are available on:
+ http://mac-on-linux.svn.sourceforge.net/viewvc/mac-on-linux/mac-drivers/video_driver/Makefile?revision=HEAD&view=markup
+
+They are not buildable on a Debian system though, hence video.x is not
+present in the package. The qemu-system-ppc binary is still useful for
+emulating a PReP platform, which does not need video.x.
+
+ -- Aurelien Jarno <aurel32@debian.org> Sun, 16 Mar 2008 19:17:39 +0100
+
+
+The qemu debian package includes a simple script called qemu-make-debian-root
+under /usr/sbin, which uses debootstrap to create an image suitable for qemu
+with a fresh Debian installation inside.
+
+If you just want a test system, not wanting to go through any installation
+process, that might be just ideal. Take a look at the manual page
+qemu-make-debian-root (8) for further usage instructions.
+
+ -- Guilherme de S. Pastore <gpastore@colband.com.br>, Sun May 15 09:49:11 2005
+
--- /dev/null
+qemu (0.10.0-0maemo4) unstable; urgency=low
+
+ * Riku voipio
+ - fix conditional sb1-qemu build
+ - split system qemu to a different package, so sb2-qemu has less
+ dependencies
+ - basic usb-musb support for omap3
+ - smc91x networking support
+ * Jussi Hakala:
+ - fix sbox-call
+ - make sb1 packaging more scratchboxy
+ * Juha Riihimäki
+ - SPI support
+ - lots of fixes and cleanups
+ - qemu snapshotting support
+
+ -- Riku Voipio <riku.voipio@iki.fi> Thu, 26 Mar 2009 14:46:21 +0200
+
+qemu (0.10.0-0maemo3) unstable; urgency=low
+
+ * debian/
+ make building sb1-qemu conditional
+ * MW:
+ linux-user: removed unnecessary MAX_SOCK_ADDR checks for socket syscalls
+ * Riku:
+ Convert musb fifo to 8bit to allow 8/16/32bit access
+ Make USB devices self-powered
+ add some USB registers
+ fix omap3_usb interrupt raising
+ * Juha
+ let beagleboard understand the -m switch
+ arm core emulation performance improvement
+ omap3 prcm and clocks clean-up
+ omap3 bootrom emulations
+
+ -- Riku Voipio <riku.voipio@iki.fi> Thu, 19 Mar 2009 16:33:06 +0200
+
+qemu (0.10.0-0maemo2) unstable; urgency=low
+
+ * Add guest-base support
+ * merge upstream
+ * more omap3 fixes
+
+ -- Riku Voipio <riku.voipio@iki.fi> Mon, 09 Mar 2009 14:53:44 +0200
+
+qemu (0.10.0-0maemo1) unstable; urgency=low
+
+ * New upstream version
+ * merge maemo patches
+
+ -- Riku Voipio <riku.voipio@iki.fi> Thu, 05 Mar 2009 11:50:07 +0200
+
+qemu (0.9.1+svn20090113-0maemo1) unstable; urgency=low
+
+ * maemo patched version
+
+ -- Riku Voipio <riku.voipio@iki.fi> Wed, 28 Jan 2009 11:18:41 +0200
+
+qemu (0.9.1+svn20090104-1) experimental; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ * Disable security/CVE-2008-0928-fedora.patch, it still breaks qcow
+ format.
+
+ -- Aurelien Jarno <aurel32@debian.org> Sun, 04 Jan 2009 16:31:40 +0100
+
+qemu (0.9.1+svn20081223-1) experimental; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ - Fix CVE-2008-2382
+ * Update patches/48_signal_terminate.patch.
+ * debian/rules: remove upstream flags from CFLAGS.
+
+ -- Aurelien Jarno <aurel32@debian.org> Tue, 23 Dec 2008 14:51:25 +0100
+
+qemu (0.9.1+svn20081214-1) experimental; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ - Fix jmp im on x86_64 when executing 32-bit code. Fix grub
+ installation (Closes: bug#467148).
+
+ -- Aurelien Jarno <aurel32@debian.org> Sun, 14 Dec 2008 23:26:04 +0100
+
+qemu (0.9.1+svn20081207-1) experimental; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ - Do not depend on gcc-3.4 anymore (Closes: bug#440425, bug#463066).
+ - Fix broken display introduced by CVE-2007-1320 (Closes: bug#422578).
+ * debian/control: remove build-dependency on gcc-3.4.
+ * debian/rules: remove code for dyngen targets.
+ * Split 90_security.patch into
+ - security/CVE-2007-5730.patch
+ - security/leftover.patch
+ * Replace 91_security.patch by security/CVE-2008-0928-fedora.patch taken
+ from fedora repository and enable it (Closes: #469649).
+
+ [ Riku Voipio ]
+ * 2 patches gone, 19 to go:
+ - 10_signal_jobs.patch: drop, merged upstream
+ - 11_signal_sigaction.patch: drop, merged upstream
+ - series: update
+
+ -- Aurelien Jarno <aurel32@debian.org> Sun, 07 Dec 2008 19:40:09 +0100
+
+qemu (0.9.1+svn20081128-1) experimental; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ - Include documentation for network downscript option (Closes:
+ bug#506994).
+ - Drop 00_bios.patch and pass --disable-blobs instead.
+ - Update 12_signal_powerpc_support.patch.
+
+ [ Riku Voipio ]
+ * Drop 31_syscalls.patch as it makes no sense using host uselib to
+ load target code into qemu's host memoryspace.
+
+ -- Aurelien Jarno <aurel32@debian.org> Sat, 29 Nov 2008 09:04:41 +0100
+
+qemu (0.9.1+svn20081112-1) experimental; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ - does not need a disk image anymore (Closes: bug#260935).
+ - 53_openbios_size.patch: drop (merged upstream).
+ - 90_security: update.
+ * debian/control: depend on openbios-sparc (>= 1.0~alpha2+20081109)
+ (Closes: bug#502411, bug#502414).
+
+ -- Aurelien Jarno <aurel32@debian.org> Sun, 09 Nov 2008 14:42:37 +0100
+
+qemu (0.9.1+svn20081101-1) experimental; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ - fix a heap overflow in Cirrus emulation (CVE-2008-4539).
+ - 50_linuxbios_isa_bios_ram.patch: update.
+ - 90_security.patch: update.
+
+ -- Aurelien Jarno <aurel32@debian.org> Sat, 01 Nov 2008 09:26:45 +0100
+
+qemu (0.9.1+svn20081023-1) experimental; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ - 12_signal_powerpc_support.patch: update.
+ - 50_linuxbios_isa_bios_ram.patch: update.
+
+ -- Aurelien Jarno <aurel32@debian.org> Thu, 23 Oct 2008 21:34:26 +0200
+
+qemu (0.9.1+svn20081016-1) experimental; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ * patches/31_syscalls.patch: remove parts merged upstream.
+ * debian/qemu-make-debian-root:
+ - Fix bug introduced when fixing bug#496394 (Closes: bug#502325).
+
+ -- Aurelien Jarno <aurel32@debian.org> Mon, 13 Oct 2008 23:11:15 +0200
+
+qemu (0.9.1+svn20081012-1) experimental; urgency=low
+
+ [ Riku Voipio ]
+ * Add a bunch of patches from scratchbox
+ - 44_socklen_t_check work better with badbehavin net apps
+ - 48_signal_terminate make qemu binary terminate on signals as expected
+ - 49_null_checks don't bother some syscalls when null/zero is passed
+
+ [ Aurelien Jarno ]
+ * New upstream snapshot.
+ - alpha is now a TCG target.
+ - comma has been added to sendkey (closes: bug#414342).
+ * patches/31_syscalls.patch: remove parts merged upstream.
+ * patches/39_syscall_fadvise64.patch: remove (merged upstream).
+ * patches/90_security.patch: remove parts merged upstream.
+ * debian/control: build-depends on libbluetooth-dev.
+
+ -- Aurelien Jarno <aurel32@debian.org> Sun, 12 Oct 2008 18:46:54 +0200
+
+qemu (0.9.1+svn20080905-1) experimental; urgency=low
+
+ * New upstream snapshot.
+ - SH4 is now a TCG target.
+ * debian/watch: update URL location.
+
+ -- Aurelien Jarno <aurel32@debian.org> Tue, 02 Sep 2008 01:43:24 +0200
+
+qemu (0.9.1+svn20080826-1) experimental; urgency=low
+
+ * New upstream snapshot.
+ * debian/qemu-make-debian-root:
+ - Use mktemp instead of $$ to create temporary directories (Closes:
+ bug#496394).
+ * Ship a libqemu-dev package (Closes: bug#451618).
+
+ -- Aurelien Jarno <aurel32@debian.org> Tue, 26 Aug 2008 09:55:36 +0200
+
+qemu (0.9.1+svn20080822-1) experimental; urgency=low
+
+ * New upstream snapshot.
+ - Focus to monitor to ask password (Closes: bug#473240).
+ - TCG SPARC host support (Closes: bug#450817).
+ - Check KQEMU availability before allocating memory (Closes: bug#414566).
+ - Fix dead keys (Closes: bug#489594).
+ - Fix ES1370 emulation (Closes: bug#494462).
+ - New USB UHCI implemnation (Closes: bug#457651).
+ - Add debian/patches/00_bios.patch.
+ - Remove debian/patches/02_snapshot_use_tmpdir.patch (merged).
+ - Remove debian/patches/04_do_not_print_rtc_freq_if_ok.patch (merged).
+ - Remove patches/05_non-fatal_if_linux_hd_missing.patch (merged).
+ - Update debian/patches/07_i386_exec_name.patch
+ - Update debian/patches/12_signal_powerpc_support.patch
+ - Remove debian/patches/33_syscall_ppc_clone.patch (merged differently).
+ - Remove debian/patches/41_arm_fpa_sigfpe.patch (merged).
+ - Remove debian/patches/42_arm_tls.patch (merged differently).
+ - Update debian/patches/55_unmux_socketcall.patch.
+ - Remove debian/patches/63_sparc_build.patch (useless).
+ - Update debian/patches/65_kfreebsd.patch.
+ - Update debian/patches/66_tls_ld.patch.
+ - Remove debian/patches/70_manpage.patch (merged).
+ - Remove debian/patches/71_doc.patch (merged).
+ - Remove debian/patches/80_ui_curses.patch (merged).
+ - Remove debian/patches/81_mips32r2_fpu.patch (merged).
+ - Remove debian/patches/82_mips_abs.patch (merged).
+ - Remove debian/patches/83_usb-serial.patch (merged).
+ - Remove debian/patches/84_rtl8139.patch (merged).
+ - Remove debian/patches/85_vvfat.patch (merged).
+ - Remove debian/patches/86_df.patch (merged).
+ - Remove debian/patches/87_eoi.patch (merged).
+ - Remove debian/patches/88_dma.patch (merged).
+ - Remove debian/patches/89_braille.patch (merged).
+ - Remove debian/patches/92_no_shutdown.patch (merged).
+ - Remove debian/patches/93_tmpfs.patch (merged).
+ - Remove debian/patches/94_security.patch (merged).
+ * debian/README.source: new file.
+ * debian/patches/*: convert to patchlevel 1 (Closes: bug#484963).
+ * debian/control:
+ - Add build-depends on libesd0-dev.
+ - Add build-depends on libpulse-dev.
+ - Add build-depends on libvdeplug2-dev.
+ - Add build-depends on etherboot.
+ - Update list of supported targets (Closes: bug#488339).
+ - Suggests kqemu-source.
+ - Bump Standards-Version to 3.8.0.
+ * debian/links:
+ - Add missing manpage symlinks.
+ * debian/rules:
+ - Enable audio drivers depending on the system.
+ - Enable DYNGEN targets depending on the system.
+ - Install PXE bios from etherboot (Closes: bug#412010).
+ - Don't ignore make clean errors.
+ - Don't build DYNGEN targets on kfreebsd-amd64 (Closes: bug#494353).
+ * debian/patches/22_net_tuntap_stall.patch: remove (outdated).
+
+ -- Aurelien Jarno <aurel32@debian.org> Fri, 22 Aug 2008 01:00:54 +0200
+
+qemu (0.9.1-5) unstable; urgency=high
+
+ [ Guillem Jover ]
+ * Add Homepage field.
+ * Add Vcs-Browser and Vcs-Svn fields.
+ * Remove packaging repository information from debian/copyright.
+ * Add former package co-maintainers to debian/copyright.
+ * Serialize patch and configure steps in debian/rules to support parallel
+ builds, as we are patching configure.
+ * Remove myself from Uploaders.
+
+ [ Aurelien Jarno ]
+ * debian/patches/70_manpage.patch: remove curses documentation, it is already
+ in debian/patches/80_ui_curses.patch (Closes: bug#477369).
+ * debian/patches/94_security.patch: add format= to drive options
+ (CVE-2008-2004).
+
+ -- Aurelien Jarno <aurel32@debian.org> Mon, 28 Apr 2008 21:54:12 +0200
+
+qemu (0.9.1-4) unstable; urgency=high
+
+ * debian/patches/52_ne2000_return.patch: drop, the patch is wrong.
+ * Backports from upstream:
+ - Typo in curses_keys.h
+ - Documentation for the -curses option
+ - Fix broken absoluteness check for cabs.d.*.
+ - USB-to-serial device.
+ - rtl8139: fix endianness on big endian targets
+ - restore rw support for vvfat
+ - x86-64: recompute DF after eflags has been modified when emulating
+ SYSCALL
+ - ignore reads to the EOI register
+ - IDE: Improve DMA transfers by increasing the buffer size
+ - Braille device support
+ - Add -no-shutdown option (Closes: #326406)
+ - Ask to use "mount -o remount" instead of "umount" and "mount"
+ /dev/shm (Closes: #476539).
+ * debian/qemu.doc-base: fix section.
+
+ -- Aurelien Jarno <aurel32@debian.org> Sun, 20 Apr 2008 23:29:42 +0200
+
+qemu (0.9.1-3) unstable; urgency=low
+
+ [ Aurelien Jarno ]
+ * debian/patches/42_arm_tls.patch: fix to get qemu-system-arm working
+ again. (Closes: #471722).
+ * debian/patches/56_dhcp.patch: fix DHCP server to correctly support
+ MS-Windows guests. (Closes: #471452).
+
+ -- Aurelien Jarno <aurel32@debian.org> Wed, 19 Mar 2008 18:58:29 +0100
+
+qemu (0.9.1-2) unstable; urgency=low
+
+ [ Aurelien Jarno ]
+ * debian/patches/80_ui_curses.patch: pull new patch from upstream CVS
+ (Closes: #442274).
+ * debian/patches/65_kfreebsd.patch: link with -lfreebsd. (Closes:
+ #465932).
+ * debian/patches/81_mips32r2_fpu.patch: patch pulled from upstream
+ to fix FPU issue on MIPS32R2.
+ * debian/patches/42_arm_tls.patch: reenable, mistakenly disabled in the
+ previous upload. (Closes: #469743).
+ * debian/rules: fix parallel building. (Closes: #469981).
+ * debian/patches/07_i386_exec_name.patch: install the i386 emulator as
+ qemu-system-i386, and change qemu into a link pointing to the i386
+ version.
+ * debian/README.Debian: add notes about qemu-system-ppc and video.x
+ (Closes: #388735).
+ * debian/patches/70_manpage.patch: describe the -curses option.
+ (Closes: #433658).
+ * debian/patches/71_doc.patch: fix the monitor change option. (Closes:
+ #467106).
+ * debian/patches/35_syscall_sockaddr.patch: fix sockaddr (Closes:
+ #469351).
+ * debian/patches/43_arm_cpustate.patch: disable (Closes: #444171).
+
+ -- Aurelien Jarno <aurel32@debian.org> Mon, 17 Mar 2008 01:29:03 +0100
+
+qemu (0.9.1-1) unstable; urgency=low
+
+ [ Aurelien Jarno ]
+ * New upstream version. (Closes: #459801)
+ - Supports s390 host. (Closes: #441119)
+ - Fix PCI bar allocation. (Closes: #413315)
+ - Fix typo in keys name. (Closes: #426181)
+ - Fix segfault of qemu-i386 (Closes: #446868).
+ - debian/control: bump depends on openbios-sparc to
+ >= 1.0~alpha2+20080106.
+ - debian/patches/02_snapshot_use_tmpdir.patch: Refreshed.
+ - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+ - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+ - debian/patches/06_exit_segfault.patch: Likewise.
+ - debian/patches/10_signal_jobs.patch: Likewise.
+ - debian/patches/11_signal_sigaction.patch: Likewise.
+ - debian/patches/12_signal_powerpc_support.patch: Likewise.
+ - debian/patches/21_net_soopts.patch: Likewise.
+ - debian/patches/30_syscall_ipc.patch: Likewise.
+ - debian/patches/31_syscalls.patch: Likewise.
+ - debian/patches/32_syscall_sysctl.patch: Likewise.
+ - debian/patches/33_syscall_ppc_clone.patch: Likewise.
+ - debian/patches/35_syscall_sockaddr.patch: Likewise.
+ - debian/patches/41_arm_fpa_sigfpe.patch: Likewise.
+ - debian/patches/42_arm_tls.patch: Likewise.
+ - debian/patches/50_linuxbios_isa_bios_ram.patch: Likewise
+ - debian/patches/51_linuxbios_piix_ram_size.patch: Likewise
+ - debian/patches/61_safe_64bit_int.patch: Removed, merged upstream.
+ - debian/patches/63_sparc_build.patch: Refreshed.
+ - debian/patches/80_ui_curses.patch: Likewise.
+ * debian/patches/90_security.patch: fix 64-bit overflow. (Closes:
+ #425634)
+ * debian/qemu-make-debian-root: add a -s option to create sparse
+ image. (Closes: #322325)
+ * debian/control: bump depends on bochsbios to >= 2.3.5-1. Use
+ BIOS-qemu-latest instead of BIOS-bochs-latest. (Closes: #402289,
+ #442822)
+ * debian/rules: build the non-dyngen part with default gcc.
+ * debian/rules: support DEB_BUILD_OPTIONS="parallel=n".
+ * debian/patches/70_manpage.patch: describe the arguments of the
+ -usbdevice option in the manpage. (Closes: #443801)
+ * debian/control: now using Standards-Version 3.7.3 (no changes needed).
+ * debian/control: build-depends on libgnutls-dev to enable TLS support
+ in VNC.
+ * debian/patches/01_nostrip.patch: don't strip binaries during make
+ install. (Closes: #437866)
+ * debian/patches/53_openbios_size.patch: increase maximum prom size to
+ support latest openbios.
+
+ -- Aurelien Jarno <aurel32@debian.org> Mon, 28 Jan 2008 21:24:14 +0100
+
+qemu (0.9.0+20070816-1) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * New upstream snapshot.
+ - Fix hang on ARM during Etch installation. (Closes: #430164)
+ - Fix data corruption with qcow 2. (Closes: #440296)
+ - Fix errors with raw images > 4 GiB. (Closes: #425634)
+ - debian/patches/01_typo_qemu-img.patch: Removed, merged upstream.
+ - debian/patches/03_machines_list_no_error.patch: Likewise.
+ - debian/patches/36_syscall_prctl.patch: Likewise.
+ - debian/patches/37_syscall_mount.patch: Likewise.
+ - debian/patches/38_syscall_semctl.patch: Likewise.
+ - debian/patches/40_sparc_fp_to_int.patch: Likewise.
+ - debian/patches/44_arm_eabi_built_on_64bit_arches.patch: Likewise.
+ - debian/patches/62_linux_boot_nasm.patch: Likewise.
+ - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Synced.
+ - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+ - debian/patches/31_syscalls.patch: Likewise.
+ - debian/patches/35_syscall_sockaddr.patch: Likewise.
+ - debian/patches/42_arm_tls.patch: Likewise.
+ - debian/patches/43_arm_cpustate.patch: Likewise.
+ - debian/patches/51_linuxbios_piix_ram_size.patch: Likewise.
+ - debian/patches/55_unmux_socketcall.patch: Likewise.
+ - debian/patches/60_ppc_ld.patch: Likewise.
+ - debian/patches/65_kfreebsd.patch: Likewise.
+ - debian/patches/80_ui_curses.patch: Likewise.
+ - debian/patches/90_security.patch: Likewise.
+ * Remove Elrond and Guilherme de S. Pastore from Uploaders, with their
+ permission, and add Aurelien Jarno and Riku Voipio.
+ * Remove Tag field, this is better maintained outside of the package.
+ * Add openbios-sparc64 to qemu_bios_files in debian/rules.
+
+ [ Aurelien Jarno ]
+ * Fix FTBFS on amd64. (Closes: #434296)
+ - Drop debian/patches/34_syscalls_types.patch
+ * debian/control:
+ - Suggest samba. (Closes: #430368)
+ * Add OpenBIOS for sparc. (Closes: #407076)
+ - debian/control: depends on openbios-sparc.
+ - debian/links: provide symlinks in /usr/share/qemu.
+
+ -- Guillem Jover <guillem@debian.org> Tue, 04 Sep 2007 04:04:47 +0300
+
+qemu (0.9.0-2) unstable; urgency=high
+
+ [ Guillem Jover ]
+ * Fix several security issues. (Closes: #424070)
+ Thanks to Tavis Ormandy <taviso@google.com>.
+ - Cirrus LGD-54XX "bitblt" heap overflow. CVE-2007-1320
+ - NE2000 "mtu" heap overflow.
+ - QEMU "net socket" heap overflow.
+ - QEMU NE2000 "receive" integer signedness error. CVE-2007-1321
+ - Infinite loop in the emulated SB16 device.
+ - Unprivileged "aam" instruction does not correctly handle the
+ undocumented divisor operand. CVE-2007-1322
+ - Unprivileged "icebp" instruction will halt emulation. CVE-2007-1322
+ - debian/patches/90_security.patch: New file.
+ * Enable adlib audio emulation. (Closes: #419170)
+ * Fix structure padding for target_eabi_flock64 when built for a 64 bit
+ architecture. (Closes: #414799)
+ Thanks to Stuart Anderson <anderson@netsweng.com>.
+ - debian/patches/44_arm_eabi_built_on_64bit_arches.patch: New file.
+ * Fix qemu to be able to use LinuxBios. (Closes: #412212)
+ Thanks to Ed Swierk <eswierk@cs.stanford.edu>.
+ - debian/patches/50_linuxbios_isa_bios_ram.patch: New file.
+ - 51_linuxbios_piix_ram_size.patch: Likewise.
+ * Fix segfault when booting a Linux kernel w/o a disk image, by exiting but
+ clarifying the message, as to use '/dev/null'. (Closes: #409817, #411780)
+ Thanks to Robert Millan <rmh@aybabtu.com>.
+ - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Updated.
+ * Fix segfault by using addrlen instead of target_addrlen in
+ do_getpeername()/do_getsockname(). (Closes: #411910)
+ Thanks to Stuart Anderson <anderson@netsweng.com>.
+ - debian/patches/35_syscall_sockaddr.patch: Updated.
+ * Fix semctl() for 32 bit targets on 64 bit hosts. (Closes: #414809)
+ Thanks to Stuart Anderson <anderson@netsweng.com>.
+ - debian/patches/38_syscall_semctl.patch: New file.
+ * Remove Elrond from Uploaders with consent, always welcome to join
+ back anytime.
+
+ -- Guillem Jover <guillem@debian.org> Wed, 16 May 2007 08:08:31 +0300
+
+qemu (0.9.0-1) experimental; urgency=low
+
+ [ Guillem Jover ]
+ * New upstream release. (Closes: #409989)
+ - Support for relative paths in backing files for disk images.
+ (Closes: #390446)
+ - debian/patches/01_doc_typos.patch: Removed, merged upstream.
+ - debian/patches/38_syscall_arm_statfs64.patch: Likewise.
+ - debian/patches/51_serial_small_divider.patch: Likewise.
+ - debian/patches/67_ppc_ftbfs.patch: Likewise.
+ - debian/patches/21_net_soopts.patch: Synced.
+ - debian/patches/30_syscall_ipc.patch: Likewise.
+ - debian/patches/31_syscalls.patch: Likewise.
+ - debian/patches/35_syscall_sockaddr.patch: Likewise.
+ - debian/patches/39_syscall_fadvise64.patch: Likewise.
+ - debian/patches/42_arm_tls.patch: Likewise.
+ - debian/patches/55_unmux_socketcall.patch: Likewise.
+ - debian/patches/80_ui_curses.patch: Likewise.
+ * Update the copyright information.
+ * The ACPI initialization code has been moved to bochsbios.
+ - debian/patches/acpi-dsdt.hex: Removed.
+ - debian/rules: Do not install acpi-dsdt.hex.
+ * Add more files to the list of roms removed from the tarball needed to
+ be touched so that upstream 'make install' does not fail.
+ * Added armeb and armel to Architecture fields and libgpmg1-dev
+ Build-Depends.
+ * Recommend vde2 instead of the transitional vde package. (Closes: #407251)
+ * Fix typo in qemu-img output. (Closes: #408542)
+ - debian/patches/01_typo_qemu-img.patch: New file.
+ Thanks to Adam Buchbinder <adam.buchbinder@gmail.com>.
+ * Symlink qemu-user(1) to qemu-m68k(1).
+ * Reduce redundancy in qemu-user(1) synopsis.
+ * Fix rounding in sparc floating point to integer conversions.
+ - debian/patches/40_sparc_fp_to_int.patch: New file.
+ Thanks to Aurelien Jarno <aurelien@aurel32.net>.
+
+ -- Guillem Jover <guillem@debian.org> Thu, 8 Feb 2007 01:01:29 +0200
+
+qemu (0.8.2-5) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * Added a missing part to the ARM NPTL support patch, initially lost.
+ - debian/patches/42_arm_tls.patch: Updated.
+
+ -- Guillem Jover <guillem@debian.org> Tue, 16 Jan 2007 11:44:00 +0200
+
+qemu (0.8.2-4) unstable; urgency=medium
+
+ [ Guillem Jover ]
+ * Disable using iasl for now until it's ported to big-endian systems and
+ include a locally built acpi-dsdt.hex file.
+
+ -- Guillem Jover <guillem@debian.org> Sun, 3 Dec 2006 21:10:23 +0200
+
+qemu (0.8.2-3) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * Hopefully really fix powerpc FTBFS.
+
+ -- Guillem Jover <guillem@debian.org> Sun, 5 Nov 2006 17:09:53 +0200
+
+qemu (0.8.2-2) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * Update Tag field to match new debtags vocabulary.
+ * Clean properly. (Closes: #390166)
+ - Remove the acpi generated files and the docs.
+ - Revert the docs regeneration forcing logic.
+ Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+ * On install use DESTDIR instead of specifying all paths. (Closes: #396139)
+ Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+ * Port to GNU/kFreeBSD. (Closes: #327622)
+ - Disable ALSA on non-linux systems.
+ - Add a Build-Depends on libfreebsd-dev on kfreebsd systems.
+ - Add kfreebsd-i386 and kfreebsd-amd64 to the Architecture field.
+ - debian/patches/65_kfreebsd.patch: New file.
+ Thanks Petr Salinger <Petr.Salinger@seznam.cz>.
+ * In qemu-make-debian-root do not explicitely install in aptitude and
+ libsigc++-1.2-5c102, they are pulled now by default. And do not remove
+ aptitude afterwards. (Closes: #392481)
+ Thanks to Ted Percival <ted@midg3t.net>.
+ * Add experimental ncurses ui support. (Closes: #369462)
+ - debian/patches/80_ui_curses.patch: New file.
+ Thanks to Andrzej Zaborowski <balrog@zabor.org>.
+ * Add SO_PEERCRED and SO_SNDTIMEO support, and fix accept syscall when
+ being passed NULL pointers.
+ - debian/patches/21_net_sockopts.patch: Renamed to ...
+ - debian/patches/21_net_soopts.patch: ... here. Modify.
+ Thanks to Pablo Virolainen.
+ * Add a fadvise64 syscall stub.
+ - debian/patches/39_syscall_fadvise64.patch: New file.
+ Thanks to Pablo Virolainen.
+ * Add EABI unmuxed socket syscalls.
+ - debian/patches/55_unmux_socketcall.patch: New file.
+ Thanks to Riku Voipio.
+ * Add TLS sections to the ARM and x86 linker scripts so that qemu user
+ emulators can be linked statically.
+ - debian/patches/66_tls_ld.patch: New file.
+ * Move the documentation of the binary blob removals from the original
+ upstream tarball from README.Debian to debian/copyright.
+ * Reword the emphasis on "FAST!" from the package description.
+ * Fix FTBFS on powerpc by adding the missing fp_status variable to the
+ int32_to_float32 function calls.
+ - debian/patches/67_ppc_ftbfs.patch: New file.
+
+ -- Guillem Jover <guillem@debian.org> Sun, 5 Nov 2006 08:48:27 +0200
+
+qemu (0.8.2-1) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * New upstream release. (Closes: #379461, #385029, #388810)
+ - Add ACPI BIOS emulation support. (Closes: #372533)
+ - Fix mouse invisible wall when using Windows XP. (Closes: #384666)
+ - debian/patches/01_doc_typos.patch: Sync.
+ - debian/patches/03_machines_list_no_error.patch: Likewise.
+ - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+ - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+ - debian/patches/06_exit_segfault.patch: Likewise.
+ - debian/patches/12_signal_powerpc_support.patch: Likewise.
+ - debian/patches/21_net_sockopt.patch: Likewise.
+ - debian/patches/22_net_tuntap_stall.patch: Likewise.
+ - debian/patches/30_syscall_ipc.patch: Likewise.
+ - debian/patches/31_syscalls.patch: Likewise.
+ - debian/patches/32_syscall_sysctl.patch: Likewise.
+ - debian/patches/33_syscall_ppc_clone.patch: Likewise.
+ - debian/patches/35_syscall_sockaddr.patch: Likewise.
+ - debian/patches/36_syscall_prctl.patch: Likewise.
+ - debian/patches/37_syscall_mount.patch: Likewise.
+ - debian/patches/41_arm_fpa_sigfpe.patch: Likewise.
+ - debian/patches/42_arm_tls.patch: Likewise.
+ - debian/patches/61_safe_64bit_int.patch: Likewise.
+ - debian/patches/63_sparc_build.patch: Likewise.
+ - debian/patches/50_missing_keycodes.patch: Removed, integrated upstream.
+ * Switch to quilt:
+ - debian/control: Add quilt (>= 0.40) to Build-Depends.
+ - debian/patches/series: New file.
+ - debian/patch.mk: Removed.
+ - debian/rules: Include '/usr/share/quilt/quilt.make' instead of
+ 'debian/patch.mk'.
+ * Build the ACPI Source Language files with iasl.
+ * Add a Tag field to the binary package, using data from debtags.
+ * Add 2006 to the debian/copyright years.
+ * Add a Recommends on vde. (Closes: #386780)
+ * Fix spelling error in package description (peripherials -> peripherals).
+ (Closes: #388700)
+ Thanks to Rakesh 'arky' Ambati <rakesh_ambati@yahoo.com>.
+ * Fix ne2000_can_receive return code to 0 when the command is STOP.
+ (Closes: #386209)
+ - debian/patches/52_ne2000_return.patch: New file.
+ Thanks to Samuel Thibault <samuel.thibault@ens-lyon.org>.
+ * Document the binary blob removals from the original upstream tarball in
+ README.Debian. (Closes: #388740)
+
+ -- Guillem Jover <guillem@debian.org> Mon, 25 Sep 2006 04:16:25 +0300
+
+qemu (0.8.1-1) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * New upstream release. (Closes: #366955, #366637)
+ - debian/patches/01_doc_typos.patch: Sync.
+ - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+ - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+ - debian/patches/12_signal_powerpc_support.patch: Likewise.
+ - debian/patches/21_net_sockopt.patch: Likewise.
+ - debian/patches/22_net_tuntap_stall.patch: Likewise.
+ - debian/patches/30_syscall_ipc.patch: Likewise.
+ - debian/patches/31_syscalls.patch: Likewise.
+ - debian/patches/32_syscall_sysctl.patch: Likewise.
+ - debian/patches/33_syscall_ppc_clone.patch: Likewise.
+ - debian/patches/35_syscall_sockaddr.patch: Likewise.
+ - debian/patches/36_syscall_prctl.patch: Likewise.
+ - debian/patches/37_syscall_mount.patch: Likewise.
+ - debian/patches/41_arm_fpa_sigfpe.patch: Likewise.
+ - debian/patches/42_arm_tls.patch: Likewise.
+ - debian/patches/43_arm_cpustate.patch: Likewise.
+ - debian/patches/50_missing_keycodes.patch: Likewise.
+ - debian/patches/51_serial_small_divider.patch: Likewise.
+ - debian/patches/61_safe_64bit_int.patch: Likewise.
+ - debian/patches/63_sparc_build.patch: Likewise.
+ - debian/patches/40_arm_nwfpe_cpsr.patch: Removed, integrated upstream.
+ * Make the patch system apply the patch on the first run.
+ - debian/patches/64_ppc_asm_constraints.patch: Add DPATCHLEVEL.
+ * Document how to use the images created with qemu-make-debian-root in the
+ man page. Thanks to Jacobo <jacobo221@hotmail.com>. (Closes: #343450)
+ * Add support for the -snapshot option to use the TMPDIR evironment
+ variable. (Closes: #353880)
+ - debian/patches/02_snapshot_use_tmpdir.patch: New file.
+ * Do not exit with an error when using '-M ?'. (Closes: #365209)
+ - debian/patches/03_machines_list_no_error.patch: New file.
+ * Added symlink for system-mipsel emulator man page.
+ * Build and clean the pc-bios directory.
+ * Avoid segfaulting by using _exit(2) instead of exit(3) in qemu user
+ emulators. (Closes: #338289)
+ - debian/patches/06_exit_segfault.patch: New file.
+ * Enable ALSA audio support and add libasound2-dev to the Build-Depends.
+ * Now using Standards-Version 3.7.2 (no changes needed).
+
+ -- Guillem Jover <guillem@debian.org> Sun, 28 May 2006 20:51:10 +0300
+
+qemu (0.8.0-3) unstable; urgency=low
+
+ [ Josh Triplett ]
+ * Fix FTBFS on PowerPC caused by asm constraint problem. (Closes: #361727)
+ - debian/patches/64_ppc_asm_constraints.patch.
+
+ [ Guillem Jover ]
+ * Clamp addrlen from host to target when using AF_UNIX. This fixes
+ socket problems when using EABI.
+ - debian/patches/35_syscall_sockaddr.patch: New file.
+ * Fix floating point comparison on ARM NWFPE, due to glue code missmatch.
+ (Closes: #356287)
+ - debian/patches/40_arm_nwfpe_cpsr.patch: New file.
+ - debian/patches/40_fpu_arm_sigfpe.patch: Rename to ...
+ - debian/patches/41_arm_fpa_sigfpe.patch: ... this. Resync.
+ Thanks to Ulrich Hecht.
+ * Fix POSIX threads creation on ARM hanging when initializing the cpu
+ structure being it cyclic.
+ - debian/patches/43_arm_cpustate.patch: New file.
+ * Add TLS support for ARM. Stolen from Scratchbox.
+ - debian/patches/42_arm_tls.patch: New file.
+ * Fix sysctl endian problem.
+ - debian/patches/32_syscall_sysctl.patch: Update.
+ Thanks to Timo Savola <tsavola@movial.fi>.
+ * Remove now default '--enable-slirp' build option. (Closes: #356284)
+ Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+ * Remove unused sharedir to 'make install'. (Closes: #356418)
+ Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+ * Fix package not cleaning properly. (Closes: #356279)
+ Thanks to Anderson Lizardo <anderson.lizardo@gmail.com> for the initial
+ patch.
+ * Add needed syscalls to make debootstrap work. (Closes: #356291)
+ - debian/patches/36_syscall_prctl.patch: New file.
+ - debian/patches/37_syscall_mount.patch: Likewise.
+ - debian/patches/38_syscall_arm_statfs64.patch: Likewise.
+ Thanks to Anderson Lizardo <anderson.lizardo@gmail.com>.
+ * Remove obsolete Build-Dependency xlibs-dev.
+
+ -- Guillem Jover <guillem@debian.org> Thu, 13 Apr 2006 11:53:00 +0300
+
+qemu (0.8.0-2) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * Switch away from cdbs to plain debhelper.
+ * Upgrade to debhelper compat level 5.
+ * Allow overriding CC compiler variable. (Closes: #345772)
+ * Do not redefine 64 bit types on 64 bit arches.
+ - debian/patches/61_safe_64bit_int.patch: New file.
+ * Allow linux_boot.bin to be built on any arch by switching to nasm,
+ and Build-Depending on it.
+ - debian/patches/62_linux_boot_nasm.patch: New file.
+ * The serial hw driver uses a small divider that gets zeroed when shifting
+ bits to the right. (Closes: #276276, #348098)
+ - debian/patches/51_serial_small_divider.patch: New file.
+ Thanks to Samuel Thibault <samuel.thibault@ens-lyon.org>.
+ * Escaped hyphens in qemu-user manpage, use italics for filenames and
+ parameters and bold for options.
+ * Partial build failure fix for Sparc. (Bugs: #317145, #336970)
+ Thanks to Jurij Smakov <jurij@wooyd.org>.
+
+ -- Guillem Jover <guillem@debian.org> Mon, 20 Feb 2006 09:17:46 +0200
+
+qemu (0.8.0-1) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * New upstream release. (Closes: #344339)
+ - Added support for Virtual FAT. (Closes: #313123)
+ - Emulate repeated keystrokes when holding a key. (Closes: #298864)
+ - debian/patches/01_doc_typos.patch: Sync.
+ - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+ - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+ - debian/patches/12_signal_powerpc_support.patch: Likewise.
+ - debian/patches/21_net_sockopt.patch: Likewise.
+ - debian/patches/22_net_tuntap_stall.patch: Likewise.
+ - debian/patches/30_syscall_ipc.patch: Likewise.
+ - debian/patches/31_syscalls.patch: Likewise.
+ - debian/patches/32_syscall_sysctl.patch: Likewise.
+ - debian/patches/33_syscall_ppc_clone.patch: Likewise.
+ - debian/patches/40_fpu_arm_sigfpe.patch: Likewise.
+ - debian/patches/50_missing_keycodes.patch: Likewise.
+ * Added mips and mipsel to the lintian overrides for the user emulators
+ being shlib-with-non-pic-code.
+ * Added symlinks for mips, mipsel and system-arm emulator manpages.
+
+ -- Guillem Jover <guillem@debian.org> Fri, 30 Dec 2005 05:44:53 +0200
+
+qemu (0.7.2-2) unstable; urgency=low
+
+ [ Josh Triplett ]
+ * Add support for signal handling on PowerPC. (Closes: #335509)
+ - debian/patches/12_signal_powerpc_support.patch: New file.
+
+ [ Guillem Jover ]
+ * Add Josh Triplett <josh@psas.pdx.edu> to Uploaders and packaging team.
+ * Fix PowerPC build failure by reintroducing the ppc linker script and
+ adding the missing _SDA_BASE_ and _SDA2_BASE_ symbols. (Closes: #336983)
+ * Remove invalid patch making X11 fail at runtime.
+ - debian/patches/20_net_socket.patch: Remove.
+ - debian/patches/32_syscall_sysctl.patch: Sync.
+ Thanks to Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>.
+ * Avoid the patch system to try until it applies.
+ - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Added patch level.
+ - debian/patches/12_signal_powerpc_support.patch: Likewise.
+
+ -- Guillem Jover <guillem@debian.org> Wed, 21 Dec 2005 22:11:34 +0200
+
+qemu (0.7.2-1) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * New upstream release. (Closes: #321232, #327168)
+ - debian/patches/12_signal_silent.patch: Integrated upstream, remove.
+ - debian/patches/50_ppc_ldscript.patch: Likewise.
+ - debian/patches/33_syscall_truncate64.patch: Likewise.
+ - debian/patches/01_doc_typos.patch: Resync with upstream.
+ - debian/patches/04_do_not_print_rtc_freq_if_ok.patch: Likewise.
+ - debian/patches/05_non-fatal_if_linux_hd_missing.patch: Likewise.
+ - debian/patches/10_signal_jobs.patch: Likewise.
+ - debian/patches/11_signal_sigaction.patch: Likewise.
+ - debian/patches/20_net_socket.patch: Likewise.
+ - debian/patches/21_net_sockopt.patch: Likewise.
+ - debian/patches/22_net_tuntap_stall.patch: Likewise.
+ - debian/patches/30_syscall_ipc.patch: Likewise.
+ - debian/patches/31_syscalls.patch: Likewise.
+ - debian/patches/32_syscall_sysctl.patch: Likewise.
+ - debian/patches/40_fpu_arm_sigfpe.patch: Likewise.
+ * Repackaged upstream source to deal with binaries w/o sources.
+ - pc-bios/video.x: New file removed.
+ * Create a new qemu-user(1) manpage and link all user emulator manpages
+ to it. (Closes: #335163)
+ * Add missing '-' and '=' keycodes for sendkey command.
+ - debian/patches/50_missing_keycodes.patch: New file. (Closes: #334071)
+ Thanks to Robert Millan <rmh@aybabtu.com>.
+ * Add manpage link for qemu-system-mips.
+ * Make sysctl byte-swap the name values.
+ - debian/patches/32_syscall_sysctl.patch: Merge patch. (Closes: #334458)
+ Thanks to Josh Triplett <josh@psas.pdx.edu>.
+ * Change documentation menu section to "Apps/Emulators". (Closes: #335062)
+ Thanks to Frans Pop <aragorn@tiscali.nl>.
+ * On PowerPC, do not zero registers r7-r31 in do_fork and zero register r3.
+ Fixing segfaults on programs using the clone syscall.
+ - debian/patches/33_syscall_ppc_clone.patch: New file. (Closes: #335159)
+ Thanks to Josh Triplett <josh@psas.pdx.edu>
+ and Paul Brook <paul@codesourcery.com>.
+ * Tighten vgabios and bochsbios versioned Depends.
+ * Add video.x to the list of roms to touch to make qemu Makefile happy.
+ * Add lintian overrides for the user emulators being shlib-with-non-pic-code.
+ * Wrap lines in debian/control fields (knowingly breaking policy).
+
+ [ Guilherme de S. Pastore ]
+ * debian/control:
+ - Updated my e-mail address.
+ * debian/copyright:
+ - Dropped André from team members list, not a single contribution ever.
+
+ -- Guillem Jover <guillem@debian.org> Mon, 31 Oct 2005 05:01:45 +0200
+
+qemu (0.7.0-4) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * Rebuild source with locally deborked dpkg-source. (Closes: #321019)
+ * Added the location of the Subversion repo used for the packages and
+ fixed the upstream URL in debian/copyright.
+ * Lower case title header in qemu-make-debian-root man page.
+ * Use dd instead of cat to generate the qemu debian root image.
+ (Closes: #315952)
+
+ -- Guillem Jover <guillem@debian.org> Wed, 3 Aug 2005 05:53:30 +0300
+
+qemu (0.7.0-3) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * Update watch file to version 3, use perlre and new upstream site.
+ * Now using Standards-Version 3.6.2 (no changes needed).
+ * Fix TUN/TAP network interface stalling the connection. (Closes: #290569)
+ Thanks to Vitaly Belostotsky <byly.useless@tochka.ru>.
+ * Link against librt, needed by the new clock_gettime syscall.
+ - debian/patches/31_syscalls.patch: Update. (Closes: #315388)
+ Thanks to Timo Savola <tsavola@movial.fi> for noticing.
+ * Force Build-Dependency on binutils >= 2.16-1 needed by the amd64 and
+ powerpc linker scripts. (Closes: #262655)
+ * Force usage of gcc-3.4. (Closes: #319527)
+ * Add missing Build-Dependency on zlib1g-dev.
+ Thanks to Reinhard Tartler <siretart@tauware.de>.
+ * Include <linux/types.h> in syscall.c to avoid the broken headers in
+ linux-kernel-headers 2.6.12.
+ - debian/patches/34_syscalls_types.patch: New file.
+ Thanks to Octavian Cerna <tavy@ylabs.com>.
+ * Fix powerpc linker script.
+ - debian/patches/50_ppc_ldscript.patch: New file.
+ Thanks to Octavian Cerna <tavy@ylabs.com>.
+
+ -- Guillem Jover <guillem@debian.org> Mon, 1 Aug 2005 02:48:09 +0300
+
+qemu (0.7.0-2) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * Add alpha, sparc, arm and s390 to Architectures (and to the
+ libgpmg1-dev Build-Depends).
+
+ * Forward SIGSTOP and SIGCONT sent to QEMU to the emulated application.
+ - debian/patches/10_signal_jobs.patch: New file.
+ Thanks to Ulrich Hecht.
+ * Return EINVAL on emulated sigaction when given invalid signal
+ parameters SIGKILL and SIGSTOP.
+ - debian/patches/11_signal_sigaction.patch: New fle.
+ Thanks to Valtteri Rahkonen.
+ * Do not print messsages for uncaught signal, thus fixing the case
+ were some applications want to kill their siblings.
+ - debian/patches/12_signal_silent.patch: New file.
+ Thanks to Valtteri Rahkonen
+
+ * Fix Unix sockets by handling correctly AF_UNIX socket address
+ structure length.
+ - debian/patches/20_net_socket.patch: New file.
+ Thanks to Timo Savola.
+ * Implement SO_LINGER, SO_RCVTIMEO, SO_SNDTIMEO, SO_PEERNAME and
+ SO_PEERCRED getsockoptions.
+ - debian/patches/21_net_sockopt.patch: New file.
+ Thanks to Valtteri Rahkonen.
+
+ * Implement SysV IPC message and semaphore syscalls.
+ - debian/patches/30_syscall_ipc.patch: New file.
+ Thanks to Valtteri Rahkonen.
+ * Implement acct, umount2, uselib, swapon, syslog, ftruncate64,
+ mincore, madvise, readahead and clock_gettime syscalls.
+ - debian/patches/31_syscalls.patch: New file.
+ Thanks to Ulrich Hecht.
+ * Implement sysctl CTL_KERN/KERN_VERSION
+ - debian/patches/32_syscall_sysctl.patch: New file.
+ Thanks to Timo Savola.
+ * Implement truncate64 syscall.
+ - debian/patches/33_syscall_truncate64.patch: New file.
+ Thanks to Valtteri Rahkonen.
+
+ * Implement ARM floating point exeption emulation.
+ - debian/patches/40_fpu_arm_sigfpe.patch: New file.
+ Thanks to Ulrich Hecht.
+
+ -- Guillem Jover <guillem@debian.org> Sun, 19 Jun 2005 15:05:37 +0300
+
+qemu (0.7.0-1) experimental; urgency=low
+
+ [ Guillem Jover ]
+ * New upstream release. (Closes: #308459, #308494)
+ * Do not require a disk image when booting a Linux kernel. (Closes: #260935)
+ Thanks to Jonas Smedegaard <dr@jones.dk>.
+
+ [ Guilherme de S. Pastore ]
+ * Rewrote README.Debian for more clarity
+ * Add support for amd64 as a host architecture. (Closes: #262655)
+ - Add build-depend on libgpmg1-dev on amd64.
+ * Fixed qemu-make-debian-root so that it shows the name by which
+ it was called on the usage notice, not "%s". (Closes: #303507)
+ Thanks to Micah Anderson <micah@riseup.net>.
+
+ [ Elrond ]
+ * Clean up more files, so they don't end up in the final .diff.gz
+ * Switch to external proll and openhackware:
+ - Instead of patching qemu's Makefile, trick it by giving it empty
+ files to install and remove them straight after install.
+ - Don't ship the roms in debian/roms any more!
+ - Instead add more symlinks.
+ - Update Depends: apropiately.
+
+ -- Guillem Jover <guillem@debian.org> Fri, 27 May 2005 02:06:20 +0300
+
+qemu (0.6.1+20050407-1) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * New upstream snapshot.
+ - Fix -user-net. (Closes: #295019)
+ - Fix win2k and winxp image booting. (Closes: #285170, #292707)
+ - Fix installation of outdated documentation. (Closes: #286931)
+ - Provide qemu-img instead of qemu-mkcow. (Closes: #290713)
+ - Remove debian/patches/05_fix_openpic_timer_test.patch, integrated
+ upstream.
+ - Remove debian/patches/02_selectable_sdl_keyboard.patch, superseded
+ by new keyboard implementation. (Closes: #284510, #299432)
+ - Remove debian/patches/01_mkcow_section_and_hyphens.patch.
+ - Conditionalize qemu -g option for some architectures. (Closes: #298988)
+ * Added new copyright year to debian/copyright.
+ * Added initial qemu-make-debian-root man page. (Closes: #286932)
+ * Fixed typos in qemu documentation. (Closes: #301933)
+ Thanks to A Costa <agcosta@gis.net>.
+ * Added Elrond <elrond@samba-tng.org> to Uploaders and packaging team.
+ * Use the default target list:
+ - Do not build qemu-fast anymore as it is deprecated upstream anyway.
+ (Closes: #278602, #281510)
+ - New targets armeb and system-x86_64.
+ * Updated ROM images under debian/roms/:
+ - OpenHackWare 0.4.
+ - Proll 18 with qemu specific patches.
+ * Remove uudecoded files from pc-bios/ on clean.
+ * Fix qemu-make-debian-root to behave correctly even if the needed
+ Recommends are not installed.
+
+ [ Guilherme de S. Pastore ]
+ * Create a doc-base entry for the package (Closes: #290669)
+ * debian/control:
+ - Add debootstrap to the 'Recommends: ' line, as needed by
+ qemu-make-debian-root (Closes: #302848)
+ - Moved sharutils from dependency to recommendation, as it is only
+ needed by qemu-make-debian-root
+ * debian/docs:
+ - Do not include README.distrib in the binary package (Closes: #302853)
+
+ [ Elrond ]
+ * Replace "libgpmg1-dev | not+linux-gnu" by "libgpmg1-dev [i386 powerpc]"
+ in Build-Depends. qemu should not need to build-depend on it anyway, the
+ real problem is described in Bug#267174. When it is solved, we can
+ remove our dependency. Until then please remember to add any arch, which
+ we will build on and that has gpm. This change hopefully calms:
+ <http://qa.debian.org/debcheck.php?dist=unstable&package=qemu>
+ * Add versions to the dependencies on bochsbios and vgabios
+ (Closes: #288997):
+ - vgabios: Use the current version from testing/unstable (0.4c+20041014-1),
+ according to Frans Pop <aragorn@tiscali.nl>, this fixed those
+ "blank screen" problems.
+ - bochsbios: Use the current version from unstable (2.1.1+20041109-3), as
+ Guillem Jover fixed the networking in that version.
+
+ -- Guillem Jover <guillem@debian.org> Thu, 7 Apr 2005 01:26:01 +0300
+
+qemu (0.6.1-1) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * New upstream release. (Closes: #281626)
+ - Booting from drive b is not supported anymore. (Closes: #275679)
+ - Fix ne2k network interface that was not working in some situations.
+ (Closes: #281862)
+ - Remove debian/patches/06_build_gcc3.4.patch, fixed upstream.
+ - Remove debian/patches/04_lfs.patch, fixed upstream.
+ - Remove debian/patches/02_fix_powerpc_FTBFS.patch, fixed upstream.
+ - Remove debian/patches/00_escape_manpage_hyphens.patch, not needed.
+ - Sync debian/patches/03_use_external_bios.patch.
+ * Include uuencoded source for proll 18, some build fixes and its binary
+ proll.bin on debian/roms/.
+ * Suggests sudo to be used by the qemu-ifup script.
+ Thanks to Elrond <elrond@samba-tng.org>.
+ * Make sudo in qemu-ifup explain what the password is for. (Closes: #281380)
+ * Add an option to select the method to convert keyevent to keycode
+ in the SDL keyboard handling code. Added support for Right Shift in the
+ generic handler. (Closes: #282658)
+ Thanks to Elrond <elrond@samba-tng.org>.
+ * Do not set RTC frequency to 1024 or warn about this if it has already
+ the correct value. (Closes: #281403)
+ * Enabled sparc-softmmu support.
+
+ -- Guillem Jover <guillem@debian.org> Sat, 27 Nov 2004 23:23:49 +0100
+
+qemu (0.6.0.dfsg.2-1) unstable; urgency=low
+
+ [ Guillem Jover ]
+ * Repackaged upstream source to remove external included files.
+ - pc-bios/ppc-rom.bin: Removed.
+ - pc-bios/OpenHackWare_0.3.tar.bz2: Likewise.
+ - pc-bios/vgabios.bin: Likewise.
+ - pc-bios/vgabios-cirrus.bin: Likewise.
+ - pc-bios/vgabios-cvs-2004-06-17.tgz: Likewise.
+ * Include uuencoded source for OpenHackWare 0.3.1 and its binary
+ ppc-rom.bin on debian/roms/. Add a Build-Depends on sharutils.
+ * Update tundev.c. Pass -tun-dev to qemu without the equal sign.
+ Thanks to Isaac Clerencia <isaac@sindominio.net>.
+ * Fix README.Debian to point to the renamed qemu-make-debian-root.
+ * Add Depends on sharutils needed by qemu-make-debian-root.
+ (Closes: #272130)
+ * Use and depend on vgabios package, which is in sync with bochsbios
+ that checks for rom bios checksums. (Closes: #281202)
+ * Enable LFS globally, thus fixing problems with qemu-mkcow when using
+ an existing large image.
+ (Closes: #279925)
+ * Fix openpic timer write test, catched from a warning about a constant
+ value larger than the type it was casted to.
+ * Fix build failure with gcc 3.4. Patch stolen from Gentoo BTS.
+
+ -- Guillem Jover <guillem@debian.org> Mon, 15 Nov 2004 10:46:54 +0100
+
+qemu (0.6.0.dfsg.1-1) unstable; urgency=high
+
+ [ Guillem Jover ]
+ * Repackaged upstream source to deal with binaries w/o sources.
+ (Closes: #268780)
+ - pc-bios/bios.bin: Removed binary without source. Now using
+ bochsbios package.
+ - pc-bios/vgabios.bin: Rebuilt from vgabios cvs 2004-06-17 snapshot,
+ source included.
+ - pc-bios/vgabios-cirrus.bin: Likewise.
+ - pc-bios/ppc-rom.bin: Rebuilt on voltaire, source included.
+ - pc-bios/linux_boot.bin: Rebuilt from source.
+ * Move make-debian-root.sh to /usr/sbin/qemu-make-debian-root.
+ (Closes: #268705)
+
+ -- Guillem Jover <guillem@debian.org> Mon, 13 Sep 2004 01:28:54 +0200
+
+qemu (0.6.0-2) unstable; urgency=high
+
+ [ Guilherme de S. Pastore ]
+ * Fixed dangling symlinks under /usr/share/man/man1. (Closes: #264764)
+
+ [ Guillem Jover ]
+ * Fix FTBFS on powerpc.
+ - debian/patches/02_fix_powerpc_FTBFS.patch: New file.
+
+ -- Guillem Jover <guillem@debian.org> Wed, 18 Aug 2004 15:50:43 +0200
+
+qemu (0.6.0-1) unstable; urgency=medium
+
+ * New maintainers. (Closes: #258900)
+ * New upstream release. (Closes: #258732)
+ - Installs ppc BIOS ROM file. (Closes: #257492)
+ - Builds with -fno-strict-aliasing. (Closes: #257123)
+
+ [ Guilherme de S. Pastore ]
+ * debian/rules:
+ - Cleaned up.
+ - Ported to use CDBS.
+ * 00_escape_manpage_hyphens.patch:
+ - Correct a little typo and escape hyphens in upstream manpage.
+ * 01_mkcow_section_and_hyphens.patch:
+ - Fix section mismatch and escape hyphens in the qemu-mkcow manpage.
+ * Added simple /etc/qemu-ifup helper script. (Closes: #245281)
+ Thanks to Martin Michlmayr <tbm@cyrius.com>.
+ * Cleaned debian/watch.
+ * UTF-8'ed debian/changelog.
+ * Updated Standards-Version to 3.6.1.1.
+ * Removed outdated and unnecessary debian/qemu-i386.sgml.
+ - Removed build dependency on docbook-to-man.
+ * Removed "x86" part from the description (hey, qemu is not x86-only
+ in any way). Deserves a complete rewrite, shall be done soon.
+
+ [ Guillem Jover ]
+ * Lower-case package short description.
+ * Added missing CPU emulations to the description.
+ * Cleaned and updated debian/copyright.
+ * Removed manually added libx11-6 dependency.
+ * Only Build-Depends on libgpmg1-dev on GNU/Linux systems.
+ * Cosmetic unification to debian/changelog.
+ * debian/rules:
+ - Remove generated files.
+ - Give exec perms to qemu-ifup.
+
+ -- Guillem Jover <guillem@debian.org> Sun, 8 Aug 2004 17:24:08 +0200
+
+qemu (0.5.5-2) unstable; urgency=low
+
+ * Re-enable SDL disabled while I was bugchasing. (Closes: #255014)
+ * Yes, this is really 0.5.5. (Closes: #254655)
+ * Enable slirp networking. (Closes: #253573)
+ * Add Build-Depends on libgpmg1-dev (found by Bastian Blank, probably breaks
+ Hurd but that's a problem for another day).
+
+ -- Paul Russell <prussell@debian.org> Thu, 24 Jun 2004 06:26:42 +0200
+
+qemu (0.5.5-1) unstable; urgency=low
+
+ * New upstream release. (Closes: #237556, #237556)
+ * Applied patch to add options to make_debian_root.sh. (Closes: #238787)
+ * Applied patch for other archs: hmmm... (Closes: #251420)
+ * Do umount -d in make_debian_root.sh. (Closes: #251775)
+
+ -- Paul Russell <prussell@debian.org> Tue, 1 Jun 2004 03:50:05 +0200
+
+qemu (0.5.4-1) unstable; urgency=low
+
+ * New upstream release. (Closes: #246634)
+ * qemu-mkcow included in upstream.
+ * Added tundev program source in doc, to see if people find it useful.
+
+ -- Paul Russell <prussell@debian.org> Mon, 3 May 2004 08:14:49 +0200
+
+qemu (0.5.3-1) unstable; urgency=low
+
+ * New upstream release. (Closes: #237556)
+ * Use aalib-config --static-libs. (Closes: #243325)
+ * Document Control-Shift to release mouse pointer. (Closes: #238074)
+
+ -- Paul Russell <prussell@debian.org> Tue, 13 Apr 2004 02:58:49 +0200
+
+qemu (0.5.2-4) unstable; urgency=low
+
+ * Fix PPC install (Michel Daenzer patch). (Closes: #238431)
+ * Simplify deps (might be wrong, but it's neater). (Closes: #238430)
+
+ -- Paul Russell <prussell@debian.org> Wed, 17 Mar 2004 01:35:47 +0100
+
+qemu (0.5.2-3) unstable; urgency=low
+
+ * Make compile on woody. (Closes: #238163)
+ * Include qemu-doc.html. (Closes: #238076)
+ * Wrote qemu-i386 man page. (Closes: #238077)
+
+ -- Paul Russell <prussell@debian.org> Mon, 15 Mar 2004 23:56:25 +0100
+
+qemu (0.5.2-2) unstable; urgency=low
+
+ * Fix build problem so bios.bin etc. can be found. (Closes: #237553)
+
+ -- Paul Russell <prussell@debian.org> Fri, 12 Mar 2004 05:43:00 +0100
+
+qemu (0.5.2-1) unstable; urgency=low
+
+ * Initial Release. (Closes: #187407)
+
+ -- Paul Russell <prussell@debian.org> Wed, 3 Mar 2004 02:18:54 +0100
+
--- /dev/null
+Source: qemu
+Section: misc
+Priority: optional
+Maintainer: Maemo Integration <integration@maemo.org>
+Build-Depends: debhelper (>= 5), quilt (>= 0.40), binutils (>= 2.16), nasm,
+ libx11-dev, libsdl1.2-dev (>> 1.2.1), libncurses5-dev, zlib1g-dev,
+ texi2html, sharutils, libgnutls-dev, libesd0-dev, etherboot,
+ libpulse-dev,
+ libfreebsd-dev [kfreebsd-i386 kfreebsd-amd64],
+ libasound2-dev [!kfreebsd-i386 !kfreebsd-amd64],
+ libbluetooth-dev [!kfreebsd-i386 !kfreebsd-amd64],
+ libgpmg1-dev [amd64 arm armel hppa i386 powerpc sparc ppc64],
+Standards-Version: 3.8.0
+
+Package: sb2-qemu-arm
+Architecture: amd64 i386 powerpc
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Qemu for scratchbox2
+ Qemu packaging for sb2. This should become eventually temporary
+ when mainstream qemu merges any remaining patches.
+
+Package: scratchbox-devkit-qemu
+Architecture: i386
+Depends: ${shlibs:Depends}, ${misc:Depends}, scratchbox-core (>= 1.0.12)
+Description: Qemu scratchbox devkit
+ The qemu for the scratchbox1 lovers.
+
+Package: sb-system-qemu
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Recommends: sbrsh
+Description: System qemu for scratchbox
+ This package includes system qemu to be used with scratchbox and sbrsh
+ for cpu transparency.
--- /dev/null
+This package was debianized by Paul Russell <prussell@debian.org> on
+Wed, 3 Mar 2004 02:18:54 +0100.
+
+Then maintained as part of the team by:
+
+ Guilherme de S. Pastore <gpastore@debian.org>
+ Elrond <elrond@samba-tng.org>
+ Guillem Jover <guillem@debian.org>
+
+Now maintained as a team by:
+
+ Aurelien Jarno <aurel32@debian.org>
+ Josh Triplett <josh@psas.pdx.edu>
+ Riku Voipio <riku@debian.org>
+
+The upstream source was downloaded from:
+
+ <http://www.qemu.org/download.html>
+
+ All the binary blobs without sources contained in the pc-bios/ directory
+ in the original upstream tarball have been removed starting from Debian
+ package version 0.6.0.dfsg.1-1. Those roms which are free can be found
+ in split packages of their own, represented accordingly in the dependecy
+ relationships.
+
+Upstream Author:
+
+ Fabrice Bellard <fabrice.bellard@free.fr>
+
+Copyright:
+
+ Copyright (C) 2003, 2004, 2005, 2006, 2007 Fabrice Bellard
+
+License:
+
+ QEMU as a whole is released under the GNU General Public License.
+ On Debian systems, the complete text of the GNU General Public License
+ can be found in the file /usr/share/common-licenses/GPL.
+
+ Parts of QEMU have specific licenses which are compatible with the
+ GNU General Public License. Hence each source file contains its own
+ licensing information.
+
+ In particular, the QEMU virtual CPU core library (libqemu.a) is
+ released under the GNU Lesser General Public License. On Debian systems,
+ the complete text of the GNU Lesser General Public License can be found
+ in the file /usr/share/common-licenses/LGPL.
+
+ Many hardware device emulation sources are released under the BSD license.
+ On Debian systems, the complete text of the BSD license be found in the
+ file /usr/share/common-licenses/BSD.
+
+
--- /dev/null
+qemu-arm-sb
+qemu-armeb-sb
+qemu-i386-sb
+qemu-mips-sb
+qemu-mipsel-sb
+qemu-ppc-sb
+qemu-sparc-sb
--- /dev/null
+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
--- /dev/null
+.\" $Id: qemu-user.1 325 2008-08-09 21:39:16Z aurel32 $
+.TH qemu\-user 1 2007-02-08 "0.9.0" Debian
+.SH NAME
+qemu\-user \- QEMU User Emulator
+.SH SYNOPSIS
+.B qemu\-user
+.RI [ options ]
+.I program
+.RI [ program-arguments... ]
+.SH DESCRIPTION
+The
+.B qemu\-user
+emulator can run binaries for other architectures but with the same operating
+system as the current one.
+.SH OPTIONS
+.TP
+.BR \-h
+Print this help.
+.TP
+.BR \-g
+Wait gdb connection to port 1234.
+.TP
+.BR \-L " \fI<path>\fP"
+Set the elf interpreter prefix (default=\fI/usr/gnemul/qemu\-arm\fP).
+.TP
+.BR \-s " \fI<size>\fP"
+Set the stack size in bytes (default=\fI524288\fP).
+.TP
+.BR \-d " \fI<options>\fP"
+Activate log (logfile=\fI/tmp/qemu.log\fP)
+.TP
+.BR \-p " \fI<pagesize>\fP"
+Set the host page size to 'pagesize'.
+.SH SEE ALSO
+.BR qemu (1),
+.BR qemu\-img (1).
+.SH AUTHOR
+This manual page was written by Guillem Jover <guillem@debian.org>.
--- /dev/null
+usr/share/qemu/
--- /dev/null
+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
--- /dev/null
+README
+TODO
+qemu-doc.html
+debian/tundev.c
--- /dev/null
+debian/qemu-ifup etc/
+debian/qemu-make-debian-root usr/sbin/
+debian/overrides/qemu usr/share/lintian/overrides/
--- /dev/null
+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
--- /dev/null
+debian/qemu-make-debian-root.8
+debian/qemu-user.1
--- /dev/null
+#!/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
+
--- /dev/null
+/*
+ * $Id: tundev.c 325 2008-08-09 21:39:16Z aurel32 $
+ */
+
+#define _GNU_SOURCE /* asprintf */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+
+/* Tiny code to open tap/tun device, and hand the fd to qemu.
+ Run as root, drops to given user. */
+int main(int argc, char *argv[])
+{
+ struct ifreq ifr;
+ struct passwd *p;
+ unsigned int i;
+ char *newargs[argc + 1];
+ int fd;
+
+ if (argc < 4) {
+ fprintf(stderr,
+ "Usage: tundev user logfile qemu <qemu options>...\n");
+ exit(1);
+ }
+
+ fd = open("/dev/net/tun", O_RDWR);
+ if (fd < 0) {
+ perror("Could not open /dev/net/tun");
+ exit(1);
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strncpy(ifr.ifr_name, "tun%d", IFNAMSIZ);
+ if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) {
+ perror("Could not get tun device");
+ exit(1);
+ }
+
+ /* Set userid. */
+ p = getpwnam(argv[1]);
+ if (!p) {
+ fprintf(stderr, "No user '%s'\n", argv[1]);
+ exit(1);
+ }
+ setgroups(0, NULL);
+ setgid(p->pw_gid);
+ if (setuid(p->pw_uid) != 0) {
+ perror("setting uid");
+ exit(1);
+ }
+
+ /* Insert -tun-fd */
+ newargs[0] = argv[3];
+ newargs[1] = "-tun-fd";
+ asprintf(&newargs[2], "%d", fd);
+ for (i = 4; i <= argc; i++)
+ newargs[i-1] = argv[i];
+
+ if (strcmp(argv[2], "-") == 0) {
+ execvp(newargs[0], newargs);
+ exit(1);
+ }
+
+ switch (fork()) {
+ case 0: {
+ close(1);
+ close(2);
+ open(argv[2], O_WRONLY|O_APPEND);
+ open(argv[2], O_WRONLY|O_APPEND);
+ close(0);
+ execvp(newargs[0], newargs);
+ exit(1);
+ }
+ case -1:
+ perror("fork failed");
+ exit(1);
+ }
+ printf("%s\n", ifr.ifr_name);
+ exit(0);
+}
--- /dev/null
+version=3
+
+http://bellard.org/qemu/download.html qemu-([\d.]*).tar.gz debian uupdate
#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'
#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 */
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;
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)
io_mem_used[i] = 1;
return i;
}
-
+ fprintf(stderr, "RAN out out io_mem_idx, max %d !\n", IO_MEM_NB_ENTRIES);
return -1;
}
--- /dev/null
+/*
+ * 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,
+};
+
/* tosa.c */
extern QEMUMachine tosapda_machine;
+/* beagle.c */
+extern QEMUMachine beagle_machine;
+
#endif
/* 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);
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
/* 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,
/* 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 = {
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
}
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;
/* 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;
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
+ * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
+ * datasheet from Micron Technology and "NAND02G-B2C" datasheet
+ * from ST Microelectronics.
+ *
* This code is licensed under the GNU GPL v2.
*/
# 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
# 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
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;
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
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:
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:
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:
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);
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);
*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);
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) {
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);
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)
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;
/* 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;
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;
}
}
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;
}
/* 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);
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;
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),
} 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;
}
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));
/* 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);
# 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;
/* 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);
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
# 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,
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 {
# 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,
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,
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);
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);
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;
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)
# 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))
# 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 {
omap2423,
omap2430,
omap3430,
+ omap3530,
} mpu_model;
CPUState *env;
omap_clk clk;
} pwt;
- struct omap_i2c_s *i2c[2];
+ struct omap_i2c_s *i2c[3];
struct omap_rtc_s *rtc;
struct omap_synctimer_s {
uint32_t val;
uint16_t readh;
+ uint32_t sysconfig; /*OMAP3*/
} synctimer;
struct omap_prcm_s *prcm;
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 */
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
# 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) */
qemu_irq parent_intr[2];
unsigned char nbanks;
int level_only;
+ uint8_t revision;
/* state */
uint32_t new_agr[2];
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)
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;
}
switch (offset) {
case 0x00: /* INTC_REVISION */
- return 0x21;
+ return s->revision;
case 0x10: /* INTC_SYSCONFIG */
return (s->autoidle >> 2) & 1;
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)
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;
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;
}
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;
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;
}
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 */
#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) {
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;
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
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)
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)
{
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;
}
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;
}
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;
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[] = {
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 */
qemu_irq *in;
qemu_irq handler[32];
+ uint8_t revision;
uint8_t config[2];
uint32_t inputs;
uint32_t outputs;
switch (addr) {
case 0x00: /* GPIO_REVISION */
- return 0x18;
+ return s->revision;
case 0x10: /* GPIO_SYSCONFIG */
return s->config[0];
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 */
break;
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REGV(addr, value);
return;
}
}
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,
}
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;
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;
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);
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)
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;
}
/* 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;
#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 */
[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 */
#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;
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)
{
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__);
}
return 0x000000f0;
case omap3430:
return 0x000000f0;
+ case omap3530:
+ return 0x000f00f0;
default:
cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__);
}
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__);
/* 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 */
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);
uint32_t value)
{
struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
+ int cs = 0;
switch (addr) {
case 0x00: /* SDRC_REVISION */
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;
}
}
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;
}
struct omap_gpmc_s {
qemu_irq irq;
+ uint8_t revision;
uint8_t sysconfig;
uint16_t irqst;
uint16_t irqen;
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);
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;
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;
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)
{
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 */
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;
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;
}
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;
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 */
}
/* 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"));
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) {
&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"),
--- /dev/null
+/*
+ * TI OMAP3 processors emulation.
+ *
+ * Copyright (C) 2008 yajin <yajin@vm-kernel.org>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "hw.h"
+#include "arm-misc.h"
+#include "omap.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "flash.h"
+#include "soc_dma.h"
+#include "audio/audio.h"
+#include "block.h"
+
+/*
+ * When the flag below is defined, the "less important" I/O regions
+ * will not be mapped -- this is needed because the current maximum
+ * number of I/O regions in qemu-system-arm (128) is easily reached
+ * when everything is mapped.
+ */
+#define OMAP3_REDUCE_IOREGIONS
+
+//#define OMAP3_DEBUG_
+
+#ifdef OMAP3_DEBUG_
+#define TRACE(fmt, ...) fprintf(stderr, "%s " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+typedef enum {
+ /* 68000000-680003FF */ L3ID_L3RT = 0,
+ /* 68000400-680007FF */ L3ID_L3SI,
+ /* 68000800-680013FF */
+ /* 68001400-680017FF */ L3ID_MPUSS_IA,
+ /* 68001800-68001BFF */ L3ID_IVASS_IA,
+ /* 68001C00-68001FFF */ L3ID_SGXSS_IA,
+ /* 68002000-680023FF */ L3ID_SMS_TA,
+ /* 68002400-680027FF */ L3ID_GPMC_TA,
+ /* 68002800-68002BFF */ L3ID_OCM_RAM_TA,
+ /* 68002C00-68002FFF */ L3ID_OCM_ROM_TA,
+ /* 68003000-680033FF */ L3ID_D2D_IA,
+ /* 68003400-680037FF */ L3ID_D2D_TA,
+ /* 68003800-68003FFF */
+ /* 68004000-680043FF */ L3ID_HSUSB_HOST_IA,
+ /* 68004400-680047FF */ L3ID_HSUSB_OTG_IA,
+ /* 68004800-68004BFF */
+ /* 68004C00-68004FFF */ L3ID_SDMA_RD_IA,
+ /* 68005000-680053FF */ L3ID_SDMA_WR_IA,
+ /* 68005400-680057FF */ L3ID_DSS_IA,
+ /* 68005800-68005BFF */ L3ID_CAMISP_IA,
+ /* 68005C00-68005FFF */ L3ID_DAP_IA,
+ /* 68006000-680063FF */ L3ID_IVASS_TA,
+ /* 68006400-680067FF */ L3ID_SGXSS_TA,
+ /* 68006800-68006BFF */ L3ID_L4_CORE_TA,
+ /* 68006C00-68006FFF */ L3ID_L4_PER_TA,
+ /* 68007000-680073FF */ L3ID_L4_EMU_TA,
+ /* 68007400-6800FFFF */
+ /* 68010000-680103FF */ L3ID_RT_PM,
+ /* 68010400-680123FF */
+ /* 68012400-680127FF */ L3ID_GPMC_PM,
+ /* 68012800-68012BFF */ L3ID_OCM_RAM_PM,
+ /* 68012C00-68012FFF */ L3ID_OCM_ROM_PM,
+ /* 68013000-680133FF */ L3ID_D2D_PM,
+ /* 68013400-68013FFF */
+ /* 68014000-680143FF */ L3ID_IVA_PM,
+ /* 68014400-68FFFFFF */
+} omap3_l3_region_id_t;
+
+struct omap_l3_region_s {
+ target_phys_addr_t offset;
+ size_t size;
+ enum {
+ L3TYPE_GENERIC = 0, /* needs to be mapped separately */
+ L3TYPE_IA, /* initiator agent */
+ L3TYPE_TA, /* target agent */
+ L3TYPE_PM, /* protection mechanism */
+ L3TYPE_UNDEFINED, /* every access will emit an error message */
+ } type;
+};
+
+struct omap3_l3_initiator_agent_s {
+ target_phys_addr_t base;
+
+ uint32_t component;
+ uint32_t control;
+ uint32_t status;
+};
+
+struct omap3_l3pm_s {
+ target_phys_addr_t base;
+
+ uint32_t error_log;
+ uint8_t control;
+ uint16_t req_info_permission[8];
+ uint16_t read_permission[8];
+ uint16_t write_permission[8];
+ uint32_t addr_match[7];
+};
+
+union omap3_l3_port_s {
+ struct omap_target_agent_s ta;
+ struct omap3_l3_initiator_agent_s ia;
+ struct omap3_l3pm_s pm;
+};
+
+struct omap_l3_s {
+ target_phys_addr_t base;
+ int region_count;
+ union omap3_l3_port_s region[0];
+};
+
+static struct omap_l3_region_s omap3_l3_region[] = {
+ [L3ID_L3RT ] = {0x00000000, 0x0400, L3TYPE_UNDEFINED},
+ [L3ID_L3SI ] = {0x00000400, 0x0400, L3TYPE_UNDEFINED},
+ [L3ID_MPUSS_IA ] = {0x00001400, 0x0400, L3TYPE_IA},
+ [L3ID_IVASS_IA ] = {0x00001800, 0x0400, L3TYPE_IA},
+ [L3ID_SGXSS_IA ] = {0x00001c00, 0x0400, L3TYPE_IA},
+ [L3ID_SMS_TA ] = {0x00002000, 0x0400, L3TYPE_TA},
+ [L3ID_GPMC_TA ] = {0x00002400, 0x0400, L3TYPE_TA},
+ [L3ID_OCM_RAM_TA ] = {0x00002800, 0x0400, L3TYPE_TA},
+ [L3ID_OCM_ROM_TA ] = {0x00002c00, 0x0400, L3TYPE_TA},
+ [L3ID_D2D_IA ] = {0x00003000, 0x0400, L3TYPE_IA},
+ [L3ID_D2D_TA ] = {0x00003400, 0x0400, L3TYPE_TA},
+ [L3ID_HSUSB_HOST_IA] = {0x00004000, 0x0400, L3TYPE_IA},
+ [L3ID_HSUSB_OTG_IA ] = {0x00004400, 0x0400, L3TYPE_IA},
+ [L3ID_SDMA_RD_IA ] = {0x00004c00, 0x0400, L3TYPE_IA},
+ [L3ID_SDMA_WR_IA ] = {0x00005000, 0x0400, L3TYPE_IA},
+ [L3ID_DSS_IA ] = {0x00005400, 0x0400, L3TYPE_IA},
+ [L3ID_CAMISP_IA ] = {0x00005800, 0x0400, L3TYPE_IA},
+ [L3ID_DAP_IA ] = {0x00005c00, 0x0400, L3TYPE_IA},
+ [L3ID_IVASS_TA ] = {0x00006000, 0x0400, L3TYPE_TA},
+ [L3ID_SGXSS_TA ] = {0x00006400, 0x0400, L3TYPE_TA},
+ [L3ID_L4_CORE_TA ] = {0x00006800, 0x0400, L3TYPE_TA},
+ [L3ID_L4_PER_TA ] = {0x00006c00, 0x0400, L3TYPE_TA},
+ [L3ID_L4_EMU_TA ] = {0x00007000, 0x0400, L3TYPE_TA},
+ [L3ID_RT_PM ] = {0x00010000, 0x0400, L3TYPE_PM},
+ [L3ID_GPMC_PM ] = {0x00012400, 0x0400, L3TYPE_PM},
+ [L3ID_OCM_RAM_PM ] = {0x00012800, 0x0400, L3TYPE_PM},
+ [L3ID_OCM_ROM_PM ] = {0x00012c00, 0x0400, L3TYPE_PM},
+ [L3ID_D2D_PM ] = {0x00013000, 0x0400, L3TYPE_PM},
+ [L3ID_IVA_PM ] = {0x00014000, 0x0400, L3TYPE_PM},
+};
+
+#ifndef OMAP3_REDUCE_IOREGIONS
+static uint32_t omap3_l3ia_read(void *opaque, target_phys_addr_t addr)
+{
+ struct omap3_l3_initiator_agent_s *s = (struct omap3_l3_initiator_agent_s *)opaque;
+
+ switch (addr) {
+ case 0x00: /* COMPONENT_L */
+ return s->component;
+ case 0x04: /* COMPONENT_H */
+ return 0;
+ case 0x18: /* CORE_L */
+ return s->component;
+ case 0x1c: /* CORE_H */
+ return (s->component >> 16);
+ case 0x20: /* AGENT_CONTROL_L */
+ return s->control;
+ case 0x24: /* AGENT_CONTROL_H */
+ return 0;
+ case 0x28: /* AGENT_STATUS_L */
+ return s->status;
+ case 0x2c: /* AGENT_STATUS_H */
+ return 0;
+ case 0x58: /* ERROR_LOG_L */
+ return 0;
+ case 0x5c: /* ERROR_LOG_H */
+ return 0;
+ case 0x60: /* ERROR_LOG_ADDR_L */
+ return 0;
+ case 0x64: /* ERROR_LOG_ADDR_H */
+ return 0;
+ default:
+ break;
+ }
+
+ OMAP_BAD_REG(s->base + addr);
+ return 0;
+}
+
+static void omap3_l3ia_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap3_l3_initiator_agent_s *s = (struct omap3_l3_initiator_agent_s *)opaque;
+
+ switch (addr) {
+ case 0x00: /* COMPONENT_L */
+ case 0x04: /* COMPONENT_H */
+ case 0x18: /* CORE_L */
+ case 0x1c: /* CORE_H */
+ case 0x60: /* ERROR_LOG_ADDR_L */
+ case 0x64: /* ERROR_LOG_ADDR_H */
+ OMAP_RO_REG(s->base + addr);
+ break;
+ case 0x24: /* AGENT_CONTROL_H */
+ case 0x2c: /* AGENT_STATUS_H */
+ case 0x5c: /* ERROR_LOG_H */
+ /* RW register but all bits are reserved/read-only */
+ break;
+ case 0x20: /* AGENT_CONTROL_L */
+ s->control = value & 0x3e070711;
+ /* TODO: some bits are reserved for some IA instances */
+ break;
+ case 0x28: /* AGENT_STATUS_L */
+ s->status &= ~(value & 0x30000000);
+ break;
+ case 0x58: /* ERROR_LOG_L */
+ /* error logging is not implemented, so ignore */
+ break;
+ default:
+ OMAP_BAD_REG(s->base + addr);
+ break;
+ }
+}
+
+static void omap3_l3ia_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap3_l3_initiator_agent_s *s =
+ (struct omap3_l3_initiator_agent_s *)opaque;
+
+ qemu_put_be32(f, s->control);
+ qemu_put_be32(f, s->status);
+}
+
+static int omap3_l3ia_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap3_l3_initiator_agent_s *s =
+ (struct omap3_l3_initiator_agent_s *)opaque;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->control = qemu_get_be32(f);
+ s->status = qemu_get_be32(f);
+
+ return 0;
+}
+
+static void omap3_l3ia_init(struct omap3_l3_initiator_agent_s *s)
+{
+ s->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+ s->control = 0x3e000000;
+ s->status = 0;
+
+ register_savevm("omap3_l3ia", (s->base >> 8) & 0xffff, 0,
+ omap3_l3ia_save_state, omap3_l3ia_load_state, s);
+}
+
+static CPUReadMemoryFunc *omap3_l3ia_readfn[] = {
+ omap_badwidth_read32,
+ omap_badwidth_read32,
+ omap3_l3ia_read,
+};
+
+static CPUWriteMemoryFunc *omap3_l3ia_writefn[] = {
+ omap_badwidth_write32,
+ omap_badwidth_write32,
+ omap3_l3ia_write,
+};
+
+static uint32_t omap3_l3ta_read(void *opaque, target_phys_addr_t addr)
+{
+ struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+
+ switch (addr) {
+ case 0x00: /* COMPONENT_L */
+ return s->component;
+ case 0x04: /* COMPONENT_H */
+ return 0;
+ case 0x18: /* CORE_L */
+ return s->component;
+ case 0x1c: /* CORE_H */
+ return (s->component >> 16);
+ case 0x20: /* AGENT_CONTROL_L */
+ return s->control;
+ case 0x24: /* AGENT_CONTROL_H */
+ return s->control_h;
+ case 0x28: /* AGENT_STATUS_L */
+ return s->status;
+ case 0x2c: /* AGENT_STATUS_H */
+ return 0;
+ case 0x58: /* ERROR_LOG_L */
+ return 0;
+ case 0x5c: /* ERROR_LOG_H */
+ return 0;
+ case 0x60: /* ERROR_LOG_ADDR_L */
+ return 0;
+ case 0x64: /* ERROR_LOG_ADDR_H */
+ return 0;
+ default:
+ break;
+ }
+
+ OMAP_BAD_REG(s->base + addr);
+ return 0;
+}
+
+static void omap3_l3ta_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+
+ switch (addr) {
+ case 0x00: /* COMPONENT_L */
+ case 0x04: /* COMPONENT_H */
+ case 0x18: /* CORE_L */
+ case 0x1c: /* CORE_H */
+ case 0x60: /* ERROR_LOG_ADDR_L */
+ case 0x64: /* ERROR_LOG_ADDR_H */
+ OMAP_RO_REG(s->base + addr);
+ break;
+ case 0x24: /* AGENT_CONTROL_H */
+ case 0x5c: /* ERROR_LOG_H */
+ /* RW register but all bits are reserved/read-only */
+ break;
+ case 0x20: /* AGENT_CONTROL_L */
+ s->control = value & 0x03000711;
+ break;
+ case 0x28: /* AGENT_STATUS_L */
+ if (s->base == OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_CORE_TA].offset
+ || s->base == OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_PER_TA].offset
+ || s->base == OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_EMU_TA].offset) {
+ s->status &= ~(value & (1 << 24));
+ } else
+ OMAP_RO_REG(s->base + addr);
+ break;
+ case 0x2c: /* AGENT_STATUS_H */
+ if (s->base != OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_CORE_TA].offset
+ && s->base != OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_PER_TA].offset
+ && s->base != OMAP3_L3_BASE + omap3_l3_region[L3ID_L4_EMU_TA].offset)
+ OMAP_RO_REG(s->base + addr);
+ /* for L4 core, per, emu TAs this is RW reg */
+ break;
+ case 0x58: /* ERROR_LOG_L */
+ /* error logging is not implemented, so ignore */
+ break;
+ default:
+ OMAP_BAD_REG(s->base + addr);
+ break;
+ }
+}
+
+static void omap3_l3ta_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap_target_agent_s *s =
+ (struct omap_target_agent_s *)opaque;
+
+ qemu_put_be32(f, s->control);
+ qemu_put_be32(f, s->status);
+}
+
+static int omap3_l3ta_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap_target_agent_s *s =
+ (struct omap_target_agent_s *)opaque;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->control = qemu_get_be32(f);
+ s->status = qemu_get_be32(f);
+
+ return 0;
+}
+
+static void omap3_l3ta_init(struct omap_target_agent_s *s)
+{
+ s->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+ s->control = 0x03000000;
+ s->status = 0;
+
+ register_savevm("omap3_l3ta", (s->base >> 8) & 0xffff, 0,
+ omap3_l3ta_save_state, omap3_l3ta_load_state, s);
+}
+
+static CPUReadMemoryFunc *omap3_l3ta_readfn[] = {
+ omap_badwidth_read32,
+ omap_badwidth_read32,
+ omap3_l3ta_read,
+};
+
+static CPUWriteMemoryFunc *omap3_l3ta_writefn[] = {
+ omap_badwidth_write32,
+ omap_badwidth_write32,
+ omap3_l3ta_write,
+};
+
+static uint32_t omap3_l3pm_read8(void *opaque, target_phys_addr_t addr)
+{
+ struct omap3_l3pm_s *s = (struct omap3_l3pm_s *)opaque;
+ int i;
+
+ switch (addr) {
+ case 0x00 ... 0x1f:
+ case 0x40 ... 0x47:
+ OMAP_BAD_REG(s->base + addr);
+ return 0;
+ /* ERROR_LOG */
+ case 0x20: return s->error_log & 0xff;
+ case 0x21: return (s->error_log >> 8) & 0xff;
+ case 0x22: return (s->error_log >> 16) & 0xff;
+ case 0x23: return (s->error_log >> 24) & 0xff;
+ case 0x24 ... 0x27: return 0;
+ /* CONTROL */
+ case 0x28 ... 0x2a: return 0;
+ case 0x2b: return s->control;
+ case 0x2c ... 0x2f: return 0;
+ /* ERROR_CLEAR_SINGLE */
+ case 0x30: return 0; /* TODO: clear single error from log */
+ case 0x31 ... 0x37: return 0;
+ /* ERROR_CLEAR_MULTI */
+ case 0x38: return 0; /* TODO: clear multiple errors from log */
+ case 0x39 ... 0x3f: return 0;
+ default:
+ break;
+ }
+
+ i = (addr - 0x48) / 0x20;
+ addr -= i * 0x20;
+ if (i < 7 || (i < 8 && addr < 0x60))
+ switch (addr) {
+ /* REQ_INFO_PERMISSION_i */
+ case 0x48: return s->req_info_permission[i] & 0xff;
+ case 0x49: return (s->req_info_permission[i] >> 8) & 0xff;
+ case 0x4a ... 0x4f: return 0;
+ /* READ_PERMISSION_i */
+ case 0x50: return s->read_permission[i] & 0xff;
+ case 0x51: return (s->read_permission[i] >> 8) & 0xff;
+ case 0x52 ... 0x57: return 0;
+ /* WRITE_PERMISSION_i */
+ case 0x58: return s->write_permission[i] & 0xff;
+ case 0x59: return (s->write_permission[i] >> 8) & 0xff;
+ case 0x5a ... 0x5f: return 0;
+ /* ADDR_MATCH_i */
+ case 0x60: return s->addr_match[i] & 0xff;
+ case 0x61: return (s->addr_match[i] >> 8) & 0xff;
+ case 0x62: return (s->addr_match[i] >> 16) & 0xff;
+ case 0x63 ... 0x67: return 0;
+ default:
+ break;
+ }
+
+ OMAP_BAD_REG(s->base + addr);
+ return 0;
+}
+
+static uint32_t omap3_l3pm_read16(void *opaque, target_phys_addr_t addr)
+{
+ return omap3_l3pm_read8(opaque, addr)
+ | (omap3_l3pm_read8(opaque, addr + 1) << 8);
+}
+
+static uint32_t omap3_l3pm_read32(void *opaque, target_phys_addr_t addr)
+{
+ return omap3_l3pm_read16(opaque, addr)
+ | (omap3_l3pm_read16(opaque, addr + 2) << 16);
+}
+
+static void omap3_l3pm_write8(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap3_l3pm_s *s = (struct omap3_l3pm_s *)opaque;
+ int i;
+
+ switch (addr) {
+ case 0x00 ... 0x1f:
+ case 0x40 ... 0x47:
+ OMAP_BAD_REGV(s->base + addr, value);
+ return;
+ /* ERROR_LOG */
+ case 0x23:
+ s->error_log &= ~((value & 0xcf) << 24);
+ case 0x20 ... 0x22:
+ case 0x24 ... 0x27:
+ return;
+ /* CONTROL */
+ case 0x2b:
+ s->control = value & 3;
+ case 0x28 ... 0x2a:
+ case 0x2c ... 0x2f:
+ return;
+ /* ERROR_CLEAR_SINGLE / ERROR_CLEAR_MULTI */
+ case 0x30 ... 0x3f:
+ OMAP_RO_REGV(s->base + addr, value);
+ return;
+ default:
+ break;
+ }
+
+ i = (addr - 0x48) / 0x20;
+ addr -= i * 0x20;
+ if (i < 7 || (i < 8 && addr < 0x60))
+ switch (addr) {
+ /* REQ_INFO_PERMISSION_i */
+ case 0x48:
+ s->req_info_permission[i] =
+ (s->req_info_permission[i] & ~0xff) | (value & 0xff);
+ return;
+ case 0x49:
+ s->req_info_permission[i] =
+ (s->req_info_permission[i] & ~0xff00) | ((value & 0xff) << 8);
+ return;
+ case 0x4a ... 0x4f:
+ return;
+ /* READ_PERMISSION_i */
+ case 0x50:
+ s->read_permission[i] =
+ (s->read_permission[i] & ~0xff) | (value & 0x3e);
+ return;
+ case 0x51:
+ s->read_permission[i] =
+ (s->read_permission[i] & ~0xff00) | ((value & 0x5f) << 8);
+ return;
+ case 0x52 ... 0x57:
+ return;
+ /* WRITE_PERMISSION_i */
+ case 0x58:
+ s->write_permission[i] =
+ (s->write_permission[i] & ~0xff) | (value & 0x3e);
+ return;
+ case 0x59:
+ s->write_permission[i] =
+ (s->write_permission[i] & ~0xff00) | ((value & 0x5f) << 8);
+ return;
+ case 0x5a ... 0x5f:
+ return;
+ /* ADDR_MATCH_i */
+ case 0x60:
+ s->addr_match[i] = (s->addr_match[i] & ~0xff) | (value & 0xff);
+ return;
+ case 0x61:
+ s->addr_match[i] =
+ (s->addr_match[i] & ~0xfe00) | ((value & 0xfe) << 8);
+ return;
+ case 0x62:
+ s->addr_match[i] =
+ (s->addr_match[i] & ~0x0f0000) | ((value & 0x0f) << 16);
+ return;
+ case 0x63 ... 0x67:
+ return;
+ default:
+ break;
+ }
+
+ OMAP_BAD_REGV(s->base + addr, value);
+}
+
+static void omap3_l3pm_write16(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ omap3_l3pm_write8(opaque, addr + 0, value & 0xff);
+ omap3_l3pm_write8(opaque, addr + 1, (value >> 8) & 0xff);
+}
+
+static void omap3_l3pm_write32(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ omap3_l3pm_write16(opaque, addr + 0, value & 0xffff);
+ omap3_l3pm_write16(opaque, addr + 2, (value >> 16) & 0xffff);
+}
+
+static void omap3_l3pm_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap3_l3pm_s *s = (struct omap3_l3pm_s *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->error_log);
+ qemu_put_byte(f, s->control);
+ for (i = 0; i < 8; i++) {
+ qemu_put_be16(f, s->req_info_permission[i]);
+ qemu_put_be16(f, s->read_permission[i]);
+ qemu_put_be16(f, s->write_permission[i]);
+ if (i < 7)
+ qemu_put_be32(f, s->addr_match[i]);
+ }
+}
+
+static int omap3_l3pm_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap3_l3pm_s *s = (struct omap3_l3pm_s *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->error_log = qemu_get_be32(f);
+ s->control = qemu_get_byte(f);
+ for (i = 0; i < 8; i++) {
+ s->req_info_permission[i] = qemu_get_be16(f);
+ s->read_permission[i] = qemu_get_be16(f);
+ s->write_permission[i] = qemu_get_be16(f);
+ if (i < 7)
+ s->addr_match[i] = qemu_get_be32(f);
+ }
+ return 0;
+}
+
+static void omap3_l3pm_init(struct omap3_l3pm_s *s)
+{
+ int i;
+
+ s->error_log = 0;
+ s->control = 0x03;
+ switch (s->base) {
+ case 0x68010000: /* PM_RT */
+ s->req_info_permission[0] = 0xffff;
+ s->req_info_permission[1] = 0;
+ for (i = 0; i < 2; i++)
+ s->read_permission[i] = s->write_permission[i] = 0x1406;
+ s->addr_match[0] = 0x10230;
+ break;
+ case 0x68012400: /* PM_GPMC */
+ s->req_info_permission[0] = 0;
+ for (i = 3; i < 8; i++)
+ s->req_info_permission[i] = 0xffff;
+ for (i = 0; i < 8; i++)
+ s->read_permission[i] = s->write_permission[i] = 0x563e;
+ s->addr_match[0] = 0x00098;
+ break;
+ case 0x68012800: /* PM_OCM_RAM */
+ s->req_info_permission[0] = 0;
+ for (i = 1; i < 8; i++)
+ s->req_info_permission[i] = 0xffff;
+ for (i = 0; i < 8; i++)
+ s->read_permission[i] = s->write_permission[i] = 0x5f3e;
+ s->addr_match[1] = 0x0f810;
+ break;
+ case 0x68012C00: /* PM_OCM_ROM */
+ s->req_info_permission[1] = 0xffff;
+ for (i = 0; i < 2; i++) {
+ s->read_permission[i] = 0x1002;
+ s->write_permission[i] = 0;
+ }
+ s->addr_match[0] = 0x14028;
+ break;
+ case 0x68013000: /* PM_MAD2D */
+ s->req_info_permission[0] = 0;
+ for (i = 1; i < 8; i++)
+ s->req_info_permission[i] = 0xffff;
+ for (i = 0; i < 8; i++)
+ s->read_permission[i] = s->write_permission[i] = 0x5f1e;
+ break;
+ case 0x68014000: /* PM_IVA2.2 */
+ s->req_info_permission[0] = 0;
+ for (i = 1; i < 4; i++)
+ s->req_info_permission[i] = 0xffff;
+ for (i = 0; i < 4; i++)
+ s->read_permission[i] = s->write_permission[i] = 0x140e;
+ break;
+ default:
+ fprintf(stderr, "%s: unknown PM region (0x%08llx)\n",
+ __FUNCTION__, s->base);
+ exit(-1);
+ break;
+ }
+
+ register_savevm("omap3_l3pm", (s->base >> 8) & 0xffff, 0,
+ omap3_l3pm_save_state, omap3_l3pm_load_state, s);
+}
+
+static CPUReadMemoryFunc *omap3_l3pm_readfn[] = {
+ omap3_l3pm_read8,
+ omap3_l3pm_read16,
+ omap3_l3pm_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_l3pm_writefn[] = {
+ omap3_l3pm_write8,
+ omap3_l3pm_write16,
+ omap3_l3pm_write32,
+};
+
+static uint32_t omap3_l3undef_read8(void *opaque, target_phys_addr_t addr)
+{
+ fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx "\n",
+ __FUNCTION__, addr);
+ return 0;
+}
+
+static uint32_t omap3_l3undef_read16(void *opaque, target_phys_addr_t addr)
+{
+ fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx "\n",
+ __FUNCTION__, addr);
+ return 0;
+}
+
+static uint32_t omap3_l3undef_read32(void *opaque, target_phys_addr_t addr)
+{
+ fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx "\n",
+ __FUNCTION__, addr);
+ return 0;
+}
+
+static void omap3_l3undef_write8(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx ", value %02x\n",
+ __FUNCTION__, addr, value);
+}
+
+static void omap3_l3undef_write16(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx ", value %04x\n",
+ __FUNCTION__, addr, value);
+}
+
+static void omap3_l3undef_write32(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ fprintf(stderr, "%s: unsupported register at " OMAP_FMT_plx ", value %08x\n",
+ __FUNCTION__, addr, value);
+}
+
+static CPUReadMemoryFunc *omap3_l3undef_readfn[] = {
+ omap3_l3undef_read8,
+ omap3_l3undef_read16,
+ omap3_l3undef_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_l3undef_writefn[] = {
+ omap3_l3undef_write8,
+ omap3_l3undef_write16,
+ omap3_l3undef_write32,
+};
+#endif
+
+static struct omap_l3_s *omap3_l3_init(target_phys_addr_t base,
+ struct omap_l3_region_s *regions,
+ int n)
+{
+#ifdef OMAP3_REDUCE_IOREGIONS
+ return NULL;
+#else
+ int i, iomemtype = 0;
+
+ struct omap_l3_s *bus = qemu_mallocz(sizeof(*bus) + n * sizeof(*bus->region));
+ bus->region_count = n;
+ bus->base = base;
+
+ for (i = 0; i < n; i++) {
+ switch (regions[i].type) {
+ case L3TYPE_GENERIC:
+ /* not mapped for now, mapping will be done later by
+ specialized code */
+ break;
+ case L3TYPE_IA:
+ iomemtype = cpu_register_io_memory(0, omap3_l3ia_readfn,
+ omap3_l3ia_writefn,
+ &bus->region[i].ia);
+ bus->region[i].ia.base = base + regions[i].offset;
+ omap3_l3ia_init(&bus->region[i].ia);
+ break;
+ case L3TYPE_TA:
+ iomemtype = cpu_register_io_memory(0, omap3_l3ta_readfn,
+ omap3_l3ta_writefn,
+ &bus->region[i].ta);
+ bus->region[i].ta.base = base + regions[i].offset;
+ omap3_l3ta_init(&bus->region[i].ta);
+ break;
+ case L3TYPE_PM:
+ iomemtype = cpu_register_io_memory(0, omap3_l3pm_readfn,
+ omap3_l3pm_writefn,
+ &bus->region[i].pm);
+ bus->region[i].pm.base = base + regions[i].offset;
+ omap3_l3pm_init(&bus->region[i].pm);
+ break;
+ case L3TYPE_UNDEFINED:
+ iomemtype = cpu_register_io_memory(0, omap3_l3undef_readfn,
+ omap3_l3undef_writefn,
+ &bus->region[i]);
+ break;
+ default:
+ fprintf(stderr, "%s: unknown L3 region type: %d\n",
+ __FUNCTION__, regions[i].type);
+ exit(-1);
+ break;
+ }
+ cpu_register_physical_memory(base + regions[i].offset,
+ regions[i].size,
+ iomemtype);
+ }
+
+ return bus;
+#endif
+}
+
+typedef enum {
+ /* 48000000-48001FFF */
+ /* 48002000-48002FFF */ L4ID_SCM = 0,
+ /* 48003000-48003FFF */ L4ID_SCM_TA,
+ /* 48004000-48005FFF */ L4ID_CM_A,
+ /* 48006000-480067FF */ L4ID_CM_B,
+ /* 48006800-48006FFF */
+ /* 48007000-48007FFF */ L4ID_CM_TA,
+ /* 48008000-48023FFF */
+ /* 48024000-48024FFF */
+ /* 48025000-48025FFF */
+ /* 48026000-4803FFFF */
+ /* 48040000-480407FF */ L4ID_CORE_AP,
+ /* 48040800-48040FFF */ L4ID_CORE_IP,
+ /* 48041000-48041FFF */ L4ID_CORE_LA,
+ /* 48042000-4804FBFF */
+ /* 4804FC00-4804FFFF */ L4ID_DSI,
+ /* 48050000-480503FF */ L4ID_DSS,
+ /* 48050400-480507FF */ L4ID_DISPC,
+ /* 48050800-48050BFF */ L4ID_RFBI,
+ /* 48050C00-48050FFF */ L4ID_VENC,
+ /* 48051000-48051FFF */ L4ID_DSS_TA,
+ /* 48052000-48055FFF */
+ /* 48056000-48056FFF */ L4ID_SDMA,
+ /* 48057000-48057FFF */ L4ID_SDMA_TA,
+ /* 48058000-4805FFFF */
+ /* 48060000-48060FFF */ L4ID_I2C3,
+ /* 48061000-48061FFF */ L4ID_I2C3_TA,
+ /* 48062000-48062FFF */ L4ID_USBTLL,
+ /* 48063000-48063FFF */ L4ID_USBTLL_TA,
+ /* 48064000-480643FF */ L4ID_USBHOST,
+ /* 48064400-480647FF */ L4ID_USBHOST_OHCI,
+ /* 48064800-4806BFFF */ L4ID_USBHOST_EHCI,
+ /* 48065000-48065FFF */ L4ID_USBHOST_TA,
+ /* 48066000-48069FFF */
+ /* 4806A000-4806AFFF */ L4ID_UART1,
+ /* 4806B000-4806BFFF */ L4ID_UART1_TA,
+ /* 4806C000-4806CFFF */ L4ID_UART2,
+ /* 4806D000-4806DFFF */ L4ID_UART2_TA,
+ /* 4806E000-4806FFFF */
+ /* 48070000-48070FFF */ L4ID_I2C1,
+ /* 48071000-48071FFF */ L4ID_I2C1_TA,
+ /* 48072000-48072FFF */ L4ID_I2C2,
+ /* 48073000-48073FFF */ L4ID_I2C2_TA,
+ /* 48074000-48074FFF */ L4ID_MCBSP1,
+ /* 48075000-48075FFF */ L4ID_MCBSP1_TA,
+ /* 48076000-48085FFF */
+ /* 48086000-48086FFF */ L4ID_GPTIMER10,
+ /* 48087000-48087FFF */ L4ID_GPTIMER10_TA,
+ /* 48088000-48088FFF */ L4ID_GPTIMER11,
+ /* 48089000-48089FFF */ L4ID_GPTIMER11_TA,
+ /* 4808A000-4808AFFF */
+ /* 4808B000-4808BFFF */
+ /* 4808C000-48093FFF */
+ /* 48094000-48094FFF */ L4ID_MAILBOX,
+ /* 48095000-48095FFF */ L4ID_MAILBOX_TA,
+ /* 48096000-48096FFF */ L4ID_MCBSP5,
+ /* 48097000-48097FFF */ L4ID_MCBSP5_TA,
+ /* 48098000-48098FFF */ L4ID_MCSPI1,
+ /* 48099000-48099FFF */ L4ID_MCSPI1_TA,
+ /* 4809A000-4809AFFF */ L4ID_MCSPI2,
+ /* 4809B000-4809BFFF */ L4ID_MCSPI2_TA,
+ /* 4809C000-4809CFFF */ L4ID_MMCSDIO1,
+ /* 4809D000-4809DFFF */ L4ID_MMCSDIO1_TA,
+ /* 4809E000-4809EFFF */ L4ID_MSPRO,
+ /* 4809F000-4809FFFF */ L4ID_MSPRO_TA,
+ /* 480A0000-480AAFFF */
+ /* 480AB000-480ABFFF */ L4ID_HSUSBOTG,
+ /* 480AC000-480ACFFF */ L4ID_HSUSBOTG_TA,
+ /* 480AD000-480ADFFF */ L4ID_MMCSDIO3,
+ /* 480AE000-480AEFFF */ L4ID_MMCSDIO3_TA,
+ /* 480AF000-480AFFFF */
+ /* 480B0000-480B0FFF */
+ /* 480B1000-480B1FFF */
+ /* 480B2000-480B2FFF */ L4ID_HDQ1WIRE,
+ /* 480B3000-480B2FFF */ L4ID_HDQ1WIRE_TA,
+ /* 480B4000-480B4FFF */ L4ID_MMCSDIO2,
+ /* 480B5000-480B5FFF */ L4ID_MMCSDIO2_TA,
+ /* 480B6000-480B6FFF */ L4ID_ICRMPU,
+ /* 480B7000-480B7FFF */ L4ID_ICRMPU_TA,
+ /* 480B8000-480B8FFF */ L4ID_MCSPI3,
+ /* 480B9000-480B9FFF */ L4ID_MCSPI3_TA,
+ /* 480BA000-480BAFFF */ L4ID_MCSPI4,
+ /* 480BB000-480BBFFF */ L4ID_MCSPI4_TA,
+ /* 480BC000-480BFFFF */ L4ID_CAMERAISP,
+ /* 480C0000-480C0FFF */ L4ID_CAMERAISP_TA,
+ /* 480C1000-480CCFFF */
+ /* 480CD000-480CDFFF */ L4ID_ICRMODEM,
+ /* 480CE000-480CEFFF */ L4ID_ICRMODEM_TA,
+ /* 480CF000-482FFFFF */
+ /* 48300000-48303FFF */
+ /* 48304000-48304FFF */ L4ID_GPTIMER12,
+ /* 48305000-48305FFF */ L4ID_GPTIMER12_TA,
+ /* 48306000-48307FFF */ L4ID_PRM_A,
+ /* 48308000-483087FF */ L4ID_PRM_B,
+ /* 48308800-48308FFF */
+ /* 48309000-48309FFF */ L4ID_PRM_TA,
+ /* 4830A000-4830AFFF */ L4ID_TAP,
+ /* 4830B000-4830BFFF */ L4ID_TAP_TA,
+ /* 4830C000-4830FFFF */
+ /* 48310000-48310FFF */ L4ID_GPIO1,
+ /* 48311000-48311FFF */ L4ID_GPIO1_TA,
+ /* 48312000-48313FFF */
+ /* 48314000-48314FFF */ L4ID_WDTIMER2,
+ /* 48315000-48315FFF */ L4ID_WDTIMER2_TA,
+ /* 48316000-48317FFF */
+ /* 48318000-48318FFF */ L4ID_GPTIMER1,
+ /* 48319000-48319FFF */ L4ID_GPTIMER1_TA,
+ /* 4831A000-4831FFFF */
+ /* 48320000-48320FFF */ L4ID_32KTIMER,
+ /* 48321000-48321FFF */ L4ID_32KTIMER_TA,
+ /* 48322000-48327FFF */
+ /* 48328000-483287FF */ L4ID_WAKEUP_AP,
+ /* 48328800-48328FFF */ L4ID_WAKEUP_C_IP,
+ /* 48329000-48329FFF */ L4ID_WAKEUP_LA,
+ /* 4832A000-4832A7FF */ L4ID_WAKEUP_E_IP,
+ /* 4832A800-4833FFFF */
+ /* 48340000-48340FFF */
+ /* 48341000-48FFFFFF */
+ /* 49000000-490007FF */ L4ID_PER_AP,
+ /* 49000800-49000FFF */ L4ID_PER_IP,
+ /* 49001000-49001FFF */ L4ID_PER_LA,
+ /* 49002000-4901FFFF */
+ /* 49020000-49020FFF */ L4ID_UART3,
+ /* 49021000-49021FFF */ L4ID_UART3_TA,
+ /* 49022000-49022FFF */ L4ID_MCBSP2,
+ /* 49023000-49023FFF */ L4ID_MCBSP2_TA,
+ /* 49024000-49024FFF */ L4ID_MCBSP3,
+ /* 49025000-49025FFF */ L4ID_MCBSP3_TA,
+ /* 49026000-49026FFF */ L4ID_MCBSP4,
+ /* 49027000-49027FFF */ L4ID_MCBSP4_TA,
+ /* 49028000-49028FFF */ L4ID_MCBSP2S,
+ /* 49029000-49029FFF */ L4ID_MCBSP2S_TA,
+ /* 4902A000-4902AFFF */ L4ID_MCBSP3S,
+ /* 4902B000-4902BFFF */ L4ID_MCBSP3S_TA,
+ /* 4902C000-4902FFFF */
+ /* 49030000-49030FFF */ L4ID_WDTIMER3,
+ /* 49031000-49031FFF */ L4ID_WDTIMER3_TA,
+ /* 49032000-49032FFF */ L4ID_GPTIMER2,
+ /* 49033000-49033FFF */ L4ID_GPTIMER2_TA,
+ /* 49034000-49034FFF */ L4ID_GPTIMER3,
+ /* 49035000-49035FFF */ L4ID_GPTIMER3_TA,
+ /* 49036000-49036FFF */ L4ID_GPTIMER4,
+ /* 49037000-49037FFF */ L4ID_GPTIMER4_TA,
+ /* 49038000-49038FFF */ L4ID_GPTIMER5,
+ /* 49039000-49039FFF */ L4ID_GPTIMER5_TA,
+ /* 4903A000-4903AFFF */ L4ID_GPTIMER6,
+ /* 4903B000-4903BFFF */ L4ID_GPTIMER6_TA,
+ /* 4903C000-4903CFFF */ L4ID_GPTIMER7,
+ /* 4903D000-4903DFFF */ L4ID_GPTIMER7_TA,
+ /* 4903E000-4903EFFF */ L4ID_GPTIMER8,
+ /* 4903F000-4903FFFF */ L4ID_GPTIMER8_TA,
+ /* 49040000-49040FFF */ L4ID_GPTIMER9,
+ /* 49041000-49041FFF */ L4ID_GPTIMER9_TA,
+ /* 49042000-4904FFFF */
+ /* 49050000-49050FFF */ L4ID_GPIO2,
+ /* 49051000-49051FFF */ L4ID_GPIO2_TA,
+ /* 49052000-49052FFF */ L4ID_GPIO3,
+ /* 49053000-49053FFF */ L4ID_GPIO3_TA,
+ /* 49054000-49054FFF */ L4ID_GPIO4,
+ /* 49055000-49055FFF */ L4ID_GPIO4_TA,
+ /* 49056000-49056FFF */ L4ID_GPIO5,
+ /* 49057000-49057FFF */ L4ID_GPIO5_TA,
+ /* 49058000-49058FFF */ L4ID_GPIO6,
+ /* 49059000-49059FFF */ L4ID_GPIO6_TA,
+ /* 4905A000-490FFFFF */
+ /* 54000000-54003FFF */
+ /* 54004000-54005FFF */
+ /* 54006000-540067FF */ L4ID_EMU_AP,
+ /* 54006800-54006FFF */ L4ID_EMU_IP_C,
+ /* 54007000-54007FFF */ L4ID_EMU_LA,
+ /* 54008000-540087FF */ L4ID_EMU_IP_DAP,
+ /* 54008800-5400FFFF */
+ /* 54010000-54017FFF */ L4ID_MPUEMU,
+ /* 54018000-54018FFF */ L4ID_MPUEMU_TA,
+ /* 54019000-54019FFF */ L4ID_TPIU,
+ /* 5401A000-5401AFFF */ L4ID_TPIU_TA,
+ /* 5401B000-5401BFFF */ L4ID_ETB,
+ /* 5401C000-5401CFFF */ L4ID_ETB_TA,
+ /* 5401D000-5401DFFF */ L4ID_DAPCTL,
+ /* 5401E000-5401EFFF */ L4ID_DAPCTL_TA,
+ /* 5401F000-5401FFFF */ L4ID_SDTI_TA,
+ /* 54020000-544FFFFF */
+ /* 54500000-5450FFFF */ L4ID_SDTI_CFG,
+ /* 54510000-545FFFFF */
+ /* 54600000-546FFFFF */ L4ID_SDTI,
+ /* 54700000-54705FFF */
+ /* 54706000-54707FFF */ L4ID_EMU_PRM_A,
+ /* 54708000-547087FF */ L4ID_EMU_PRM_B,
+ /* 54708800-54708FFF */
+ /* 54709000-54709FFF */ L4ID_EMU_PRM_TA,
+ /* 5470A000-5470FFFF */
+ /* 54710000-54710FFF */ L4ID_EMU_GPIO1,
+ /* 54711000-54711FFF */ L4ID_EMU_GPIO1_TA,
+ /* 54712000-54713FFF */
+ /* 54714000-54714FFF */ L4ID_EMU_WDTM2,
+ /* 54715000-54715FFF */ L4ID_EMU_WDTM2_TA,
+ /* 54716000-54717FFF */
+ /* 54718000-54718FFF */ L4ID_EMU_GPTM1,
+ /* 54719000-54719FFF */ L4ID_EMU_GPTM1_TA,
+ /* 5471A000-5471FFFF */
+ /* 54720000-54720FFF */ L4ID_EMU_32KTM,
+ /* 54721000-54721FFF */ L4ID_EMU_32KTM_TA,
+ /* 54722000-54727FFF */
+ /* 54728000-547287FF */ L4ID_EMU_WKUP_AP,
+ /* 54728800-54728FFF */ L4ID_EMU_WKUP_IPC,
+ /* 54729000-54729FFF */ L4ID_EMU_WKUP_LA,
+ /* 5472A000-5472A7FF */ L4ID_EMU_WKUP_IPE,
+ /* 5472A800-547FFFFF */
+} omap3_l4_region_id_t;
+
+typedef enum {
+ L4TYPE_GENERIC = 0, /* not mapped by default, must be mapped separately */
+ L4TYPE_IA, /* initiator agent */
+ L4TYPE_TA, /* target agent */
+ L4TYPE_LA, /* link register agent */
+ L4TYPE_AP /* address protection */
+} omap3_l4_region_type_t;
+
+/* we reuse the "access" member for defining region type -- the original
+ omap_l4_region_s "access" member is not used anywhere else anyway! */
+static struct omap_l4_region_s omap3_l4_region[] = {
+ /* L4-Core */
+ [L4ID_SCM ] = {0x00002000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_SCM_TA ] = {0x00003000, 0x1000, L4TYPE_TA},
+ [L4ID_CM_A ] = {0x00004000, 0x2000, L4TYPE_GENERIC},
+ [L4ID_CM_B ] = {0x00006000, 0x0800, L4TYPE_GENERIC},
+ [L4ID_CM_TA ] = {0x00007000, 0x1000, L4TYPE_TA},
+ [L4ID_CORE_AP ] = {0x00040000, 0x0800, L4TYPE_AP},
+ [L4ID_CORE_IP ] = {0x00040800, 0x0800, L4TYPE_IA},
+ [L4ID_CORE_LA ] = {0x00041000, 0x1000, L4TYPE_LA},
+ [L4ID_DSI ] = {0x0004fc00, 0x0400, L4TYPE_GENERIC},
+ [L4ID_DSS ] = {0x00050000, 0x0400, L4TYPE_GENERIC},
+ [L4ID_DISPC ] = {0x00050400, 0x0400, L4TYPE_GENERIC},
+ [L4ID_RFBI ] = {0x00050800, 0x0400, L4TYPE_GENERIC},
+ [L4ID_VENC ] = {0x00050c00, 0x0400, L4TYPE_GENERIC},
+ [L4ID_DSS_TA ] = {0x00051000, 0x1000, L4TYPE_TA},
+ [L4ID_SDMA ] = {0x00056000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_SDMA_TA ] = {0x00057000, 0x1000, L4TYPE_TA},
+ [L4ID_I2C3 ] = {0x00060000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_I2C3_TA ] = {0x00061000, 0x1000, L4TYPE_TA},
+ [L4ID_USBTLL ] = {0x00062000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_USBTLL_TA ] = {0x00063000, 0x1000, L4TYPE_TA},
+ [L4ID_USBHOST ] = {0x00064000, 0x0400, L4TYPE_GENERIC},
+ [L4ID_USBHOST_OHCI] = {0x00064400, 0x0400, L4TYPE_GENERIC},
+ [L4ID_USBHOST_EHCI] = {0x00064800, 0x0400, L4TYPE_GENERIC},
+ [L4ID_USBHOST_TA ] = {0x00065000, 0x1000, L4TYPE_TA},
+ [L4ID_UART1 ] = {0x0006a000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_UART1_TA ] = {0x0006b000, 0x1000, L4TYPE_TA},
+ [L4ID_UART2 ] = {0x0006c000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_UART2_TA ] = {0x0006d000, 0x1000, L4TYPE_TA},
+ [L4ID_I2C1 ] = {0x00070000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_I2C1_TA ] = {0x00071000, 0x1000, L4TYPE_TA},
+ [L4ID_I2C2 ] = {0x00072000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_I2C2_TA ] = {0x00073000, 0x1000, L4TYPE_TA},
+ [L4ID_MCBSP1 ] = {0x00074000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCBSP1_TA ] = {0x00075000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER10 ] = {0x00086000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER10_TA] = {0x00087000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER11 ] = {0x00088000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER11_TA] = {0x00089000, 0x1000, L4TYPE_TA},
+ [L4ID_MAILBOX ] = {0x00094000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MAILBOX_TA ] = {0x00095000, 0x1000, L4TYPE_TA},
+ [L4ID_MCBSP5 ] = {0x00096000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCBSP5_TA ] = {0x00097000, 0x1000, L4TYPE_TA},
+ [L4ID_MCSPI1 ] = {0x00098000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCSPI1_TA ] = {0x00099000, 0x1000, L4TYPE_TA},
+ [L4ID_MCSPI2 ] = {0x0009a000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCSPI2_TA ] = {0x0009b000, 0x1000, L4TYPE_TA},
+ [L4ID_MMCSDIO1 ] = {0x0009c000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MMCSDIO1_TA ] = {0x0009d000, 0x1000, L4TYPE_TA},
+ [L4ID_MSPRO ] = {0x0009e000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MSPRO_TA ] = {0x0009f000, 0x1000, L4TYPE_TA},
+ [L4ID_HSUSBOTG ] = {0x000ab000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_HSUSBOTG_TA ] = {0x000ac000, 0x1000, L4TYPE_TA},
+ [L4ID_MMCSDIO3 ] = {0x000ad000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MMCSDIO3_TA ] = {0x000ae000, 0x1000, L4TYPE_TA},
+ [L4ID_HDQ1WIRE ] = {0x000b2000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_HDQ1WIRE_TA ] = {0x000b3000, 0x1000, L4TYPE_TA},
+ [L4ID_MMCSDIO2 ] = {0x000b4000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MMCSDIO2_TA ] = {0x000b5000, 0x1000, L4TYPE_TA},
+ [L4ID_ICRMPU ] = {0x000b6000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_ICRMPU_TA ] = {0x000b7000, 0x1000, L4TYPE_TA},
+ [L4ID_MCSPI3 ] = {0x000b8000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCSPI3_TA ] = {0x000b9000, 0x1000, L4TYPE_TA},
+ [L4ID_MCSPI4 ] = {0x000ba000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCSPI4_TA ] = {0x000bb000, 0x1000, L4TYPE_TA},
+ [L4ID_CAMERAISP ] = {0x000bc000, 0x4000, L4TYPE_GENERIC},
+ [L4ID_CAMERAISP_TA] = {0x000c0000, 0x1000, L4TYPE_TA},
+ [L4ID_ICRMODEM ] = {0x000cd000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_ICRMODEM_TA ] = {0x000ce000, 0x1000, L4TYPE_TA},
+ /* L4-Wakeup interconnect region A */
+ [L4ID_GPTIMER12 ] = {0x00304000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER12_TA] = {0x00305000, 0x1000, L4TYPE_TA},
+ [L4ID_PRM_A ] = {0x00306000, 0x2000, L4TYPE_GENERIC},
+ [L4ID_PRM_B ] = {0x00308000, 0x0800, L4TYPE_GENERIC},
+ [L4ID_PRM_TA ] = {0x00309000, 0x1000, L4TYPE_TA},
+ /* L4-Core */
+ [L4ID_TAP ] = {0x0030a000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_TAP_TA ] = {0x0030b000, 0x1000, L4TYPE_TA},
+ /* L4-Wakeup interconnect region B */
+ [L4ID_GPIO1 ] = {0x00310000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPIO1_TA ] = {0x00311000, 0x1000, L4TYPE_TA},
+ [L4ID_WDTIMER2 ] = {0x00314000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_WDTIMER2_TA ] = {0x00315000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER1 ] = {0x00318000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER1_TA ] = {0x00319000, 0x1000, L4TYPE_TA},
+ [L4ID_32KTIMER ] = {0x00320000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_32KTIMER_TA ] = {0x00321000, 0x1000, L4TYPE_TA},
+ [L4ID_WAKEUP_AP ] = {0x00328000, 0x0800, L4TYPE_AP},
+ [L4ID_WAKEUP_C_IP ] = {0x00328800, 0x0800, L4TYPE_IA},
+ [L4ID_WAKEUP_LA ] = {0x00329000, 0x1000, L4TYPE_LA},
+ [L4ID_WAKEUP_E_IP ] = {0x0032a000, 0x0800, L4TYPE_IA},
+ /* L4-Per */
+ [L4ID_PER_AP ] = {0x01000000, 0x0800, L4TYPE_AP},
+ [L4ID_PER_IP ] = {0x01000800, 0x0800, L4TYPE_IA},
+ [L4ID_PER_LA ] = {0x01001000, 0x1000, L4TYPE_LA},
+ [L4ID_UART3 ] = {0x01020000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_UART3_TA ] = {0x01021000, 0x1000, L4TYPE_TA},
+ [L4ID_MCBSP2 ] = {0x01022000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCBSP2_TA ] = {0x01023000, 0x1000, L4TYPE_TA},
+ [L4ID_MCBSP3 ] = {0x01024000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCBSP3_TA ] = {0x01025000, 0x1000, L4TYPE_TA},
+ [L4ID_MCBSP4 ] = {0x01026000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCBSP4_TA ] = {0x01027000, 0x1000, L4TYPE_TA},
+ [L4ID_MCBSP2S ] = {0x01028000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCBSP2S_TA ] = {0x01029000, 0x1000, L4TYPE_TA},
+ [L4ID_MCBSP3S ] = {0x0102a000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_MCBSP3S_TA ] = {0x0102b000, 0x1000, L4TYPE_TA},
+ [L4ID_WDTIMER3 ] = {0x01030000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_WDTIMER3_TA ] = {0x01031000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER2 ] = {0x01032000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER2_TA ] = {0x01033000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER3 ] = {0x01034000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER3_TA ] = {0x01035000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER4 ] = {0x01036000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER4_TA ] = {0x01037000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER5 ] = {0x01038000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER5_TA ] = {0x01039000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER6 ] = {0x0103a000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER6_TA ] = {0x0103b000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER7 ] = {0x0103c000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER7_TA ] = {0x0103d000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER8 ] = {0x0103e000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER8_TA ] = {0x0103f000, 0x1000, L4TYPE_TA},
+ [L4ID_GPTIMER9 ] = {0x01040000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPTIMER9_TA ] = {0x01041000, 0x1000, L4TYPE_TA},
+ [L4ID_GPIO2 ] = {0x01050000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPIO2_TA ] = {0x01051000, 0x1000, L4TYPE_TA},
+ [L4ID_GPIO3 ] = {0x01052000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPIO3_TA ] = {0x01053000, 0x1000, L4TYPE_TA},
+ [L4ID_GPIO4 ] = {0x01054000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPIO4_TA ] = {0x01055000, 0x1000, L4TYPE_TA},
+ [L4ID_GPIO5 ] = {0x01056000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPIO5_TA ] = {0x01057000, 0x1000, L4TYPE_TA},
+ [L4ID_GPIO6 ] = {0x01058000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_GPIO6_TA ] = {0x01059000, 0x1000, L4TYPE_TA},
+ /* L4-Emu */
+ [L4ID_EMU_AP ] = {0x0c006000, 0x0800, L4TYPE_AP},
+ [L4ID_EMU_IP_C ] = {0x0c006800, 0x0800, L4TYPE_IA},
+ [L4ID_EMU_LA ] = {0x0c007000, 0x1000, L4TYPE_LA},
+ [L4ID_EMU_IP_DAP ] = {0x0c008000, 0x0800, L4TYPE_IA},
+ [L4ID_MPUEMU ] = {0x0c010000, 0x8000, L4TYPE_GENERIC},
+ [L4ID_MPUEMU_TA ] = {0x0c018000, 0x1000, L4TYPE_TA},
+ [L4ID_TPIU ] = {0x0c019000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_TPIU_TA ] = {0x0c01a000, 0x1000, L4TYPE_TA},
+ [L4ID_ETB ] = {0x0c01b000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_ETB_TA ] = {0x0c01c000, 0x1000, L4TYPE_TA},
+ [L4ID_DAPCTL ] = {0x0c01d000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_DAPCTL_TA ] = {0x0c01e000, 0x1000, L4TYPE_TA},
+ [L4ID_EMU_PRM_A ] = {0x0c706000, 0x2000, L4TYPE_GENERIC},
+ [L4ID_EMU_PRM_B ] = {0x0c706800, 0x0800, L4TYPE_GENERIC},
+ [L4ID_EMU_PRM_TA ] = {0x0c709000, 0x1000, L4TYPE_TA},
+ [L4ID_EMU_GPIO1 ] = {0x0c710000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_EMU_GPIO1_TA] = {0x0c711000, 0x1000, L4TYPE_TA},
+ [L4ID_EMU_WDTM2 ] = {0x0c714000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_EMU_WDTM2_TA] = {0x0c715000, 0x1000, L4TYPE_TA},
+ [L4ID_EMU_GPTM1 ] = {0x0c718000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_EMU_GPTM1_TA] = {0x0c719000, 0x1000, L4TYPE_TA},
+ [L4ID_EMU_32KTM ] = {0x0c720000, 0x1000, L4TYPE_GENERIC},
+ [L4ID_EMU_32KTM_TA] = {0x0c721000, 0x1000, L4TYPE_TA},
+ [L4ID_EMU_WKUP_AP ] = {0x0c728000, 0x0800, L4TYPE_AP},
+ [L4ID_EMU_WKUP_IPC] = {0x0c728800, 0x0800, L4TYPE_IA},
+ [L4ID_EMU_WKUP_LA ] = {0x0c729000, 0x1000, L4TYPE_LA},
+ [L4ID_EMU_WKUP_IPE] = {0x0c72a000, 0x0800, L4TYPE_IA},
+};
+
+typedef enum {
+ L4A_SCM = 0,
+ L4A_CM,
+ L4A_PRM,
+ L4A_GPTIMER1,
+ L4A_GPTIMER2,
+ L4A_GPTIMER3,
+ L4A_GPTIMER4,
+ L4A_GPTIMER5,
+ L4A_GPTIMER6,
+ L4A_GPTIMER7,
+ L4A_GPTIMER8,
+ L4A_GPTIMER9,
+ L4A_GPTIMER10,
+ L4A_GPTIMER11,
+ L4A_GPTIMER12,
+ L4A_WDTIMER2,
+ L4A_32KTIMER,
+ L4A_UART1,
+ L4A_UART2,
+ L4A_UART3,
+ L4A_DSS,
+ L4A_GPIO1,
+ L4A_GPIO2,
+ L4A_GPIO3,
+ L4A_GPIO4,
+ L4A_GPIO5,
+ L4A_GPIO6,
+ L4A_MMC1,
+ L4A_MMC2,
+ L4A_MMC3,
+ L4A_I2C1,
+ L4A_I2C2,
+ L4A_I2C3,
+ L4A_TAP,
+ L4A_USBHS_OTG,
+ L4A_USBHS_HOST,
+ L4A_USBHS_TLL,
+ L4A_MCSPI1,
+ L4A_MCSPI2,
+ L4A_MCSPI3,
+ L4A_MCSPI4,
+ L4A_SDMA
+} omap3_l4_agent_info_id_t;
+
+struct omap3_l4_agent_info_s {
+ omap3_l4_agent_info_id_t agent_id;
+ omap3_l4_region_id_t first_region_id;
+ int region_count;
+};
+
+static const struct omap3_l4_agent_info_s omap3_l4_agent_info[] = {
+ /* L4-Core Agents */
+ {L4A_DSS, L4ID_DSI, 6},
+ /* TODO: camera */
+ {L4A_USBHS_OTG, L4ID_HSUSBOTG, 2},
+ {L4A_USBHS_HOST, L4ID_USBHOST, 4},
+ {L4A_USBHS_TLL, L4ID_USBTLL, 2},
+ {L4A_UART1, L4ID_UART1, 2},
+ {L4A_UART2, L4ID_UART2, 2},
+ {L4A_I2C1, L4ID_I2C1, 2},
+ {L4A_I2C2, L4ID_I2C2, 2},
+ {L4A_I2C3, L4ID_I2C3, 2},
+ /* TODO: McBSP1 */
+ /* TODO: McBSP5 */
+ {L4A_GPTIMER10, L4ID_GPTIMER10, 2},
+ {L4A_GPTIMER11, L4ID_GPTIMER11, 2},
+ {L4A_MCSPI1, L4ID_MCSPI1, 2},
+ {L4A_MCSPI2, L4ID_MCSPI2, 2},
+ {L4A_MMC1, L4ID_MMCSDIO1, 2},
+ {L4A_MMC2, L4ID_MMCSDIO2, 2},
+ {L4A_MMC3, L4ID_MMCSDIO3, 2},
+ /* TODO: HDQ/1-Wire */
+ /* TODO: Mailbox */
+ {L4A_MCSPI3, L4ID_MCSPI3, 2},
+ {L4A_MCSPI4, L4ID_MCSPI4, 2},
+ {L4A_SDMA, L4ID_SDMA, 2},
+ {L4A_CM, L4ID_CM_A, 3},
+ {L4A_SCM, L4ID_SCM, 2},
+ {L4A_TAP, L4ID_TAP, 2},
+ /* L4-Wakeup Agents */
+ {L4A_GPTIMER12, L4ID_GPTIMER12, 2},
+ {L4A_PRM, L4ID_PRM_A, 3},
+ {L4A_GPIO1, L4ID_GPIO1, 2},
+ {L4A_WDTIMER2, L4ID_WDTIMER2, 2},
+ {L4A_GPTIMER1, L4ID_GPTIMER1, 2},
+ {L4A_32KTIMER, L4ID_32KTIMER, 2},
+ /* L4-Per Agents */
+ {L4A_UART3, L4ID_UART3, 2},
+ /* TODO: McBSP2 */
+ /* TODO: McBSP3 */
+ {L4A_GPTIMER2, L4ID_GPTIMER2, 2},
+ {L4A_GPTIMER3, L4ID_GPTIMER3, 2},
+ {L4A_GPTIMER4, L4ID_GPTIMER4, 2},
+ {L4A_GPTIMER5, L4ID_GPTIMER5, 2},
+ {L4A_GPTIMER6, L4ID_GPTIMER6, 2},
+ {L4A_GPTIMER7, L4ID_GPTIMER7, 2},
+ {L4A_GPTIMER8, L4ID_GPTIMER8, 2},
+ {L4A_GPTIMER9, L4ID_GPTIMER9, 2},
+ {L4A_GPIO2, L4ID_GPIO2, 2},
+ {L4A_GPIO3, L4ID_GPIO3, 2},
+ {L4A_GPIO4, L4ID_GPIO4, 2},
+ {L4A_GPIO5, L4ID_GPIO5, 2},
+ {L4A_GPIO6, L4ID_GPIO6, 2},
+};
+
+#ifndef OMAP3_REDUCE_IOREGIONS
+static uint32_t omap3_l4ta_read(void *opaque, target_phys_addr_t addr)
+{
+ struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+
+ switch (addr) {
+ case 0x00: /* COMPONENT_L */
+ return s->component;
+ case 0x04: /* COMPONENT_H */
+ return 0;
+ case 0x18: /* CORE_L */
+ return s->component;
+ case 0x1c: /* CORE_H */
+ return (s->component >> 16);
+ case 0x20: /* AGENT_CONTROL_L */
+ return s->control;
+ case 0x24: /* AGENT_CONTROL_H */
+ return s->control_h;
+ case 0x28: /* AGENT_STATUS_L */
+ return s->status;
+ case 0x2c: /* AGENT_STATUS_H */
+ return 0;
+ default:
+ break;
+ }
+
+ OMAP_BAD_REG(s->base + addr);
+ return 0;
+}
+
+static void omap3_l4ta_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+
+ switch (addr) {
+ case 0x00: /* COMPONENT_L */
+ case 0x04: /* COMPONENT_H */
+ case 0x18: /* CORE_L */
+ case 0x1c: /* CORE_H */
+ OMAP_RO_REG(s->base + addr);
+ break;
+ case 0x20: /* AGENT_CONTROL_L */
+ s->control = value & 0x00000701;
+ break;
+ case 0x24: /* AGENT_CONTROL_H */
+ s->control_h = value & 0x100; /* TODO: shouldn't this be read-only? */
+ break;
+ case 0x28: /* AGENT_STATUS_L */
+ if (value & 0x100)
+ s->status &= ~0x100; /* REQ_TIMEOUT */
+ break;
+ case 0x2c: /* AGENT_STATUS_H */
+ /* no writable bits although the register is listed as RW */
+ break;
+ default:
+ OMAP_BAD_REG(s->base + addr);
+ break;
+ }
+}
+
+static void omap3_l4ta_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+
+ qemu_put_be32(f, s->control);
+ qemu_put_be32(f, s->control_h);
+ qemu_put_be32(f, s->status);
+}
+
+static int omap3_l4ta_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap_target_agent_s *s = (struct omap_target_agent_s *)opaque;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->control = qemu_get_be32(f);
+ s->control_h = qemu_get_be32(f);
+ s->status = qemu_get_be32(f);
+
+ return 0;
+}
+
+static CPUReadMemoryFunc *omap3_l4ta_readfn[] = {
+ omap_badwidth_read32,
+ omap_badwidth_read32,
+ omap3_l4ta_read,
+};
+
+static CPUWriteMemoryFunc *omap3_l4ta_writefn[] = {
+ omap_badwidth_write32,
+ omap_badwidth_write32,
+ omap3_l4ta_write,
+};
+#endif
+
+static struct omap_target_agent_s *omap3_l4ta_init(struct omap_l4_s *bus, int cs)
+{
+#ifndef OMAP3_REDUCE_IOREGIONS
+ int iomemtype;
+#endif
+ int i;
+ struct omap_target_agent_s *ta = 0;
+ const struct omap3_l4_agent_info_s *info = 0;
+
+ for (i = 0; i < bus->ta_num; i++)
+ if (omap3_l4_agent_info[i].agent_id == cs) {
+ ta = &bus->ta[i];
+ info = &omap3_l4_agent_info[i];
+ break;
+ }
+ if (!ta) {
+ fprintf(stderr, "%s: invalid agent id (%i)\n", __FUNCTION__, cs);
+ exit(-1);
+ }
+ if (ta->bus) {
+ fprintf(stderr, "%s: target agent (%d) already initialized\n",
+ __FUNCTION__, cs);
+ exit(-1);
+ }
+
+ ta->bus = bus;
+ ta->start = &omap3_l4_region[info->first_region_id];
+ ta->regions = info->region_count;
+
+ ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+ ta->status = 0x00000000;
+ ta->control = 0x00000200;
+
+ for (i = 0; i < info->region_count; i++)
+ if (omap3_l4_region[info->first_region_id + i].access == L4TYPE_TA)
+ break;
+ if (i >= info->region_count) {
+ fprintf(stderr, "%s: specified agent (%d) has no TA region\n",
+ __FUNCTION__, cs);
+ exit(-1);
+ }
+
+#ifndef OMAP3_REDUCE_IOREGIONS
+ iomemtype = l4_register_io_memory(0, omap3_l4ta_readfn,
+ omap3_l4ta_writefn, ta);
+ ta->base = omap_l4_attach(ta, i, iomemtype);
+
+ register_savevm("omap3_l4ta", ta->base >> 8, 0,
+ omap3_l4ta_save_state, omap3_l4ta_load_state, ta);
+#else
+ ta->base = ta->bus->base + ta->start[i].offset;
+#endif
+
+ return ta;
+}
+
+/* common PRM domain registers */
+struct omap3_prm_domain_s {
+ uint32_t rm_rstctrl; /* 50 */
+ uint32_t rm_rstst; /* 58 */
+ uint32_t pm_wken; /* a0 */
+ uint32_t pm_mpugrpsel; /* a4 */
+ uint32_t pm_ivagrpsel; /* a8 */
+ uint32_t pm_wkst; /* b0 */
+ uint32_t pm_wkst3; /* b8 */
+ uint32_t pm_wkdep; /* c8 */
+ uint32_t pm_evgenctrl; /* d4 */
+ uint32_t pm_evgenontim; /* d8 */
+ uint32_t pm_evgenofftim; /* dc */
+ uint32_t pm_pwstctrl; /* e0 */
+ uint32_t pm_pwstst; /* e4 */
+ uint32_t pm_prepwstst; /* e8 */
+ uint32_t pm_wken3; /* f0 */
+};
+
+struct omap3_prm_s {
+ qemu_irq mpu_irq;
+ qemu_irq iva_irq;
+ struct omap_mpu_state_s *omap;
+
+ struct omap3_prm_domain_s iva2;
+ struct omap3_prm_domain_s mpu;
+ struct omap3_prm_domain_s core;
+ struct omap3_prm_domain_s sgx;
+ struct omap3_prm_domain_s wkup;
+ struct omap3_prm_domain_s dss;
+ struct omap3_prm_domain_s cam;
+ struct omap3_prm_domain_s per;
+ struct omap3_prm_domain_s emu;
+ struct omap3_prm_domain_s neon;
+ struct omap3_prm_domain_s usbhost;
+
+ uint32_t prm_irqstatus_iva2;
+ uint32_t prm_irqenable_iva2;
+
+ uint32_t pm_iva2grpsel3_core;
+ uint32_t pm_mpugrpsel3_core;
+
+ struct {
+ uint32_t prm_revision;
+ uint32_t prm_sysconfig;
+ uint32_t prm_irqstatus_mpu;
+ uint32_t prm_irqenable_mpu;
+ } ocp;
+
+ struct {
+ uint32_t prm_clksel;
+ uint32_t prm_clkout_ctrl;
+ } ccr; /* clock_control_reg */
+
+ struct {
+ uint32_t prm_vc_smps_sa;
+ uint32_t prm_vc_smps_vol_ra;
+ uint32_t prm_vc_smps_cmd_ra;
+ uint32_t prm_vc_cmd_val_0;
+ uint32_t prm_vc_cmd_val_1;
+ uint32_t prm_vc_hc_conf;
+ uint32_t prm_vc_i2c_cfg;
+ uint32_t prm_vc_bypass_val;
+ uint32_t prm_rstctrl;
+ uint32_t prm_rsttimer;
+ uint32_t prm_rstst;
+ uint32_t prm_voltctrl;
+ uint32_t prm_sram_pcharge;
+ uint32_t prm_clksrc_ctrl;
+ uint32_t prm_obs;
+ uint32_t prm_voltsetup1;
+ uint32_t prm_voltoffset;
+ uint32_t prm_clksetup;
+ uint32_t prm_polctrl;
+ uint32_t prm_voltsetup2;
+ /* the following smartreflex control registers taken from linux kernel
+ * source as their descriptions are missing in the OMAP3 TRM */
+ struct {
+ uint32_t config;
+ uint32_t vstepmin;
+ uint32_t vstepmax;
+ uint32_t vlimitto;
+ uint32_t voltage;
+ uint32_t status;
+ } prm_vp[2];
+ } gr; /* global_reg */
+};
+
+static void omap3_prm_int_update(struct omap3_prm_s *s)
+{
+ qemu_set_irq(s->mpu_irq, s->ocp.prm_irqstatus_mpu & s->ocp.prm_irqenable_mpu);
+ qemu_set_irq(s->iva_irq, s->prm_irqstatus_iva2 & s->prm_irqenable_iva2);
+}
+
+static void omap3_prm_reset(struct omap3_prm_s *s)
+{
+ bzero(&s->iva2, sizeof(s->iva2));
+ s->iva2.rm_rstctrl = 0x7;
+ s->iva2.rm_rstst = 0x1;
+ s->iva2.pm_wkdep = 0xb3;
+ s->iva2.pm_pwstctrl = 0xff0f07;
+ s->iva2.pm_pwstst = 0xff7;
+ s->prm_irqstatus_iva2 = 0x0;
+ s->prm_irqenable_iva2 = 0x0;
+
+ bzero(&s->ocp, sizeof(s->ocp));
+ s->ocp.prm_revision = 0x10;
+ s->ocp.prm_sysconfig = 0x1;
+
+ bzero(&s->mpu, sizeof(s->mpu));
+ s->mpu.rm_rstst = 0x1;
+ s->mpu.pm_wkdep = 0xa5;
+ s->mpu.pm_pwstctrl = 0x30107;
+ s->mpu.pm_pwstst = 0xc7;
+ s->mpu.pm_evgenctrl = 0x12;
+
+ bzero(&s->core, sizeof(s->core));
+ s->core.rm_rstst = 0x1;
+ s->core.pm_wken = 0xc33ffe18;
+ s->core.pm_mpugrpsel = 0xc33ffe18;
+ s->core.pm_ivagrpsel = 0xc33ffe18;
+ s->core.pm_pwstctrl = 0xf0307;
+ s->core.pm_pwstst = 0xf7;
+ s->core.pm_wken3 = 0x4;
+ s->pm_iva2grpsel3_core = 0x4;
+ s->pm_mpugrpsel3_core = 0x4;
+
+ bzero(&s->sgx, sizeof(s->sgx));
+ s->sgx.rm_rstst = 0x1;
+ s->sgx.pm_wkdep = 0x16;
+ s->sgx.pm_pwstctrl = 0x30107;
+ s->sgx.pm_pwstst = 0x3;
+
+ bzero(&s->wkup, sizeof(s->wkup));
+ s->wkup.pm_wken = 0x3cb;
+ s->wkup.pm_mpugrpsel = 0x3cb;
+ s->wkup.pm_pwstst = 0x3; /* TODO: check on real hardware */
+
+ bzero(&s->ccr, sizeof(s->ccr));
+ s->ccr.prm_clksel = 0x3; /* TRM says 0x4, but on HW this is 0x3 */
+ s->ccr.prm_clkout_ctrl = 0x80;
+
+ bzero(&s->dss, sizeof(s->dss));
+ s->dss.rm_rstst = 0x1;
+ s->dss.pm_wken = 0x1;
+ s->dss.pm_wkdep = 0x16;
+ s->dss.pm_pwstctrl = 0x30107;
+ s->dss.pm_pwstst = 0x3;
+
+ bzero(&s->cam, sizeof(s->cam));
+ s->cam.rm_rstst = 0x1;
+ s->cam.pm_wkdep = 0x16;
+ s->cam.pm_pwstctrl = 0x30107;
+ s->cam.pm_pwstst = 0x3;
+
+ bzero(&s->per, sizeof(s->per));
+ s->per.rm_rstst = 0x1;
+ s->per.pm_wken = 0x3efff;
+ s->per.pm_mpugrpsel = 0x3efff;
+ s->per.pm_ivagrpsel = 0x3efff;
+ s->per.pm_wkdep = 0x17;
+ s->per.pm_pwstctrl = 0x30107;
+ s->per.pm_pwstst = 0x7;
+
+ bzero(&s->emu, sizeof(s->emu));
+ s->emu.rm_rstst = 0x1;
+ s->emu.pm_pwstst = 0x13;
+
+ bzero(&s->gr, sizeof(s->gr));
+ s->gr.prm_vc_i2c_cfg = 0x18;
+ s->gr.prm_rsttimer = 0x1006;
+ s->gr.prm_rstst = 0x1;
+ s->gr.prm_sram_pcharge = 0x50;
+ s->gr.prm_clksrc_ctrl = 0x43;
+ s->gr.prm_polctrl = 0xa;
+ /* TODO: figure out reset values for prm_vp[1,2] registers */
+
+ bzero(&s->neon, sizeof(s->neon));
+ s->neon.rm_rstst = 0x1;
+ s->neon.pm_wkdep = 0x2;
+ s->neon.pm_pwstctrl = 0x7;
+ s->neon.pm_pwstst = 0x3;
+
+ bzero(&s->usbhost, sizeof(s->usbhost));
+ s->usbhost.rm_rstst = 0x1;
+ s->usbhost.pm_wken = 0x1;
+ s->usbhost.pm_mpugrpsel = 0x1;
+ s->usbhost.pm_ivagrpsel = 0x1;
+ s->usbhost.pm_wkdep = 0x17;
+ s->usbhost.pm_pwstctrl = 0x30107;
+ s->usbhost.pm_pwstst = 0x3;
+
+ omap3_prm_int_update(s);
+}
+
+static uint32_t omap3_prm_read(void *opaque, target_phys_addr_t addr)
+{
+ struct omap3_prm_s *s = (struct omap3_prm_s *)opaque;
+ struct omap3_prm_domain_s *d = 0;
+
+ TRACE("%04x", addr);
+
+ /* handle common domain registers first - all domains may not
+ have all common registers though but we're returning zeroes there */
+ switch ((addr >> 8) & 0xff) {
+ case 0x00: d = &s->iva2; break;
+ case 0x09: d = &s->mpu; break;
+ case 0x0a: d = &s->core; break;
+ case 0x0b: d = &s->sgx; break;
+ case 0x0c: d = &s->wkup; break;
+ case 0x0e: d = &s->dss; break;
+ case 0x0f: d = &s->cam; break;
+ case 0x10: d = &s->per; break;
+ case 0x11: d = &s->emu; break;
+ case 0x13: d = &s->neon; break;
+ case 0x14: d = &s->usbhost; break;
+ default: break;
+ }
+ if (d)
+ switch (addr & 0xff) {
+ case 0x50: return d->rm_rstctrl;
+ case 0x58: return d->rm_rstst;
+ case 0xa0: return d->pm_wken;
+ case 0xa4: return d->pm_mpugrpsel;
+ case 0xa8: return d->pm_ivagrpsel;
+ case 0xb0: return d->pm_wkst;
+ case 0xb8: return d->pm_wkst3;
+ case 0xc8: return d->pm_wkdep;
+ case 0xd4: return d->pm_evgenctrl;
+ case 0xd8: return d->pm_evgenontim;
+ case 0xdc: return d->pm_evgenofftim;
+ case 0xe0: return d->pm_pwstctrl;
+ case 0xe4: return d->pm_pwstst;
+ case 0xe8: return d->pm_prepwstst;
+ case 0xf0: return d->pm_wken3;
+ default: break;
+ }
+
+ /* okay, not a common domain register so let's take a closer look */
+ switch (addr) {
+ case 0x00f8: return s->prm_irqstatus_iva2;
+ case 0x00fc: return s->prm_irqenable_iva2;
+ case 0x0804: return s->ocp.prm_revision;
+ case 0x0814: return s->ocp.prm_sysconfig;
+ case 0x0818: return s->ocp.prm_irqstatus_mpu;
+ case 0x081c: return s->ocp.prm_irqenable_mpu;
+ case 0x0af4: return s->pm_iva2grpsel3_core;
+ case 0x0af8: return s->pm_mpugrpsel3_core;
+ case 0x0d40: return s->ccr.prm_clksel;
+ case 0x0d70: return s->ccr.prm_clkout_ctrl;
+ case 0x0de4: return 0x3; /* TODO: check on real hardware */
+ case 0x1220: return s->gr.prm_vc_smps_sa;
+ case 0x1224: return s->gr.prm_vc_smps_vol_ra;
+ case 0x1228: return s->gr.prm_vc_smps_cmd_ra;
+ case 0x122c: return s->gr.prm_vc_cmd_val_0;
+ case 0x1230: return s->gr.prm_vc_cmd_val_1;
+ case 0x1234: return s->gr.prm_vc_hc_conf;
+ case 0x1238: return s->gr.prm_vc_i2c_cfg;
+ case 0x123c: return s->gr.prm_vc_bypass_val;
+ case 0x1250: return s->gr.prm_rstctrl;
+ case 0x1254: return s->gr.prm_rsttimer;
+ case 0x1258: return s->gr.prm_rstst;
+ case 0x1260: return s->gr.prm_voltctrl;
+ case 0x1264: return s->gr.prm_sram_pcharge;
+ case 0x1270: return s->gr.prm_clksrc_ctrl;
+ case 0x1280: return s->gr.prm_obs;
+ case 0x1290: return s->gr.prm_voltsetup1;
+ case 0x1294: return s->gr.prm_voltoffset;
+ case 0x1298: return s->gr.prm_clksetup;
+ case 0x129c: return s->gr.prm_polctrl;
+ case 0x12a0: return s->gr.prm_voltsetup2;
+ case 0x12b0: return s->gr.prm_vp[0].config;
+ case 0x12b4: return s->gr.prm_vp[0].vstepmin;
+ case 0x12b8: return s->gr.prm_vp[0].vstepmax;
+ case 0x12bc: return s->gr.prm_vp[0].vlimitto;
+ case 0x12c0: return s->gr.prm_vp[0].voltage;
+ case 0x12c4: return s->gr.prm_vp[0].status;
+ case 0x12d0: return s->gr.prm_vp[1].config;
+ case 0x12d4: return s->gr.prm_vp[1].vstepmin;
+ case 0x12d8: return s->gr.prm_vp[1].vstepmax;
+ case 0x12dc: return s->gr.prm_vp[1].vlimitto;
+ case 0x12e0: return s->gr.prm_vp[1].voltage;
+ case 0x12e4: return s->gr.prm_vp[1].status;
+ default: break;
+ }
+
+ OMAP_BAD_REG(addr);
+ return 0;
+}
+
+static inline void omap3_prm_clksrc_ctrl_update(struct omap3_prm_s *s)
+{
+ uint32_t value = s->gr.prm_clksrc_ctrl;
+
+ if ((value & 0xd0) == 0x40)
+ omap_clk_setrate(omap_findclk(s->omap, "omap3_sys_clk"), 1, 1);
+ else if ((value & 0xd0) == 0x80)
+ omap_clk_setrate(omap_findclk(s->omap, "omap3_sys_clk"), 2, 1);
+}
+
+static void omap3_prm_clksel_update(struct omap3_prm_s *s)
+{
+ omap_clk newparent = 0;
+
+ switch (s->ccr.prm_clksel & 7) {
+ case 0: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk12"); break;
+ case 1: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk13"); break;
+ case 2: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk192"); break;
+ case 3: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk26"); break;
+ case 4: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk384"); break;
+ case 5: newparent = omap_findclk(s->omap, "omap3_osc_sys_clk168"); break;
+ default:
+ fprintf(stderr, "%s: invalid sys_clk input selection (%d) - ignored\n",
+ __FUNCTION__, s->ccr.prm_clksel & 7);
+ break;
+ }
+ if (newparent) {
+ omap_clk_reparent(omap_findclk(s->omap, "omap3_sys_clk"), newparent);
+ omap_clk_reparent(omap_findclk(s->omap, "omap3_sys_clkout1"), newparent);
+ }
+}
+
+static void omap3_prm_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap3_prm_s *s = (struct omap3_prm_s *)opaque;
+
+ TRACE("%04x = %08x", addr, value);
+ switch (addr) {
+ /* IVA2_PRM */
+ case 0x0050: s->iva2.rm_rstctrl = value & 0x7; break;
+ case 0x0058: s->iva2.rm_rstst &= ~(value & 0x3f0f); break;
+ case 0x00c8: s->iva2.pm_wkdep = value & 0xb3; break;
+ case 0x00e0: s->iva2.pm_pwstctrl = 0xcff000 | (value & 0x300f0f); break;
+ case 0x00e4: OMAP_RO_REG(addr); break;
+ case 0x00e8: s->iva2.pm_prepwstst = value & 0xff7;
+ case 0x00f8:
+ s->prm_irqstatus_iva2 &= ~(value & 0x7);
+ omap3_prm_int_update(s);
+ break;
+ case 0x00fc:
+ s->prm_irqenable_iva2 = value & 0x7;
+ omap3_prm_int_update(s);
+ break;
+ /* OCP_System_Reg_PRM */
+ case 0x0804: OMAP_RO_REG(addr); break;
+ case 0x0814: s->ocp.prm_sysconfig = value & 0x1; break;
+ case 0x0818:
+ s->ocp.prm_irqstatus_mpu &= ~(value & 0x03c003fd);
+ omap3_prm_int_update(s);
+ break;
+ case 0x081c:
+ s->ocp.prm_irqenable_mpu = value & 0x03c003fd;
+ omap3_prm_int_update(s);
+ break;
+ /* MPU_PRM */
+ case 0x0958: s->mpu.rm_rstst &= ~(value & 0x080f); break;
+ case 0x09c8: s->mpu.pm_wkdep = value & 0xa5; break;
+ case 0x09d4: s->mpu.pm_evgenctrl = value & 0x1f; break;
+ case 0x09d8: s->mpu.pm_evgenontim = value; break;
+ case 0x09dc: s->mpu.pm_evgenofftim = value; break;
+ case 0x09e0: s->mpu.pm_pwstctrl = value & 0x3010f; break;
+ case 0x09e4: OMAP_RO_REG(addr); break;
+ case 0x09e8: s->mpu.pm_prepwstst = value & 0xc7; break;
+ /* CORE_PRM */
+ case 0x0a50: s->core.rm_rstctrl = value & 0x3; break; /* TODO: check if available on real hw */
+ case 0x0a58: s->core.rm_rstst &= ~(value & 0x7); break;
+ case 0x0aa0: s->core.pm_wken = 0x80000008 | (value & 0x433ffe10); break;
+ case 0x0aa4: s->core.pm_mpugrpsel = 0x80000008 | (value & 0x433ffe10); break;
+ case 0x0aa8: s->core.pm_ivagrpsel = 0x80000008 | (value & 0x433ffe10); break;
+ case 0x0ab0: s->core.pm_wkst = value & 0x433ffe10; break;
+ case 0x0ab8: s->core.pm_wkst3 &= ~(value & 0x4); break;
+ case 0x0ae0: s->core.pm_pwstctrl = (value & 0x0f031f); break;
+ case 0x0ae4: OMAP_RO_REG(addr); break;
+ case 0x0ae8: s->core.pm_prepwstst = value & 0xf7; break;
+ case 0x0af0: s->core.pm_wken3 = value & 0x4; break;
+ case 0x0af4: s->pm_iva2grpsel3_core = value & 0x4; break;
+ case 0x0af8: s->pm_mpugrpsel3_core = value & 0x4; break;
+ /* SGX_PRM */
+ case 0x0b58: s->sgx.rm_rstst &= ~(value & 0xf); break;
+ case 0x0bc8: s->sgx.pm_wkdep = value & 0x16; break;
+ case 0x0be0: s->sgx.pm_pwstctrl = 0x030104 | (value & 0x3); break;
+ case 0x0be4: OMAP_RO_REG(addr); break;
+ case 0x0be8: s->sgx.pm_prepwstst = value & 0x3; break;
+ /* WKUP_PRM */
+ case 0x0ca0: s->wkup.pm_wken = 0x2 | (value & 0x0103c9); break;
+ case 0x0ca4: s->wkup.pm_mpugrpsel = 0x0102 | (value & 0x02c9); break;
+ case 0x0ca8: s->wkup.pm_ivagrpsel = value & 0x03cb; break;
+ case 0x0cb0: s->wkup.pm_wkst &= ~(value & 0x0103cb); break;
+ /* Clock_Control_Reg_PRM */
+ case 0x0d40:
+ s->ccr.prm_clksel = value & 0x7;
+ omap3_prm_clksel_update(s);
+ break;
+ case 0x0d70:
+ s->ccr.prm_clkout_ctrl = value & 0x80;
+ omap_clk_onoff(omap_findclk(s->omap, "omap3_sys_clkout1"),
+ s->ccr.prm_clkout_ctrl & 0x80);
+ break;
+ /* DSS_PRM */
+ case 0x0e58: s->dss.rm_rstst &= ~(value & 0xf); break;
+ case 0x0ea0: s->dss.pm_wken = value & 1; break;
+ case 0x0ec8: s->dss.pm_wkdep = value & 0x16; break;
+ case 0x0ee0: s->dss.pm_pwstctrl = 0x030104 | (value & 3); break;
+ case 0x0ee4: OMAP_RO_REG(addr); break;
+ case 0x0ee8: s->dss.pm_prepwstst = value & 3; break;
+ /* CAM_PRM */
+ case 0x0f58: s->cam.rm_rstst &= (value & 0xf); break;
+ case 0x0fc8: s->cam.pm_wkdep = value & 0x16; break;
+ case 0x0fe0: s->cam.pm_pwstctrl = 0x030104 | (value & 3); break;
+ case 0x0fe4: OMAP_RO_REG(addr); break;
+ case 0x0fe8: s->cam.pm_prepwstst = value & 0x3; break;
+ /* PER_PRM */
+ case 0x1058: s->per.rm_rstst &= ~(value & 0xf); break;
+ case 0x10a0: s->per.pm_wken = value & 0x03efff; break;
+ case 0x10a4: s->per.pm_mpugrpsel = value & 0x03efff; break;
+ case 0x10a8: s->per.pm_ivagrpsel = value & 0x03efff; break;
+ case 0x10b0: s->per.pm_wkst &= ~(value & 0x03efff); break;
+ case 0x10c8: s->per.pm_wkdep = value & 0x17; break;
+ case 0x10e0: s->per.pm_pwstctrl = 0x030100 | (value & 7); break;
+ case 0x10e4: OMAP_RO_REG(addr); break;
+ case 0x10e8: s->per.pm_prepwstst = value & 0x7; break;
+ /* EMU_PRM */
+ case 0x1158: s->emu.rm_rstst &= ~(value & 7); break;
+ case 0x11e4: OMAP_RO_REG(addr); break;
+ /* Global_Reg_PRM */
+ case 0x1220: s->gr.prm_vc_smps_sa = value & 0x7f007f; break;
+ case 0x1224: s->gr.prm_vc_smps_vol_ra = value & 0xff00ff; break;
+ case 0x1228: s->gr.prm_vc_smps_cmd_ra = value & 0xff00ff; break;
+ case 0x122c: s->gr.prm_vc_cmd_val_0 = value; break;
+ case 0x1230: s->gr.prm_vc_cmd_val_1 = value; break;
+ case 0x1234: s->gr.prm_vc_hc_conf = value & 0x1f001f; break;
+ case 0x1238: s->gr.prm_vc_i2c_cfg = value & 0x3f; break;
+ case 0x123c: s->gr.prm_vc_bypass_val = value & 0x01ffff7f; break;
+ case 0x1250: s->gr.prm_rstctrl = 0; break; /* TODO: resets */
+ case 0x1254: s->gr.prm_rsttimer = value & 0x1fff; break;
+ case 0x1258: s->gr.prm_rstst &= ~(value & 0x7fb); break;
+ case 0x1260: s->gr.prm_voltctrl = value & 0x1f; break;
+ case 0x1264: s->gr.prm_sram_pcharge = value & 0xff; break;
+ case 0x1270:
+ s->gr.prm_clksrc_ctrl = value & 0xd8; /* set osc bypass mode */
+ omap3_prm_clksrc_ctrl_update(s);
+ break;
+ case 0x1280: OMAP_RO_REG(addr); break;
+ case 0x1290: s->gr.prm_voltsetup1 = value; break;
+ case 0x1294: s->gr.prm_voltoffset = value & 0xffff; break;
+ case 0x1298: s->gr.prm_clksetup = value & 0xffff; break;
+ case 0x129c: s->gr.prm_polctrl = value & 0xf; break;
+ case 0x12a0: s->gr.prm_voltsetup2 = value & 0xffff; break;
+ /* TODO: check if any functionality is needed behind writes to the
+ * prm_vp[1,2] registers */
+ case 0x12b0: s->gr.prm_vp[0].config = value; break;
+ case 0x12b4: s->gr.prm_vp[0].vstepmin = value; break;
+ case 0x12b8: s->gr.prm_vp[0].vstepmax = value; break;
+ case 0x12bc: s->gr.prm_vp[0].vlimitto = value; break;
+ case 0x12c0: s->gr.prm_vp[0].voltage = value; break;
+ case 0x12c4: s->gr.prm_vp[0].status = value; break;
+ case 0x12d0: s->gr.prm_vp[1].config = value; break;
+ case 0x12d4: s->gr.prm_vp[1].vstepmin = value; break;
+ case 0x12d8: s->gr.prm_vp[1].vstepmax = value; break;
+ case 0x12dc: s->gr.prm_vp[1].vlimitto = value; break;
+ case 0x12e0: s->gr.prm_vp[1].voltage = value; break;
+ case 0x12e4: s->gr.prm_vp[1].status = value; break;
+ /* NEON_PRM */
+ case 0x1358: s->neon.rm_rstst &= ~(value & 0xf); break;
+ case 0x13c8: s->neon.pm_wkdep = value & 0x2; break;
+ case 0x13e0: s->neon.pm_pwstctrl = 0x4 | (value & 3); break;
+ case 0x13e4: OMAP_RO_REG(addr); break;
+ case 0x13e8: s->neon.pm_prepwstst = value & 3; break;
+ /* USBHOST_PRM */
+ case 0x1458: s->usbhost.rm_rstst &= ~(value & 0xf); break;
+ case 0x14a0: s->usbhost.pm_wken = value & 1; break;
+ case 0x14a4: s->usbhost.pm_mpugrpsel = value & 1; break;
+ case 0x14a8: s->usbhost.pm_ivagrpsel = value & 1; break;
+ case 0x14b0: s->usbhost.pm_wkst &= ~(value & 1); break;
+ case 0x14c8: s->usbhost.pm_wkdep = value & 0x17; break;
+ case 0x14e0: s->usbhost.pm_pwstctrl = 0x030104 | (value & 0x13); break;
+ case 0x14e4: OMAP_RO_REG(addr); break;
+ case 0x14e8: s->usbhost.pm_prepwstst = value & 3; break;
+ default:
+ OMAP_BAD_REGV(addr, value);
+ break;
+ }
+}
+
+static void omap3_prm_save_domain_state(QEMUFile *f,
+ struct omap3_prm_domain_s *s)
+{
+ qemu_put_be32(f, s->rm_rstctrl);
+ qemu_put_be32(f, s->rm_rstst);
+ qemu_put_be32(f, s->pm_wken);
+ qemu_put_be32(f, s->pm_mpugrpsel);
+ qemu_put_be32(f, s->pm_ivagrpsel);
+ qemu_put_be32(f, s->pm_wkst);
+ qemu_put_be32(f, s->pm_wkst3);
+ qemu_put_be32(f, s->pm_wkdep);
+ qemu_put_be32(f, s->pm_evgenctrl);
+ qemu_put_be32(f, s->pm_evgenontim);
+ qemu_put_be32(f, s->pm_evgenofftim);
+ qemu_put_be32(f, s->pm_pwstctrl);
+ qemu_put_be32(f, s->pm_pwstst);
+ qemu_put_be32(f, s->pm_prepwstst);
+ qemu_put_be32(f, s->pm_wken3);
+}
+
+static void omap3_prm_load_domain_state(QEMUFile *f,
+ struct omap3_prm_domain_s *s)
+{
+ s->rm_rstctrl = qemu_get_be32(f);
+ s->rm_rstst = qemu_get_be32(f);
+ s->pm_wken = qemu_get_be32(f);
+ s->pm_mpugrpsel = qemu_get_be32(f);
+ s->pm_ivagrpsel = qemu_get_be32(f);
+ s->pm_wkst = qemu_get_be32(f);
+ s->pm_wkst3 = qemu_get_be32(f);
+ s->pm_wkdep = qemu_get_be32(f);
+ s->pm_evgenctrl = qemu_get_be32(f);
+ s->pm_evgenontim = qemu_get_be32(f);
+ s->pm_evgenofftim = qemu_get_be32(f);
+ s->pm_pwstctrl = qemu_get_be32(f);
+ s->pm_pwstst = qemu_get_be32(f);
+ s->pm_prepwstst = qemu_get_be32(f);
+ s->pm_wken3 = qemu_get_be32(f);
+}
+
+static void omap3_prm_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap3_prm_s *s = (struct omap3_prm_s *)opaque;
+ int i;
+
+ omap3_prm_save_domain_state(f, &s->iva2);
+ omap3_prm_save_domain_state(f, &s->mpu);
+ omap3_prm_save_domain_state(f, &s->core);
+ omap3_prm_save_domain_state(f, &s->sgx);
+ omap3_prm_save_domain_state(f, &s->wkup);
+ omap3_prm_save_domain_state(f, &s->dss);
+ omap3_prm_save_domain_state(f, &s->cam);
+ omap3_prm_save_domain_state(f, &s->per);
+ omap3_prm_save_domain_state(f, &s->emu);
+ omap3_prm_save_domain_state(f, &s->neon);
+ omap3_prm_save_domain_state(f, &s->usbhost);
+
+ qemu_put_be32(f, s->prm_irqstatus_iva2);
+ qemu_put_be32(f, s->prm_irqenable_iva2);
+ qemu_put_be32(f, s->pm_iva2grpsel3_core);
+ qemu_put_be32(f, s->pm_mpugrpsel3_core);
+
+ qemu_put_be32(f, s->ocp.prm_revision);
+ qemu_put_be32(f, s->ocp.prm_sysconfig);
+ qemu_put_be32(f, s->ocp.prm_irqstatus_mpu);
+ qemu_put_be32(f, s->ocp.prm_irqenable_mpu);
+
+ qemu_put_be32(f, s->ccr.prm_clksel);
+ qemu_put_be32(f, s->ccr.prm_clkout_ctrl);
+
+ qemu_put_be32(f, s->gr.prm_vc_smps_sa);
+ qemu_put_be32(f, s->gr.prm_vc_smps_vol_ra);
+ qemu_put_be32(f, s->gr.prm_vc_smps_cmd_ra);
+ qemu_put_be32(f, s->gr.prm_vc_cmd_val_0);
+ qemu_put_be32(f, s->gr.prm_vc_cmd_val_1);
+ qemu_put_be32(f, s->gr.prm_vc_hc_conf);
+ qemu_put_be32(f, s->gr.prm_vc_i2c_cfg);
+ qemu_put_be32(f, s->gr.prm_vc_bypass_val);
+ qemu_put_be32(f, s->gr.prm_rstctrl);
+ qemu_put_be32(f, s->gr.prm_rsttimer);
+ qemu_put_be32(f, s->gr.prm_rstst);
+ qemu_put_be32(f, s->gr.prm_voltctrl);
+ qemu_put_be32(f, s->gr.prm_sram_pcharge);
+ qemu_put_be32(f, s->gr.prm_clksrc_ctrl);
+ qemu_put_be32(f, s->gr.prm_obs);
+ qemu_put_be32(f, s->gr.prm_voltsetup1);
+ qemu_put_be32(f, s->gr.prm_voltoffset);
+ qemu_put_be32(f, s->gr.prm_clksetup);
+ qemu_put_be32(f, s->gr.prm_polctrl);
+ qemu_put_be32(f, s->gr.prm_voltsetup2);
+ for (i = 0; i < 2; i++) {
+ qemu_put_be32(f, s->gr.prm_vp[i].config);
+ qemu_put_be32(f, s->gr.prm_vp[i].vstepmin);
+ qemu_put_be32(f, s->gr.prm_vp[i].vstepmax);
+ qemu_put_be32(f, s->gr.prm_vp[i].vlimitto);
+ qemu_put_be32(f, s->gr.prm_vp[i].voltage);
+ qemu_put_be32(f, s->gr.prm_vp[i].status);
+ }
+}
+
+static int omap3_prm_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap3_prm_s *s = (struct omap3_prm_s *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ omap3_prm_load_domain_state(f, &s->iva2);
+ omap3_prm_load_domain_state(f, &s->mpu);
+ omap3_prm_load_domain_state(f, &s->core);
+ omap3_prm_load_domain_state(f, &s->sgx);
+ omap3_prm_load_domain_state(f, &s->wkup);
+ omap3_prm_load_domain_state(f, &s->dss);
+ omap3_prm_load_domain_state(f, &s->cam);
+ omap3_prm_load_domain_state(f, &s->per);
+ omap3_prm_load_domain_state(f, &s->emu);
+ omap3_prm_load_domain_state(f, &s->neon);
+ omap3_prm_load_domain_state(f, &s->usbhost);
+
+ s->prm_irqstatus_iva2 = qemu_get_be32(f);
+ s->prm_irqenable_iva2 = qemu_get_be32(f);
+ s->pm_iva2grpsel3_core = qemu_get_be32(f);
+ s->pm_mpugrpsel3_core = qemu_get_be32(f);
+
+ s->ocp.prm_revision = qemu_get_be32(f);
+ s->ocp.prm_sysconfig = qemu_get_be32(f);
+ s->ocp.prm_irqstatus_mpu = qemu_get_be32(f);
+ s->ocp.prm_irqenable_mpu = qemu_get_be32(f);
+
+ s->ccr.prm_clksel = qemu_get_be32(f);
+ s->ccr.prm_clkout_ctrl = qemu_get_be32(f);
+
+ s->gr.prm_vc_smps_sa = qemu_get_be32(f);
+ s->gr.prm_vc_smps_vol_ra = qemu_get_be32(f);
+ s->gr.prm_vc_smps_cmd_ra = qemu_get_be32(f);
+ s->gr.prm_vc_cmd_val_0 = qemu_get_be32(f);
+ s->gr.prm_vc_cmd_val_1 = qemu_get_be32(f);
+ s->gr.prm_vc_hc_conf = qemu_get_be32(f);
+ s->gr.prm_vc_i2c_cfg = qemu_get_be32(f);
+ s->gr.prm_vc_bypass_val = qemu_get_be32(f);
+ s->gr.prm_rstctrl = qemu_get_be32(f);
+ s->gr.prm_rsttimer = qemu_get_be32(f);
+ s->gr.prm_rstst = qemu_get_be32(f);
+ s->gr.prm_voltctrl = qemu_get_be32(f);
+ s->gr.prm_sram_pcharge = qemu_get_be32(f);
+ s->gr.prm_clksrc_ctrl = qemu_get_be32(f);
+ s->gr.prm_obs = qemu_get_be32(f);
+ s->gr.prm_voltsetup1 = qemu_get_be32(f);
+ s->gr.prm_voltoffset = qemu_get_be32(f);
+ s->gr.prm_clksetup = qemu_get_be32(f);
+ s->gr.prm_polctrl = qemu_get_be32(f);
+ s->gr.prm_voltsetup2 = qemu_get_be32(f);
+ for (i = 0; i < 2; i++) {
+ s->gr.prm_vp[i].config = qemu_get_be32(f);
+ s->gr.prm_vp[i].vstepmin = qemu_get_be32(f);
+ s->gr.prm_vp[i].vstepmax = qemu_get_be32(f);
+ s->gr.prm_vp[i].vlimitto = qemu_get_be32(f);
+ s->gr.prm_vp[i].voltage = qemu_get_be32(f);
+ s->gr.prm_vp[i].status = qemu_get_be32(f);
+ }
+
+ omap3_prm_int_update(s);
+ omap3_prm_clksrc_ctrl_update(s);
+ omap3_prm_clksel_update(s);
+ omap_clk_onoff(omap_findclk(s->omap, "omap3_sys_clkout1"),
+ s->ccr.prm_clkout_ctrl & 0x80);
+
+ return 0;
+}
+
+static CPUReadMemoryFunc *omap3_prm_readfn[] = {
+ omap_badwidth_read32,
+ omap_badwidth_read32,
+ omap3_prm_read,
+};
+
+static CPUWriteMemoryFunc *omap3_prm_writefn[] = {
+ omap_badwidth_write32,
+ omap_badwidth_write32,
+ omap3_prm_write,
+};
+
+static struct omap3_prm_s *omap3_prm_init(struct omap_target_agent_s *ta,
+ qemu_irq mpu_int, qemu_irq iva_int,
+ struct omap_mpu_state_s *mpu)
+{
+ int iomemtype;
+ struct omap3_prm_s *s = (struct omap3_prm_s *) qemu_mallocz(sizeof(*s));
+
+ s->mpu_irq = mpu_int;
+ s->iva_irq = iva_int;
+ s->omap = mpu;
+ omap3_prm_reset(s);
+
+ iomemtype = l4_register_io_memory(0, omap3_prm_readfn,
+ omap3_prm_writefn, s);
+ omap_l4_attach(ta, 0, iomemtype);
+ omap_l4_attach(ta, 1, iomemtype);
+
+ register_savevm("omap3_prm", -1, 0,
+ omap3_prm_save_state, omap3_prm_load_state, s);
+
+ return s;
+}
+
+struct omap3_cm_s {
+ qemu_irq irq[3];
+ struct omap_mpu_state_s *mpu;
+
+ /* IVA2_CM: base + 0x0000 */
+ uint32_t cm_fclken_iva2; /* 00 */
+ uint32_t cm_clken_pll_iva2; /* 04 */
+ uint32_t cm_idlest_iva2; /* 20 */
+ uint32_t cm_idlest_pll_iva2; /* 24 */
+ uint32_t cm_autoidle_pll_iva2; /* 34 */
+ uint32_t cm_clksel1_pll_iva2; /* 40 */
+ uint32_t cm_clksel2_pll_iva2; /* 44 */
+ uint32_t cm_clkstctrl_iva2; /* 48 */
+ uint32_t cm_clkstst_iva2; /* 4c */
+
+ /* OCP_System_Reg_CM: base + 0x0800 */
+ uint32_t cm_revision; /* 00 */
+ uint32_t cm_sysconfig; /* 10 */
+
+ /* MPU_CM: base + 0x0900 */
+ uint32_t cm_clken_pll_mpu; /* 04 */
+ uint32_t cm_idlest_mpu; /* 20 */
+ uint32_t cm_idlest_pll_mpu; /* 24 */
+ uint32_t cm_autoidle_pll_mpu; /* 34 */
+ uint32_t cm_clksel1_pll_mpu; /* 40 */
+ uint32_t cm_clksel2_pll_mpu; /* 44 */
+ uint32_t cm_clkstctrl_mpu; /* 48 */
+ uint32_t cm_clkstst_mpu; /* 4c */
+
+ /* CORE_CM: base + 0x0a00 */
+ uint32_t cm_fclken1_core; /* 0a00 */
+ uint32_t cm_fclken2_core; /* 0a04 */
+ uint32_t cm_fclken3_core; /* 0a08 */
+ uint32_t cm_iclken1_core; /* 0a10 */
+ uint32_t cm_iclken2_core; /* 0a14 */
+ uint32_t cm_iclken3_core; /* 0a18 */
+ uint32_t cm_idlest1_core; /* 0a20 */
+ uint32_t cm_idlest2_core; /* 0a24 */
+ uint32_t cm_idlest3_core; /* 0a28 */
+ uint32_t cm_autoidle1_core; /* 0a30 */
+ uint32_t cm_autoidle2_core; /* 0a34 */
+ uint32_t cm_autoidle3_core; /* 0a38 */
+ uint32_t cm_clksel_core; /* 0a40 */
+ uint32_t cm_clkstctrl_core; /* 0a48 */
+ uint32_t cm_clkstst_core; /* 0a4c */
+
+ /* SGX_CM: base + 0x0b00 */
+ uint32_t cm_fclken_sgx; /* 00 */
+ uint32_t cm_iclken_sgx; /* 10 */
+ uint32_t cm_idlest_sgx; /* 20 */
+ uint32_t cm_clksel_sgx; /* 40 */
+ uint32_t cm_sleepdep_sgx; /* 44 */
+ uint32_t cm_clkstctrl_sgx; /* 48 */
+ uint32_t cm_clkstst_sgx; /* 4c */
+
+ /* WKUP_CM: base + 0x0c00 */
+ uint32_t cm_fclken_wkup; /* 00 */
+ uint32_t cm_iclken_wkup; /* 10 */
+ uint32_t cm_idlest_wkup; /* 20 */
+ uint32_t cm_autoidle_wkup; /* 30 */
+ uint32_t cm_clksel_wkup; /* 40 */
+ uint32_t cm_c48; /* 48 */
+
+ /* Clock_Control_Reg_CM: base + 0x0d00 */
+ uint32_t cm_clken_pll; /* 00 */
+ uint32_t cm_clken2_pll; /* 04 */
+ uint32_t cm_idlest_ckgen; /* 20 */
+ uint32_t cm_idlest2_ckgen; /* 24 */
+ uint32_t cm_autoidle_pll; /* 30 */
+ uint32_t cm_autoidle2_pll; /* 34 */
+ uint32_t cm_clksel1_pll; /* 40 */
+ uint32_t cm_clksel2_pll; /* 44 */
+ uint32_t cm_clksel3_pll; /* 48 */
+ uint32_t cm_clksel4_pll; /* 4c */
+ uint32_t cm_clksel5_pll; /* 50 */
+ uint32_t cm_clkout_ctrl; /* 70 */
+
+ /* DSS_CM: base + 0x0e00 */
+ uint32_t cm_fclken_dss; /* 00 */
+ uint32_t cm_iclken_dss; /* 10 */
+ uint32_t cm_idlest_dss; /* 20 */
+ uint32_t cm_autoidle_dss; /* 30 */
+ uint32_t cm_clksel_dss; /* 40 */
+ uint32_t cm_sleepdep_dss; /* 44 */
+ uint32_t cm_clkstctrl_dss; /* 48 */
+ uint32_t cm_clkstst_dss; /* 4c */
+
+ /* CAM_CM: base + 0x0f00 */
+ uint32_t cm_fclken_cam; /* 00 */
+ uint32_t cm_iclken_cam; /* 10 */
+ uint32_t cm_idlest_cam; /* 20 */
+ uint32_t cm_autoidle_cam; /* 30 */
+ uint32_t cm_clksel_cam; /* 40 */
+ uint32_t cm_sleepdep_cam; /* 44 */
+ uint32_t cm_clkstctrl_cam; /* 48 */
+ uint32_t cm_clkstst_cam; /* 4c */
+
+ /* PER_CM: base + 0x1000 */
+ uint32_t cm_fclken_per; /* 00 */
+ uint32_t cm_iclken_per; /* 10 */
+ uint32_t cm_idlest_per; /* 20 */
+ uint32_t cm_autoidle_per; /* 30 */
+ uint32_t cm_clksel_per; /* 40 */
+ uint32_t cm_sleepdep_per; /* 44 */
+ uint32_t cm_clkstctrl_per; /* 48 */
+ uint32_t cm_clkstst_per; /* 4c */
+
+ /* EMU_CM: base + 0x1100 */
+ uint32_t cm_clksel1_emu; /* 40 */
+ uint32_t cm_clkstctrl_emu; /* 48 */
+ uint32_t cm_clkstst_emu; /* 4c */
+ uint32_t cm_clksel2_emu; /* 50 */
+ uint32_t cm_clksel3_emu; /* 54 */
+
+ /* Global_Reg_CM: base + 0x1200 */
+ uint32_t cm_polctrl; /* 9c */
+
+ /* NEON_CM: base + 0x1300 */
+ uint32_t cm_idlest_neon; /* 20 */
+ uint32_t cm_clkstctrl_neon; /* 48 */
+
+ /* USBHOST_CM: base + 0x1400 */
+ uint32_t cm_fclken_usbhost; /* 00 */
+ uint32_t cm_iclken_usbhost; /* 10 */
+ uint32_t cm_idlest_usbhost; /* 20 */
+ uint32_t cm_autoidle_usbhost; /* 30 */
+ uint32_t cm_sleepdep_usbhost; /* 44 */
+ uint32_t cm_clkstctrl_usbhost; /* 48 */
+ uint32_t cm_clkstst_usbhost; /* 4c */
+};
+
+static inline void omap3_cm_clksel_wkup_update(struct omap3_cm_s *s)
+{
+ omap_clk_reparent(omap_findclk(s->mpu, "omap3_gp1_fclk"),
+ omap_findclk(s->mpu,
+ (s->cm_clksel_wkup & 1) /* CLKSEL_GPT1 */
+ ? "omap3_sys_clk"
+ : "omap3_32k_fclk"));
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_rm_iclk"),
+ (s->cm_clksel_wkup >> 1) & 3, /* CLKSEL_RM */
+ 1);
+
+ /* Tell GPTIMER to generate new clk rate */
+ omap_gp_timer_change_clk(s->mpu->gptimer[0]);
+
+ TRACE("gptimer1 fclk=%lld",
+ omap_clk_getrate(omap_findclk(s->mpu, "omap3_gp1_fclk")));
+
+ /* TODO: CM_USIM_CLK */
+}
+
+static inline void omap3_cm_iva2_update(struct omap3_cm_s *s)
+{
+ uint32_t iva2_dpll_mul = ((s->cm_clksel1_pll_iva2 >> 8) & 0x7ff);
+ uint32_t iva2_dpll_div, iva2_dpll_clkout_div, iva2_clk_src;
+ omap_clk iva2_clk = omap_findclk(s->mpu, "omap3_iva2_clk");
+
+ omap_clk_onoff(iva2_clk, s->cm_fclken_iva2 & 1);
+
+ switch ((s->cm_clken_pll_iva2 & 0x7)) {
+ case 0x01: /* low power stop mode */
+ case 0x05: /* low power bypass mode */
+ s->cm_idlest_pll_iva2 &= ~1;
+ break;
+ case 0x07: /* locked */
+ if (iva2_dpll_mul < 2)
+ s->cm_idlest_pll_iva2 &= ~1;
+ else
+ s->cm_idlest_pll_iva2 |= 1;
+ break;
+ default:
+ break;
+ }
+
+ if (s->cm_idlest_pll_iva2 & 1) {
+ iva2_dpll_div = s->cm_clksel1_pll_iva2 & 0x7f;
+ iva2_dpll_clkout_div = s->cm_clksel2_pll_iva2 & 0x1f;
+ omap_clk_reparent(iva2_clk, omap_findclk(s->mpu, "omap3_sys_clk"));
+ omap_clk_setrate(iva2_clk,
+ (iva2_dpll_div + 1) * iva2_dpll_clkout_div,
+ iva2_dpll_mul);
+ } else {
+ /* bypass mode */
+ iva2_clk_src = (s->cm_clksel1_pll_iva2 >> 19) & 0x07;
+ omap_clk_reparent(iva2_clk, omap_findclk(s->mpu, "omap3_core_clk"));
+ omap_clk_setrate(iva2_clk, iva2_clk_src, 1);
+ }
+}
+
+static inline void omap3_cm_mpu_update(struct omap3_cm_s *s)
+{
+ uint32_t mpu_dpll_mul = ((s->cm_clksel1_pll_mpu >> 8) & 0x7ff);
+ uint32_t mpu_dpll_div, mpu_dpll_clkout_div, mpu_clk_src;
+ omap_clk mpu_clk = omap_findclk(s->mpu, "omap3_mpu_clk");
+
+ switch ((s->cm_clken_pll_mpu & 0x7)) {
+ case 0x05: /* low power bypass mode */
+ s->cm_idlest_pll_mpu &= ~1;
+ break;
+ case 0x07: /* locked */
+ if (mpu_dpll_mul < 2)
+ s->cm_idlest_pll_mpu &= ~1;
+ else
+ s->cm_idlest_pll_mpu |= 1;
+ break;
+ default:
+ break;
+ }
+
+ if (s->cm_idlest_pll_mpu & 1) {
+ mpu_dpll_div = s->cm_clksel1_pll_mpu & 0x7f;
+ mpu_dpll_clkout_div = s->cm_clksel2_pll_mpu & 0x1f;
+ omap_clk_reparent(mpu_clk, omap_findclk(s->mpu, "omap3_sys_clk"));
+ omap_clk_setrate(mpu_clk,
+ (mpu_dpll_div + 1) * mpu_dpll_clkout_div,
+ mpu_dpll_mul);
+ } else {
+ /* bypass mode */
+ mpu_clk_src = (s->cm_clksel1_pll_mpu >> 19) & 0x07;
+ omap_clk_reparent(mpu_clk, omap_findclk(s->mpu, "omap3_core_clk"));
+ omap_clk_setrate(mpu_clk, mpu_clk_src, 1);
+ }
+}
+
+static inline void omap3_cm_dpll3_update(struct omap3_cm_s *s)
+{
+ uint32_t core_dpll_mul = ((s->cm_clksel1_pll >> 16) & 0x7ff);
+ uint32_t core_dpll_div, core_dpll_clkout_div, div_dpll3;
+
+ switch ((s->cm_clken_pll & 0x7)) {
+ case 0x05: /* low power bypass */
+ case 0x06: /* fast relock bypass */
+ s->cm_idlest_ckgen &= ~1;
+ break;
+ case 0x07: /* locked */
+ if (core_dpll_mul < 2)
+ s->cm_idlest_ckgen &= ~1;
+ else
+ s->cm_idlest_ckgen |= 1;
+ break;
+ default:
+ break;
+ }
+
+ if (s->cm_idlest_ckgen & 1) {
+ core_dpll_div = (s->cm_clksel1_pll >> 8) & 0x7f;
+ core_dpll_clkout_div = (s->cm_clksel1_pll >> 27) & 0x1f;
+ div_dpll3 = (s->cm_clksel1_emu >> 16) & 0x1f;
+
+ if (s->cm_clksel2_emu & 0x80000) { /* OVERRIDE_ENABLE */
+ core_dpll_mul = (s->cm_clksel2_emu >> 8) & 0x7ff;
+ core_dpll_div = s->cm_clksel2_emu & 0x7f;
+ }
+
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_core_clk"),
+ (core_dpll_div + 1) * core_dpll_clkout_div,
+ core_dpll_mul);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_core2_clk"),
+ (core_dpll_div + 1) * core_dpll_clkout_div,
+ core_dpll_mul * 2);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_emu_core_alwon_clk"),
+ (core_dpll_div + 1) * div_dpll3,
+ core_dpll_mul * 2);
+ } else {
+ /* bypass mode */
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_core_clk"), 1, 1);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_core2_clk"), 1, 1);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_emu_core_alwon_clk"), 1, 1);
+ }
+}
+
+static inline void omap3_cm_dpll4_update(struct omap3_cm_s *s)
+{
+ uint32_t per_dpll_mul = ((s->cm_clksel2_pll >> 8) & 0x7ff);
+ uint32_t per_dpll_div, div_96m, clksel_tv, clksel_dss1, clksel_cam, div_dpll4;
+
+ switch (((s->cm_clken_pll >> 16) & 0x7)) {
+ case 0x01: /* lower power stop mode */
+ s->cm_idlest_ckgen &= ~2;
+ break;
+ case 0x07: /* locked */
+ if (per_dpll_mul < 2)
+ s->cm_idlest_ckgen &= ~2;
+ else
+ s->cm_idlest_ckgen |= 2;
+ break;
+ default:
+ break;
+ }
+
+ if (s->cm_idlest_ckgen & 2) {
+ per_dpll_div = s->cm_clksel2_pll & 0x7f;
+ div_96m = s->cm_clksel3_pll & 0x1f;
+ clksel_tv = (s->cm_clksel_dss >> 8) & 0x1f;
+ clksel_dss1 = s->cm_clksel_dss & 0x1f;
+ clksel_cam = s->cm_clksel_cam & 0x1f;
+ div_dpll4 = (s->cm_clksel1_emu >> 24) & 0x1f;
+
+ if (s->cm_clksel3_emu & 0x80000) { /* OVERRIDE_ENABLE */
+ per_dpll_mul = (s->cm_clksel3_emu >> 8) & 0x7ff;
+ per_dpll_div = s->cm_clksel3_emu & 0x7f;
+ }
+
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_96m_fclk"),
+ (per_dpll_div + 1) * div_96m,
+ per_dpll_mul * 2);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_54m_fclk"),
+ (per_dpll_div + 1) * clksel_tv,
+ per_dpll_mul * 2);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_dss1_alwon_fclk"),
+ (per_dpll_div + 1) * clksel_dss1,
+ per_dpll_mul * 2);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_cam_mclk"),
+ (per_dpll_div + 1) * clksel_cam,
+ per_dpll_mul * 2);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_per_alwon_clk"),
+ (per_dpll_div + 1) * div_dpll4,
+ per_dpll_mul * 2);
+ } else {
+ /* bypass mode */
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_96m_fclk"), 1, 1);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_54m_fclk"), 1, 1);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_dss1_alwon_fclk"), 1, 1);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_cam_mclk"), 1, 1);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_per_alwon_clk"), 1, 1);
+ }
+}
+
+static inline void omap3_cm_dpll5_update(struct omap3_cm_s *s)
+{
+ uint32_t per2_dpll_mul = ((s->cm_clksel4_pll >> 8) & 0x7ff);
+ uint32_t per2_dpll_div, div_120m;
+
+ switch ((s->cm_clken2_pll & 0x7)) {
+ case 0x01: /* low power stop mode */
+ s->cm_idlest2_ckgen &= ~1;
+ break;
+ case 0x07: /* locked */
+ if (per2_dpll_mul < 2)
+ s->cm_idlest2_ckgen &= ~1;
+ else
+ s->cm_idlest2_ckgen |= 1;
+ break;
+ default:
+ break;
+ }
+
+ if (s->cm_idlest2_ckgen & 1) {
+ per2_dpll_div = s->cm_clksel4_pll & 0x7f;
+ div_120m = s->cm_clksel5_pll & 0x1f;
+
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_120m_fclk"),
+ (per2_dpll_div + 1) * div_120m,
+ per2_dpll_mul);
+ } else {
+ /* bypass mode */
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_120m_fclk"), 1, 1);
+ }
+}
+
+static inline void omap3_cm_48m_update(struct omap3_cm_s *s)
+{
+ omap_clk pclk = omap_findclk(s->mpu,
+ (s->cm_clksel1_pll & 0x8) /* SOURCE_48M */
+ ? "omap3_sys_altclk"
+ : "omap3_96m_fclk");
+
+ omap_clk_reparent(omap_findclk(s->mpu, "omap3_48m_fclk"), pclk);
+ omap_clk_reparent(omap_findclk(s->mpu, "omap3_12m_fclk"), pclk);
+}
+
+static inline void omap3_cm_gp10gp11_update(struct omap3_cm_s *s)
+{
+ omap_clk gp10 = omap_findclk(s->mpu, "omap3_gp10_fclk");
+ omap_clk gp11 = omap_findclk(s->mpu, "omap3_gp11_fclk");
+ omap_clk sys = omap_findclk(s->mpu, "omap3_sys_clk");
+ omap_clk f32k = omap_findclk(s->mpu, "omap3_32k_fclk");
+
+ omap_clk_reparent(gp10, (s->cm_clksel_core & 0x40) ? sys : f32k);
+ omap_clk_reparent(gp11, (s->cm_clksel_core & 0x80) ? sys : f32k);
+ omap_gp_timer_change_clk(s->mpu->gptimer[9]);
+ omap_gp_timer_change_clk(s->mpu->gptimer[10]);
+
+ TRACE("gptimer10 fclk = %lld", omap_clk_getrate(gp10));
+ TRACE("gptimer11 fclk = %lld", omap_clk_getrate(gp11));
+}
+
+static inline void omap3_cm_per_gptimer_update(struct omap3_cm_s *s)
+{
+ omap_clk sys = omap_findclk(s->mpu, "omap3_sys_clk");
+ omap_clk f32k = omap_findclk(s->mpu, "omap3_32k_fclk");
+ uint32_t cm_clksel_per = s->cm_clksel_per;
+ uint32_t n;
+ char clkname[] = "omap3_gp#_fclk";
+
+ for (n = 1; n < 9; n++, cm_clksel_per >>= 1) {
+ clkname[8] = '1' + n; /* 2 - 9 */
+ omap_clk_reparent(omap_findclk(s->mpu, clkname),
+ (cm_clksel_per & 1) ? sys : f32k);
+ omap_gp_timer_change_clk(s->mpu->gptimer[n]);
+ TRACE("gptimer%d fclk = %lld", n + 1,
+ omap_clk_getrate(omap_findclk(s->mpu, clkname)));
+ }
+}
+
+static inline void omap3_cm_clkout2_update(struct omap3_cm_s *s)
+{
+ omap_clk c = omap_findclk(s->mpu, "omap3_sys_clkout2");
+
+ omap_clk_onoff(c, (s->cm_clkout_ctrl >> 7) & 1);
+ switch (s->cm_clkout_ctrl & 0x3) {
+ case 0:
+ omap_clk_reparent(c, omap_findclk(s->mpu, "omap3_core_clk"));
+ break;
+ case 1:
+ omap_clk_reparent(c, omap_findclk(s->mpu, "omap3_sys_clk"));
+ break;
+ case 2:
+ omap_clk_reparent(c, omap_findclk(s->mpu, "omap3_96m_fclk"));
+ break;
+ case 3:
+ omap_clk_reparent(c, omap_findclk(s->mpu, "omap3_54m_fclk"));
+ break;
+ default:
+ break;
+ }
+ omap_clk_setrate(c, 1 << ((s->cm_clkout_ctrl >> 3) & 7), 1);
+}
+
+static inline void omap3_cm_fclken1_core_update(struct omap3_cm_s *s)
+{
+ uint32_t v = s->cm_fclken1_core;
+
+ /* TODO: EN_MCBSP1,5 */
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_gp10_fclk"), (v >> 11) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_gp11_fclk"), (v >> 12) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_uart1_fclk"), (v >> 13) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_uart2_fclk"), (v >> 14) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c1_fclk"), (v >> 15) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c2_fclk"), (v >> 16) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c3_fclk"), (v >> 17) & 1);
+ /* TODO: EN_HDQ, EN_SPI1-4 */
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc1_fclk"), (v >> 24) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc2_fclk"), (v >> 25) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc3_fclk"), (v >> 30) & 1);
+}
+
+static inline void omap3_cm_iclken1_core_update(struct omap3_cm_s *s)
+{
+ uint32_t v = s->cm_iclken1_core;
+
+ /* TODO: EN_SDRC, EN_HSOTGUSB, EN_OMAPCTRL, EN_MAILBOXES, EN_MCBSP1,5 */
+ /* TODO: EN_GPT10, EN_GPT11 */
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_uart1_iclk"), (v >> 13) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_uart2_iclk"), (v >> 14) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c1_iclk"), (v >> 15) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c2_iclk"), (v >> 16) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_i2c3_iclk"), (v >> 17) & 1);
+ /* TODO: EN_HDQ, EN_SPI1-4 */
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc1_iclk"), (v >> 24) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc2_iclk"), (v >> 25) & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_mmc3_iclk"), (v >> 30) & 1);
+ /* set USB OTG idle if iclk is enabled and SDMA always in standby */
+ v &= ~0x24;
+ v |= (v & 0x10) << 1;
+ s->cm_idlest1_core = ~v;
+}
+
+static inline void omap3_cm_l3l4iclk_update(struct omap3_cm_s *s)
+{
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_l3_iclk"),
+ s->cm_clksel_core & 0x3, 1);
+ omap_clk_setrate(omap_findclk(s->mpu, "omap3_l4_iclk"),
+ (s->cm_clksel_core >> 2) & 0x3, 1);
+}
+
+static void omap3_cm_reset(struct omap3_cm_s *s)
+{
+ s->cm_fclken_iva2 = 0x0;
+ s->cm_clken_pll_iva2 = 0x11;
+ s->cm_idlest_iva2 = 0x1;
+ s->cm_idlest_pll_iva2 = 0;
+ s->cm_autoidle_pll_iva2 = 0x0;
+ s->cm_clksel1_pll_iva2 = 0x80000;
+ s->cm_clksel2_pll_iva2 = 0x1;
+ s->cm_clkstctrl_iva2 = 0x0;
+ s->cm_clkstst_iva2 = 0x0;
+
+ s->cm_revision = 0x10;
+ s->cm_sysconfig = 0x1;
+
+ s->cm_clken_pll_mpu = 0x15;
+ s->cm_idlest_mpu = 0x1;
+ s->cm_idlest_pll_mpu = 0;
+ s->cm_autoidle_pll_mpu = 0x0;
+ s->cm_clksel1_pll_mpu = 0x80000;
+ s->cm_clksel2_pll_mpu = 0x1;
+ s->cm_clkstctrl_mpu = 0x0;
+ s->cm_clkstst_mpu = 0x0;
+
+ s->cm_fclken1_core = 0x0;
+ s->cm_fclken2_core = 0x0;
+ s->cm_fclken3_core = 0x0;
+ s->cm_iclken1_core = 0x42;
+ s->cm_iclken2_core = 0x0;
+ s->cm_iclken3_core = 0x0;
+ /*allow access to devices*/
+ s->cm_idlest1_core = 0x0;
+ s->cm_idlest2_core = 0x0;
+ /*ide status =0 */
+ s->cm_idlest3_core = 0xa;
+ s->cm_autoidle1_core = 0x0;
+ s->cm_autoidle2_core = 0x0;
+ s->cm_autoidle3_core = 0x0;
+ s->cm_clksel_core = 0x105;
+ s->cm_clkstctrl_core = 0x0;
+ s->cm_clkstst_core = 0x0;
+
+ s->cm_fclken_sgx = 0x0;
+ s->cm_iclken_sgx = 0x0;
+ s->cm_idlest_sgx = 0x1;
+ s->cm_clksel_sgx = 0x0;
+ s->cm_sleepdep_sgx = 0x0;
+ s->cm_clkstctrl_sgx = 0x0;
+ s->cm_clkstst_sgx = 0x0;
+
+ s->cm_fclken_wkup = 0x0;
+ s->cm_iclken_wkup = 0x0;
+ /*assume all clock can be accessed*/
+ s->cm_idlest_wkup = 0x0;
+ s->cm_autoidle_wkup = 0x0;
+ s->cm_clksel_wkup = 0x12;
+
+ s->cm_clken_pll = 0x110015;
+ s->cm_clken2_pll = 0x11;
+ s->cm_idlest_ckgen = 0x3f3c; /* FIXME: provide real clock statuses */
+ s->cm_idlest2_ckgen = 0xa; /* FIXME: provide real clock statuses */
+ s->cm_autoidle_pll = 0x0;
+ s->cm_autoidle2_pll = 0x0;
+ s->cm_clksel1_pll = 0x8000040;
+ s->cm_clksel2_pll = 0x0;
+ s->cm_clksel3_pll = 0x1;
+ s->cm_clksel4_pll = 0x0;
+ s->cm_clksel5_pll = 0x1;
+ s->cm_clkout_ctrl = 0x3;
+
+
+ s->cm_fclken_dss = 0x0;
+ s->cm_iclken_dss = 0x0;
+ /*dss can be accessed*/
+ s->cm_idlest_dss = 0x0;
+ s->cm_autoidle_dss = 0x0;
+ s->cm_clksel_dss = 0x1010;
+ s->cm_sleepdep_dss = 0x0;
+ s->cm_clkstctrl_dss = 0x0;
+ s->cm_clkstst_dss = 0x0;
+
+ s->cm_fclken_cam = 0x0;
+ s->cm_iclken_cam = 0x0;
+ s->cm_idlest_cam = 0x1;
+ s->cm_autoidle_cam = 0x0;
+ s->cm_clksel_cam = 0x10;
+ s->cm_sleepdep_cam = 0x0;
+ s->cm_clkstctrl_cam = 0x0;
+ s->cm_clkstst_cam = 0x0;
+
+ s->cm_fclken_per = 0x0;
+ s->cm_iclken_per = 0x0;
+ //s->cm_idlest_per = 0x3ffff;
+ s->cm_idlest_per = 0x0; //enable GPIO access
+ s->cm_autoidle_per = 0x0;
+ s->cm_clksel_per = 0x0;
+ s->cm_sleepdep_per = 0x0;
+ s->cm_clkstctrl_per = 0x0;
+ s->cm_clkstst_per = 0x0;
+
+ s->cm_clksel1_emu = 0x10100a50;
+ s->cm_clkstctrl_emu = 0x2;
+ s->cm_clkstst_emu = 0x0;
+ s->cm_clksel2_emu = 0x0;
+ s->cm_clksel3_emu = 0x0;
+
+ s->cm_polctrl = 0x0;
+
+ s->cm_idlest_neon = 0x1;
+ s->cm_clkstctrl_neon = 0x0;
+
+ s->cm_fclken_usbhost = 0x0;
+ s->cm_iclken_usbhost = 0x0;
+ s->cm_idlest_usbhost = 0x3;
+ s->cm_autoidle_usbhost = 0x0;
+ s->cm_sleepdep_usbhost = 0x0;
+ s->cm_clkstctrl_usbhost = 0x0;
+ s->cm_clkstst_usbhost = 0x0;
+}
+
+static uint32_t omap3_cm_read(void *opaque, target_phys_addr_t addr)
+{
+ struct omap3_cm_s *s = (struct omap3_cm_s *) opaque;
+
+ switch (addr) {
+ /* IVA2_CM */
+ case 0x0000: return s->cm_fclken_iva2;
+ case 0x0004: return s->cm_clken_pll_iva2;
+ case 0x0020: return s->cm_idlest_iva2;
+ case 0x0024: return s->cm_idlest_pll_iva2;
+ case 0x0034: return s->cm_autoidle_pll_iva2;
+ case 0x0040: return s->cm_clksel1_pll_iva2;
+ case 0x0044: return s->cm_clksel2_pll_iva2;
+ case 0x0048: return s->cm_clkstctrl_iva2;
+ case 0x004c: return s->cm_clkstst_iva2;
+ /* OCP_System_Reg_CM */
+ case 0x0800: return s->cm_revision;
+ case 0x0810: return s->cm_sysconfig;
+ /* MPU_CM */
+ case 0x0904: return s->cm_clken_pll_mpu;
+ case 0x0920: return s->cm_idlest_mpu & 0x0; /*MPU is active*/
+ case 0x0924: return s->cm_idlest_pll_mpu;
+ case 0x0934: return s->cm_autoidle_pll_mpu;
+ case 0x0940: return s->cm_clksel1_pll_mpu;
+ case 0x0944: return s->cm_clksel2_pll_mpu;
+ case 0x0948: return s->cm_clkstctrl_mpu;
+ case 0x094c: return s->cm_clkstst_mpu;
+ /* CORE_CM */
+ case 0x0a00: return s->cm_fclken1_core;
+ case 0x0a04: return s->cm_fclken2_core;
+ case 0x0a08: return s->cm_fclken3_core;
+ case 0x0a10: return s->cm_iclken1_core;
+ case 0x0a14: return s->cm_iclken2_core;
+ case 0x0a18: return s->cm_iclken3_core;
+ case 0x0a20: return s->cm_idlest1_core;
+ case 0x0a24: return s->cm_idlest2_core;
+ case 0x0a28: return s->cm_idlest3_core;
+ case 0x0a30: return s->cm_autoidle1_core;
+ case 0x0a34: return s->cm_autoidle2_core;
+ case 0x0a38: return s->cm_autoidle3_core;
+ case 0x0a40: return s->cm_clksel_core;
+ case 0x0a48: return s->cm_clkstctrl_core;
+ case 0x0a4c: return s->cm_clkstst_core;
+ /* SGX_CM */
+ case 0x0b00: return s->cm_fclken_sgx;
+ case 0x0b10: return s->cm_iclken_sgx;
+ case 0x0b20: return s->cm_idlest_sgx & 0x0;
+ case 0x0b40: return s->cm_clksel_sgx;
+ case 0x0b44: return s->cm_sleepdep_sgx;
+ case 0x0b48: return s->cm_clkstctrl_sgx;
+ case 0x0b4c: return s->cm_clkstst_sgx;
+ /* WKUP_CM */
+ case 0x0c00: return s->cm_fclken_wkup;
+ case 0x0c10: return s->cm_iclken_wkup;
+ case 0x0c20: return 0; /* TODO: Check if the timer can be accessed. */
+ case 0x0c30: return s->cm_idlest_wkup;
+ case 0x0c40: return s->cm_clksel_wkup;
+ case 0x0c48: return s->cm_c48;
+ /* Clock_Control_Reg_CM */
+ case 0x0d00: return s->cm_clken_pll;
+ case 0x0d04: return s->cm_clken2_pll;
+ case 0x0d20: return s->cm_idlest_ckgen;
+ case 0x0d24: return s->cm_idlest2_ckgen;
+ case 0x0d30: return s->cm_autoidle_pll;
+ case 0x0d34: return s->cm_autoidle2_pll;
+ case 0x0d40: return s->cm_clksel1_pll;
+ case 0x0d44: return s->cm_clksel2_pll;
+ case 0x0d48: return s->cm_clksel3_pll;
+ case 0x0d4c: return s->cm_clksel4_pll;
+ case 0x0d50: return s->cm_clksel5_pll;
+ case 0x0d70: return s->cm_clkout_ctrl;
+ /* DSS_CM */
+ case 0x0e00: return s->cm_fclken_dss;
+ case 0x0e10: return s->cm_iclken_dss;
+ case 0x0e20: return s->cm_idlest_dss;
+ case 0x0e30: return s->cm_autoidle_dss;
+ case 0x0e40: return s->cm_clksel_dss;
+ case 0x0e44: return s->cm_sleepdep_dss;
+ case 0x0e48: return s->cm_clkstctrl_dss;
+ case 0x0e4c: return s->cm_clkstst_dss;
+ /* CAM_CM */
+ case 0x0f00: return s->cm_fclken_cam;
+ case 0x0f10: return s->cm_iclken_cam;
+ case 0x0f20: return s->cm_idlest_cam & 0x0;
+ case 0x0f30: return s->cm_autoidle_cam;
+ case 0x0f40: return s->cm_clksel_cam;
+ case 0x0f44: return s->cm_sleepdep_cam;
+ case 0x0f48: return s->cm_clkstctrl_cam;
+ case 0x0f4c: return s->cm_clkstst_cam;
+ /* PER_CM */
+ case 0x1000: return s->cm_fclken_per;
+ case 0x1010: return s->cm_iclken_per;
+ case 0x1020: return s->cm_idlest_per ;
+ case 0x1030: return s->cm_autoidle_per;
+ case 0x1040: return s->cm_clksel_per;
+ case 0x1044: return s->cm_sleepdep_per;
+ case 0x1048: return s->cm_clkstctrl_per;
+ case 0x104c: return s->cm_clkstst_per;
+ /* EMU_CM */
+ case 0x1140: return s->cm_clksel1_emu;
+ case 0x1148: return s->cm_clkstctrl_emu;
+ case 0x114c: return s->cm_clkstst_emu & 0x0;
+ case 0x1150: return s->cm_clksel2_emu;
+ case 0x1154: return s->cm_clksel3_emu;
+ /* Global_Reg_CM */
+ case 0x129c: return s->cm_polctrl;
+ /* NEON_CM */
+ case 0x1320: return s->cm_idlest_neon & 0x0;
+ case 0x1348: return s->cm_clkstctrl_neon;
+ /* USBHOST_CM */
+ case 0x1400: return s->cm_fclken_usbhost;
+ case 0x1410: return s->cm_iclken_usbhost;
+ case 0x1420: return s->cm_idlest_usbhost & 0x0;
+ case 0x1430: return s->cm_autoidle_usbhost;
+ case 0x1444: return s->cm_sleepdep_usbhost;
+ case 0x1448: return s->cm_clkstctrl_usbhost;
+ case 0x144c: return s->cm_clkstst_usbhost;
+ /* unknown */
+ default: break;
+ }
+ OMAP_BAD_REG(addr);
+ return 0;
+}
+
+static void omap3_cm_write(void *opaque,
+ target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap3_cm_s *s = (struct omap3_cm_s *)opaque;
+
+ switch (addr) {
+ case 0x0020:
+ case 0x0024:
+ case 0x004c:
+ case 0x0800:
+ case 0x0920:
+ case 0x0924:
+ case 0x094c:
+ case 0x0a20:
+ case 0x0a24:
+ case 0x0a28:
+ case 0x0a4c:
+ case 0x0b20:
+ case 0x0b4c:
+ case 0x0c20:
+ case 0x0d20:
+ case 0x0d24:
+ case 0x0e20:
+ case 0x0e4c:
+ case 0x0f20:
+ case 0x0f4c:
+ case 0x1020:
+ case 0x104c:
+ case 0x114c:
+ case 0x1320:
+ case 0x1420:
+ case 0x144c:
+ OMAP_RO_REGV(addr, value);
+ break;
+ /* IVA2_CM */
+ case 0x0000:
+ s->cm_fclken_iva2 = value & 0x1;
+ omap3_cm_iva2_update(s);
+ break;
+ case 0x0004:
+ s->cm_clken_pll_iva2 = value & 0x7ff;
+ omap3_cm_iva2_update(s);
+ break;
+ case 0x0034:
+ s->cm_autoidle_pll_iva2 = value & 0x7;
+ break;
+ case 0x0040:
+ s->cm_clksel1_pll_iva2 = value & 0x3fff7f;
+ omap3_cm_iva2_update(s);
+ break;
+ case 0x0044:
+ s->cm_clksel2_pll_iva2 = value & 0x1f;
+ omap3_cm_iva2_update(s);
+ break;
+ case 0x0048:
+ s->cm_clkstctrl_iva2 = value & 0x3;
+ break;
+ /* OCP_System_Reg_CM */
+ case 0x0810:
+ s->cm_sysconfig = value & 0x1;
+ break;
+ /* MPU_CM */
+ case 0x0904:
+ s->cm_clken_pll_mpu = value & 0x7ff;
+ omap3_cm_mpu_update(s);
+ break;
+ case 0x0934:
+ s->cm_autoidle_pll_mpu = value & 0x7;
+ break;
+ case 0x0940:
+ s->cm_clksel1_pll_mpu = value & 0x3fff7f;
+ omap3_cm_mpu_update(s);
+ break;
+ case 0x0944:
+ s->cm_clksel2_pll_mpu = value & 0x1f;
+ omap3_cm_mpu_update(s);
+ break;
+ case 0x0948:
+ s->cm_clkstctrl_mpu = value & 0x3;
+ break;
+ /* CORE_CM */
+ case 0xa00:
+ s->cm_fclken1_core = value & 0x43fffe00;
+ omap3_cm_fclken1_core_update(s);
+ break;
+ case 0xa04:
+ /* TODO: check if modifying this has any effect */
+ s->cm_fclken2_core = value;
+ break;
+ case 0xa08:
+ s->cm_fclken3_core = value & 0x7;
+ /* TODO: EN_USBTLL, EN_TS */
+ break;
+ case 0xa10:
+ s->cm_iclken1_core = value & 0x637ffed2;
+ omap3_cm_iclken1_core_update(s);
+ break;
+ case 0xa14:
+ s->cm_iclken2_core = value & 0x1f;
+ break;
+ case 0xa18:
+ s->cm_iclken3_core = value & 0x4;
+ s->cm_idlest3_core = 0xd & ~(s->cm_iclken3_core & 4);
+ break;
+ case 0xa30:
+ s->cm_autoidle1_core = value & 0x7ffffed0;
+ break;
+ case 0xa34:
+ s->cm_autoidle2_core = value & 0x1f;
+ break;
+ case 0xa38:
+ s->cm_autoidle3_core = value & 0x2;
+ break;
+ case 0xa40:
+ s->cm_clksel_core = (value & 0xff) | 0x100;
+ omap3_cm_gp10gp11_update(s);
+ omap3_cm_l3l4iclk_update(s);
+ break;
+ case 0xa48:
+ s->cm_clkstctrl_core = value & 0xf;
+ break;
+ /* SGX_CM */
+ case 0xb00: s->cm_fclken_sgx = value & 0x2; break;
+ case 0xb10: s->cm_iclken_sgx = value & 0x1; break;
+ case 0xb40: s->cm_clksel_sgx = value; break; /* TODO: SGX clock */
+ case 0xb44: s->cm_sleepdep_sgx = value & 0x2; break;
+ case 0xb48: s->cm_clkstctrl_sgx = value & 0x3; break;
+ /* WKUP_CM */
+ case 0xc00:
+ s->cm_fclken_wkup = value & 0x2e9;
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_gp1_fclk"),
+ s->cm_fclken_wkup & 1);
+ /* TODO: EN_GPIO1 */
+ /* TODO: EN_WDT2 */
+ break;
+ case 0xc10:
+ s->cm_iclken_wkup = value & 0x23f;
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_wkup_l4_iclk"),
+ s->cm_iclken_wkup ? 1 : 0);
+ break;
+ case 0xc30: s->cm_autoidle_wkup = value & 0x23f; break;
+ case 0xc40:
+ s->cm_clksel_wkup = value & 0x7f;
+ omap3_cm_clksel_wkup_update(s);
+ break;
+ /* Clock_Control_Reg_CM */
+ case 0xd00:
+ s->cm_clken_pll = value & 0xffff17ff;
+ omap3_cm_dpll3_update(s);
+ omap3_cm_dpll4_update(s);
+ break;
+ case 0xd04:
+ s->cm_clken2_pll = value & 0x7ff;
+ omap3_cm_dpll5_update(s);
+ break;
+ case 0xd30: s->cm_autoidle_pll = value & 0x3f; break;
+ case 0xd34: s->cm_autoidle2_pll = value & 0x7; break;
+ case 0xd40:
+ s->cm_clksel1_pll = value & 0xffffbffc;
+ omap3_cm_dpll3_update(s);
+ omap3_cm_48m_update(s);
+ /* TODO: 96m and 54m update */
+ break;
+ case 0xd44:
+ s->cm_clksel2_pll = value & 0x7ff7f;
+ omap3_cm_dpll4_update(s);
+ break;
+ case 0xd48:
+ s->cm_clksel3_pll = value & 0x1f;
+ omap3_cm_dpll4_update(s);
+ break;
+ case 0xd4c:
+ s->cm_clksel4_pll = value & 0x7ff7f;
+ omap3_cm_dpll5_update(s);
+ break;
+ case 0xd50:
+ s->cm_clksel5_pll = value & 0x1f;
+ omap3_cm_dpll5_update(s);
+ break;
+ case 0xd70:
+ s->cm_clkout_ctrl = value & 0xbb;
+ omap3_cm_clkout2_update(s);
+ break;
+ /* DSS_CM */
+ case 0xe00: s->cm_fclken_dss = value & 0x7; break;
+ case 0xe10: s->cm_iclken_dss = value & 0x1; break;
+ case 0xe30: s->cm_autoidle_dss = value & 0x1; break;
+ case 0xe40:
+ s->cm_clksel_dss = value & 0x1f1f;
+ omap3_cm_dpll4_update(s);
+ break;
+ case 0xe44: s->cm_sleepdep_dss = value & 0x7; break;
+ case 0xe48: s->cm_clkstctrl_dss = value & 0x3; break;
+ /* CAM_CM */
+ case 0xf00: s->cm_fclken_cam = value & 0x3; break;
+ case 0xf10: s->cm_iclken_cam = value & 0x1; break;
+ case 0xf30: s->cm_autoidle_cam = value & 0x1; break;
+ case 0xf40:
+ s->cm_clksel_cam = value & 0x1f;
+ omap3_cm_dpll4_update(s);
+ break;
+ case 0xf44: s->cm_sleepdep_cam = value & 0x2; break;
+ case 0xf48: s->cm_clkstctrl_cam = value & 0x3; break;
+ /* PER_CM */
+ case 0x1000: s->cm_fclken_per = value & 0x3ffff; break;
+ case 0x1010: s->cm_iclken_per = value & 0x3ffff; break;
+ case 0x1030: s->cm_autoidle_per = value &0x3ffff; break;
+ case 0x1040:
+ s->cm_clksel_per = value & 0xff;
+ omap3_cm_per_gptimer_update(s);
+ break;
+ case 0x1044: s->cm_sleepdep_per = value & 0x6; break;
+ case 0x1048: s->cm_clkstctrl_per = value &0x7; break;
+ /* EMU_CM */
+ case 0x1140:
+ s->cm_clksel1_emu = value & 0x1f1f3fff;
+ omap3_cm_dpll3_update(s);
+ omap3_cm_dpll4_update(s);
+ break;
+ case 0x1148: s->cm_clkstctrl_emu = value & 0x3; break;
+ case 0x1150:
+ s->cm_clksel2_emu = value & 0xfff7f;
+ omap3_cm_dpll3_update(s);
+ break;
+ case 0x1154:
+ s->cm_clksel3_emu = value & 0xfff7f;
+ omap3_cm_dpll4_update(s);
+ break;
+ /* Global_Reg_CM */
+ case 0x129c: s->cm_polctrl = value & 0x1; break;
+ /* NEON_CM */
+ case 0x1348: s->cm_clkstctrl_neon = value & 0x3; break;
+ /* USBHOST_CM */
+ case 0x1400: s->cm_fclken_usbhost = value & 0x3; break;
+ case 0x1410: s->cm_iclken_usbhost = value & 0x1; break;
+ case 0x1430: s->cm_autoidle_usbhost = value & 0x1; break;
+ case 0x1444: s->cm_sleepdep_usbhost = value & 0x6; break;
+ case 0x1448: s->cm_clkstctrl_usbhost = value & 0x3; break;
+ /* unknown */
+ default:
+ OMAP_BAD_REGV(addr, value);
+ break;
+ }
+}
+
+static void omap3_cm_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap3_cm_s *s = (struct omap3_cm_s *)opaque;
+
+ qemu_put_be32(f, s->cm_fclken_iva2);
+ qemu_put_be32(f, s->cm_clken_pll_iva2);
+ qemu_put_be32(f, s->cm_idlest_iva2);
+ qemu_put_be32(f, s->cm_idlest_pll_iva2);
+ qemu_put_be32(f, s->cm_autoidle_pll_iva2);
+ qemu_put_be32(f, s->cm_clksel1_pll_iva2);
+ qemu_put_be32(f, s->cm_clksel2_pll_iva2);
+ qemu_put_be32(f, s->cm_clkstctrl_iva2);
+ qemu_put_be32(f, s->cm_clkstst_iva2);
+
+ qemu_put_be32(f, s->cm_revision);
+ qemu_put_be32(f, s->cm_sysconfig);
+
+ qemu_put_be32(f, s->cm_clken_pll_mpu);
+ qemu_put_be32(f, s->cm_idlest_mpu);
+ qemu_put_be32(f, s->cm_idlest_pll_mpu);
+ qemu_put_be32(f, s->cm_autoidle_pll_mpu);
+ qemu_put_be32(f, s->cm_clksel1_pll_mpu);
+ qemu_put_be32(f, s->cm_clksel2_pll_mpu);
+ qemu_put_be32(f, s->cm_clkstctrl_mpu);
+ qemu_put_be32(f, s->cm_clkstst_mpu);
+
+ qemu_put_be32(f, s->cm_fclken1_core);
+ qemu_put_be32(f, s->cm_fclken2_core);
+ qemu_put_be32(f, s->cm_fclken3_core);
+ qemu_put_be32(f, s->cm_iclken1_core);
+ qemu_put_be32(f, s->cm_iclken2_core);
+ qemu_put_be32(f, s->cm_iclken3_core);
+ qemu_put_be32(f, s->cm_idlest1_core);
+ qemu_put_be32(f, s->cm_idlest2_core);
+ qemu_put_be32(f, s->cm_idlest3_core);
+ qemu_put_be32(f, s->cm_autoidle1_core);
+ qemu_put_be32(f, s->cm_autoidle2_core);
+ qemu_put_be32(f, s->cm_autoidle3_core);
+ qemu_put_be32(f, s->cm_clksel_core);
+ qemu_put_be32(f, s->cm_clkstctrl_core);
+ qemu_put_be32(f, s->cm_clkstst_core);
+
+ qemu_put_be32(f, s->cm_fclken_sgx);
+ qemu_put_be32(f, s->cm_iclken_sgx);
+ qemu_put_be32(f, s->cm_idlest_sgx);
+ qemu_put_be32(f, s->cm_clksel_sgx);
+ qemu_put_be32(f, s->cm_sleepdep_sgx);
+ qemu_put_be32(f, s->cm_clkstctrl_sgx);
+ qemu_put_be32(f, s->cm_clkstst_sgx);
+
+ qemu_put_be32(f, s->cm_fclken_wkup);
+ qemu_put_be32(f, s->cm_iclken_wkup);
+ qemu_put_be32(f, s->cm_idlest_wkup);
+ qemu_put_be32(f, s->cm_autoidle_wkup);
+ qemu_put_be32(f, s->cm_clksel_wkup);
+ qemu_put_be32(f, s->cm_c48);
+
+ qemu_put_be32(f, s->cm_clken_pll);
+ qemu_put_be32(f, s->cm_clken2_pll);
+ qemu_put_be32(f, s->cm_idlest_ckgen);
+ qemu_put_be32(f, s->cm_idlest2_ckgen);
+ qemu_put_be32(f, s->cm_autoidle_pll);
+ qemu_put_be32(f, s->cm_autoidle2_pll);
+ qemu_put_be32(f, s->cm_clksel1_pll);
+ qemu_put_be32(f, s->cm_clksel2_pll);
+ qemu_put_be32(f, s->cm_clksel3_pll);
+ qemu_put_be32(f, s->cm_clksel4_pll);
+ qemu_put_be32(f, s->cm_clksel5_pll);
+ qemu_put_be32(f, s->cm_clkout_ctrl);
+
+ qemu_put_be32(f, s->cm_fclken_dss);
+ qemu_put_be32(f, s->cm_iclken_dss);
+ qemu_put_be32(f, s->cm_idlest_dss);
+ qemu_put_be32(f, s->cm_autoidle_dss);
+ qemu_put_be32(f, s->cm_clksel_dss);
+ qemu_put_be32(f, s->cm_sleepdep_dss);
+ qemu_put_be32(f, s->cm_clkstctrl_dss);
+ qemu_put_be32(f, s->cm_clkstst_dss);
+
+ qemu_put_be32(f, s->cm_fclken_cam);
+ qemu_put_be32(f, s->cm_iclken_cam);
+ qemu_put_be32(f, s->cm_idlest_cam);
+ qemu_put_be32(f, s->cm_autoidle_cam);
+ qemu_put_be32(f, s->cm_clksel_cam);
+ qemu_put_be32(f, s->cm_sleepdep_cam);
+ qemu_put_be32(f, s->cm_clkstctrl_cam);
+ qemu_put_be32(f, s->cm_clkstst_cam);
+
+ qemu_put_be32(f, s->cm_fclken_per);
+ qemu_put_be32(f, s->cm_iclken_per);
+ qemu_put_be32(f, s->cm_idlest_per);
+ qemu_put_be32(f, s->cm_autoidle_per);
+ qemu_put_be32(f, s->cm_clksel_per);
+ qemu_put_be32(f, s->cm_sleepdep_per);
+ qemu_put_be32(f, s->cm_clkstctrl_per);
+ qemu_put_be32(f, s->cm_clkstst_per);
+
+ qemu_put_be32(f, s->cm_clksel1_emu);
+ qemu_put_be32(f, s->cm_clkstctrl_emu);
+ qemu_put_be32(f, s->cm_clkstst_emu);
+ qemu_put_be32(f, s->cm_clksel2_emu);
+ qemu_put_be32(f, s->cm_clksel3_emu);
+
+ qemu_put_be32(f, s->cm_polctrl);
+
+ qemu_put_be32(f, s->cm_idlest_neon);
+ qemu_put_be32(f, s->cm_clkstctrl_neon);
+
+ qemu_put_be32(f, s->cm_fclken_usbhost);
+ qemu_put_be32(f, s->cm_iclken_usbhost);
+ qemu_put_be32(f, s->cm_idlest_usbhost);
+ qemu_put_be32(f, s->cm_autoidle_usbhost);
+ qemu_put_be32(f, s->cm_sleepdep_usbhost);
+ qemu_put_be32(f, s->cm_clkstctrl_usbhost);
+ qemu_put_be32(f, s->cm_clkstst_usbhost);
+}
+
+static int omap3_cm_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap3_cm_s *s = (struct omap3_cm_s *)opaque;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->cm_fclken_iva2 = qemu_get_be32(f);
+ s->cm_clken_pll_iva2 = qemu_get_be32(f);
+ s->cm_idlest_iva2 = qemu_get_be32(f);
+ s->cm_idlest_pll_iva2 = qemu_get_be32(f);
+ s->cm_autoidle_pll_iva2 = qemu_get_be32(f);
+ s->cm_clksel1_pll_iva2 = qemu_get_be32(f);
+ s->cm_clksel2_pll_iva2 = qemu_get_be32(f);
+ s->cm_clkstctrl_iva2 = qemu_get_be32(f);
+ s->cm_clkstst_iva2 = qemu_get_be32(f);
+
+ s->cm_revision = qemu_get_be32(f);
+ s->cm_sysconfig = qemu_get_be32(f);
+
+ s->cm_clken_pll_mpu = qemu_get_be32(f);
+ s->cm_idlest_mpu = qemu_get_be32(f);
+ s->cm_idlest_pll_mpu = qemu_get_be32(f);
+ s->cm_autoidle_pll_mpu = qemu_get_be32(f);
+ s->cm_clksel1_pll_mpu = qemu_get_be32(f);
+ s->cm_clksel2_pll_mpu = qemu_get_be32(f);
+ s->cm_clkstctrl_mpu = qemu_get_be32(f);
+ s->cm_clkstst_mpu = qemu_get_be32(f);
+
+ s->cm_fclken1_core = qemu_get_be32(f);
+ s->cm_fclken2_core = qemu_get_be32(f);
+ s->cm_fclken3_core = qemu_get_be32(f);
+ s->cm_iclken1_core = qemu_get_be32(f);
+ s->cm_iclken2_core = qemu_get_be32(f);
+ s->cm_iclken3_core = qemu_get_be32(f);
+ s->cm_idlest1_core = qemu_get_be32(f);
+ s->cm_idlest2_core = qemu_get_be32(f);
+ s->cm_idlest3_core = qemu_get_be32(f);
+ s->cm_autoidle1_core = qemu_get_be32(f);
+ s->cm_autoidle2_core = qemu_get_be32(f);
+ s->cm_autoidle3_core = qemu_get_be32(f);
+ s->cm_clksel_core = qemu_get_be32(f);
+ s->cm_clkstctrl_core = qemu_get_be32(f);
+ s->cm_clkstst_core = qemu_get_be32(f);
+
+ s->cm_fclken_sgx = qemu_get_be32(f);
+ s->cm_iclken_sgx = qemu_get_be32(f);
+ s->cm_idlest_sgx = qemu_get_be32(f);
+ s->cm_clksel_sgx = qemu_get_be32(f);
+ s->cm_sleepdep_sgx = qemu_get_be32(f);
+ s->cm_clkstctrl_sgx = qemu_get_be32(f);
+ s->cm_clkstst_sgx = qemu_get_be32(f);
+
+ s->cm_fclken_wkup = qemu_get_be32(f);
+ s->cm_iclken_wkup = qemu_get_be32(f);
+ s->cm_idlest_wkup = qemu_get_be32(f);
+ s->cm_autoidle_wkup = qemu_get_be32(f);
+ s->cm_clksel_wkup = qemu_get_be32(f);
+ s->cm_c48 = qemu_get_be32(f);
+
+ s->cm_clken_pll = qemu_get_be32(f);
+ s->cm_clken2_pll = qemu_get_be32(f);
+ s->cm_idlest_ckgen = qemu_get_be32(f);
+ s->cm_idlest2_ckgen = qemu_get_be32(f);
+ s->cm_autoidle_pll = qemu_get_be32(f);
+ s->cm_autoidle2_pll = qemu_get_be32(f);
+ s->cm_clksel1_pll = qemu_get_be32(f);
+ s->cm_clksel2_pll = qemu_get_be32(f);
+ s->cm_clksel3_pll = qemu_get_be32(f);
+ s->cm_clksel4_pll = qemu_get_be32(f);
+ s->cm_clksel5_pll = qemu_get_be32(f);
+ s->cm_clkout_ctrl = qemu_get_be32(f);
+
+ s->cm_fclken_dss = qemu_get_be32(f);
+ s->cm_iclken_dss = qemu_get_be32(f);
+ s->cm_idlest_dss = qemu_get_be32(f);
+ s->cm_autoidle_dss = qemu_get_be32(f);
+ s->cm_clksel_dss = qemu_get_be32(f);
+ s->cm_sleepdep_dss = qemu_get_be32(f);
+ s->cm_clkstctrl_dss = qemu_get_be32(f);
+ s->cm_clkstst_dss = qemu_get_be32(f);
+
+ s->cm_fclken_cam = qemu_get_be32(f);
+ s->cm_iclken_cam = qemu_get_be32(f);
+ s->cm_idlest_cam = qemu_get_be32(f);
+ s->cm_autoidle_cam = qemu_get_be32(f);
+ s->cm_clksel_cam = qemu_get_be32(f);
+ s->cm_sleepdep_cam = qemu_get_be32(f);
+ s->cm_clkstctrl_cam = qemu_get_be32(f);
+ s->cm_clkstst_cam = qemu_get_be32(f);
+
+ s->cm_fclken_per = qemu_get_be32(f);
+ s->cm_iclken_per = qemu_get_be32(f);
+ s->cm_idlest_per = qemu_get_be32(f);
+ s->cm_autoidle_per = qemu_get_be32(f);
+ s->cm_clksel_per = qemu_get_be32(f);
+ s->cm_sleepdep_per = qemu_get_be32(f);
+ s->cm_clkstctrl_per = qemu_get_be32(f);
+ s->cm_clkstst_per = qemu_get_be32(f);
+
+ s->cm_clksel1_emu = qemu_get_be32(f);
+ s->cm_clkstctrl_emu = qemu_get_be32(f);
+ s->cm_clkstst_emu = qemu_get_be32(f);
+ s->cm_clksel2_emu = qemu_get_be32(f);
+ s->cm_clksel3_emu = qemu_get_be32(f);
+
+ s->cm_polctrl = qemu_get_be32(f);
+
+ s->cm_idlest_neon = qemu_get_be32(f);
+ s->cm_clkstctrl_neon = qemu_get_be32(f);
+
+ s->cm_fclken_usbhost = qemu_get_be32(f);
+ s->cm_iclken_usbhost = qemu_get_be32(f);
+ s->cm_idlest_usbhost = qemu_get_be32(f);
+ s->cm_autoidle_usbhost = qemu_get_be32(f);
+ s->cm_sleepdep_usbhost = qemu_get_be32(f);
+ s->cm_clkstctrl_usbhost = qemu_get_be32(f);
+ s->cm_clkstst_usbhost = qemu_get_be32(f);
+
+ omap3_cm_iva2_update(s);
+ omap3_cm_mpu_update(s);
+ omap3_cm_fclken1_core_update(s);
+ omap3_cm_iclken1_core_update(s);
+ omap3_cm_gp10gp11_update(s);
+ omap3_cm_l3l4iclk_update(s);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_gp1_fclk"),
+ s->cm_fclken_wkup & 1);
+ omap_clk_onoff(omap_findclk(s->mpu, "omap3_wkup_l4_iclk"),
+ s->cm_iclken_wkup ? 1 : 0);
+ omap3_cm_clksel_wkup_update(s);
+ omap3_cm_dpll3_update(s);
+ omap3_cm_dpll4_update(s);
+ omap3_cm_dpll5_update(s);
+ omap3_cm_48m_update(s);
+ omap3_cm_clkout2_update(s);
+ omap3_cm_per_gptimer_update(s);
+
+ return 0;
+}
+
+static CPUReadMemoryFunc *omap3_cm_readfn[] = {
+ omap_badwidth_read32,
+ omap_badwidth_read32,
+ omap3_cm_read,
+};
+
+static CPUWriteMemoryFunc *omap3_cm_writefn[] = {
+ omap_badwidth_write32,
+ omap_badwidth_write32,
+ omap3_cm_write,
+};
+
+static struct omap3_cm_s *omap3_cm_init(struct omap_target_agent_s *ta,
+ qemu_irq mpu_int, qemu_irq dsp_int,
+ qemu_irq iva_int,
+ struct omap_mpu_state_s *mpu)
+{
+ int iomemtype;
+ struct omap3_cm_s *s = (struct omap3_cm_s *) qemu_mallocz(sizeof(*s));
+
+ s->irq[0] = mpu_int;
+ s->irq[1] = dsp_int;
+ s->irq[2] = iva_int;
+ s->mpu = mpu;
+ omap3_cm_reset(s);
+
+ iomemtype = l4_register_io_memory(0, omap3_cm_readfn, omap3_cm_writefn, s);
+ omap_l4_attach(ta, 0, iomemtype);
+ omap_l4_attach(ta, 1, iomemtype);
+
+ register_savevm("omap3_cm", -1, 0,
+ omap3_cm_save_state, omap3_cm_load_state, s);
+ return s;
+}
+
+#define OMAP3_SEC_WDT 1
+#define OMAP3_MPU_WDT 2
+#define OMAP3_IVA2_WDT 3
+/*omap3 watchdog timer*/
+struct omap3_wdt_s
+{
+ qemu_irq irq; /*IVA2 IRQ */
+ struct omap_mpu_state_s *mpu;
+ omap_clk clk;
+ QEMUTimer *timer;
+
+ int active;
+ int64_t rate;
+ int64_t time;
+ //int64_t ticks_per_sec;
+
+ uint32_t wd_sysconfig;
+ uint32_t wd_sysstatus;
+ uint32_t wisr;
+ uint32_t wier;
+ uint32_t wclr;
+ uint32_t wcrr;
+ uint32_t wldr;
+ uint32_t wtgr;
+ uint32_t wwps;
+ uint32_t wspr;
+
+ /*pre and ptv in wclr */
+ uint32_t pre;
+ uint32_t ptv;
+ //uint32_t val;
+
+ uint16_t writeh; /* LSB */
+ uint16_t readh; /* MSB */
+};
+
+static inline void omap3_wdt_timer_update(struct omap3_wdt_s *wdt_timer)
+{
+ int64_t expires;
+ if (wdt_timer->active) {
+ expires = muldiv64(0xffffffffll - wdt_timer->wcrr,
+ ticks_per_sec, wdt_timer->rate);
+ qemu_mod_timer(wdt_timer->timer, wdt_timer->time + expires);
+ } else
+ qemu_del_timer(wdt_timer->timer);
+}
+
+static void omap3_wdt_clk_setup(struct omap3_wdt_s *timer)
+{
+ /*TODO: Add irq as user to clk */
+}
+
+static inline uint32_t omap3_wdt_timer_read(struct omap3_wdt_s *timer)
+{
+ uint64_t distance;
+
+ if (timer->active) {
+ distance = qemu_get_clock(vm_clock) - timer->time;
+ distance = muldiv64(distance, timer->rate, ticks_per_sec);
+
+ if (distance >= 0xffffffff - timer->wcrr)
+ return 0xffffffff;
+ else
+ return timer->wcrr + distance;
+ } else
+ return timer->wcrr;
+}
+
+/*
+static inline void omap3_wdt_timer_sync(struct omap3_wdt_s *timer)
+{
+ if (timer->active) {
+ timer->val = omap3_wdt_timer_read(timer);
+ timer->time = qemu_get_clock(vm_clock);
+ }
+}*/
+
+static void omap3_wdt_reset(struct omap3_wdt_s *s, int wdt_index)
+{
+ s->wd_sysconfig = 0x0;
+ s->wd_sysstatus = 0x0;
+ s->wisr = 0x0;
+ s->wier = 0x0;
+ s->wclr = 0x20;
+ s->wcrr = 0x0;
+ switch (wdt_index) {
+ case OMAP3_MPU_WDT:
+ case OMAP3_IVA2_WDT:
+ s->wldr = 0xfffb0000;
+ break;
+ case OMAP3_SEC_WDT:
+ s->wldr = 0xffa60000;
+ break;
+ default:
+ break;
+ }
+ s->wtgr = 0x0;
+ s->wwps = 0x0;
+ s->wspr = 0x0;
+
+ switch (wdt_index) {
+ case OMAP3_SEC_WDT:
+ case OMAP3_MPU_WDT:
+ s->active = 1;
+ break;
+ case OMAP3_IVA2_WDT:
+ s->active = 0;
+ break;
+ default:
+ break;
+ }
+ s->pre = s->wclr & (1 << 5);
+ s->ptv = (s->wclr & 0x1c) >> 2;
+ s->rate = omap_clk_getrate(s->clk) >> (s->pre ? s->ptv : 0);
+
+ s->active = 1;
+ s->time = qemu_get_clock(vm_clock);
+ omap3_wdt_timer_update(s);
+}
+
+static uint32_t omap3_wdt_read32(void *opaque, target_phys_addr_t addr,
+ int wdt_index)
+{
+ struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
+
+ switch (addr) {
+ case 0x10: return s->wd_sysconfig;
+ case 0x14: return s->wd_sysstatus;
+ case 0x18: return s->wisr & 0x1;
+ case 0x1c: return s->wier & 0x1;
+ case 0x24: return s->wclr & 0x3c;
+ case 0x28: /* WCRR */
+ s->wcrr = omap3_wdt_timer_read(s);
+ s->time = qemu_get_clock(vm_clock);
+ return s->wcrr;
+ case 0x2c: return s->wldr;
+ case 0x30: return s->wtgr;
+ case 0x34: return s->wwps;
+ case 0x48: return s->wspr;
+ default: break;
+ }
+ OMAP_BAD_REG(addr);
+ return 0;
+}
+
+static uint32_t omap3_mpu_wdt_read16(void *opaque, target_phys_addr_t addr)
+{
+ struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
+ uint32_t ret;
+
+ if (addr & 2)
+ return s->readh;
+
+ ret = omap3_wdt_read32(opaque, addr, OMAP3_MPU_WDT);
+ s->readh = ret >> 16;
+ return ret & 0xffff;
+}
+
+static uint32_t omap3_mpu_wdt_read32(void *opaque, target_phys_addr_t addr)
+{
+ return omap3_wdt_read32(opaque, addr, OMAP3_MPU_WDT);
+}
+
+static void omap3_wdt_write32(void *opaque, target_phys_addr_t addr,
+ uint32_t value, int wdt_index)
+{
+ struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
+
+ switch (addr) {
+ case 0x14: /* WD_SYSSTATUS */
+ case 0x34: /* WWPS */
+ OMAP_RO_REGV(addr, value);
+ break;
+ case 0x10: /*WD_SYSCONFIG */
+ s->wd_sysconfig = value & 0x33f;
+ break;
+ case 0x18: /* WISR */
+ s->wisr = value & 0x1;
+ break;
+ case 0x1c: /* WIER */
+ s->wier = value & 0x1;
+ break;
+ case 0x24: /* WCLR */
+ s->wclr = value & 0x3c;
+ break;
+ case 0x28: /* WCRR */
+ s->wcrr = value;
+ s->time = qemu_get_clock(vm_clock);
+ omap3_wdt_timer_update(s);
+ break;
+ case 0x2c: /* WLDR */
+ s->wldr = value; /* It will take effect after next overflow */
+ break;
+ case 0x30: /* WTGR */
+ if (value != s->wtgr) {
+ s->wcrr = s->wldr;
+ s->pre = s->wclr & (1 << 5);
+ s->ptv = (s->wclr & 0x1c) >> 2;
+ s->rate = omap_clk_getrate(s->clk) >> (s->pre ? s->ptv : 0);
+ s->time = qemu_get_clock(vm_clock);
+ omap3_wdt_timer_update(s);
+ }
+ s->wtgr = value;
+ break;
+ case 0x48: /* WSPR */
+ if (((value & 0xffff) == 0x5555) && ((s->wspr & 0xffff) == 0xaaaa)) {
+ s->active = 0;
+ s->wcrr = omap3_wdt_timer_read(s);
+ omap3_wdt_timer_update(s);
+ }
+ if (((value & 0xffff) == 0x4444) && ((s->wspr & 0xffff) == 0xbbbb)) {
+ s->active = 1;
+ s->time = qemu_get_clock(vm_clock);
+ omap3_wdt_timer_update(s);
+ }
+ s->wspr = value;
+ break;
+ default:
+ OMAP_BAD_REGV(addr, value);
+ break;
+ }
+}
+
+static void omap3_mpu_wdt_write16(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap3_wdt_s *s = (struct omap3_wdt_s *) opaque;
+
+ if (addr & 2)
+ return omap3_wdt_write32(opaque, addr, (value << 16) | s->writeh,
+ OMAP3_MPU_WDT);
+ else
+ s->writeh = (uint16_t) value;
+}
+
+static void omap3_mpu_wdt_write32(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ omap3_wdt_write32(opaque, addr, value, OMAP3_MPU_WDT);
+}
+
+static CPUReadMemoryFunc *omap3_mpu_wdt_readfn[] = {
+ omap_badwidth_read32,
+ omap3_mpu_wdt_read16,
+ omap3_mpu_wdt_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_mpu_wdt_writefn[] = {
+ omap_badwidth_write32,
+ omap3_mpu_wdt_write16,
+ omap3_mpu_wdt_write32,
+};
+
+static void omap3_mpu_wdt_timer_tick(void *opaque)
+{
+ struct omap3_wdt_s *wdt_timer = (struct omap3_wdt_s *) opaque;
+
+ /*TODO:Sent reset pulse to PRCM */
+ wdt_timer->wcrr = wdt_timer->wldr;
+
+ /*after overflow, generate the new wdt_timer->rate */
+ wdt_timer->pre = wdt_timer->wclr & (1 << 5);
+ wdt_timer->ptv = (wdt_timer->wclr & 0x1c) >> 2;
+ wdt_timer->rate =
+ omap_clk_getrate(wdt_timer->clk) >> (wdt_timer->pre ? wdt_timer->
+ ptv : 0);
+
+ wdt_timer->time = qemu_get_clock(vm_clock);
+ omap3_wdt_timer_update(wdt_timer);
+}
+
+static void omap3_mpu_wdt_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap3_wdt_s *s = (struct omap3_wdt_s *)opaque;
+
+ qemu_put_timer(f, s->timer);
+ qemu_put_sbe32(f, s->active);
+ qemu_put_be64(f, s->rate);
+ qemu_put_be64(f, s->time);
+ qemu_put_be32(f, s->wd_sysconfig);
+ qemu_put_be32(f, s->wd_sysstatus);
+ qemu_put_be32(f, s->wisr);
+ qemu_put_be32(f, s->wier);
+ qemu_put_be32(f, s->wclr);
+ qemu_put_be32(f, s->wcrr);
+ qemu_put_be32(f, s->wldr);
+ qemu_put_be32(f, s->wtgr);
+ qemu_put_be32(f, s->wwps);
+ qemu_put_be32(f, s->wspr);
+ qemu_put_be32(f, s->pre);
+ qemu_put_be32(f, s->ptv);
+ qemu_put_be16(f, s->writeh);
+ qemu_put_be16(f, s->readh);
+}
+
+static int omap3_mpu_wdt_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap3_wdt_s *s = (struct omap3_wdt_s *)opaque;
+
+ if (version_id)
+ return -EINVAL;
+
+ qemu_get_timer(f, s->timer);
+ s->active = qemu_get_sbe32(f);
+ s->rate = qemu_get_be64(f);
+ s->time = qemu_get_be64(f);
+ s->wd_sysconfig = qemu_get_be32(f);
+ s->wd_sysstatus = qemu_get_be32(f);
+ s->wisr = qemu_get_be32(f);
+ s->wier = qemu_get_be32(f);
+ s->wclr = qemu_get_be32(f);
+ s->wcrr = qemu_get_be32(f);
+ s->wldr = qemu_get_be32(f);
+ s->wtgr = qemu_get_be32(f);
+ s->wwps = qemu_get_be32(f);
+ s->wspr = qemu_get_be32(f);
+ s->pre = qemu_get_be32(f);
+ s->ptv = qemu_get_be32(f);
+ s->writeh = qemu_get_be16(f);
+ s->readh = qemu_get_be16(f);
+
+ return 0;
+}
+
+static struct omap3_wdt_s *omap3_mpu_wdt_init(struct omap_target_agent_s *ta,
+ qemu_irq irq, omap_clk fclk,
+ omap_clk iclk,
+ struct omap_mpu_state_s *mpu)
+{
+ int iomemtype;
+ struct omap3_wdt_s *s = (struct omap3_wdt_s *) qemu_mallocz(sizeof(*s));
+
+ s->irq = irq;
+ s->clk = fclk;
+ s->timer = qemu_new_timer(vm_clock, omap3_mpu_wdt_timer_tick, s);
+
+ omap3_wdt_reset(s, OMAP3_MPU_WDT);
+ if (irq != NULL)
+ omap3_wdt_clk_setup(s);
+
+ iomemtype = l4_register_io_memory(0, omap3_mpu_wdt_readfn,
+ omap3_mpu_wdt_writefn, s);
+ omap_l4_attach(ta, 0, iomemtype);
+
+ register_savevm("omap3_mpu_wdt", -1, 0,
+ omap3_mpu_wdt_save_state, omap3_mpu_wdt_load_state, s);
+ return s;
+}
+
+struct omap3_scm_s {
+ struct omap_mpu_state_s *mpu;
+
+ uint8 interface[48]; /*0x4800 2000*/
+ uint8 padconfs[576]; /*0x4800 2030*/
+ uint32 general[228]; /*0x4800 2270*/
+ uint8 mem_wkup[1024]; /*0x4800 2600*/
+ uint8 padconfs_wkup[84]; /*0x4800 2a00*/
+ uint32 general_wkup[8]; /*0x4800 2a60*/
+};
+
+static void omap3_scm_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap3_scm_s *s = (struct omap3_scm_s *)opaque;
+ int i;
+
+ qemu_put_buffer(f, s->interface, sizeof(s->interface));
+ qemu_put_buffer(f, s->padconfs, sizeof(s->padconfs));
+ for (i = 0; i < sizeof(s->general)/sizeof(uint32); i++)
+ qemu_put_be32(f, s->general[i]);
+ qemu_put_buffer(f, s->mem_wkup, sizeof(s->mem_wkup));
+ qemu_put_buffer(f, s->padconfs_wkup, sizeof(s->padconfs_wkup));
+ for (i = 0; i < sizeof(s->general_wkup)/sizeof(uint32); i++)
+ qemu_put_be32(f, s->general_wkup[i]);
+}
+
+static int omap3_scm_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap3_scm_s *s = (struct omap3_scm_s *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ qemu_get_buffer(f, s->interface, sizeof(s->interface));
+ qemu_get_buffer(f, s->padconfs, sizeof(s->padconfs));
+ for (i = 0; i < sizeof(s->general)/sizeof(uint32); i++)
+ s->general[i] = qemu_get_be32(f);
+ qemu_get_buffer(f, s->mem_wkup, sizeof(s->mem_wkup));
+ qemu_get_buffer(f, s->padconfs_wkup, sizeof(s->padconfs_wkup));
+ for (i = 0; i < sizeof(s->general_wkup)/sizeof(uint32); i++)
+ s->general_wkup[i] = qemu_get_be32(f);
+
+ return 0;
+}
+
+#define PADCONFS_VALUE(wakeup0,wakeup1,offmode0,offmode1, \
+ inputenable0,inputenable1,pupd0,pupd1,muxmode0,muxmode1,offset) \
+ do { \
+ *(padconfs+offset/4) = (wakeup0 <<14)|(offmode0<<9)|(inputenable0<<8)|(pupd0<<3)|(muxmode0); \
+ *(padconfs+offset/4) |= (wakeup1 <<30)|(offmode1<<25)|(inputenable1<<24)|(pupd1<<19)|(muxmode1<<16); \
+} while (0)
+
+
+static void omap3_scm_reset(struct omap3_scm_s *s)
+{
+ uint32 * padconfs;
+ padconfs = (uint32 *)(s->padconfs);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x0);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x4);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x8);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0xc);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x10);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x14);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x18);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x1c);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x20);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x24);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x28);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x2c);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x30);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x34);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x38);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x3c);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x40);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x44);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,1,0,7,0x48);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x4c);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x50);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x54);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x58);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,0,0x5c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x60);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x64);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x68);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x6c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x70);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x74);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x78);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x7c);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,3,0,7,0x80);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x84);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x88);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,0,7,0,0x8c);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x90);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x94);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,0,7,0,0x98);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,7,0x9c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0xa0);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0xa4);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0xa8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xac);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xb0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xb4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xb8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xbc);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xc0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xc4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xc8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xcc);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xd0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xd4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xd8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xdc);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xe0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xe4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xe8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xec);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xf0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xf4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xf8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0xfc);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x100);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x104);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x108);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x10c);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x110);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x114);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x118);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x11c);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x120);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x124);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,3,7,7,0x128);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x12c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x130);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x134);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x138);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x13c);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x140);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x144);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x148);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x14c);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x150);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x154);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x158);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x15c);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x160);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x164);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,3,7,7,0x168);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x16c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x170);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x174);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x178);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x17c);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x180);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x184);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,3,7,7,0x188);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x18c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x190);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x194);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x198);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,3,7,7,0x19c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x1a0);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x1a4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x1a8);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x1ac);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,1,7,7,0x1b0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1b4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1b8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1bc);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1c0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1c4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1c8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1cc);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1d0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1d4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1d8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1dc);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1e0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1e4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1e8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1ec);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1f0);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1f4);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1f8);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1fc);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x200);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x204);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x208);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x20c);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x210);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x214);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x218);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x21c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x220);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,1,0,0,0x224);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,1,0,0,0x228);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,1,0,0,0x22c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x230);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,7,7,0x234);
+
+ padconfs = (uint32 *)(s->general);
+ memset(s->general, 0, sizeof(s->general));
+ s->general[0x01] = 0x4000000; /* CONTROL_DEVCONF_0 */
+ s->general[0x1c] = 0x1; /* 0x480022e0?? */
+ s->general[0x20] = 0x30f; /* CONTROL_STATUS:
+ * - device type = GP Device
+ * - sys_boot:6 = oscillator bypass mode
+ * - sys_boot:0-5 = NAND, USB, UART3, MMC1*/
+ s->general[0x75] = 0x7fc0; /* CONTROL_PROG_IO0 */
+ s->general[0x76] = 0xaa; /* CONTROL_PROG_IO1 */
+ s->general[0x7c] = 0x2700; /* CONTROL_SDRC_SHARING */
+ s->general[0x7d] = 0x300000; /* CONTROL_SDRC_MCFG0 */
+ s->general[0x7e] = 0x300000; /* CONTROL_SDRC_MCFG1 */
+ s->general[0x81] = 0xffff; /* CONTROL_MODEM_GPMC_DT_FW_REQ_INFO */
+ s->general[0x82] = 0xffff; /* CONTROL_MODEM_GPMC_DT_FW_RD */
+ s->general[0x83] = 0xffff; /* CONTROL_MODEM_GPMC_DT_FW_WR */
+ s->general[0x84] = 0x6; /* CONTROL_MODEM_GPMC_BOOT_CODE */
+ s->general[0x85] = 0xffffffff; /* CONTROL_MODEM_SMS_RG_ATT1 */
+ s->general[0x86] = 0xffff; /* CONTROL_MODEM_SMS_RG_RDPERM1 */
+ s->general[0x87] = 0xffff; /* CONTROL_MODEM_SMS_RG_WRPERM1 */
+ s->general[0x88] = 0x1; /* CONTROL_MODEM_D2D_FW_DEBUG_MODE */
+ s->general[0x8b] = 0xffffffff; /* CONTROL_DPF_OCM_RAM_FW_REQINFO */
+ s->general[0x8c] = 0xffff; /* CONTROL_DPF_OCM_RAM_FW_WR */
+ s->general[0x8e] = 0xffff; /* CONTROL_DPF_REGION4_GPMC_FW_REQINFO */
+ s->general[0x8f] = 0xffff; /* CONTROL_DPF_REGION4_GPMC_FW_WR */
+ s->general[0x91] = 0xffff; /* CONTROL_DPF_REGION1_IVA2_FW_REQINFO */
+ s->general[0x92] = 0xffff; /* CONTROL_DPF_REGION1_IVA2_FW_WR */
+ s->general[0xac] = 0x109; /* CONTROL_PBIAS_LITE */
+ s->general[0xb2] = 0xffff; /* CONTROL_DPF_MAD2D_FW_ADDR_MATCH */
+ s->general[0xb3] = 0xffff; /* CONTROL_DPF_MAD2D_FW_REQINFO */
+ s->general[0xb4] = 0xffff; /* CONTROL_DPF_MAD2D_FW_WR */
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,4,4,0x368); /* PADCONF_ETK_CLK */
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,4,4,0x36c); /* PADCONF_ETK_D0 */
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,4,4,0x370); /* PADCONF_ETK_D2 */
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x374); /* PADCONF_ETK_D4 */
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x378); /* PADCONF_ETK_D6 */
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x37c); /* PADCONF_ETK_D8 */
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x380); /* PADCONF_ETK_D10 */
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x384); /* PADCONF_ETK_D12 */
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,4,4,0x388); /* PADCONF_ETK_D14 */
+
+ padconfs = (uint32 *)(s->padconfs_wkup);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x0);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x4);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,0,0,0,0x8);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0xc);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x10);
+ PADCONFS_VALUE(0,0,0,0,1,1,0,0,0,0,0x14);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,7,7,0x18);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x1c);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x20);
+ PADCONFS_VALUE(0,0,0,0,1,1,3,3,0,0,0x24);
+ PADCONFS_VALUE(0,0,0,0,1,1,1,1,0,0,0x2c);
+
+ s->general_wkup[0] = 0x66ff; /* 0x48002A60?? */
+}
+
+static uint32_t omap3_scm_read8(void *opaque, target_phys_addr_t addr)
+{
+ struct omap3_scm_s *s = (struct omap3_scm_s *) opaque;
+ uint8_t* temp;
+
+ switch (addr) {
+ case 0x000 ... 0x02f: return s->interface[addr];
+ case 0x030 ... 0x26f: return s->padconfs[addr - 0x30];
+ case 0x270 ... 0x5ff: temp = (uint8_t *)s->general; return temp[addr - 0x270];
+ case 0x600 ... 0x9ff: return s->mem_wkup[addr - 0x600];
+ case 0xa00 ... 0xa5f: return s->padconfs_wkup[addr - 0xa00];
+ case 0xa60 ... 0xa7f: temp = (uint8_t *)s->general_wkup; return temp[addr - 0xa60];
+ default: break;
+ }
+ OMAP_BAD_REG(addr);
+ return 0;
+}
+
+static uint32_t omap3_scm_read16(void *opaque, target_phys_addr_t addr)
+{
+ uint32_t v;
+ v = omap3_scm_read8(opaque, addr);
+ v |= omap3_scm_read8(opaque, addr + 1) << 8;
+ return v;
+}
+
+static uint32_t omap3_scm_read32(void *opaque, target_phys_addr_t addr)
+{
+ uint32_t v;
+ v = omap3_scm_read8(opaque, addr);
+ v |= omap3_scm_read8(opaque, addr + 1) << 8;
+ v |= omap3_scm_read8(opaque, addr + 2) << 16;
+ v |= omap3_scm_read8(opaque, addr + 3) << 24;
+ return v;
+}
+
+static void omap3_scm_write8(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap3_scm_s *s = (struct omap3_scm_s *) opaque;
+ uint8_t* temp;
+
+ switch (addr) {
+ case 0x000 ... 0x02f: s->interface[addr] = value; break;
+ case 0x030 ... 0x26f: s->padconfs[addr-0x30] = value; break;
+ case 0x270 ... 0x5ff: temp = (uint8_t *)s->general; temp[addr-0x270] = value; break;
+ case 0x600 ... 0x9ff: s->mem_wkup[addr-0x600] = value; break;
+ case 0xa00 ... 0xa5f: s->padconfs_wkup[addr-0xa00] = value; break;
+ case 0xa60 ... 0xa7f: temp = (uint8_t *)s->general_wkup; temp[addr-0xa60] = value; break;
+ default: OMAP_BAD_REGV(addr, value); break;
+ }
+}
+
+static void omap3_scm_write16(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ omap3_scm_write8(opaque, addr + 0, (value) & 0xff);
+ omap3_scm_write8(opaque, addr + 1, (value >> 8) & 0xff);
+}
+
+static void omap3_scm_write32(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ omap3_scm_write8(opaque, addr + 0, (value) & 0xff);
+ omap3_scm_write8(opaque, addr + 1, (value >> 8) & 0xff);
+ omap3_scm_write8(opaque, addr + 2, (value >> 16) & 0xff);
+ omap3_scm_write8(opaque, addr + 3, (value >> 24) & 0xff);
+}
+
+static CPUReadMemoryFunc *omap3_scm_readfn[] = {
+ omap3_scm_read8,
+ omap3_scm_read16,
+ omap3_scm_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_scm_writefn[] = {
+ omap3_scm_write8,
+ omap3_scm_write16,
+ omap3_scm_write32,
+};
+
+static struct omap3_scm_s *omap3_scm_init(struct omap_target_agent_s *ta,
+ struct omap_mpu_state_s *mpu)
+{
+ int iomemtype;
+ struct omap3_scm_s *s = (struct omap3_scm_s *) qemu_mallocz(sizeof(*s));
+
+ s->mpu = mpu;
+
+ omap3_scm_reset(s);
+
+ iomemtype = l4_register_io_memory(0, omap3_scm_readfn,
+ omap3_scm_writefn, s);
+ omap_l4_attach(ta, 0, iomemtype);
+
+ register_savevm("omap3_scm", -1, 0,
+ omap3_scm_save_state, omap3_scm_load_state, s);
+ return s;
+}
+
+/*dummy SDRAM Memory Scheduler emulation*/
+struct omap3_sms_s
+{
+ struct omap_mpu_state_s *mpu;
+
+ uint32 sms_sysconfig;
+ uint32 sms_sysstatus;
+ uint32 sms_rg_att[8];
+ uint32 sms_rg_rdperm[8];
+ uint32 sms_rg_wrperm[8];
+ uint32 sms_rg_start[7];
+ uint32 sms_rg_end[7];
+ uint32 sms_security_control;
+ uint32 sms_class_arbiter0;
+ uint32 sms_class_arbiter1;
+ uint32 sms_class_arbiter2;
+ uint32 sms_interclass_arbiter;
+ uint32 sms_class_rotation[3];
+ uint32 sms_err_addr;
+ uint32 sms_err_type;
+ uint32 sms_pow_ctrl;
+ uint32 sms_rot_control[12];
+ uint32 sms_rot_size[12];
+ uint32 sms_rot_physical_ba[12];
+};
+
+static void omap3_sms_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap3_sms_s *s = (struct omap3_sms_s *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->sms_sysconfig);
+ qemu_put_be32(f, s->sms_sysstatus);
+ for (i = 0; i < 8; i++) {
+ qemu_put_be32(f, s->sms_rg_att[i]);
+ qemu_put_be32(f, s->sms_rg_rdperm[i]);
+ qemu_put_be32(f, s->sms_rg_wrperm[i]);
+ if (i < 7) {
+ qemu_put_be32(f, s->sms_rg_start[i]);
+ qemu_put_be32(f, s->sms_rg_end[i]);
+ }
+ }
+ qemu_put_be32(f, s->sms_security_control);
+ qemu_put_be32(f, s->sms_class_arbiter0);
+ qemu_put_be32(f, s->sms_class_arbiter1);
+ qemu_put_be32(f, s->sms_class_arbiter2);
+ qemu_put_be32(f, s->sms_interclass_arbiter);
+ qemu_put_be32(f, s->sms_class_rotation[0]);
+ qemu_put_be32(f, s->sms_class_rotation[1]);
+ qemu_put_be32(f, s->sms_class_rotation[2]);
+ qemu_put_be32(f, s->sms_err_addr);
+ qemu_put_be32(f, s->sms_err_type);
+ qemu_put_be32(f, s->sms_pow_ctrl);
+ for (i = 0; i< 12; i++) {
+ qemu_put_be32(f, s->sms_rot_control[i]);
+ qemu_put_be32(f, s->sms_rot_size[i]);
+ qemu_put_be32(f, s->sms_rot_physical_ba[i]);
+ }
+}
+
+static int omap3_sms_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap3_sms_s *s = (struct omap3_sms_s *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->sms_sysconfig = qemu_get_be32(f);
+ s->sms_sysstatus = qemu_get_be32(f);
+ for (i = 0; i < 8; i++) {
+ s->sms_rg_att[i] = qemu_get_be32(f);
+ s->sms_rg_rdperm[i] = qemu_get_be32(f);
+ s->sms_rg_wrperm[i] = qemu_get_be32(f);
+ if (i < 7) {
+ s->sms_rg_start[i] = qemu_get_be32(f);
+ s->sms_rg_end[i] = qemu_get_be32(f);
+ }
+ }
+ s->sms_security_control = qemu_get_be32(f);
+ s->sms_class_arbiter0 = qemu_get_be32(f);
+ s->sms_class_arbiter1 = qemu_get_be32(f);
+ s->sms_class_arbiter2 = qemu_get_be32(f);
+ s->sms_interclass_arbiter = qemu_get_be32(f);
+ s->sms_class_rotation[0] = qemu_get_be32(f);
+ s->sms_class_rotation[1] = qemu_get_be32(f);
+ s->sms_class_rotation[2] = qemu_get_be32(f);
+ s->sms_err_addr = qemu_get_be32(f);
+ s->sms_err_type = qemu_get_be32(f);
+ s->sms_pow_ctrl = qemu_get_be32(f);
+ for (i = 0; i< 12; i++) {
+ s->sms_rot_control[i] = qemu_get_be32(f);
+ s->sms_rot_size[i] = qemu_get_be32(f);
+ s->sms_rot_physical_ba[i] = qemu_get_be32(f);
+ }
+
+ return 0;
+}
+
+static uint32_t omap3_sms_read32(void *opaque, target_phys_addr_t addr)
+{
+ struct omap3_sms_s *s = (struct omap3_sms_s *) opaque;
+
+ switch (addr)
+ {
+ case 0x10:
+ return s->sms_sysconfig;
+ case 0x14:
+ return s->sms_sysstatus;
+ case 0x48:
+ case 0x68:
+ case 0x88:
+ case 0xa8:
+ case 0xc8:
+ case 0xe8:
+ case 0x108:
+ case 0x128:
+ return s->sms_rg_att[(addr-0x48)/0x20];
+ case 0x50:
+ case 0x70:
+ case 0x90:
+ case 0xb0:
+ case 0xd0:
+ case 0xf0:
+ case 0x110:
+ case 0x130:
+ return s->sms_rg_rdperm[(addr-0x50)/0x20];
+ case 0x58:
+ case 0x78:
+ case 0x98:
+ case 0xb8:
+ case 0xd8:
+ case 0xf8:
+ case 0x118:
+ return s->sms_rg_wrperm[(addr-0x58)/0x20];
+ case 0x60:
+ case 0x80:
+ case 0xa0:
+ case 0xc0:
+ case 0xe0:
+ case 0x100:
+ case 0x120:
+ return s->sms_rg_start[(addr-0x60)/0x20];
+
+ case 0x64:
+ case 0x84:
+ case 0xa4:
+ case 0xc4:
+ case 0xe4:
+ case 0x104:
+ case 0x124:
+ return s->sms_rg_end[(addr-0x64)/0x20];
+ case 0x140:
+ return s->sms_security_control;
+ case 0x150:
+ return s->sms_class_arbiter0;
+ case 0x154:
+ return s->sms_class_arbiter1;
+ case 0x158:
+ return s->sms_class_arbiter2;
+ case 0x160:
+ return s->sms_interclass_arbiter;
+ case 0x164:
+ case 0x168:
+ case 0x16c:
+ return s->sms_class_rotation[(addr-0x164)/4];
+ case 0x170:
+ return s->sms_err_addr;
+ case 0x174:
+ return s->sms_err_type;
+ case 0x178:
+ return s->sms_pow_ctrl;
+ case 0x180:
+ case 0x190:
+ case 0x1a0:
+ case 0x1b0:
+ case 0x1c0:
+ case 0x1d0:
+ case 0x1e0:
+ case 0x1f0:
+ case 0x200:
+ case 0x210:
+ case 0x220:
+ case 0x230:
+ return s->sms_rot_control[(addr-0x180)/0x10];
+ case 0x184:
+ case 0x194:
+ case 0x1a4:
+ case 0x1b4:
+ case 0x1c4:
+ case 0x1d4:
+ case 0x1e4:
+ case 0x1f4:
+ case 0x204:
+ case 0x214:
+ case 0x224:
+ case 0x234:
+ return s->sms_rot_size[(addr-0x184)/0x10];
+
+ case 0x188:
+ case 0x198:
+ case 0x1a8:
+ case 0x1b8:
+ case 0x1c8:
+ case 0x1d8:
+ case 0x1e8:
+ case 0x1f8:
+ case 0x208:
+ case 0x218:
+ case 0x228:
+ case 0x238:
+ return s->sms_rot_size[(addr-0x188)/0x10];
+
+ default:
+ break;
+ }
+ OMAP_BAD_REG(addr);
+ return 0;
+}
+
+static void omap3_sms_write32(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap3_sms_s *s = (struct omap3_sms_s *) opaque;
+ //int i;
+
+ switch (addr)
+ {
+ case 0x14:
+ OMAP_RO_REG(addr);
+ return;
+ case 0x10:
+ s->sms_sysconfig = value & 0x1f;
+ break;
+
+ case 0x48:
+ case 0x68:
+ case 0x88:
+ case 0xa8:
+ case 0xc8:
+ case 0xe8:
+ case 0x108:
+ case 0x128:
+ s->sms_rg_att[(addr-0x48)/0x20] = value;
+ break;
+ case 0x50:
+ case 0x70:
+ case 0x90:
+ case 0xb0:
+ case 0xd0:
+ case 0xf0:
+ case 0x110:
+ case 0x130:
+ s->sms_rg_rdperm[(addr-0x50)/0x20] = value&0xffff;
+ break;
+ case 0x58:
+ case 0x78:
+ case 0x98:
+ case 0xb8:
+ case 0xd8:
+ case 0xf8:
+ case 0x118:
+ s->sms_rg_wrperm[(addr-0x58)/0x20] = value&0xffff;
+ break;
+ case 0x60:
+ case 0x80:
+ case 0xa0:
+ case 0xc0:
+ case 0xe0:
+ case 0x100:
+ case 0x120:
+ s->sms_rg_start[(addr-0x60)/0x20] = value;
+ break;
+ case 0x64:
+ case 0x84:
+ case 0xa4:
+ case 0xc4:
+ case 0xe4:
+ case 0x104:
+ case 0x124:
+ s->sms_rg_end[(addr-0x64)/0x20] = value;
+ break;
+ case 0x140:
+ s->sms_security_control = value &0xfffffff;
+ break;
+ case 0x150:
+ s->sms_class_arbiter0 = value;
+ break;
+ case 0x154:
+ s->sms_class_arbiter1 = value;
+ break;
+ case 0x158:
+ s->sms_class_arbiter2 = value;
+ break;
+ case 0x160:
+ s->sms_interclass_arbiter = value;
+ break;
+ case 0x164:
+ case 0x168:
+ case 0x16c:
+ s->sms_class_rotation[(addr-0x164)/4] = value;
+ break;
+ case 0x170:
+ s->sms_err_addr = value;
+ break;
+ case 0x174:
+ s->sms_err_type = value;
+ break;
+ case 0x178:
+ s->sms_pow_ctrl = value;
+ break;
+ case 0x180:
+ case 0x190:
+ case 0x1a0:
+ case 0x1b0:
+ case 0x1c0:
+ case 0x1d0:
+ case 0x1e0:
+ case 0x1f0:
+ case 0x200:
+ case 0x210:
+ case 0x220:
+ case 0x230:
+ s->sms_rot_control[(addr-0x180)/0x10] = value;
+ break;
+ case 0x184:
+ case 0x194:
+ case 0x1a4:
+ case 0x1b4:
+ case 0x1c4:
+ case 0x1d4:
+ case 0x1e4:
+ case 0x1f4:
+ case 0x204:
+ case 0x214:
+ case 0x224:
+ case 0x234:
+ s->sms_rot_size[(addr-0x184)/0x10] = value;
+ break;
+
+ case 0x188:
+ case 0x198:
+ case 0x1a8:
+ case 0x1b8:
+ case 0x1c8:
+ case 0x1d8:
+ case 0x1e8:
+ case 0x1f8:
+ case 0x208:
+ case 0x218:
+ case 0x228:
+ case 0x238:
+ s->sms_rot_size[(addr-0x188)/0x10] = value;
+ break;
+ default:
+ OMAP_BAD_REGV(addr, value);
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *omap3_sms_readfn[] = {
+ omap_badwidth_read32,
+ omap_badwidth_read32,
+ omap3_sms_read32,
+};
+
+static CPUWriteMemoryFunc *omap3_sms_writefn[] = {
+ omap_badwidth_write32,
+ omap_badwidth_write32,
+ omap3_sms_write32,
+};
+
+static void omap3_sms_reset(struct omap3_sms_s *s)
+{
+ s->sms_sysconfig = 0x1;
+ s->sms_class_arbiter0 = 0x500000;
+ s->sms_class_arbiter1 = 0x500;
+ s->sms_class_arbiter2 = 0x55000;
+ s->sms_interclass_arbiter = 0x400040;
+ s->sms_class_rotation[0] = 0x1;
+ s->sms_class_rotation[1] = 0x1;
+ s->sms_class_rotation[2] = 0x1;
+ s->sms_pow_ctrl = 0x80;
+}
+
+static struct omap3_sms_s *omap3_sms_init(struct omap_mpu_state_s *mpu)
+{
+ int iomemtype;
+ struct omap3_sms_s *s = (struct omap3_sms_s *) qemu_mallocz(sizeof(*s));
+
+ s->mpu = mpu;
+
+ omap3_sms_reset(s);
+
+ iomemtype = cpu_register_io_memory(0, omap3_sms_readfn,
+ omap3_sms_writefn, s);
+ cpu_register_physical_memory(0x6c000000, 0x10000, iomemtype);
+
+ register_savevm("omap3_sms", -1, 0,
+ omap3_sms_save_state, omap3_sms_load_state, s);
+ return s;
+}
+
+static const struct dma_irq_map omap3_dma_irq_map[] = {
+ {0, OMAP_INT_3XXX_SDMA_IRQ0},
+ {0, OMAP_INT_3XXX_SDMA_IRQ1},
+ {0, OMAP_INT_3XXX_SDMA_IRQ2},
+ {0, OMAP_INT_3XXX_SDMA_IRQ3},
+};
+
+static int omap3_validate_addr(struct omap_mpu_state_s *s,
+ target_phys_addr_t addr)
+{
+ return 1;
+}
+
+struct omap_mpu_state_s *omap3530_mpu_init(unsigned long sdram_size,
+ CharDriverState *chr_uart1,
+ CharDriverState *chr_uart2,
+ CharDriverState *chr_uart3)
+{
+ struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
+ qemu_mallocz(sizeof(struct omap_mpu_state_s));
+ ram_addr_t sram_base, q2_base;
+ qemu_irq *cpu_irq;
+ qemu_irq drqs[4];
+ int i;
+
+ s->mpu_model = omap3530;
+ s->env = cpu_init("cortex-a8-r2");
+ if (!s->env) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+ s->sdram_size = sdram_size;
+ s->sram_size = OMAP3XXX_SRAM_SIZE;
+
+ /* Clocks */
+ omap_clk_init(s);
+
+ /* Memory-mapped stuff */
+ q2_base = qemu_ram_alloc(s->sdram_size);
+ cpu_register_physical_memory(OMAP3_Q2_BASE, s->sdram_size,
+ q2_base | IO_MEM_RAM);
+ sram_base = qemu_ram_alloc(s->sram_size);
+ cpu_register_physical_memory(OMAP3_SRAM_BASE, s->sram_size,
+ sram_base | IO_MEM_RAM);
+
+ s->l4 = omap_l4_init(OMAP3_L4_BASE,
+ sizeof(omap3_l4_agent_info)
+ / sizeof(struct omap3_l4_agent_info_s));
+
+ cpu_irq = arm_pic_init_cpu(s->env);
+ s->ih[0] = omap2_inth_init(s, 0x48200000, 0x1000, 3, &s->irq[0],
+ cpu_irq[ARM_PIC_CPU_IRQ],
+ cpu_irq[ARM_PIC_CPU_FIQ],
+ omap_findclk(s, "omap3_mpu_intc_fclk"),
+ omap_findclk(s, "omap3_mpu_intc_iclk"));
+
+ for (i = 0; i < 4; i++)
+ drqs[i] = s->irq[omap3_dma_irq_map[i].ih][omap3_dma_irq_map[i].intr];
+ s->dma = omap3_dma4_init(omap3_l4ta_init(s->l4, L4A_SDMA), s, drqs, 32,
+ omap_findclk(s, "omap3_sdma_fclk"),
+ omap_findclk(s, "omap3_sdma_iclk"));
+ s->port->addr_valid = omap3_validate_addr;
+ soc_dma_port_add_mem_ram(s->dma, q2_base, OMAP2_Q2_BASE, s->sdram_size);
+ soc_dma_port_add_mem_ram(s->dma, sram_base, OMAP2_SRAM_BASE, s->sram_size);
+
+
+ s->omap3_cm = omap3_cm_init(omap3_l4ta_init(s->l4, L4A_CM), NULL, NULL, NULL, s);
+
+ s->omap3_prm = omap3_prm_init(omap3_l4ta_init(s->l4, L4A_PRM),
+ s->irq[0][OMAP_INT_3XXX_PRCM_MPU_IRQ],
+ NULL, s);
+
+ s->omap3_mpu_wdt = omap3_mpu_wdt_init(omap3_l4ta_init(s->l4, L4A_WDTIMER2),
+ NULL,
+ omap_findclk(s, "omap3_wkup_32k_fclk"),
+ omap_findclk(s, "omap3_wkup_l4_iclk"),
+ s);
+
+ s->omap3_l3 = omap3_l3_init(OMAP3_L3_BASE,
+ omap3_l3_region,
+ sizeof(omap3_l3_region)
+ / sizeof(struct omap_l3_region_s));
+ s->omap3_scm = omap3_scm_init(omap3_l4ta_init(s->l4, L4A_SCM), s);
+
+ s->omap3_sms = omap3_sms_init(s);
+
+ s->gptimer[0] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER1),
+ s->irq[0][OMAP_INT_3XXX_GPT1_IRQ],
+ omap_findclk(s, "omap3_gp1_fclk"),
+ omap_findclk(s, "omap3_wkup_l4_iclk"));
+ s->gptimer[1] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER2),
+ s->irq[0][OMAP_INT_3XXX_GPT2_IRQ],
+ omap_findclk(s, "omap3_gp2_fclk"),
+ omap_findclk(s, "omap3_per_l4_iclk"));
+ s->gptimer[2] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER3),
+ s->irq[0][OMAP_INT_3XXX_GPT3_IRQ],
+ omap_findclk(s, "omap3_gp3_fclk"),
+ omap_findclk(s, "omap3_per_l4_iclk"));
+ s->gptimer[3] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER4),
+ s->irq[0][OMAP_INT_3XXX_GPT4_IRQ],
+ omap_findclk(s, "omap3_gp4_fclk"),
+ omap_findclk(s, "omap3_per_l4_iclk"));
+ s->gptimer[4] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER5),
+ s->irq[0][OMAP_INT_3XXX_GPT5_IRQ],
+ omap_findclk(s, "omap3_gp5_fclk"),
+ omap_findclk(s, "omap3_per_l4_iclk"));
+ s->gptimer[5] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER6),
+ s->irq[0][OMAP_INT_3XXX_GPT6_IRQ],
+ omap_findclk(s, "omap3_gp6_fclk"),
+ omap_findclk(s, "omap3_per_l4_iclk"));
+ s->gptimer[6] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER7),
+ s->irq[0][OMAP_INT_3XXX_GPT7_IRQ],
+ omap_findclk(s, "omap3_gp7_fclk"),
+ omap_findclk(s, "omap3_per_l4_iclk"));
+ s->gptimer[7] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER8),
+ s->irq[0][OMAP_INT_3XXX_GPT8_IRQ],
+ omap_findclk(s, "omap3_gp8_fclk"),
+ omap_findclk(s, "omap3_per_l4_iclk"));
+ s->gptimer[8] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER9),
+ s->irq[0][OMAP_INT_3XXX_GPT9_IRQ],
+ omap_findclk(s, "omap3_gp9_fclk"),
+ omap_findclk(s, "omap3_per_l4_iclk"));
+ s->gptimer[9] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER10),
+ s->irq[0][OMAP_INT_3XXX_GPT10_IRQ],
+ omap_findclk(s, "omap3_gp10_fclk"),
+ omap_findclk(s, "omap3_core_l4_iclk"));
+ s->gptimer[10] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER11),
+ s->irq[0][OMAP_INT_3XXX_GPT11_IRQ],
+ omap_findclk(s, "omap3_gp12_fclk"),
+ omap_findclk(s, "omap3_core_l4_iclk"));
+ s->gptimer[11] = omap_gp_timer_init(omap3_l4ta_init(s->l4, L4A_GPTIMER12),
+ s->irq[0][OMAP_INT_3XXX_GPT12_IRQ],
+ omap_findclk(s, "omap3_gp12_fclk"),
+ omap_findclk(s, "omap3_wkup_l4_iclk"));
+
+
+ omap_synctimer_init(omap3_l4ta_init(s->l4, L4A_32KTIMER), s,
+ omap_findclk(s, "omap3_sys_32k"), NULL);
+
+ s->sdrc = omap_sdrc_init(0x6d000000);
+
+ s->gpmc = omap_gpmc_init(s, 0x6e000000, s->irq[0][OMAP_INT_3XXX_GPMC_IRQ]);
+
+
+ s->uart[0] = omap2_uart_init(omap3_l4ta_init(s->l4, L4A_UART1),
+ s->irq[0][OMAP_INT_3XXX_UART1_IRQ],
+ omap_findclk(s, "omap3_uart1_fclk"),
+ omap_findclk(s, "omap3_uart1_iclk"),
+ s->drq[OMAP3XXX_DMA_UART1_TX],
+ s->drq[OMAP3XXX_DMA_UART1_RX],
+ chr_uart1);
+ s->uart[1] = omap2_uart_init(omap3_l4ta_init(s->l4, L4A_UART2),
+ s->irq[0][OMAP_INT_3XXX_UART2_IRQ],
+ omap_findclk(s, "omap3_uart2_fclk"),
+ omap_findclk(s, "omap3_uart2_iclk"),
+ s->drq[OMAP3XXX_DMA_UART2_TX],
+ s->drq[OMAP3XXX_DMA_UART2_RX],
+ chr_uart2);
+ s->uart[2] = omap2_uart_init(omap3_l4ta_init(s->l4, L4A_UART3),
+ s->irq[0][OMAP_INT_3XXX_UART3_IRQ],
+ omap_findclk(s, "omap3_uart2_fclk"),
+ omap_findclk(s, "omap3_uart3_iclk"),
+ s->drq[OMAP3XXX_DMA_UART3_TX],
+ s->drq[OMAP3XXX_DMA_UART3_RX],
+ chr_uart3);
+
+ s->dss = omap_dss_init(s, omap3_l4ta_init(s->l4, L4A_DSS),
+ s->irq[0][OMAP_INT_3XXX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
+ NULL,NULL,NULL,NULL,NULL);
+
+ s->gpif = omap3_gpif_init();
+ omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO1),
+ s->irq[0][OMAP_INT_3XXX_GPIO1_MPU_IRQ],
+ NULL,NULL,0);
+ omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO2),
+ s->irq[0][OMAP_INT_3XXX_GPIO2_MPU_IRQ],
+ NULL,NULL,1);
+ omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO3),
+ s->irq[0][OMAP_INT_3XXX_GPIO3_MPU_IRQ],
+ NULL,NULL,2);
+ omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO4),
+ s->irq[0][OMAP_INT_3XXX_GPIO4_MPU_IRQ],
+ NULL,NULL,3);
+ omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO5),
+ s->irq[0][OMAP_INT_3XXX_GPIO5_MPU_IRQ],
+ NULL,NULL,4);
+ omap3_gpio_init(s, s->gpif, omap3_l4ta_init(s->l4, L4A_GPIO6),
+ s->irq[0][OMAP_INT_3XXX_GPIO6_MPU_IRQ],
+ NULL,NULL,5);
+
+ omap_tap_init(omap3_l4ta_init(s->l4, L4A_TAP), s);
+
+ s->omap3_mmc[0] = omap3_mmc_init(omap3_l4ta_init(s->l4, L4A_MMC1),
+ s->irq[0][OMAP_INT_3XXX_MMC1_IRQ],
+ &s->drq[OMAP3XXX_DMA_MMC1_TX],
+ omap_findclk(s, "omap3_mmc1_fclk"),
+ omap_findclk(s, "omap3_mmc1_iclk"));
+
+ s->omap3_mmc[1] = omap3_mmc_init(omap3_l4ta_init(s->l4, L4A_MMC2),
+ s->irq[0][OMAP_INT_3XXX_MMC2_IRQ],
+ &s->drq[OMAP3XXX_DMA_MMC2_TX],
+ omap_findclk(s, "omap3_mmc2_fclk"),
+ omap_findclk(s, "omap3_mmc2_iclk"));
+
+ s->omap3_mmc[2] = omap3_mmc_init(omap3_l4ta_init(s->l4, L4A_MMC3),
+ s->irq[0][OMAP_INT_3XXX_MMC3_IRQ],
+ &s->drq[OMAP3XXX_DMA_MMC3_TX],
+ omap_findclk(s, "omap3_mmc3_fclk"),
+ omap_findclk(s, "omap3_mmc3_iclk"));
+
+ s->i2c[0] = omap3_i2c_init(omap3_l4ta_init(s->l4, L4A_I2C1),
+ s->irq[0][OMAP_INT_3XXX_I2C1_IRQ],
+ &s->drq[OMAP3XXX_DMA_I2C1_TX],
+ omap_findclk(s, "omap3_i2c1_fclk"),
+ omap_findclk(s, "omap3_i2c1_iclk"),
+ 8);
+ s->i2c[1] = omap3_i2c_init(omap3_l4ta_init(s->l4, L4A_I2C2),
+ s->irq[0][OMAP_INT_3XXX_I2C2_IRQ],
+ &s->drq[OMAP3XXX_DMA_I2C2_TX],
+ omap_findclk(s, "omap3_i2c2_fclk"),
+ omap_findclk(s, "omap3_i2c2_iclk"),
+ 8);
+ s->i2c[2] = omap3_i2c_init(omap3_l4ta_init(s->l4, L4A_I2C3),
+ s->irq[0][OMAP_INT_3XXX_I2C3_IRQ],
+ &s->drq[OMAP3XXX_DMA_I2C3_TX],
+ omap_findclk(s, "omap3_i2c3_fclk"),
+ omap_findclk(s, "omap3_i2c3_iclk"),
+ 64);
+
+ s->omap3_usb = omap3_hsusb_init(omap3_l4ta_init(s->l4, L4A_USBHS_OTG),
+ omap3_l4ta_init(s->l4, L4A_USBHS_HOST),
+ omap3_l4ta_init(s->l4, L4A_USBHS_TLL),
+ s->irq[0][OMAP_INT_3XXX_HSUSB_MC],
+ s->irq[0][OMAP_INT_3XXX_HSUSB_DMA],
+ s->irq[0][OMAP_INT_3XXX_OHCI_IRQ],
+ s->irq[0][OMAP_INT_3XXX_EHCI_IRQ],
+ s->irq[0][OMAP_INT_3XXX_TLL_IRQ]);
+
+ s->mcspi[0] = omap_mcspi_init(omap3_l4ta_init(s->l4, L4A_MCSPI1), s, 4,
+ s->irq[0][OMAP_INT_3XXX_MCSPI1_IRQ],
+ &s->drq[OMAP3XXX_DMA_SPI1_TX0],
+ omap_findclk(s, "omap3_spi1_fclk"),
+ omap_findclk(s, "omap3_spi1_iclk"));
+ s->mcspi[1] = omap_mcspi_init(omap3_l4ta_init(s->l4, L4A_MCSPI2), s, 2,
+ s->irq[0][OMAP_INT_3XXX_MCSPI2_IRQ],
+ &s->drq[OMAP3XXX_DMA_SPI2_TX0],
+ omap_findclk(s, "omap3_spi2_fclk"),
+ omap_findclk(s, "omap3_spi2_iclk"));
+ drqs[0] = s->drq[OMAP3XXX_DMA_SPI3_TX0];
+ drqs[1] = s->drq[OMAP3XXX_DMA_SPI3_RX0];
+ drqs[2] = s->drq[OMAP3XXX_DMA_SPI3_TX1];
+ drqs[3] = s->drq[OMAP3XXX_DMA_SPI3_RX1];
+ s->mcspi[2] = omap_mcspi_init(omap3_l4ta_init(s->l4, L4A_MCSPI3), s, 2,
+ s->irq[0][OMAP_INT_3XXX_MCSPI3_IRQ],
+ drqs,
+ omap_findclk(s, "omap3_spi3_fclk"),
+ omap_findclk(s, "omap3_spi3_iclk"));
+ s->mcspi[3] = omap_mcspi_init(omap3_l4ta_init(s->l4, L4A_MCSPI4), s, 1,
+ s->irq[0][OMAP_INT_3XXX_MCSPI4_IRQ],
+ &s->drq[OMAP3XXX_DMA_SPI4_TX0],
+ omap_findclk(s, "omap3_spi4_fclk"),
+ omap_findclk(s, "omap3_spi4_iclk"));
+
+ return s;
+}
--- /dev/null
+/*
+ * 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");
+ }
+}
--- /dev/null
+/*
+ * QEMU Epson S1D13744/S1D13745 templates
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * QEMU OMAP3 LCD Panel Emulation templates
+ *
+ * Copyright (c) 2008 yajin <yajin@vm-kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#define SKIP_PIXEL(to) to += deststep
+#if DEPTH == 8
+# define PIXEL_TYPE uint8_t
+# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) *to ++ = from
+#elif DEPTH == 15 || DEPTH == 16
+# define PIXEL_TYPE uint16_t
+# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) *to ++ = from
+#elif DEPTH == 24
+# define PIXEL_TYPE uint8_t
+# define COPY_PIXEL(to, from) \
+ to[0] = from; to[1] = (from) >> 8; to[2] = (from) >> 16; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) \
+ *to ++ = from; *to ++ = (from) >> 8; *to ++ = (from) >> 16
+#elif DEPTH == 32
+# define PIXEL_TYPE uint32_t
+# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) *to ++ = from
+#else
+# error unknown bit depth
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP_WORDS 1
+#endif
+
+
+static void glue(omap3_lcd_panel_draw_line16_, DEPTH)(PIXEL_TYPE *dest,
+ const uint16_t *src,
+ unsigned int width)
+{
+#if !defined(SWAP_WORDS) && DEPTH == 16
+ memcpy(dest, src, width);
+#else
+ uint16_t data;
+ unsigned int r, g, b;
+ const uint16_t *end = (const void *) src + width;
+ while (src < end) {
+ data = lduw_raw(src ++);
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x1f) << 3;
+ data >>= 5;
+ COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+ }
+#endif
+}
+
+static void glue(omap3_lcd_panel_draw_line24a_, DEPTH)(PIXEL_TYPE *dest,
+ const uint8_t *src,
+ unsigned int width)
+{
+#if !defined(SWAP_WORDS) && DEPTH == 32
+ memcpy(dest, src, width);
+#else
+ unsigned int r, g, b;
+ const uint8_t *end = (const void *) src + width;
+ while (src < end) {
+ b = *(src++);
+ g = *(src++);
+ r = *(src++);
+ src++;
+ COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+ }
+#endif
+}
+
+static void glue(omap3_lcd_panel_draw_line24b_, DEPTH)(PIXEL_TYPE *dest,
+ const uint8_t *src,
+ unsigned int width)
+{
+#if DEPTH == 24
+ memcpy(dest, src, width);
+#else
+ unsigned int r, g, b;
+ const uint8_t *end = (const void *) src + width;
+ while (src < end) {
+ b = *(src++);
+ g = *(src++);
+ r = *(src++);
+ COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+ }
+#endif
+}
+
+/* No rotation */
+static omap3_lcd_panel_fn_t glue(omap3_lcd_panel_draw_fn_, DEPTH)[0x10] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ (omap3_lcd_panel_fn_t)glue(omap3_lcd_panel_draw_line16_, DEPTH),
+ NULL,
+ (omap3_lcd_panel_fn_t)glue(omap3_lcd_panel_draw_line24a_, DEPTH),
+ (omap3_lcd_panel_fn_t)glue(omap3_lcd_panel_draw_line24b_, DEPTH),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+/* 90deg, 180deg and 270deg rotation */
+static omap3_lcd_panel_fn_t glue(omap3_lcd_panel_draw_fn_r_, DEPTH)[0x10] = {
+ /* TODO */
+ [0 ... 0xf] = NULL,
+};
+
+#undef DEPTH
+#undef SKIP_PIXEL
+#undef COPY_PIXEL
+#undef COPY_PIXEL1
+#undef PIXEL_TYPE
+
+#undef SWAP_WORDS
+
+
--- /dev/null
+/*
+ * OMAP3 Multimedia Card/Secure Digital/Secure Digital I/O (MMC/SD/SDIO) Card Interface emulation
+ *
+ * Copyright (C) 2008 yajin <yajin@vm-kernel.org>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "hw.h"
+#include "omap.h"
+#include "sd.h"
+
+/* debug levels:
+ 0 - no debug
+ 1 - print out all commands in processing order
+ 2 - dump all register accesses and buffer management */
+#define MMC_DEBUG_LEVEL 0
+
+#if MMC_DEBUG_LEVEL>0
+#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#if MMC_DEBUG_LEVEL>1
+#define TRACE2(...) TRACE(__VA_ARGS__)
+#else
+#define TRACE2(...)
+#endif
+#else
+#define TRACE(...)
+#define TRACE2(...)
+#endif
+
+struct omap3_mmc_s
+{
+ qemu_irq irq;
+ qemu_irq *dma;
+ qemu_irq coverswitch;
+ omap_clk clk;
+ SDState *card;
+
+ uint32_t sysconfig;
+ uint32_t sysstatus;
+ uint32_t csre;
+ uint32_t systest;
+ uint32_t con;
+ uint32_t pwcnt;
+ uint32_t blk;
+ uint32_t arg;
+ uint32_t cmd;
+ uint32_t rsp10;
+ uint32_t rsp32;
+ uint32_t rsp54;
+ uint32_t rsp76;
+ uint32_t data;
+ uint32_t pstate;
+ uint32_t hctl;
+ uint32_t sysctl;
+ uint32_t stat;
+ uint32_t ie;
+ uint32_t ise;
+ uint32_t ac12;
+ uint32_t capa;
+ uint32_t cur_capa;
+ uint32_t rev;
+
+ uint16_t blen_counter;
+ uint16_t nblk_counter;
+
+ uint32_t fifo[256];
+ int fifo_start;
+ int fifo_len;
+
+ int ddir;
+ int transfer;
+ int stop;
+
+ uint32_t stat_pending;
+};
+
+
+typedef enum
+{
+ sd_nore = 0, /* no response */
+ sd_136_bits = 1, /* response length 136 bits */
+ sd_48_bits = 2, /* response length 48 bits */
+ sd_48b_bits = 3, /* response length 48 bits with busy after response */
+} omap3_sd_rsp_type_t;
+
+static void omap3_mmc_command(struct omap3_mmc_s *host);
+
+static void omap3_mmc_interrupts_update(struct omap3_mmc_s *s)
+{
+ qemu_set_irq(s->irq, !!((s->stat | s->stat_pending) & s->ie & s->ise));
+}
+
+static void omap3_mmc_fifolevel_update(struct omap3_mmc_s *host)
+{
+ enum { ongoing, ready, aborted } state = ongoing;
+
+ if ((host->cmd & (1 << 21))) { /* DP */
+ if (host->ddir) {
+ TRACE2("receive, dma=%d, fifo_len=%d bytes",
+ host->cmd & 1, host->fifo_len * 4);
+
+ /* omap3_mmc_transfer ensures we always have data in FIFO
+ during receive as long as all data has not been transferred -
+ NOTE that the actual transfer may be finished already (i.e.
+ host->transfer is cleared) but not all data has been read out
+ from FIFO yet */
+ if (host->fifo_len) {
+ if (host->cmd & 1) { /* DE */
+ if (host->fifo_len * 4 == (host->blk & 0x7ff)) { /* BLEN */
+ if (host->stop)
+ state = aborted;
+ else
+ qemu_irq_raise(host->dma[1]);
+ } else
+ qemu_irq_lower(host->dma[1]);
+ } else {
+ if (host->stop
+ && host->fifo_len * 4 == (host->blk & 0x7ff))
+ state = aborted;
+ else {
+ host->pstate |= 0x0800; /* BRE */
+ host->stat_pending |= 0x20; /* BRR */
+ }
+ }
+ }
+ else
+ state = host->stop ? aborted : ready;
+ } else {
+ /* omap3_mmc_transfer keeps FIFO empty during transmit so
+ we just check all blocks have been transferred or not */
+ if (host->transfer) {
+ if (host->cmd & 1) { /* DE */
+ if (host->blen_counter == (host->blk & 0x7ff)) { /* BLEN */
+ if (host->stop)
+ state = aborted;
+ else
+ qemu_irq_raise(host->dma[0]);
+ } else
+ qemu_irq_lower(host->dma[0]);
+ } else {
+ if (host->stop
+ && host->blen_counter == (host->blk & 0x7ff))
+ state = aborted;
+ else {
+ host->pstate |= 0x0400; /* BWE */
+ host->stat_pending |= 0x10; /* BWR */
+ }
+ }
+ } else
+ state = host->stop ? aborted : ready;
+ }
+
+ if ((host->cmd & 1) || state != ongoing) { /* DE */
+ host->pstate &= ~0x0c00; /* BRE | BWE */
+ host->stat_pending &= ~0x30; /* BRR | BWR */
+ host->stat &= ~0x30; /* BRR | BWR */
+ if (state != ongoing) {
+ TRACE2("transfer %s",
+ state == ready
+ ? "complete"
+ : "aborted --> complete");
+ host->stat_pending |= 0x2; /* TC */
+ if (host->cmd & 0x04) { /* ACEN */
+ host->stop = 0x0cc30000;
+ state = aborted;
+ }
+ if (state == aborted) {
+ host->cmd = host->stop;
+ host->stop = 0;
+ omap3_mmc_command(host);
+ }
+ }
+ }
+ }
+}
+
+static void omap3_mmc_transfer(struct omap3_mmc_s *host)
+{
+ int i;
+ uint32_t x;
+#if MMC_DEBUG_LEVEL>1
+ int j;
+ uint8_t c, sym[17];
+#endif
+
+ /* IF data transfer is inactive
+ OR block count enabled with zero block count
+ OR in receive mode and we have unread data in FIFO
+ OR in transmit mode and we have no data in FIFO,
+ THEN don't do anything */
+ if (!host->transfer
+ || ((host->cmd & 2) && !host->nblk_counter)
+ || (host->ddir && host->fifo_len)
+ || (!host->ddir && !host->fifo_len))
+ return;
+
+ if (host->ddir) {
+ TRACE2("begin, %d blocks (%d bytes/block) left to receive, %d bytes in FIFO",
+ (host->cmd & 2) ? host->nblk_counter : 1,
+ host->blk & 0x7ff,
+ host->fifo_len * 4);
+ while (host->blen_counter && host->fifo_len < 255) {
+ for (i = 0, x = 0; i < 32 && host->blen_counter; i += 8, host->blen_counter--)
+ x |= sd_read_data(host->card) << i;
+ host->fifo[(host->fifo_start + host->fifo_len) & 0xff] = x;
+ host->fifo_len++;
+ }
+ TRACE2("end, %d bytes in FIFO:", host->fifo_len * 4);
+#if MMC_DEBUG_LEVEL>1
+ for (i = 0; i < host->fifo_len; ) {
+ fprintf(stderr, "%s: [0x%03x] ", __FUNCTION__, i * 4);
+ do {
+ x = host->fifo[(host->fifo_start + i) & 0xff];
+ for (j = 0; j < 4; j++) {
+ c = (x >> (j * 8)) & 0xff;
+ fprintf(stderr, "%02x ", c);
+ sym[(i & 3) * 4 + j] = (c < 32 || c > 126) ? '.' : c;
+ }
+ } while (((++i) & 3));
+ sym[16] = 0;
+ fprintf(stderr, "%s\n", sym);
+ }
+#endif
+ } else {
+ TRACE2("%d bytes left to transmit in current block", host->blen_counter);
+ while (host->blen_counter && host->fifo_len) {
+ for (i = 0; i < 32 && host->blen_counter; i += 8, host->blen_counter--)
+ sd_write_data(host->card, (host->fifo[host->fifo_start] >> i) & 0xff);
+ host->fifo_start++;
+ host->fifo_len--;
+ host->fifo_start &= 0xff;
+ }
+ }
+
+ if (!host->blen_counter) {
+ if (host->cmd & 2) /* BCE */
+ host->nblk_counter--;
+ TRACE2("block done, %d blocks left",
+ (host->cmd & (1 << 5)) ? host->nblk_counter : 0);
+ host->blen_counter = host->blk & 0x7ff;
+ if (!(host->cmd & (1 << 5)) /* MSBS */
+ || !host->nblk_counter) {
+ host->nblk_counter = (host->blk >> 16) & 0xffff;
+ host->transfer = 0;
+ host->pstate &= ~0x0306; /* RTA | WTA | DLA | DATI */
+ }
+ }
+}
+
+static void omap3_mmc_command(struct omap3_mmc_s *host)
+{
+ uint32_t rspstatus, mask;
+ int rsplen, timeout;
+ struct sd_request_s request;
+ uint8_t response[16];
+ int cmd = (host->cmd >> 24) & 0x3f; /* INDX */
+
+ TRACE("%d type=%d arg=0x%08x blk=0x%08x, fifo=%d/%d",
+ cmd, (host->cmd >> 22) & 3, host->arg, host->blk,
+ host->fifo_start, host->fifo_len);
+
+ if ((host->con & 2) && !cmd) { /* INIT and CMD0 */
+ host->stat_pending |= 0x1;
+ host->pstate &= 0xfffffffe;
+ return;
+ }
+
+ if (host->cmd & (1 << 21)) { /* DP */
+ host->fifo_start = 0;
+ host->fifo_len = 0;
+ host->transfer = 1;
+ host->ddir = (host->cmd >> 4) & 1;
+ /* DLA | DATI | (RTA/WTA) */
+ host->pstate |= 0x6 | (host->ddir ? 0x200 : 0x100);
+ } else {
+ host->transfer = 0;
+ host->pstate &= ~0x306; /* RTA | WTA | DLA | DATI */
+ }
+
+ timeout = 0;
+ mask = 0;
+ rspstatus = 0;
+
+ request.cmd = cmd;
+ request.arg = host->arg;
+ request.crc = 0; /* FIXME */
+
+ rsplen = sd_do_command(host->card, &request, response);
+
+ switch ((host->cmd >> 16) & 3) { /* RSP_TYPE */
+ case sd_nore:
+ rsplen = 0;
+ break;
+ case sd_136_bits:
+ if (rsplen < 16) {
+ timeout = 1;
+ break;
+ }
+ rsplen = 16;
+ host->rsp76 = (response[0] << 24) | (response[1] << 16) |
+ (response[2] << 8) | (response[3] << 0);
+ host->rsp54 = (response[4] << 24) | (response[5] << 16) |
+ (response[6] << 8) | (response[7] << 0);
+ host->rsp32 = (response[8] << 24) | (response[9] << 16) |
+ (response[10] << 8) | (response[11] << 0);
+ host->rsp10 = (response[12] << 24) | (response[13] << 16) |
+ (response[14] << 8) | (response[15] << 0);
+ break;
+ case sd_48_bits:
+ case sd_48b_bits:
+ if (rsplen < 4) {
+ timeout = 1;
+ break;
+ }
+ rsplen = 4;
+ host->rsp10 = (response[0] << 24) | (response[1] << 16) |
+ (response[2] << 8) | (response[3] << 0);
+ switch (cmd) {
+ case 41: /* r3 */
+ case 8: /* r7 */
+ break;
+ case 3: /* r6 */
+ mask = 0xe00;
+ rspstatus = (response[2] << 8) | response[3];
+ break;
+ default:
+ mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
+ ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
+ LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
+ CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
+ CID_CSD_OVERWRITE | WP_ERASE_SKIP;
+ rspstatus = (response[0] << 24) | (response[1] << 16) |
+ (response[2] << 8) | (response[3] << 0);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (cmd == 12 || cmd == 52) { /* stop transfer commands */
+ /*host->fifo_start = 0;*/
+ /*host->fifo_len = 0;*/
+ host->transfer = 0;
+ host->pstate &= ~0x0f06; /* BRE | BWE | RTA | WTA | DLA | DATI */
+ host->stat_pending &= ~0x30; /* BRR | BWR */
+ host->stat &= ~0x30; /* BRR | BWR */
+ host->stat_pending |= 0x2; /* TC */
+ qemu_irq_lower(host->dma[0]);
+ qemu_irq_lower(host->dma[1]);
+ }
+
+ if (rspstatus & mask & host->csre) {
+ host->stat_pending |= 1 << 28; /* CERR */
+ host->pstate &= ~0x306; /* RTA | WTA | DLA | DATI */
+ host->transfer = 0;
+ } else {
+ host->stat &= ~(1 << 28); /* CERR */
+ host->stat_pending &= ~(1 << 28); /* CERR */
+ }
+ host->stat_pending |= timeout ? (1 << 16) : 0x1; /* CTO : CC */
+}
+
+static void omap3_mmc_reset(struct omap3_mmc_s *s)
+{
+ s->sysconfig = 0x00000015;
+ s->con = 0x00000500;
+ s->pstate = 0x00040000;
+ s->capa = 0x00e10080;
+ s->rev = 0x26000000;
+
+ s->fifo_start = 0;
+ s->fifo_len = 0;
+ s->stop = 0;
+}
+
+static uint32_t omap3_mmc_read(void *opaque, target_phys_addr_t addr)
+{
+ struct omap3_mmc_s *s = (struct omap3_mmc_s *) opaque;
+ uint32_t i ;
+
+ switch (addr) {
+ case 0x10:
+ TRACE2("SYSCONFIG = %08x", s->sysconfig);
+ return s->sysconfig;
+ case 0x14:
+ TRACE2("SYSSTATUS = %08x", s->sysstatus | 0x1);
+ return s->sysstatus | 0x1; /*reset completed */
+ case 0x24:
+ TRACE2("CSRE = %08x", s->csre);
+ return s->csre;
+ case 0x28:
+ TRACE2("SYSTEST = %08x", s->systest);
+ return s->systest;
+ case 0x2c: /* MMCHS_CON */
+ TRACE2("CON = %08x", s->con);
+ return s->con;
+ case 0x30:
+ TRACE2("PWCNT = %08x", s->pwcnt);
+ return s->pwcnt;
+ case 0x104: /* MMCHS_BLK */
+ TRACE2("BLK = %08x", s->blk);
+ return s->blk;
+ case 0x108: /* MMCHS_ARG */
+ TRACE2("ARG = %08x", s->arg);
+ return s->arg;
+ case 0x10c:
+ TRACE2("CMD = %08x", s->cmd);
+ return s->cmd;
+ case 0x110:
+ TRACE2("RSP10 = %08x", s->rsp10);
+ return s->rsp10;
+ case 0x114:
+ TRACE2("RSP32 = %08x", s->rsp32);
+ return s->rsp32;
+ case 0x118:
+ TRACE2("RSP54 = %08x", s->rsp54);
+ return s->rsp54;
+ case 0x11c:
+ TRACE2("RSP76 = %08x", s->rsp76);
+ return s->rsp76;
+ case 0x120:
+ /* in PIO mode, access allowed only when BRE is set */
+ if (!(s->cmd & 1) && !(s->pstate & 0x0800)) {
+ s->stat_pending |= 1 << 29; /* BADA */
+ i = 0;
+ } else {
+ i = s->fifo[s->fifo_start];
+ s->fifo[s->fifo_start] = 0;
+ if (s->fifo_len == 0) {
+ fprintf(stderr, "%s: FIFO underrun\n", __FUNCTION__);
+ return i;
+ }
+ s->fifo_start++;
+ s->fifo_len--;
+ s->fifo_start &= 255;
+ omap3_mmc_transfer(s);
+ omap3_mmc_fifolevel_update(s);
+ }
+ omap3_mmc_interrupts_update(s);
+ return i;
+ case 0x124: /* MMCHS_PSTATE */
+ TRACE2("PSTATE = %08x", s->pstate);
+ return s->pstate;
+ case 0x128:
+ TRACE2("HCTL = %08x", s->hctl);
+ return s->hctl;
+ case 0x12c: /* MMCHS_SYSCTL */
+ TRACE2("SYSCTL = %08x", s->sysctl);
+ return s->sysctl;
+ case 0x130: /* MMCHS_STAT */
+ s->stat |= s->stat_pending;
+ if (s->stat & 0xffff0000)
+ s->stat |= 1 << 15; /* ERRI */
+ else
+ s->stat &= ~(1 << 15); /* ERRI */
+ s->stat_pending = 0;
+ TRACE2("STAT = %08x", s->stat);
+ return s->stat;
+ case 0x134:
+ TRACE2("IE = %08x", s->ie);
+ return s->ie;
+ case 0x138:
+ TRACE2("ISE = %08x", s->ise);
+ return s->ise;
+ case 0x13c:
+ TRACE2("AC12 = %08x", s->ac12);
+ return s->ac12;
+ case 0x140: /* MMCHS_CAPA */
+ TRACE2("CAPA = %08x", s->capa);
+ return s->capa;
+ case 0x148:
+ TRACE2("CUR_CAPA = %08x", s->cur_capa);
+ return s->cur_capa;
+ case 0x1fc:
+ TRACE2("REV = %08x", s->rev);
+ return s->rev;
+ default:
+ OMAP_BAD_REG(addr);
+ exit(-1);
+ return 0;
+ }
+}
+
+static void omap3_mmc_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap3_mmc_s *s = (struct omap3_mmc_s *) opaque;
+
+ switch (addr) {
+ case 0x014:
+ case 0x110:
+ case 0x114:
+ case 0x118:
+ case 0x11c:
+ case 0x124:
+ case 0x13c:
+ case 0x1fc:
+ OMAP_RO_REG(addr);
+ break;
+ case 0x010:
+ TRACE2("SYSCONFIG = %08x", value);
+ if (value & 2)
+ omap3_mmc_reset(s);
+ s->sysconfig = value & 0x31d;
+ break;
+ case 0x024:
+ TRACE2("CSRE = %08x", value);
+ s->csre = value;
+ break;
+ case 0x028:
+ TRACE2("SYSTEST = %08x", value);
+ s->systest = value;
+ break;
+ case 0x02c: /* MMCHS_CON */
+ TRACE2("CON = %08x", value);
+ if (value & 0x10) /* MODE */
+ fprintf(stderr, "%s: SYSTEST mode is not supported\n",
+ __FUNCTION__);
+ if (value & 0x20) /* DW8 */
+ fprintf(stderr, "%s: 8-bit data width is not supported\n",
+ __FUNCTION__);
+ if (value & 0x1000) /* CEATA */
+ fprintf(stderr, "%s: CE-ATA control mode not supported\n",
+ __FUNCTION__);
+ s->con = value & 0x1ffff;
+ break;
+ case 0x030:
+ TRACE2("PWCNT = %08x", value);
+ s->pwcnt = value;
+ break;
+ case 0x104: /* MMCHS_BLK */
+ TRACE2("BLK = %08x", value);
+ s->blk = value & 0xffff07ff;
+ s->blen_counter = value & 0x7ff;
+ s->nblk_counter = (value >> 16) & 0xffff;
+ break;
+ case 0x108: /* MMCHS_ARG */
+ TRACE2("ARG = %08x", value);
+ s->arg = value;
+ break;
+ case 0x10c: /* MMCHS_CMD */
+ TRACE2("CMD = %08x", value);
+ if (!s->card) {
+ s->stat_pending |= (1 << 16); /* CTO */
+ } else {
+ /* TODO: writing to bits 0-15 should have no effect during
+ an active data transfer */
+ if (!s->stop
+ && (((value >> 24) & 0x3f) == 12
+ || ((value >> 24) & 0x3f) == 52)) {
+ s->stop = value & 0x3ffb0037;
+ } else {
+ s->cmd = value & 0x3ffb0037;
+ omap3_mmc_command(s);
+ }
+ omap3_mmc_transfer(s);
+ omap3_mmc_fifolevel_update(s);
+ }
+ omap3_mmc_interrupts_update(s);
+ break;
+ case 0x120:
+ /* in PIO mode, access allowed only when BWE is set */
+ if (!(s->cmd & 1) && !(s->pstate & 0x0400)) {
+ s->stat_pending |= 1 << 29; /* BADA */
+ } else {
+ if (s->fifo_len == 256) {
+ fprintf(stderr, "%s: FIFO overrun\n", __FUNCTION__);
+ break;
+ }
+ s->fifo[(s->fifo_start + s->fifo_len) & 255] = value;
+ s->fifo_len++;
+ omap3_mmc_transfer(s);
+ omap3_mmc_fifolevel_update(s);
+ }
+ omap3_mmc_interrupts_update(s);
+ break;
+ case 0x128: /* MMCHS_HCTL */
+ TRACE2("HCTL = %08x", value);
+ s->hctl = value & 0xf0f0f02;
+ if (s->hctl & (1 << 16)) /* SBGR */
+ fprintf(stderr, "%s: Stop at block gap feature not implemented!\n", __FUNCTION__);
+ break;
+ case 0x12c: /* MMCHS_SYSCTL */
+ TRACE2("SYSCTL = %08x", value);
+ if (value & 0x04000000) { /* SRD */
+ s->data = 0;
+ s->pstate &= ~0x00000f06; /* BRE, BWE, RTA, WTA, DLA, DATI */
+ s->hctl &= ~0x00030000; /* SGBR, CR */
+ s->stat &= ~0x00000034; /* BRR, BWR, BGE */
+ s->stat_pending &= ~0x00000034;
+ s->fifo_start = 0;
+ s->fifo_len = 0;
+ }
+ if (value & 0x02000000) { /* SRC */
+ s->pstate &= ~0x00000001; /* CMDI */
+ }
+ if (value & 0x01000000) { /* SRA */
+ uint32_t capa = s->capa;
+ uint32_t cur_capa = s->cur_capa;
+ omap3_mmc_reset(s);
+ s->capa = capa;
+ s->cur_capa = cur_capa;
+ }
+ value = (value & ~2) | ((value & 1) << 1); /* copy ICE directly to ICS */
+ s->sysctl = value & 0x000fffc7;
+ break;
+ case 0x130:
+ TRACE2("STAT = %08x", value);
+ value = value & 0x317f0237;
+ s->stat &= ~value;
+ /* stat_pending is NOT cleared */
+ omap3_mmc_interrupts_update(s);
+ break;
+ case 0x134: /* MMCHS_IE */
+ TRACE2("IE = %08x", value);
+ if (!(s->con & 0x4000)) /* if CON:OBIE is clear, ignore write to OBI_ENABLE */
+ value = (value & ~0x200) | (s->ie & 0x200);
+ s->ie = value & 0x317f0337;
+ if (!(s->ie & 0x100)) {
+ s->stat &= ~0x100;
+ s->stat_pending &= ~0x100;
+ }
+ omap3_mmc_interrupts_update(s);
+ break;
+ case 0x138:
+ TRACE2("ISE = %08x", value);
+ s->ise = value & 0x317f0337;
+ omap3_mmc_interrupts_update(s);
+ break;
+ case 0x140: /* MMCHS_CAPA */
+ TRACE2("CAPA = %08x", value);
+ s->capa &= ~0x07000000;
+ s->capa |= value & 0x07000000;
+ break;
+ case 0x148:
+ TRACE2("CUR_CAPA = %08x", value);
+ s->cur_capa = value & 0xffffff;
+ break;
+ default:
+ OMAP_BAD_REG(addr);
+ exit(-1);
+ }
+}
+
+static CPUReadMemoryFunc *omap3_mmc_readfn[] = {
+ omap_badwidth_read32,
+ omap_badwidth_read32,
+ omap3_mmc_read,
+};
+
+static CPUWriteMemoryFunc *omap3_mmc_writefn[] = {
+ omap_badwidth_write32,
+ omap_badwidth_write32,
+ omap3_mmc_write,
+};
+
+static void omap3_mmc_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap3_mmc_s *s = (struct omap3_mmc_s *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->sysconfig);
+ qemu_put_be32(f, s->sysstatus);
+ qemu_put_be32(f, s->csre);
+ qemu_put_be32(f, s->systest);
+ qemu_put_be32(f, s->con);
+ qemu_put_be32(f, s->pwcnt);
+ qemu_put_be32(f, s->blk);
+ qemu_put_be32(f, s->arg);
+ qemu_put_be32(f, s->cmd);
+ qemu_put_be32(f, s->rsp10);
+ qemu_put_be32(f, s->rsp32);
+ qemu_put_be32(f, s->rsp54);
+ qemu_put_be32(f, s->rsp76);
+ qemu_put_be32(f, s->data);
+ qemu_put_be32(f, s->pstate);
+ qemu_put_be32(f, s->hctl);
+ qemu_put_be32(f, s->sysctl);
+ qemu_put_be32(f, s->stat);
+ qemu_put_be32(f, s->ie);
+ qemu_put_be32(f, s->ise);
+ qemu_put_be32(f, s->ac12);
+ qemu_put_be32(f, s->capa);
+ qemu_put_be32(f, s->cur_capa);
+ qemu_put_be32(f, s->rev);
+ qemu_put_be16(f, s->blen_counter);
+ qemu_put_be16(f, s->nblk_counter);
+ for (i = 0; i < sizeof(s->fifo)/sizeof(uint32_t); i++)
+ qemu_put_be32(f, s->fifo[i]);
+ qemu_put_sbe32(f, s->fifo_start);
+ qemu_put_sbe32(f, s->fifo_len);
+ qemu_put_sbe32(f, s->ddir);
+ qemu_put_sbe32(f, s->transfer);
+ qemu_put_sbe32(f, s->stop);
+ qemu_put_be32(f, s->stat_pending);
+}
+
+static int omap3_mmc_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap3_mmc_s *s = (struct omap3_mmc_s *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->sysconfig = qemu_get_be32(f);
+ s->sysstatus = qemu_get_be32(f);
+ s->csre = qemu_get_be32(f);
+ s->systest = qemu_get_be32(f);
+ s->con = qemu_get_be32(f);
+ s->pwcnt = qemu_get_be32(f);
+ s->blk = qemu_get_be32(f);
+ s->arg = qemu_get_be32(f);
+ s->cmd = qemu_get_be32(f);
+ s->rsp10 = qemu_get_be32(f);
+ s->rsp32 = qemu_get_be32(f);
+ s->rsp54 = qemu_get_be32(f);
+ s->rsp76 = qemu_get_be32(f);
+ s->data = qemu_get_be32(f);
+ s->pstate = qemu_get_be32(f);
+ s->hctl = qemu_get_be32(f);
+ s->sysctl = qemu_get_be32(f);
+ s->stat = qemu_get_be32(f);
+ s->ie = qemu_get_be32(f);
+ s->ise = qemu_get_be32(f);
+ s->ac12 = qemu_get_be32(f);
+ s->capa = qemu_get_be32(f);
+ s->cur_capa = qemu_get_be32(f);
+ s->rev = qemu_get_be32(f);
+ s->blen_counter = qemu_get_be16(f);
+ s->nblk_counter = qemu_get_be16(f);
+ for (i = 0; i < sizeof(s->fifo)/sizeof(uint32_t); i++)
+ s->fifo[i] = qemu_get_be32(f);
+ s->fifo_start = qemu_get_sbe32(f);
+ s->fifo_len = qemu_get_sbe32(f);
+ s->ddir = qemu_get_sbe32(f);
+ s->transfer = qemu_get_sbe32(f);
+ s->stop = qemu_get_sbe32(f);
+ s->stat_pending = qemu_get_be32(f);
+
+ omap3_mmc_fifolevel_update(s);
+ omap3_mmc_interrupts_update(s);
+
+ return 0;
+}
+
+struct omap3_mmc_s *omap3_mmc_init(struct omap_target_agent_s *ta,
+ qemu_irq irq, qemu_irq dma[],
+ omap_clk fclk, omap_clk iclk)
+{
+ int iomemtype;
+ struct omap3_mmc_s *s = (struct omap3_mmc_s *)
+ qemu_mallocz(sizeof(struct omap3_mmc_s));
+
+ s->irq = irq;
+ s->dma = dma;
+ s->clk = fclk;
+
+ omap3_mmc_reset(s);
+
+ iomemtype = l4_register_io_memory(0, omap3_mmc_readfn,
+ omap3_mmc_writefn, s);
+ omap_l4_attach(ta, 0, iomemtype);
+
+ register_savevm("omap3_mmc", (ta->base >> 12) & 0xff, 0,
+ omap3_mmc_save_state, omap3_mmc_load_state, s);
+ return s;
+}
+
+void omap3_mmc_attach(struct omap3_mmc_s *s,
+ BlockDriverState *bd)
+{
+ if (s->card) {
+ fprintf(stderr, "%s: SD card already attached!\n", __FUNCTION__);
+ exit(-1);
+ }
+ s->card = sd_init(bd, 0);
+ sd_enable(s->card, 1);
+}
--- /dev/null
+/*
+ * 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;
+}
+
#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;
.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 */
&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
};
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;
#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 */
/* 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) {
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);
}
}
uint16_t status = ch->status;
#endif
+ TRACE("frame %d", a->frame);
do {
/* Transfer a single element */
/* FIXME: check the endianness */
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. */
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;
return ch->interrupts;
case 0x0c: /* DMA4_CSR */
+ TRACE("CSR = %04x", ch->cstatus);
return ch->cstatus;
case 0x10: /* DMA4_CSDP */
return ch->color;
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REG(0x80 + chnum * 0x60 + addr);
return 0;
}
}
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 */
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 */
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);
}
}
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;
}
#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;
int autoidle;
int control;
+ uint32_t sdi_control;
+ uint32_t pll_control;
int enable;
struct omap_dss_panel_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;
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;
int nx;
int ny;
+ int rotation_flag;
+ int gfx_format;
+ int gfx_channel;
+
target_phys_addr_t addr[3];
uint32_t attr;
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;
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)
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;
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:
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;
}
}
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;
}
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 */
* 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
*/
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;
}
}
/* 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)
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);
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 */
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. */
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])
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])
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;
}
}
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;
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;
}
}
break;
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REGV(addr, value);
+ break;
}
}
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;
}
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;
+}
* TI OMAP on-chip I2C controller. Only "new I2C" mode supported.
*
* Copyright (C) 2007 Andrzej Zaborowski <balrog@zabor.org>
+ * Copyright (C) 2009 Nokia Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
#include "i2c.h"
#include "omap.h"
+#define I2C_MAX_FIFO_SIZE (1 << 6)
+#define I2C_FIFO_SIZE_MASK ((I2C_MAX_FIFO_SIZE) - 1)
+
struct omap_i2c_s {
qemu_irq irq;
qemu_irq drq[2];
- i2c_slave slave;
+ i2c_slave slave[4];
i2c_bus *bus;
uint8_t revision;
- uint8_t mask;
+ uint16_t mask;
uint16_t stat;
+ uint16_t we;
uint16_t dma;
uint16_t count;
int count_cur;
- uint32_t fifo;
- int rxlen;
- int txlen;
+ uint16_t sysc;
uint16_t control;
- uint16_t addr[2];
+ uint16_t own_addr[4];
+ uint16_t slave_addr;
+ uint8_t sblock;
uint8_t divider;
- uint8_t times[2];
+ uint16_t times[2];
uint16_t test;
+ int fifostart;
+ int fifolen;
+ int fifosize;
+ uint8_t fifo[I2C_MAX_FIFO_SIZE];
};
#define OMAP2_INTR_REV 0x34
#define OMAP2_GC_REV 0x34
+#define OMAP3_INTR_REV 0x3c
+
+//#define I2C_DEBUG
+#ifdef I2C_DEBUG
+#define TRACE(fmt, ...) fprintf(stderr, "%s " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
static void omap_i2c_interrupts_update(struct omap_i2c_s *s)
{
+ TRACE("IRQ=%04x,RDRQ=%d,XDRQ=%d",
+ s->stat & s->mask,
+ ((s->dma >> 15 ) & 1) & ((s->stat >> 3) & 1),
+ ((s->dma >> 7 ) & 1 )& ((s->stat >> 4 ) & 1));
qemu_set_irq(s->irq, s->stat & s->mask);
- if ((s->dma >> 15) & 1) /* RDMA_EN */
- qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
- if ((s->dma >> 7) & 1) /* XDMA_EN */
- qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
+ if ((s->dma >> 15) & 1) /* RDMA_EN */
+ qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */
+ if ((s->dma >> 7) & 1) /* XDMA_EN */
+ qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */
}
/* These are only stubs now. */
static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event)
{
- struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
-
- if ((~s->control >> 15) & 1) /* I2C_EN */
- return;
-
- switch (event) {
- case I2C_START_SEND:
- case I2C_START_RECV:
- s->stat |= 1 << 9; /* AAS */
- break;
- case I2C_FINISH:
- s->stat |= 1 << 2; /* ARDY */
- break;
- case I2C_NACK:
- s->stat |= 1 << 1; /* NACK */
- break;
- }
-
- omap_i2c_interrupts_update(s);
+ fprintf(stderr, "%s: I^2C slave mode not supported\n", __FUNCTION__);
+
+ /* code below is broken, i2c_slave CANNOT be cast to omap_i2c_s! */
+
+ //struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
+ //
+ //if ((~s->control >> 15) & 1) /* I2C_EN */
+ // return;
+ //
+ //switch (event) {
+ // case I2C_START_SEND:
+ // case I2C_START_RECV:
+ // s->stat |= 1 << 9; /* AAS */
+ // break;
+ // case I2C_FINISH:
+ // s->stat |= 1 << 2; /* ARDY */
+ // break;
+ // case I2C_NACK:
+ // s->stat |= 1 << 1; /* NACK */
+ // break;
+ // default:
+ // break;
+ //}
+ //
+ //omap_i2c_interrupts_update(s);
}
static int omap_i2c_rx(i2c_slave *i2c)
{
- struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
- uint8_t ret = 0;
-
- if ((~s->control >> 15) & 1) /* I2C_EN */
- return -1;
-
- if (s->txlen)
- ret = s->fifo >> ((-- s->txlen) << 3) & 0xff;
- else
- s->stat |= 1 << 10; /* XUDF */
- s->stat |= 1 << 4; /* XRDY */
-
- omap_i2c_interrupts_update(s);
- return ret;
+ fprintf(stderr, "%s: I^2C slave mode not supported\n", __FUNCTION__);
+ return 0;
+
+ /* code below is broken, i2c_slave CANNOT be cast to omap_i2c_s! */
+
+ //struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
+ //uint8_t ret = 0;
+ //
+ //if ((~s->control >> 15) & 1) /* I2C_EN */
+ // return -1;
+ //
+ //if (s->rxlen < s->txlen)
+ // ret = s->fifo[s->rxlen++];
+ //else
+ // s->stat |= 1 << 10; /* XUDF */
+ //s->stat |= 1 << 4; /* XRDY */
+ //
+ //omap_i2c_interrupts_update(s);
+ //return ret;
}
static int omap_i2c_tx(i2c_slave *i2c, uint8_t data)
{
- struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
-
- if ((~s->control >> 15) & 1) /* I2C_EN */
- return 1;
-
- if (s->rxlen < 4)
- s->fifo |= data << ((s->rxlen ++) << 3);
- else
- s->stat |= 1 << 11; /* ROVR */
- s->stat |= 1 << 3; /* RRDY */
-
- omap_i2c_interrupts_update(s);
+ fprintf(stderr, "%s: I^2C slave mode not supported\n", __FUNCTION__);
return 1;
+
+ /* code below is broken, i2c_slave CANNOT be cast to omap_i2c_s! */
+
+ //struct omap_i2c_s *s = (struct omap_i2c_s *) i2c;
+ //
+ //if ((~s->control >> 15) & 1) /* I2C_EN */
+ // return 1;
+ //
+ //if (s->txlen < s->fifosize)
+ // s->fifo[s->txlen++] = data;
+ //else
+ // s->stat |= 1 << 11; /* ROVR */
+ //s->stat |= 1 << 3; /* RRDY */
+ //
+ //omap_i2c_interrupts_update(s);
+ //return 1;
}
static void omap_i2c_fifo_run(struct omap_i2c_s *s)
{
- int ack = 1;
+ int ack = 1, i;
if (!i2c_bus_busy(s->bus))
return;
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)
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;
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);
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;
}
}
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;
}
}
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;
}
--- /dev/null
+/*
+ * TI OMAP processor's Multichannel SPI emulation.
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "hw.h"
+#include "omap.h"
+
+#define SPI_FIFOSIZE 64
+#define SPI_REV_OMAP2420 0x14
+#define SPI_REV_OMAP3530 0x21
+#define IS_OMAP3_SPI(s) ((s)->revision >= SPI_REV_OMAP3530)
+
+struct omap_mcspi_s {
+ qemu_irq irq;
+ int chnum;
+ uint8_t revision;
+
+ uint32_t sysconfig;
+ uint32_t systest;
+ uint32_t irqst;
+ uint32_t irqen;
+ uint32_t wken;
+ uint32_t control;
+ uint32_t xferlevel;
+ struct omap_mcspi_fifo_s {
+ int start;
+ int len;
+ int size;
+ uint8_t buf[SPI_FIFOSIZE];
+ } tx_fifo, rx_fifo;
+ int fifo_ch;
+ int fifo_wcnt;
+
+ struct omap_mcspi_ch_s {
+ qemu_irq txdrq;
+ qemu_irq rxdrq;
+ uint32_t (*txrx)(void *opaque, uint32_t, int);
+ void *opaque;
+
+ uint32_t tx;
+ uint32_t rx;
+
+ uint32_t config;
+ uint32_t status;
+ uint32_t control;
+ } ch[0];
+};
+
+static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
+{
+ qemu_set_irq(s->irq, s->irqst & s->irqen);
+}
+
+static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_s *s,
+ int chnum)
+{
+ struct omap_mcspi_ch_s *ch = &s->ch[chnum];
+ if ((ch->control & 1) && /* EN */
+ (ch->config & (1 << 14)) && /* DMAW */
+ (ch->status & (1 << 1)) && /* TXS */
+ ((ch->config >> 12) & 3) != 1) { /* TRM */
+ if (!IS_OMAP3_SPI(s) ||
+ !(ch->config & (1 << 27)) || /* FFEW */
+ s->tx_fifo.len <= (s->xferlevel & 0x3f)) /* AEL */
+ qemu_irq_raise(ch->txdrq);
+ else
+ qemu_irq_lower(ch->txdrq);
+ }
+ if ((ch->control & 1) && /* EN */
+ (ch->config & (1 << 15)) && /* DMAW */
+ (ch->status & (1 << 0)) && /* RXS */
+ ((ch->config >> 12) & 3) != 2) { /* TRM */
+ if (!IS_OMAP3_SPI(s) ||
+ !(ch->config & (1 << 28)) || /* FFER */
+ s->rx_fifo.len >= ((s->xferlevel >> 8) & 0x3f)) /* AFL */
+ qemu_irq_raise(ch->rxdrq);
+ else
+ qemu_irq_lower(ch->rxdrq);
+ }
+}
+
+static void omap_mcspi_fifo_reset(struct omap_mcspi_s *s)
+{
+ struct omap_mcspi_ch_s *ch;
+
+ s->tx_fifo.len = 0;
+ s->rx_fifo.len = 0;
+ s->tx_fifo.start = 0;
+ s->rx_fifo.start = 0;
+ if (s->fifo_ch < 0) {
+ s->tx_fifo.size = s->rx_fifo.size = 0;
+ } else {
+ ch = &s->ch[s->fifo_ch];
+ s->tx_fifo.size = ((ch->config >> 27) & 1) ? SPI_FIFOSIZE : 0;
+ s->rx_fifo.size = ((ch->config >> 28) & 1) ? SPI_FIFOSIZE : 0;
+ if (((ch->config >> 27) & 3) == 3) {
+ s->tx_fifo.size >>= 1;
+ s->rx_fifo.size >>= 1;
+ }
+ }
+}
+
+static void omap_mcspi_save_state(QEMUFile *f, void *opaque)
+{
+ struct omap_mcspi_s *s = (struct omap_mcspi_s *)opaque;
+ int i;
+
+ qemu_put_be32(f, s->sysconfig);
+ qemu_put_be32(f, s->systest);
+ qemu_put_be32(f, s->irqst);
+ qemu_put_be32(f, s->irqen);
+ qemu_put_be32(f, s->wken);
+ qemu_put_be32(f, s->control);
+ qemu_put_be32(f, s->xferlevel);
+ qemu_put_sbe32(f, s->tx_fifo.start);
+ qemu_put_sbe32(f, s->tx_fifo.len);
+ qemu_put_sbe32(f, s->tx_fifo.size);
+ qemu_put_buffer(f, s->tx_fifo.buf, sizeof(s->tx_fifo.buf));
+ qemu_put_sbe32(f, s->rx_fifo.start);
+ qemu_put_sbe32(f, s->rx_fifo.len);
+ qemu_put_sbe32(f, s->rx_fifo.size);
+ qemu_put_buffer(f, s->rx_fifo.buf, sizeof(s->rx_fifo.buf));
+ qemu_put_sbe32(f, s->fifo_ch);
+ qemu_put_sbe32(f, s->fifo_wcnt);
+ for (i = 0; i < s->chnum; i++) {
+ qemu_put_be32(f, s->ch[i].tx);
+ qemu_put_be32(f, s->ch[i].rx);
+ qemu_put_be32(f, s->ch[i].config);
+ qemu_put_be32(f, s->ch[i].status);
+ qemu_put_be32(f, s->ch[i].control);
+ }
+}
+
+static int omap_mcspi_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct omap_mcspi_s *s = (struct omap_mcspi_s *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->sysconfig = qemu_get_be32(f);
+ s->systest = qemu_get_be32(f);
+ s->irqst = qemu_get_be32(f);
+ s->irqen = qemu_get_be32(f);
+ s->wken = qemu_get_be32(f);
+ s->control = qemu_get_be32(f);
+ s->xferlevel = qemu_get_be32(f);
+ s->tx_fifo.start = qemu_get_be32(f);
+ s->tx_fifo.len = qemu_get_be32(f);
+ s->tx_fifo.size = qemu_get_be32(f);
+ qemu_get_buffer(f, s->tx_fifo.buf, sizeof(s->tx_fifo.buf));
+ s->rx_fifo.start = qemu_get_be32(f);
+ s->rx_fifo.len = qemu_get_be32(f);
+ s->rx_fifo.size = qemu_get_be32(f);
+ qemu_get_buffer(f, s->rx_fifo.buf, sizeof(s->rx_fifo.buf));
+ s->fifo_ch = qemu_get_sbe32(f);
+ s->fifo_wcnt = qemu_get_sbe32(f);
+ for (i = 0; i < s->chnum; i++) {
+ s->ch[i].tx = qemu_get_be32(f);
+ s->ch[i].rx = qemu_get_be32(f);
+ s->ch[i].config = qemu_get_be32(f);
+ s->ch[i].status = qemu_get_be32(f);
+ s->ch[i].control = qemu_get_be32(f);
+ omap_mcspi_dmarequest_update(s, i);
+ }
+ omap_mcspi_interrupt_update(s);
+
+ return 0;
+}
+
+/* returns next word in FIFO or the n first bytes if there is not
+ * enough data in FIFO */
+static uint32_t omap_mcspi_fifo_get(struct omap_mcspi_fifo_s *s, int wl)
+{
+ uint32_t v, sh;
+
+ for (v = 0, sh = 0; wl > 0 && s->len; wl -= 8, s->len--, sh += 8) {
+ v |= ((uint32_t)s->buf[s->start++]) << sh;
+ if (s->start >= s->size)
+ s->start = 0;
+ }
+ return v;
+}
+
+/* pushes a word to FIFO or the first n bytes of the word if the FIFO
+ * is too full to hold the full word */
+static void omap_mcspi_fifo_put(struct omap_mcspi_fifo_s *s, int wl,
+ uint32_t v)
+{
+ int p = s->start + s->len;
+
+ for (; wl > 0 && s->len < s->size; wl -=8, v >>= 8, s->len++) {
+ if (p >= s->size)
+ p -= s->size;
+ s->buf[p++] = (uint8_t)(v & 0xff);
+ }
+}
+
+static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
+{
+ struct omap_mcspi_ch_s *ch = s->ch + chnum;
+ int trm = (ch->config >> 12) & 3;
+ int wl;
+
+ if (!(ch->control & 1)) /* EN */
+ return;
+ if ((ch->status & 1) && trm != 2 && /* RXS */
+ !(ch->config & (1 << 19))) /* TURBO */
+ goto intr_update;
+ if ((ch->status & (1 << 1)) && trm != 1) /* TXS */
+ goto intr_update;
+
+ if (!(s->control & 1) || /* SINGLE */
+ (ch->config & (1 << 20))) { /* FORCE */
+ if (ch->txrx) {
+ wl = 1 + (0x1f & (ch->config >> 7)); /* WL */
+ if (!IS_OMAP3_SPI(s) || s->fifo_ch != chnum ||
+ !((ch->config >> 27) & 3)) /* FFER | FFEW */
+ ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
+ else {
+ switch ((ch->config >> 27) & 3) {
+ case 1: /* !FFER, FFEW */
+ if (trm != 1)
+ ch->tx = omap_mcspi_fifo_get(&s->tx_fifo, wl);
+ ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
+ s->fifo_wcnt--;
+ break;
+ case 2: /* FFER, !FFEW */
+ ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
+ if (trm != 2)
+ omap_mcspi_fifo_put(&s->rx_fifo, wl, ch->rx);
+ s->fifo_wcnt--;
+ break;
+ case 3: /* FFER, FFEW */
+ while (s->rx_fifo.len < s->rx_fifo.size &&
+ s->tx_fifo.len && s->fifo_wcnt) {
+ if (trm != 1)
+ ch->tx = omap_mcspi_fifo_get(&s->tx_fifo, wl);
+ ch->rx = ch->txrx(ch->opaque, ch->tx, wl);
+ if (trm != 2)
+ omap_mcspi_fifo_put(&s->rx_fifo, wl, ch->rx);
+ s->fifo_wcnt--;
+ }
+ break;
+ default:
+ break;
+ }
+ if ((ch->config & (1 << 28)) && /* FFER */
+ s->rx_fifo.len >= s->rx_fifo.size)
+ ch->status |= 1 << 6; /* RXFFF */
+ ch->status &= ~(1 << 5); /* RXFFE */
+ ch->status &= ~(1 << 4); /* TXFFF */
+ if ((ch->config & (1 << 27)) && /* FFEW */
+ !s->tx_fifo.len)
+ ch->status |= 1 << 3; /* TXFFE */
+ if (!s->fifo_wcnt &&
+ ((s->xferlevel >> 16) & 0xffff)) /* WCNT */
+ s->irqst |= 1 << 17; /* EOW */
+ }
+ }
+ }
+
+ ch->tx = 0;
+ ch->status |= 1 << 2; /* EOT */
+ ch->status |= 1 << 1; /* TXS */
+ if (trm != 2)
+ ch->status |= 1; /* RXS */
+
+intr_update:
+ if ((ch->status & 1) && trm != 2 && /* RXS */
+ !(ch->config & (1 << 19))) /* TURBO */
+ if (!IS_OMAP3_SPI(s) || s->fifo_ch != chnum ||
+ !((ch->config >> 28) & 1) || /* FFER */
+ s->rx_fifo.len >= ((s->xferlevel >> 8) & 0x3f)) /* AFL */
+ s->irqst |= 1 << (2 + 4 * chnum); /* RX_FULL */
+ if ((ch->status & (1 << 1)) && trm != 1) /* TXS */
+ if (!IS_OMAP3_SPI(s) || s->fifo_ch != chnum ||
+ !((ch->config >> 27) & 1) || /* FFEW */
+ s->tx_fifo.len <= (s->xferlevel & 0x3f)) /* AEL */
+ s->irqst |= 1 << (4 * chnum); /* TX_EMPTY */
+ omap_mcspi_interrupt_update(s);
+ omap_mcspi_dmarequest_update(s, chnum);
+}
+
+void omap_mcspi_reset(struct omap_mcspi_s *s)
+{
+ int ch;
+
+ s->sysconfig = 0;
+ s->systest = 0;
+ s->irqst = 0;
+ s->irqen = 0;
+ s->wken = 0;
+ s->control = 4;
+
+ s->fifo_ch = -1;
+ omap_mcspi_fifo_reset(s);
+
+ for (ch = 0; ch < s->chnum; ch ++) {
+ s->ch[ch].config = 0x060000;
+ s->ch[ch].status = 2; /* TXS */
+ s->ch[ch].control = 0;
+
+ omap_mcspi_dmarequest_update(s, ch);
+ }
+
+ omap_mcspi_interrupt_update(s);
+}
+
+static uint32_t omap_mcspi_read(void *opaque, target_phys_addr_t addr)
+{
+ struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+ int ch = 0;
+ uint32_t ret;
+
+ switch (addr) {
+ case 0x00: /* MCSPI_REVISION */
+ return s->revision;
+
+ case 0x10: /* MCSPI_SYSCONFIG */
+ return s->sysconfig;
+
+ case 0x14: /* MCSPI_SYSSTATUS */
+ return 1; /* RESETDONE */
+
+ case 0x18: /* MCSPI_IRQSTATUS */
+ return s->irqst;
+
+ case 0x1c: /* MCSPI_IRQENABLE */
+ return s->irqen;
+
+ case 0x20: /* MCSPI_WAKEUPENABLE */
+ return s->wken;
+
+ case 0x24: /* MCSPI_SYST */
+ return s->systest;
+
+ case 0x28: /* MCSPI_MODULCTRL */
+ return s->control;
+
+ case 0x68: ch ++;
+ case 0x54: ch ++;
+ case 0x40: ch ++;
+ case 0x2c: /* MCSPI_CHCONF */
+ return (ch < s->chnum) ? s->ch[ch].config : 0;
+
+ case 0x6c: ch ++;
+ case 0x58: ch ++;
+ case 0x44: ch ++;
+ case 0x30: /* MCSPI_CHSTAT */
+ return (ch < s->chnum) ? s->ch[ch].status : 0;
+
+ case 0x70: ch ++;
+ case 0x5c: ch ++;
+ case 0x48: ch ++;
+ case 0x34: /* MCSPI_CHCTRL */
+ return (ch < s->chnum) ? s->ch[ch].control : 0;
+
+ case 0x74: ch ++;
+ case 0x60: ch ++;
+ case 0x4c: ch ++;
+ case 0x38: /* MCSPI_TX */
+ if (ch < s->chnum)
+ return s->ch[ch].tx;
+ break;
+
+ case 0x78: ch ++;
+ case 0x64: ch ++;
+ case 0x50: ch ++;
+ case 0x3c: /* MCSPI_RX */
+ if (ch < s->chnum) {
+ if (!IS_OMAP3_SPI(s) || ch != s->fifo_ch ||
+ !(s->ch[ch].config & (1 << 28))) { /* FFER */
+ s->ch[ch].status &= ~1; /* RXS */
+ ret = s->ch[ch].rx;
+ omap_mcspi_transfer_run(s, ch);
+ return ret;
+ }
+ if (!s->rx_fifo.len)
+ fprintf(stderr, "%s: rxfifo underflow!\n", __FUNCTION__);
+ else {
+ qemu_irq_lower(s->ch[ch].rxdrq);
+ s->ch[ch].status &= ~(1 << 6); /* RXFFF */
+ if (((s->ch[ch].config >> 12) & 3) != 2) /* TRM */
+ ret = omap_mcspi_fifo_get(&s->rx_fifo,
+ 1 + ((s->ch[ch].config >> 7) & 0x1f)); /* WL */
+ else
+ ret = s->ch[ch].rx;
+ if (!s->rx_fifo.len) {
+ s->ch[ch].status &= ~1; /* RXS */
+ s->ch[ch].status |= 1 << 5; /* RXFFE */
+ omap_mcspi_transfer_run(s, ch);
+ }
+ return ret;
+ }
+ }
+ return 0;
+
+ case 0x7c: /* MCSPI_XFERLEVEL */
+ if (IS_OMAP3_SPI(s)) {
+ if ((s->xferlevel >> 16) & 0xffff) /* WCNT */
+ ret = ((s->xferlevel & 0xffff0000) - (s->fifo_wcnt << 16));
+ else
+ ret = ((-s->fifo_wcnt) & 0xffff) << 16;
+ return (s->xferlevel & 0xffff) | ret;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ OMAP_BAD_REG(addr);
+ return 0;
+}
+
+static void omap_mcspi_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+ uint32_t old;
+ int ch = 0;
+
+ switch (addr) {
+ case 0x00: /* MCSPI_REVISION */
+ case 0x14: /* MCSPI_SYSSTATUS */
+ case 0x30: /* MCSPI_CHSTAT0 */
+ case 0x3c: /* MCSPI_RX0 */
+ case 0x44: /* MCSPI_CHSTAT1 */
+ case 0x50: /* MCSPI_RX1 */
+ case 0x58: /* MCSPI_CHSTAT2 */
+ case 0x64: /* MCSPI_RX2 */
+ case 0x6c: /* MCSPI_CHSTAT3 */
+ case 0x78: /* MCSPI_RX3 */
+ OMAP_RO_REGV(addr, value);
+ return;
+
+ case 0x10: /* MCSPI_SYSCONFIG */
+ if (value & (1 << 1)) /* SOFTRESET */
+ omap_mcspi_reset(s);
+ s->sysconfig = value & 0x31d;
+ break;
+
+ case 0x18: /* MCSPI_IRQSTATUS */
+ if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
+ s->irqst &= ~value;
+ omap_mcspi_interrupt_update(s);
+ }
+ break;
+
+ case 0x1c: /* MCSPI_IRQENABLE */
+ s->irqen = value & (IS_OMAP3_SPI(s) ? 0x3777f : 0x1777f);
+ omap_mcspi_interrupt_update(s);
+ break;
+
+ case 0x20: /* MCSPI_WAKEUPENABLE */
+ s->wken = value & 1;
+ break;
+
+ case 0x24: /* MCSPI_SYST */
+ if (s->control & (1 << 3)) /* SYSTEM_TEST */
+ if (value & (1 << 11)) { /* SSB */
+ s->irqst |= 0x1777f;
+ omap_mcspi_interrupt_update(s);
+ }
+ s->systest = value & 0xfff;
+ break;
+
+ case 0x28: /* MCSPI_MODULCTRL */
+ if (value & (1 << 3)) /* SYSTEM_TEST */
+ if (s->systest & (1 << 11)) { /* SSB */
+ s->irqst |= IS_OMAP3_SPI(s) ? 0x3777f : 0x1777f;
+ omap_mcspi_interrupt_update(s);
+ }
+ s->control = value & 0xf;
+ break;
+
+ case 0x68: ch ++;
+ case 0x54: ch ++;
+ case 0x40: ch ++;
+ case 0x2c: /* MCSPI_CHCONF */
+ if (ch < s->chnum) {
+ old = s->ch[ch].config;
+ s->ch[ch].config = value & (IS_OMAP3_SPI(s)
+ ? 0x3fffffff : 0x7fffff);
+ if (IS_OMAP3_SPI(s) &&
+ ((value ^ old) & (3 << 27))) { /* FFER | FFEW */
+ s->fifo_ch = ((value & (3 << 27))) ? ch : -1;
+ omap_mcspi_fifo_reset(s);
+ }
+ if (((value ^ old) & (3 << 14)) || /* DMAR | DMAW */
+ (IS_OMAP3_SPI(s) &&
+ ((value ^ old) & (3 << 27)))) /* FFER | FFEW */
+ omap_mcspi_dmarequest_update(s, ch);
+ if (((value >> 12) & 3) == 3) /* TRM */
+ fprintf(stderr, "%s: invalid TRM value (3)\n",
+ __FUNCTION__);
+ if (((value >> 7) & 0x1f) < 3) /* WL */
+ fprintf(stderr, "%s: invalid WL value (%i)\n",
+ __FUNCTION__, (value >> 7) & 0x1f);
+ if (IS_OMAP3_SPI(s) &&
+ ((value >> 23) & 1)) /* SBE */
+ fprintf(stderr, "%s: start-bit mode is not supported\n",
+ __FUNCTION__);
+ }
+ break;
+
+ case 0x70: ch ++;
+ case 0x5c: ch ++;
+ case 0x48: ch ++;
+ case 0x34: /* MCSPI_CHCTRL */
+ if (ch < s->chnum) {
+ old = s->ch[ch].control;
+ s->ch[ch].control = value & (IS_OMAP3_SPI(s) ? 0xff01 : 1);
+ if (value & ~old & 1) { /* EN */
+ if (IS_OMAP3_SPI(s) && s->fifo_ch == ch)
+ omap_mcspi_fifo_reset(s);
+ omap_mcspi_transfer_run(s, ch);
+ }
+ }
+ break;
+
+ case 0x74: ch ++;
+ case 0x60: ch ++;
+ case 0x4c: ch ++;
+ case 0x38: /* MCSPI_TX */
+ if (ch < s->chnum) {
+ if (!IS_OMAP3_SPI(s) || s->fifo_ch != ch ||
+ !(s->ch[ch].config & (1 << 27))) { /* FFEW */
+ s->ch[ch].tx = value;
+ s->ch[ch].status &= ~(1 << 1); /* TXS */
+ omap_mcspi_transfer_run(s, ch);
+ } else {
+ if (s->tx_fifo.len >= s->tx_fifo.size)
+ fprintf(stderr, "%s: txfifo overflow!\n",
+ __FUNCTION__);
+ else {
+ qemu_irq_lower(s->ch[ch].txdrq);
+ s->ch[ch].status &= ~0x0a; /* TXFFE | TXS */
+ if (((s->ch[ch].config >> 12) & 3) != 1) { /* TRM */
+ omap_mcspi_fifo_put(
+ &s->tx_fifo,
+ 1 + ((s->ch[ch].config >> 7) & 0x1f), /* WL */
+ value);
+ if (s->tx_fifo.len >= s->tx_fifo.size)
+ s->ch[ch].status |= 1 << 4; /* TXFFF */
+ if (s->tx_fifo.len >= (s->xferlevel & 0x3f))
+ omap_mcspi_transfer_run(s, ch);
+ } else {
+ s->ch[ch].tx = value;
+ omap_mcspi_transfer_run(s, ch);
+ }
+ }
+ }
+ }
+ break;
+
+ case 0x7c:
+ if (IS_OMAP3_SPI(s)) {
+ if (value != s->xferlevel) {
+ s->fifo_wcnt = (value >> 16) & 0xffff;
+ s->xferlevel = value & 0xffff3f3f;
+ omap_mcspi_fifo_reset(s);
+ }
+ } else
+ OMAP_BAD_REGV(addr, value);
+ break;
+
+ default:
+ OMAP_BAD_REGV(addr, value);
+ return;
+ }
+}
+
+static CPUReadMemoryFunc *omap_mcspi_readfn[] = {
+ omap_badwidth_read32,
+ omap_badwidth_read32,
+ omap_mcspi_read,
+};
+
+static CPUWriteMemoryFunc *omap_mcspi_writefn[] = {
+ omap_badwidth_write32,
+ omap_badwidth_write32,
+ omap_mcspi_write,
+};
+
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta,
+ struct omap_mpu_state_s *mpu,
+ int chnum, qemu_irq irq, qemu_irq *drq,
+ omap_clk fclk, omap_clk iclk)
+{
+ struct omap_mcspi_s *s = (struct omap_mcspi_s *)
+ qemu_mallocz(sizeof(struct omap_mcspi_s) +
+ chnum * sizeof(struct omap_mcspi_ch_s));
+ struct omap_mcspi_ch_s *ch = s->ch;
+
+ s->irq = irq;
+ s->chnum = chnum;
+ /* revision was hardcoded as 0x91 in original code -- odd */
+ s->revision = cpu_class_omap3(mpu) ? SPI_REV_OMAP3530 : SPI_REV_OMAP2420;
+ while (chnum --) {
+ ch->txdrq = *drq ++;
+ ch->rxdrq = *drq ++;
+ ch ++;
+ }
+ omap_mcspi_reset(s);
+
+ omap_l4_attach(ta, 0, l4_register_io_memory(0, omap_mcspi_readfn,
+ omap_mcspi_writefn, s));
+ register_savevm("omap_mcspi", (ta->base >> 8), 0,
+ omap_mcspi_save_state, omap_mcspi_load_state, s);
+ return s;
+}
+
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+ uint32_t (*txrx)(void *opaque, uint32_t, int),
+ void *opaque,
+ int chipselect)
+{
+ if (chipselect < 0 || chipselect >= s->chnum)
+ cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n",
+ __FUNCTION__, chipselect);
+
+ s->ch[chipselect].txrx = txrx;
+ s->ch[chipselect].opaque = opaque;
+}
#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
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)
{
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;
}
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");
#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
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;
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);
}
}
+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
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);
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;
}
goto bad_cmd;
switch (sd->state) {
case sd_standby_state:
- break;
+ return sd_r0;
default:
break;
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;
}
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);
}
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;
}
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;
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);
smc91c111_receive, smc91c111_can_receive, s);
qemu_format_nic_info_str(s->vc, s->macaddr);
/* ??? Save/restore. */
+ return s;
}
#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)
{
{
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)
{
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;
}
* 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);
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;
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:
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,
#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;
{
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
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) {
case musb_irq_tx:
case musb_irq_rx:
+ TRACE("rxtx");
s->usbip_intr = musb_core_intr_get(s->musb);
/* Fall through. */
default:
--- /dev/null
+/*
+ * TI TWL4030 for beagle board
+ *
+ * Copyright (C) 2008 yajin<yajin@vm-kernel.org>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Register implementation based on TPS65950 ES1.0 specification.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "i2c.h"
+#include "sysemu.h"
+#include "console.h"
+#include "cpu-all.h"
+
+//#define VERBOSE 1
+
+#ifdef VERBOSE
+#define TRACE(fmt, ...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, __##VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+struct twl4030_i2c_s {
+ i2c_slave i2c;
+ int firstbyte;
+ uint8_t reg;
+ qemu_irq irq;
+ uint8 reg_data[256];
+ struct twl4030_s *twl4030;
+};
+
+struct twl4030_s {
+ struct twl4030_i2c_s *i2c[5];
+
+ int key_cfg;
+ int key_tst;
+
+ uint8_t seq_mem[64][4]; /* power-management sequencing memory */
+};
+
+static const uint8_t addr_48_reset_values[256] = {
+ 0x51, 0x04, 0x02, 0xc0, 0x41, 0x41, 0x41, 0x10, /* 0x00...0x07 */
+ 0x10, 0x10, 0x06, 0x06, 0x06, 0x1f, 0x1f, 0x1f, /* 0x08...0x0f */
+ 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, /* 0x18...0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x03, /* 0x20...0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+ 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, /* 0x30...0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
+ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, /* 0x80...0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90...0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
+ 0x00, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8...0xb8 */
+ 0xa0, 0xa0, 0x64, 0x7f, 0x6c, 0x75, 0x64, 0x20, /* 0xc0...0xc7 */
+ 0x01, 0x17, 0x01, 0x02, 0x00, 0x36, 0x44, 0x07, /* 0xc8...0xcf */
+ 0x3b, 0x17, 0x6b, 0x04, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
+ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 /* 0xf8...0xff */
+};
+
+static const uint8_t addr_49_reset_values[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
+ 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, /* 0x08...0x0f */
+ 0x3f, 0x3f, 0x3f, 0x3f, 0x25, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+ 0x00, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x55, /* 0x18...0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+ 0x13, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x00, /* 0x30...0x37 */
+ 0x00, 0x00, 0x06, 0x00, 0x44, 0x69, 0x00, 0x00, /* 0x38...0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80...0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
+ 0x00, 0x90, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, /* 0x90...0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
+ 0x00, 0x00, 0x04, 0x00, 0x55, 0x01, 0x55, 0x05, /* 0xa8...0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, /* 0xb0...0xb7 */
+ 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, /* 0xb8...0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* 0xc0...0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8...0xff */
+};
+
+static const uint8_t addr_4a_reset_values[256] = {
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
+ 0xc0, 0x8c, 0xde, 0xde, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18...0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30...0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+ 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x55, 0x07, /* 0x60...0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
+ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, /* 0x80...0x87 */
+ 0x00, 0x68, 0x9b, 0x86, 0x48, 0x2a, 0x07, 0x28, /* 0x88...0x8f */
+ 0x09, 0x69, 0x90, 0x00, 0x2a, 0x00, 0x02, 0x00, /* 0x90...0x97 */
+ 0x10, 0xcd, 0x02, 0x68, 0x03, 0x00, 0x00, 0x00, /* 0x98...0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
+ 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, /* 0xb8...0xbf */
+ 0x0f, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x01, 0x00, /* 0xc0...0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, /* 0xd0...0xd7 */
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, /* 0xe0...0xe7 */
+ 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xf8...0xff */
+};
+
+static const uint8_t addr_4b_reset_values[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x18...0x1f */
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, /* 0x20...0x27 */
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0xbf, 0xbf, /* 0x30...0x37 */
+ 0xbf, 0xab, 0x00, 0x08, 0x3f, 0x15, 0x40, 0x0e, /* 0x38...0x3f */
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, /* 0x48...0x4f */
+ 0x00, 0x02, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x00, /* 0x50...0x57 */
+ 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
+ 0x00, 0x00, 0x2f, 0x18, 0x0f, 0x08, 0x0f, 0x08, /* 0x60...0x67 */
+ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x80, 0x03, /* 0x70...0x77 */
+ 0x08, 0x09, 0x00, 0x00, 0x08, 0x03, 0x80, 0x03, /* 0x78...0x7f */
+ 0x08, 0x02, 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, /* 0x80...0x87 */
+ 0x08, 0x08, 0x20, 0x00, 0x00, 0x02, 0x80, 0x04, /* 0x88...0x8f */
+ 0x08, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, /* 0x90...0x97 */
+ 0x08, 0x02, 0xe0, 0x01, 0x08, 0x00, 0xe0, 0x00, /* 0x98...0x9f */
+ 0x08, 0x01, 0xe0, 0x01, 0x08, 0x04, 0xe0, 0x03, /* 0xa0...0xa7 */
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
+ 0x20, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, /* 0xb8...0xbf */
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, /* 0xc0...0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, /* 0xc8...0xcf */
+ 0x00, 0x08, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
+ 0x14, 0x08, 0xe0, 0x02, 0x08, 0xe0, 0x00, 0x08, /* 0xd8...0xdf */
+ 0xe0, 0x05, 0x08, 0xe0, 0x06, 0x08, 0xe0, 0x00, /* 0xe0...0xe7 */
+ 0x08, 0xe0, 0x00, 0x08, 0xe0, 0x06, 0x06, 0xe0, /* 0xe8...0xef */
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xf8...0xff */
+};
+
+static uint8_t twl4030_48_read(void *opaque, uint8_t addr)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+ TRACE("addr=0x%02x", addr);
+ switch (addr) {
+ case 0x00: /* VENDOR_ID_LO */
+ case 0x01: /* VENDOR_ID_HI */
+ case 0x02: /* PRODUCT_ID_LO */
+ case 0x03: /* PRODUCT_ID_HI */
+ return s->reg_data[addr];
+ case 0x04: /* FUNC_CTRL */
+ case 0x05: /* FUNC_CRTL_SET */
+ case 0x06: /* FUNC_CRTL_CLR */
+ return s->reg_data[0x04];
+ case 0x07: /* IFC_CTRL */
+ case 0x08: /* IFC_CRTL_SET */
+ case 0x09: /* IFC_CRTL_CLR */
+ return s->reg_data[0x07];
+ case 0xac: /* POWER_CTRL */
+ case 0xad: /* POWER_SET */
+ case 0xae: /* POWER_CLR */
+ return s->reg_data[0xac];
+ case 0xfd: /* PHY_PWR_CTRL */
+ case 0xfe: /* PHY_CLK_CTRL */
+ return s->reg_data[addr];
+ case 0xff: /* PHY_CLK_CTRL */
+ return s->reg_data[0xfe] & 0x1;
+ default:
+ fprintf(stderr, "%s: unknown register 0x%02x pc %x\n",
+ __FUNCTION__, addr, cpu_single_env->regs[15]);
+ break;
+ }
+ return 0;
+}
+
+static void twl4030_48_write(void *opaque, uint8_t addr, uint8_t value)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+ TRACE("addr=0x%02x, value=0x%02x", addr, value);
+ switch (addr) {
+ case 0x04: /* IFC_CTRL */
+ s->reg_data[0x04] = value & 0x80;
+ break;
+ case 0x05: /* IFC_CRTL_SET */
+ s->reg_data[0x04] = (s->reg_data[0x04] | value) & 0x80;
+ break;
+ case 0x06: /* IFC_CRTL_CLEAR */
+ s->reg_data[0x04] = (s->reg_data[0x04] & ~value) & 0x80;
+ break;
+ case 0x07: /* IFC_CTRL */
+ s->reg_data[0x07] = value & 0x61;
+ break;
+ case 0x08: /* IFC_CRTL_SET */
+ s->reg_data[0x07] = (s->reg_data[0x07] | value) & 0x61;
+ break;
+ case 0x09: /* IFC_CRTL_CLEAR */
+ s->reg_data[0x07] = (s->reg_data[0x07] & ~value) & 0x61;
+ break;
+ case 0xac: /* POWER_CTRL */
+ s->reg_data[0xac] = value & 0x20;
+ break;
+ case 0xad: /* POWER_SET */
+ s->reg_data[0xac] = (s->reg_data[0xac] | value) & 0x20;
+ break;
+ case 0xae: /* POWER_CLEAR */
+ s->reg_data[0xac] = (s->reg_data[0xac] & ~value) & 0x20;
+ break;
+ case 0xfd: /* PHY_PWR_CTRL */
+ s->reg_data[addr] = value & 0x1;
+ break;
+ case 0xfe: /* PHY_CLK_CTRL */
+ s->reg_data[addr] = value & 0x7;
+ break;
+ default:
+ fprintf(stderr, "%s: unknown register 0x%02x pc %x\n",
+ __FUNCTION__, addr, cpu_single_env->regs[15]);
+ break;
+ }
+}
+
+static int twl4030_48_tx(i2c_slave *i2c, uint8_t data)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+ /* Interpret register address byte */
+ if (s->firstbyte) {
+ s->reg = data;
+ s->firstbyte = 0;
+ } else
+ twl4030_48_write(s, s->reg++, data);
+
+ return 0;
+}
+
+static int twl4030_48_rx(i2c_slave *i2c)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+
+ return twl4030_48_read(s, s->reg++);
+}
+
+static void twl4030_48_reset(i2c_slave *i2c)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+ s->reg = 0x00;
+ memcpy(s->reg_data, addr_48_reset_values, 256);
+}
+
+static void twl4030_48_event(i2c_slave *i2c, enum i2c_event event)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+
+ if (event == I2C_START_SEND)
+ s->firstbyte = 1;
+}
+
+static uint8_t twl4030_49_read(void *opaque, uint8_t addr)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+ TRACE("addr=0x%02x", addr);
+ switch (addr) {
+ /* AUDIO_VOICE region */
+ case 0x01: /* CODEC_MODE */
+ case 0x02: /* OPTION */
+ case 0x04: /* MICBIAS_CTL */
+ case 0x05: /* ANAMICL */
+ case 0x06: /* ANAMICR */
+ case 0x07: /* AVADC_CTL */
+ case 0x08: /* ADCMICSEL */
+ case 0x09: /* DIGMIXING */
+ case 0x0a: /* ATXL1PGA */
+ case 0x0b: /* ATXR1PGA */
+ case 0x0c: /* AVTXL2PGA */
+ case 0x0d: /* AVTXR2PGA */
+ case 0x0e: /* AUDIO_IF */
+ case 0x0f: /* VOICE_IF */
+ case 0x10: /* ARXR1PGA */
+ case 0x11: /* ARXL1PGA */
+ case 0x12: /* ARXR2PGA */
+ case 0x13: /* ARXL2PGA */
+ case 0x14: /* VRXPGA */
+ case 0x15: /* VSTPGA */
+ case 0x16: /* VRX2ARXPGA */
+ case 0x17: /* AVDAC_CTL */
+ case 0x18: /* ARX2VTXPGA */
+ case 0x19: /* ARXL1_APGA_CTL */
+ case 0x1a: /* ARXR1_APGA_CTL */
+ case 0x1b: /* ARXL2_APGA_CTL */
+ case 0x1c: /* ARXR2_APGA_CTL */
+ case 0x1d: /* ATX2ARXPGA */
+ case 0x1e: /* BT_IF */
+ case 0x1f: /* BTPGA */
+ case 0x20: /* BTSTPGA */
+ case 0x21: /* EAR_CTL */
+ case 0x22: /* HS_SEL */
+ case 0x23: /* HS_GAIN_SET */
+ case 0x24: /* HS_POPN_SET */
+ case 0x25: /* PREDL_CTL */
+ case 0x26: /* PREDR_CTL */
+ case 0x27: /* PRECKL_CTL */
+ case 0x28: /* PRECKR_CTL */
+ case 0x29: /* HFL_CTL */
+ case 0x2a: /* HFR_CTL */
+ case 0x2b: /* ALC_CTL */
+ case 0x2c: /* ALC_SET1 */
+ case 0x2d: /* ALC_SET2 */
+ case 0x2e: /* BOOST_CTL */
+ case 0x2f: /* SOFTVOL_CTL */
+ case 0x30: /* DTMF_FREQSEL */
+ case 0x31: /* DTMF_TONEXT1H */
+ case 0x32: /* DTMF_TONEXT1L */
+ case 0x33: /* DTMF_TONEXT2H */
+ case 0x34: /* DTMF_TONEXT2L */
+ case 0x35: /* DTMF_TONOFF */
+ case 0x36: /* DTMF_WANONOFF */
+ case 0x37: /* CODEC_RX_SCRAMBLE_H */
+ case 0x38: /* CODEC_RX_SCRAMBLE_M */
+ case 0x39: /* CODEC_RX_SCRAMBLE_L */
+ case 0x3a: /* APLL_CTL */
+ case 0x3b: /* DTMF_CTL */
+ case 0x3c: /* DTMF_PGA_CTL2 */
+ case 0x3d: /* DTMF_PGA_CTL1 */
+ case 0x3e: /* MISC_SET_1 */
+ case 0x3f: /* PCMBTMUX */
+ case 0x43: /* RX_PATH_SEL */
+ case 0x44: /* VDL_APGA_CTL */
+ case 0x45: /* VIBRA_CTL */
+ case 0x46: /* VIBRA_SET */
+ case 0x48: /* ANAMIC_GAIN */
+ case 0x49: /* MISC_SET_2 */
+ /* Test region */
+ case 0x4c: /* AUDIO_TEST_CTL */
+ case 0x4d: /* INT_TEST_CTL */
+ case 0x4e: /* DAC_ADC_TEST_CTL */
+ case 0x4f: /* RXTX_TRIM_IB */
+ case 0x50: /* CLD_CONTROL */
+ case 0x51: /* CLD_MODE_TIMING */
+ case 0x52: /* CLD_TRIM_RAMP */
+ case 0x53: /* CLD_TESTV_CTL */
+ case 0x54: /* APLL_TEST_CTL */
+ case 0x55: /* APLL_TEST_DIV */
+ case 0x56: /* APLL_TEST_CTL2 */
+ case 0x57: /* APLL_TEST_CUR */
+ case 0x58: /* DIGIMIC_BIAS1_CTL */
+ case 0x59: /* DIGIMIC_BIAS2_CTL */
+ case 0x5a: /* RX_OFFSET_VOICE */
+ case 0x5b: /* RX_OFFSET_AL1 */
+ case 0x5c: /* RX_OFFSET_AR1 */
+ case 0x5d: /* RX_OFFSET_AL2 */
+ case 0x5e: /* RX_OFFSET_AR2 */
+ case 0x5f: /* OFFSET1 */
+ case 0x60: /* OFFSET2 */
+ /* PIH region */
+ case 0x81: /* PIH_ISR_P1 */
+ case 0x82: /* PIH_ISR_P2 */
+ case 0x83: /* PIH_SIR */
+ /* INTBR region */
+ case 0x85: /* IDCODE_7_0 */
+ case 0x86: /* IDCODE_15_8 */
+ case 0x87: /* IDCODE_23_16 */
+ case 0x88: /* IDCODE_31_24 */
+ case 0x89: /* DIEID_7_0 */
+ case 0x8a: /* DIEID_15_8 */
+ case 0x8b: /* DIEID_23_16 */
+ case 0x8c: /* DIEID_31_24 */
+ case 0x8d: /* DIEID_39_32 */
+ case 0x8e: /* DIEID_47_40 */
+ case 0x8f: /* DIEID_55_48 */
+ case 0x90: /* DIEID_63_56 */
+ case 0x91: /* GPBR1 */
+ case 0x92: /* PMBR1 */
+ case 0x93: /* PMBR2 */
+ case 0x94: /* GPPUPDCTR1 */
+ case 0x95: /* GPPUPDCTR2 */
+ case 0x96: /* GPPUPDCTR3 */
+ case 0x97: /* UNLOCK_TEST_REG */
+ /* GPIO region */
+ case 0x98: /* GPIO_DATAIN1 */
+ case 0x99: /* GPIO_DATAIN2 */
+ case 0x9a: /* GPIO_DATAIN3 */
+ case 0x9b: /* GPIO_DATADIR1 */
+ case 0x9c: /* GPIO_DATADIR2 */
+ case 0x9d: /* GPIO_DATADIR3 */
+ case 0x9e: /* GPIO_DATAOUT1 */
+ case 0x9f: /* GPIO_DATAOUT2 */
+ case 0xa0: /* GPIO_DATAOUT3 */
+ case 0xa1: /* GPIO_CLEARGPIODATAOUT1 */
+ case 0xa2: /* GPIO_CLEARGPIODATAOUT2 */
+ case 0xa3: /* GPIO_CLEARGPIODATAOUT3 */
+ case 0xa4: /* GPIO_SETGPIODATAOUT1 */
+ case 0xa5: /* GPIO_SETGPIODATAOUT2 */
+ case 0xa6: /* GPIO_SETGPIODATAOUT3 */
+ case 0xa7: /* GPIO_DEBEN1 */
+ case 0xa8: /* GPIO_DEBEN2 */
+ case 0xa9: /* GPIO_DEBEN3 */
+ case 0xaa: /* GPIO_CTRL */
+ case 0xab: /* GPIO_PUPDCTR1 */
+ case 0xac: /* GPIO_PUPDCTR2 */
+ case 0xad: /* GPIO_PUPDCTR3 */
+ case 0xae: /* GPIO_PUPDCTR4 */
+ case 0xaf: /* GPIO_PUPDCTR5 */
+ case 0xb0: /* GPIO_TEST */
+ case 0xb1: /* GPIO_ISR1A */
+ case 0xb2: /* GPIO_ISR2A */
+ case 0xb3: /* GPIO_ISR3A */
+ case 0xb4: /* GPIO_IMR1A */
+ case 0xb5: /* GPIO_IMR2A */
+ case 0xb6: /* GPIO_IMR3A */
+ case 0xb7: /* GPIO_ISR1B */
+ case 0xb8: /* GPIO_ISR2B */
+ case 0xb9: /* GPIO_ISR3B */
+ case 0xba: /* GPIO_IMR1B */
+ case 0xbb: /* GPIO_IMR2B */
+ case 0xbc: /* GPIO_IMR3B */
+ case 0xbd: /* GPIO_SIR1 */
+ case 0xbe: /* GPIO_SIR2 */
+ case 0xbf: /* GPIO_SIR3 */
+ case 0xc0: /* GPIO_EDR1 */
+ case 0xc1: /* GPIO_EDR2 */
+ case 0xc2: /* GPIO_EDR3 */
+ case 0xc3: /* GPIO_EDR4 */
+ case 0xc4: /* GPIO_EDR5 */
+ case 0xc5: /* GPIO_SIH_CTRL */
+ return s->reg_data[addr];
+ default:
+ fprintf(stderr, "%s: unknown register 0x%02x pc %x\n",
+ __FUNCTION__, addr, cpu_single_env->regs[15]);
+ break;
+ }
+ return 0;
+}
+
+static void twl4030_49_write(void *opaque, uint8_t addr, uint8_t value)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+ TRACE("addr=0x%02x, value=0x%02x", addr, value);
+ switch (addr) {
+ /* AUDIO_VOICE region */
+ case 0x01: /* CODEC_MODE */
+ case 0x02: /* OPTION */
+ case 0x04: /* MICBIAS_CTL */
+ case 0x05: /* ANAMICL */
+ case 0x06: /* ANAMICR */
+ case 0x07: /* AVADC_CTL */
+ case 0x08: /* ADCMICSEL */
+ case 0x09: /* DIGMIXING */
+ case 0x0a: /* ATXL1PGA */
+ case 0x0b: /* ATXR1PGA */
+ case 0x0c: /* AVTXL2PGA */
+ case 0x0d: /* AVTXR2PGA */
+ case 0x0e: /* AUDIO_IF */
+ case 0x0f: /* VOICE_IF */
+ case 0x10: /* ARXR1PGA */
+ case 0x11: /* ARXL1PGA */
+ case 0x12: /* ARXR2PGA */
+ case 0x13: /* ARXL2PGA */
+ case 0x14: /* VRXPGA */
+ case 0x15: /* VSTPGA */
+ case 0x16: /* VRX2ARXPGA */
+ case 0x17: /* AVDAC_CTL */
+ case 0x18: /* ARX2VTXPGA */
+ case 0x19: /* ARXL1_APGA_CTL */
+ case 0x1a: /* ARXR1_APGA_CTL */
+ case 0x1b: /* ARXL2_APGA_CTL */
+ case 0x1c: /* ARXR2_APGA_CTL */
+ case 0x1d: /* ATX2ARXPGA */
+ case 0x1e: /* BT_IF */
+ case 0x1f: /* BTPGA */
+ case 0x20: /* BTSTPGA */
+ case 0x21: /* EAR_CTL */
+ case 0x22: /* HS_SEL */
+ case 0x23: /* HS_GAIN_SET */
+ case 0x24: /* HS_POPN_SET */
+ case 0x25: /* PREDL_CTL */
+ case 0x26: /* PREDR_CTL */
+ case 0x27: /* PRECKL_CTL */
+ case 0x28: /* PRECKR_CTL */
+ case 0x29: /* HFL_CTL */
+ case 0x2a: /* HFR_CTL */
+ case 0x2b: /* ALC_CTL */
+ case 0x2c: /* ALC_SET1 */
+ case 0x2d: /* ALC_SET2 */
+ case 0x2e: /* BOOST_CTL */
+ case 0x2f: /* SOFTVOL_CTL */
+ case 0x30: /* DTMF_FREQSEL */
+ case 0x31: /* DTMF_TONEXT1H */
+ case 0x32: /* DTMF_TONEXT1L */
+ case 0x33: /* DTMF_TONEXT2H */
+ case 0x34: /* DTMF_TONEXT2L */
+ case 0x35: /* DTMF_TONOFF */
+ case 0x36: /* DTMF_WANONOFF */
+ case 0x37: /* CODEC_RX_SCRAMBLE_H */
+ case 0x38: /* CODEC_RX_SCRAMBLE_M */
+ case 0x39: /* CODEC_RX_SCRAMBLE_L */
+ case 0x3a: /* APLL_CTL */
+ case 0x3b: /* DTMF_CTL */
+ case 0x3c: /* DTMF_PGA_CTL2 */
+ case 0x3d: /* DTMF_PGA_CTL1 */
+ case 0x3e: /* MISC_SET_1 */
+ case 0x3f: /* PCMBTMUX */
+ case 0x43: /* RX_PATH_SEL */
+ case 0x44: /* VDL_APGA_CTL */
+ case 0x45: /* VIBRA_CTL */
+ case 0x46: /* VIBRA_SET */
+ case 0x48: /* ANAMIC_GAIN */
+ case 0x49: /* MISC_SET_2 */
+ s->reg_data[addr] = value;
+ break;
+ /* Test region */
+ case 0x4c: /* AUDIO_TEST_CTL */
+ case 0x4d: /* INT_TEST_CTL */
+ case 0x4e: /* DAC_ADC_TEST_CTL */
+ case 0x4f: /* RXTX_TRIM_IB */
+ case 0x50: /* CLD_CONTROL */
+ case 0x51: /* CLD_MODE_TIMING */
+ case 0x52: /* CLD_TRIM_RAMP */
+ case 0x53: /* CLD_TESTV_CTL */
+ case 0x54: /* APLL_TEST_CTL */
+ case 0x55: /* APLL_TEST_DIV */
+ case 0x56: /* APLL_TEST_CTL2 */
+ case 0x57: /* APLL_TEST_CUR */
+ case 0x58: /* DIGIMIC_BIAS1_CTL */
+ case 0x59: /* DIGIMIC_BIAS2_CTL */
+ s->reg_data[addr] = value;
+ break;
+ case 0x5a: /* RX_OFFSET_VOICE */
+ case 0x5b: /* RX_OFFSET_AL1 */
+ case 0x5c: /* RX_OFFSET_AR1 */
+ case 0x5d: /* RX_OFFSET_AL2 */
+ case 0x5e: /* RX_OFFSET_AR2 */
+ case 0x5f: /* OFFSET1 */
+ case 0x60: /* OFFSET2 */
+ /* read-only, ignore */
+ break;
+ /* PIH region */
+ case 0x81: /* PIH_ISR_P1 */
+ case 0x82: /* PIH_ISR_P2 */
+ case 0x83: /* PIH_SIR */
+ s->reg_data[addr] = value;
+ break;
+ /* INTBR region */
+ case 0x85: /* IDCODE_7_0 */
+ case 0x86: /* IDCODE_15_8 */
+ case 0x87: /* IDCODE_23_16 */
+ case 0x88: /* IDCODE_31_24 */
+ case 0x89: /* DIEID_7_0 */
+ case 0x8a: /* DIEID_15_8 */
+ case 0x8b: /* DIEID_23_16 */
+ case 0x8c: /* DIEID_31_24 */
+ case 0x8d: /* DIEID_39_32 */
+ case 0x8e: /* DIEID_47_40 */
+ case 0x8f: /* DIEID_55_48 */
+ case 0x90: /* DIEID_63_56 */
+ /* read-only, ignore */
+ break;
+ case 0x91: /* GPBR1 */
+ case 0x92: /* PMBR1 */
+ case 0x93: /* PMBR2 */
+ case 0x94: /* GPPUPDCTR1 */
+ case 0x95: /* GPPUPDCTR2 */
+ case 0x96: /* GPPUPDCTR3 */
+ case 0x97: /* UNLOCK_TEST_REG */
+ s->reg_data[addr] = value;
+ break;
+ /* GPIO region */
+ case 0x98: /* GPIODATAIN1 */
+ case 0x99: /* GPIODATAIN2 */
+ case 0x9a: /* GPIODATAIN3 */
+ /* read-only, ignore */
+ break;
+ case 0x9b: /* GPIODATADIR1 */
+ case 0x9c: /* GPIODATADIR2 */
+ case 0x9d: /* GPIODATADIR3 */
+ case 0x9e: /* GPIODATAOUT1 */
+ case 0x9f: /* GPIODATAOUT2 */
+ case 0xa0: /* GPIODATAOUT3 */
+ case 0xa1: /* CLEARGPIODATAOUT1 */
+ case 0xa2: /* CLEARGPIODATAOUT2 */
+ case 0xa3: /* CLEARGPIODATAOUT3 */
+ case 0xa4: /* SETGPIODATAOUT1 */
+ case 0xa5: /* SETGPIODATAOUT2 */
+ case 0xa6: /* SETGPIODATAOUT3 */
+ case 0xa7: /* GPIO_DEBEN1 */
+ case 0xa8: /* GPIO_DEBEN2 */
+ case 0xa9: /* GPIO_DEBEN3 */
+ case 0xaa: /* GPIO_CTRL */
+ case 0xab: /* GPIOPUPDCTR1 */
+ case 0xac: /* GPIOPUPDCTR2 */
+ case 0xad: /* GPIOPUPDCTR3 */
+ case 0xae: /* GPIOPUPDCTR4 */
+ s->reg_data[addr] = value;
+ break;
+ case 0xaf: /* GPIOPUPDCTR5 */
+ s->reg_data[addr] = value & 0x0f;
+ break;
+ case 0xb0: /* GPIO_TEST */
+ case 0xb1: /* GPIO_ISR1A */
+ case 0xb2: /* GPIO_ISR2A */
+ case 0xb3: /* GPIO_ISR3A */
+ case 0xb4: /* GPIO_IMR1A */
+ case 0xb5: /* GPIO_IMR2A */
+ s->reg_data[addr] = value;
+ break;
+ case 0xb6: /* GPIO_IMR3A */
+ s->reg_data[addr] = value & 0x03;
+ break;
+ case 0xb7: /* GPIO_ISR1B */
+ case 0xb8: /* GPIO_ISR2B */
+ case 0xb9: /* GPIO_ISR3B */
+ case 0xba: /* GPIO_IMR1B */
+ case 0xbb: /* GPIO_IMR2B */
+ case 0xbc: /* GPIO_IMR3B */
+ case 0xbd: /* GPIO_SIR1 */
+ case 0xbe: /* GPIO_SIR2 */
+ case 0xbf: /* GPIO_SIR3 */
+ case 0xc0: /* GPIO_EDR1 */
+ case 0xc1: /* GPIO_EDR2 */
+ case 0xc2: /* GPIO_EDR3 */
+ case 0xc3: /* GPIO_EDR4 */
+ case 0xc4: /* GPIO_EDR5 */
+ s->reg_data[addr] = value;
+ break;
+ case 0xc5: /* GPIO_SIH_CTRL */
+ s->reg_data[addr] = value & 0x07;
+ break;
+ default:
+ fprintf(stderr, "%s: unknown register 0x%02x pc %x\n",
+ __FUNCTION__, addr, cpu_single_env->regs[15]);
+ break;
+ }
+}
+
+
+static int twl4030_49_tx(i2c_slave *i2c, uint8_t data)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+ /* Interpret register address byte */
+ if (s->firstbyte) {
+ s->reg = data;
+ s->firstbyte = 0;
+ } else
+ twl4030_49_write(s, s->reg++, data);
+
+ return 0;
+}
+
+static int twl4030_49_rx(i2c_slave *i2c)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+
+ return twl4030_49_read(s, s->reg++);
+}
+
+static void twl4030_49_reset(i2c_slave *i2c)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+ s->reg = 0x00;
+ memcpy(s->reg_data, addr_49_reset_values, 256);
+}
+
+static void twl4030_49_event(i2c_slave *i2c, enum i2c_event event)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+
+ if (event == I2C_START_SEND)
+ s->firstbyte = 1;
+}
+
+static uint8_t twl4030_4a_read(void *opaque, uint8_t addr)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+ TRACE("addr=0x%02x", addr);
+ switch (addr) {
+ case 0x61: /* MADC_ISR1 */
+ case 0xb9: /* BCIISR1A */
+ case 0xba: /* BCIISR2A */
+ case 0xe3: /* KEYP_ISR1 */
+ case 0xee: /* LEDEN */
+ return s->reg_data[addr];
+ default:
+ fprintf(stderr, "%s: unknown register %02x pc %x\n",
+ __FUNCTION__, addr, cpu_single_env->regs[15] );
+ break;
+ }
+ return 0;
+}
+
+static void twl4030_4a_write(void *opaque, uint8_t addr, uint8_t value)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+ TRACE("addr=0x%02x, value=0x%02x", addr, value);
+ switch (addr) {
+ case 0x61: /* MADC_ISR1 */
+ s->reg_data[value] &= ~(value & 0x0f);
+ break;
+ case 0x62: /* MADC_IMR1 */
+ s->reg_data[value] = value & 0x0f;
+ break;
+ case 0xb9: /* BCIISR1A */
+ s->reg_data[value] &= ~value;
+ break;
+ case 0xba: /* BCIISR2A */
+ s->reg_data[value] &= ~(value & 0x0f);
+ break;
+ case 0xbb: /* BCIIMR1A */
+ s->reg_data[addr] = value;
+ break;
+ case 0xbc: /* BCIIMR2A */
+ s->reg_data[addr] = value & 0x0f;
+ break;
+ case 0xe4: /* KEYP_IMR1 */
+ s->reg_data[addr] = value & 0x0f;
+ break;
+ case 0xe9: /* KEYP_SIH_CTRL */
+ s->reg_data[addr] = value & 0x07;
+ break;
+ case 0xee: /* LEDEN */
+ s->reg_data[addr] = value;
+ TRACE("LEDA power=%s/enable=%s, LEDB power=%s/enable=%s",
+ value & 0x10 ? "on" : "off", value & 0x01 ? "yes" : "no",
+ value & 0x20 ? "on" : "off", value & 0x02 ? "yes" : "no");
+ break;
+ case 0xef: /* PWMAON */
+ s->reg_data[addr] = value;
+ break;
+ case 0xf0: /* PWMAOFF */
+ s->reg_data[addr] = value & 0x7f;
+ break;
+ default:
+ fprintf(stderr, "%s: unknown register %02x pc %x\n",
+ __FUNCTION__, addr, cpu_single_env->regs[15]);
+ break;
+ }
+}
+
+static int twl4030_4a_tx(i2c_slave *i2c, uint8_t data)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+ /* Interpret register address byte */
+ if (s->firstbyte) {
+ s->reg = data;
+ s->firstbyte = 0;
+ } else
+ twl4030_4a_write(s, s->reg++, data);
+
+ return 0;
+}
+
+static int twl4030_4a_rx(i2c_slave *i2c)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+
+ return twl4030_4a_read(s, s->reg++);
+}
+
+static void twl4030_4a_reset(i2c_slave *i2c)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+ s->reg = 0x00;
+ memcpy(s->reg_data, addr_4a_reset_values, 256);
+}
+
+static void twl4030_4a_event(i2c_slave *i2c, enum i2c_event event)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+
+ if (event == I2C_START_SEND)
+ s->firstbyte = 1;
+}
+
+static uint8_t twl4030_4b_read(void *opaque, uint8_t addr)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+
+ TRACE("addr=0x%02x", addr);
+ switch (addr) {
+ case 0x1c: /* RTC */
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d: /*RTC end */
+ case 0x2e: /* PWR_ISR1 */
+ case 0x33: /* PWR_EDR1 */
+ case 0x34: /* PWR_EDR2 */
+ return s->reg_data[addr];
+ case 0x45: /* STS_HW_CONDITIONS - USB plugged, no VBUS -> host usb */
+ return 0x4;
+ default:
+ fprintf(stderr, "%s: unknown register %02x pc %x \n",
+ __FUNCTION__, addr, cpu_single_env->regs[15] );
+ break;
+ }
+ return 0;
+}
+
+
+static void twl4030_4b_write(void *opaque, uint8_t addr, uint8_t value)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;
+ uint8_t seq_addr, seq_sub;
+
+ TRACE("addr=0x%02x, value=0x%02x", addr, value);
+ switch (addr) {
+ case 0x1c: /* SECONDS_REG */
+ case 0x1d: /* MINUTES_REG */
+ case 0x23: /* ALARM_SECONDS_REG */
+ case 0x24: /* ALARM_MINUTES_REG */
+ s->reg_data[addr] = value & 0x7f;
+ break;
+ case 0x1e: /* HOURS_REG */
+ case 0x25: /* ALARM_HOURS_REG */
+ s->reg_data[addr] = value & 0xbf;
+ break;
+ case 0x1f: /* DAYS_REG */
+ case 0x26: /* ALARM_DAYS_REG */
+ s->reg_data[addr] = value & 0x3f;
+ break;
+ case 0x20: /* MONTHS_REG */
+ case 0x27: /* ALARM_MONTHS_REG */
+ s->reg_data[addr] = value & 0x1f;
+ break;
+ case 0x21: /* YEARS_REG */
+ case 0x28: /* ALARM_YEARS_REG */
+ s->reg_data[addr] = value;
+ break;
+ case 0x22: /* WEEKS_REG */
+ s->reg_data[addr] = value & 0x07;
+ break;
+ case 0x29: /* RTC_CTRL_REG */
+ s->reg_data[addr] = value & 0x7f;
+ break;
+ case 0x2a: /* RTC_STATUS_REG */
+ s->reg_data[addr] = value & 0xfe;
+ break;
+ case 0x2b: /* RTC_INTERRUPTS_REG */
+ s->reg_data[addr] = value & 0x0f;
+ break;
+ case 0x2c: /* RTC_COMP_LSB_REG */
+ case 0x2d: /* RTC_COMP_MSB_REG */
+ s->reg_data[addr] = value;
+ break;
+ case 0x33: /* PWR_EDR1 */
+ case 0x34: /* PWR_EDR2 */
+ s->reg_data[addr] = value;
+ break;
+ case 0x46: /* P1_SW_EVENTS */
+ case 0x47: /* P2_SW_EVENTS */
+ case 0x48: /* P3_SW_EVENTS */
+ s->reg_data[addr] = value & 0x78;
+ break;
+ case 0x52: /* SEQ_ADD_W2P */
+ case 0x53: /* SEQ_ADD_P2A */
+ case 0x54: /* SEQ_ADD_A2W */
+ case 0x55: /* SEQ_ADD_A2S */
+ case 0x56: /* SEQ_ADD_S2A12 */
+ case 0x57: /* SEQ_ADD_S2A3 */
+ case 0x58: /* SEQ_ADD_WARM */
+ if (s->twl4030->key_cfg)
+ s->reg_data[addr] = value & 0x3f;
+ break;
+ case 0x59: /* MEMORY_ADDRESS */
+ if (s->twl4030->key_cfg)
+ s->reg_data[addr] = value;
+ break;
+ case 0x5a: /* MEMORY_DATA */
+ if (s->twl4030->key_cfg) {
+ s->reg_data[addr] = value;
+ seq_addr = s->reg_data[0x59];
+ seq_sub = seq_addr & 3;
+ seq_addr >>= 2;
+ if ((seq_addr >= 0x2b && seq_addr <= 0x3e) || (seq_addr <= 0x0e && seq_sub == 3))
+ s->twl4030->seq_mem[seq_addr][seq_sub] = value;
+ }
+ s->reg_data[0x59]++; /* TODO: check if autoincrement is write-protected as well */
+ break;
+ case 0x7a: /* VAUX3_DEV_GRP */
+ case 0x82: /* VMMC1_DEV_GRP */
+ case 0x8e: /* VPLL2_DEV_GRP */
+ case 0x96: /* VDAC_DEV_GRP */
+ case 0xcc: /* VUSB1V5_DEV_GRP */
+ case 0xcf: /* VUSB1V8_DEV_GRP */
+ case 0xd2: /* VUSB3V1_DEV_GRP */
+ case 0xe6: /* HFCLKOUT_DEV_GRP */
+ s->reg_data[addr] = (s->reg_data[addr] & 0x0f) | (value & 0xf0);
+ break;
+ case 0x2f: /* PWR_IMR1 */
+ s->reg_data[addr] = value;
+ break;
+ case 0x35: /* PWR_SIH_CTRL */
+ s->reg_data[addr] = value & 0x07;
+ break;
+ case 0x3b: /* CFG_BOOT */
+ if (s->twl4030->key_cfg)
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);
+ break;
+ case 0x44: /* PROTECT_KEY */
+ s->twl4030->key_cfg = 0;
+ s->twl4030->key_tst = 0;
+ switch (value) {
+ case 0x0C:
+ if (s->reg_data[addr] == 0xC0)
+ s->twl4030->key_cfg = 1;
+ break;
+ case 0xE0:
+ if (s->reg_data[addr] == 0x0E)
+ s->twl4030->key_tst = 1;
+ break;
+ case 0xEC:
+ if (s->reg_data[addr] == 0xCE) {
+ s->twl4030->key_cfg = 1;
+ s->twl4030->key_tst = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ s->reg_data[addr] = value;
+ break;
+ case 0x7d: /* VAUX3_DEDICATED */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x77;
+ else
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);
+ break;
+ case 0x85: /* VMMC1_DEDICATED */
+ case 0x99: /* VDAC_DEDICATED */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x73;
+ else
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);
+ break;
+ case 0x91: /* VPLL2_DEDICATED */
+ if (s->twl4030->key_tst)
+ s->reg_data[addr] = value & 0x7f;
+ else
+ s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
+ break;
+ case 0xcd: /* VUSB1V5_TYPE */
+ case 0xd0: /* VUSB1V8_TYPE */
+ case 0xd3: /* VUSB3V1_TYPE */
+ s->reg_data[addr] = value & 0x1f;
+ break;
+ case 0xd8: /* VUSB_DEDICATED1 */
+ s->reg_data[addr] = value & 0x1f;
+ break;
+ case 0xd9: /* VUSB_DEDICATED2 */
+ s->reg_data[addr] = value & 0x08;
+ break;
+
+ default:
+ fprintf(stderr, "%s: unknown register %02x value %0x pc %x\n",
+ __FUNCTION__, addr, value, cpu_single_env->regs[15]);
+ break;
+ }
+}
+
+static int twl4030_4b_tx(i2c_slave *i2c, uint8_t data)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+ /* Interpret register address byte */
+ if (s->firstbyte) {
+ s->reg = data;
+ s->firstbyte = 0;
+ } else
+ twl4030_4b_write(s, s->reg++, data);
+
+ return 1;
+}
+
+static int twl4030_4b_rx(i2c_slave *i2c)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+
+ return twl4030_4b_read(s, s->reg++);
+}
+
+static void twl4030_4b_reset(i2c_slave *i2c)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+ s->reg = 0x00;
+ memcpy(s->reg_data, addr_4b_reset_values, 256);
+ s->twl4030->key_cfg = 0;
+ s->twl4030->key_tst = 0;
+}
+
+static void twl4030_4b_event(i2c_slave *i2c, enum i2c_event event)
+{
+ struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;
+
+ if (event == I2C_START_SEND)
+ s->firstbyte = 1;
+}
+
+static void twl4030_save_state(QEMUFile *f, void *opaque)
+{
+ struct twl4030_s *s = (struct twl4030_s *)opaque;
+ int i;
+
+ qemu_put_sbe32(f, s->key_cfg);
+ qemu_put_sbe32(f, s->key_tst);
+ for (i = 0; i < 64; i++)
+ qemu_put_buffer(f, s->seq_mem[i], 4);
+ for (i = 0; i < 5; i++) {
+ qemu_put_sbe32(f, s->i2c[i]->firstbyte);
+ qemu_put_byte(f, s->i2c[i]->reg);
+ qemu_put_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
+ }
+}
+
+static int twl4030_load_state(QEMUFile *f, void *opaque, int version_id)
+{
+ struct twl4030_s *s = (struct twl4030_s *)opaque;
+ int i;
+
+ if (version_id)
+ return -EINVAL;
+
+ s->key_cfg = qemu_get_sbe32(f);
+ s->key_tst = qemu_get_sbe32(f);
+ for (i = 0; i < 64; i++)
+ qemu_get_buffer(f, s->seq_mem[i], 4);
+ for (i = 0; i < 5; i++) {
+ s->i2c[i]->firstbyte = qemu_get_sbe32(f);
+ s->i2c[i]->reg = qemu_get_byte(f);
+ qemu_get_buffer(f, s->i2c[i]->reg_data, sizeof(s->i2c[i]->reg_data));
+ }
+
+ return 0;
+}
+
+struct twl4030_s *twl4030_init(i2c_bus *bus, qemu_irq irq)
+{
+ int i;
+
+ struct twl4030_s *s = (struct twl4030_s *) qemu_mallocz(sizeof(*s));
+
+ for (i = 0; i < 5; i++) {
+ s->i2c[i]=(struct twl4030_i2c_s *)i2c_slave_init(
+ bus, 0, sizeof(struct twl4030_i2c_s));
+ s->i2c[i]->irq = irq;
+ s->i2c[i]->twl4030 = s;
+ }
+ s->i2c[0]->i2c.event = twl4030_48_event;
+ s->i2c[0]->i2c.recv = twl4030_48_rx;
+ s->i2c[0]->i2c.send = twl4030_48_tx;
+ twl4030_48_reset(&s->i2c[0]->i2c);
+ i2c_set_slave_address((i2c_slave *)&s->i2c[0]->i2c,0x48);
+
+ s->i2c[1]->i2c.event = twl4030_49_event;
+ s->i2c[1]->i2c.recv = twl4030_49_rx;
+ s->i2c[1]->i2c.send = twl4030_49_tx;
+ twl4030_49_reset(&s->i2c[1]->i2c);
+ i2c_set_slave_address((i2c_slave *)&s->i2c[1]->i2c,0x49);
+
+ s->i2c[2]->i2c.event = twl4030_4a_event;
+ s->i2c[2]->i2c.recv = twl4030_4a_rx;
+ s->i2c[2]->i2c.send = twl4030_4a_tx;
+ twl4030_4a_reset(&s->i2c[2]->i2c);
+ i2c_set_slave_address((i2c_slave *)&s->i2c[2]->i2c,0x4a);
+
+ s->i2c[3]->i2c.event = twl4030_4b_event;
+ s->i2c[3]->i2c.recv = twl4030_4b_rx;
+ s->i2c[3]->i2c.send = twl4030_4b_tx;
+ twl4030_4b_reset(&s->i2c[3]->i2c);
+ i2c_set_slave_address((i2c_slave *)&s->i2c[3]->i2c,0x4b);
+
+ register_savevm("twl4030", -1, 0,
+ twl4030_save_state, twl4030_load_state, s);
+
+ return s;
+}
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,
*/
#include "qemu-common.h"
#include "usb.h"
+#include "hw.h"
//#define DEBUG
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)
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,
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;
}
#include "qemu-timer.h"
#include "usb.h"
#include "irq.h"
+#include "hw.h"
/* Common USB registers */
#define MUSB_HDRC_FADDR 0x00 /* 8-bit */
#define MUSB_HDRC_INTRTX 0x02 /* 16-bit */
#define MUSB_HDRC_INTRRX 0x04
-#define MUSB_HDRC_INTRTXE 0x06
-#define MUSB_HDRC_INTRRXE 0x08
+#define MUSB_HDRC_INTRTXE 0x06
+#define MUSB_HDRC_INTRRXE 0x08
#define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */
#define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */
#define MUSB_HDRC_FRAME 0x0c /* 16-bit */
*/
/* POWER */
-#define MGC_M_POWER_ISOUPDATE 0x80
+#define MGC_M_POWER_ISOUPDATE 0x80
#define MGC_M_POWER_SOFTCONN 0x40
#define MGC_M_POWER_HSENAB 0x20
#define MGC_M_POWER_HSMODE 0x10
#define MGC_M_INTR_RESUME 0x02
#define MGC_M_INTR_RESET 0x04
#define MGC_M_INTR_BABBLE 0x04
-#define MGC_M_INTR_SOF 0x08
+#define MGC_M_INTR_SOF 0x08
#define MGC_M_INTR_CONNECT 0x10
#define MGC_M_INTR_DISCONNECT 0x20
#define MGC_M_INTR_SESSREQ 0x40
#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */
/* DEVCTL */
-#define MGC_M_DEVCTL_BDEVICE 0x80
+#define MGC_M_DEVCTL_BDEVICE 0x80
#define MGC_M_DEVCTL_FSDEV 0x40
#define MGC_M_DEVCTL_LSDEV 0x20
#define MGC_M_DEVCTL_VBUS 0x18
#define MGC_M_ULPI_REGCTL_COMPLETE 0x02
#define MGC_M_ULPI_REGCTL_REG 0x01
+/* #define MUSB_DEBUG */
+
+#ifdef MUSB_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+
static void musb_attach(USBPort *port, USBDevice *dev);
struct musb_s {
int setup_len;
int session;
- uint32_t buf[0x2000];
+ uint8_t buf[0x8000];
struct musb_ep_s {
uint16_t faddr[2];
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];
/* 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)
{
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;
}
/* 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)) {
/* 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;
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])
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 */
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;
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);
__FUNCTION__, value);
s->ep[ep].fifosize = value;
break;
-
default:
printf("%s: unknown register at %02x\n", __FUNCTION__, 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:
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;
{
struct musb_s *s = (struct musb_s *) opaque;
int ep;
+// TRACE("ADDR = 0x%08x = %08x", addr, value);
switch (addr) {
case MUSB_HDRC_FADDR:
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);
};
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:
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);
};
{
struct musb_s *s = (struct musb_s *) opaque;
int ep;
+ //TRACE("ADDR = 0x%08x = %08x", addr, value);
switch (addr) {
case MUSB_HDRC_INTRTXE:
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):
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);
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;
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);
};
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;
+}
#include "usb.h"
#include "pci.h"
#include "pxa.h"
+#include "omap.h"
//#define DEBUG_OHCI
/* Dump packet contents. */
enum ohci_type {
OHCI_TYPE_PCI,
- OHCI_TYPE_PXA
+ OHCI_TYPE_PXA,
+ OHCI_TYPE_OMAP
};
typedef struct {
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;
+}
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");
/* This is the Linux kernel elf-loading code, ported into user space */
+#include <sys/time.h>
+#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include "qemu.h"
#include "disas.h"
#undef ELF_ARCH
#endif
+#define ELF_OSABI ELFOSABI_SYSV
+
/* from personality.h */
/*
regs->rip = infop->entry;
}
-#else
+#define USE_ELF_CORE_DUMP
+
+typedef struct target_pt_regs elf_gregset_t;
+
+/*
+ * For register format that gdb uses, see <sys/reg.h>. These
+ * should be in same format (which is usually same as target_pt_regs).
+ */
+static void elf_core_copy_regs(elf_gregset_t *elfregs, const CPUState *env)
+{
+ (void) memset(elfregs, 0, sizeof (*elfregs));
+
+ /* GPRs */
+ elfregs->r15 = env->regs[15];
+ elfregs->r14 = env->regs[14];
+ elfregs->r13 = env->regs[13];
+ elfregs->r12 = env->regs[12];
+ elfregs->rbp = env->regs[R_EBP];
+ elfregs->rbx = env->regs[R_EBX];
+ elfregs->r11 = env->regs[11];
+ elfregs->r10 = env->regs[10];
+ elfregs->r9 = env->regs[9];
+ elfregs->r8 = env->regs[8];
+ elfregs->rax = env->regs[R_EAX];
+ elfregs->rcx = env->regs[R_ECX];
+ elfregs->rdx = env->regs[R_EDX];
+ elfregs->rsi = env->regs[R_ESI];
+ elfregs->rdi = env->regs[R_EDI];
+ elfregs->orig_rax = env->regs[R_EAX];
+ elfregs->rip = env->eip;
+ elfregs->rsp = env->regs[R_ESP];
+ elfregs->eflags = env->eflags;
+
+ /* segment registers */
+ elfregs->cs = env->segs[R_CS].selector;
+ elfregs->ss = env->segs[R_SS].selector;
+}
+
+#else /* !TARGET_X86_64 */
#define ELF_START_MMAP 0x80000000
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
}
#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
_regs->gpr[5] = pos;
}
-#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
regs->regs[29] = infop->start_stack;
}
-#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif /* TARGET_MIPS */
regs->regs[15] = infop->start_stack;
}
-#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
regs->erp = infop->entry;
}
-#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 8192
#endif
regs->pc = infop->entry;
}
-#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 8192
#endif
regs->unique, infop->start_data);
}
-#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 8192
#endif /* TARGET_ALPHA */
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
#endif
#undef NEW_AUX_ENT
+ info->saved_auxv = sp;
+
sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
return sp;
}
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;
info->entry = elf_entry;
+#ifdef USE_ELF_CORE_DUMP
+ bprm->core_dump = &elf_core_dump;
+#endif
+
+
return 0;
}
+#ifdef USE_ELF_CORE_DUMP
+
+/*
+ * Definitions to generate Intel SVR4-like core files.
+ * These mostly have the same names as the SVR4 types with "elf_"
+ * tacked on the front to prevent clashes with linux definitions,
+ * and the typedef forms have been avoided. This is mostly like
+ * the SVR4 structure, but more Linuxy, with things that Linux does
+ * not support and which gdb doesn't really use excluded.
+ *
+ * Fields we don't dump (their contents is zero) in linux-user qemu
+ * are marked with XXX.
+ *
+ * TODO: check that dumped field types are correct (e.g should we
+ * use abi_long or something else).
+ *
+ * Core dump code is copied from linux kernel (fs/binfmt_elf.c).
+ */
+
+/* An ELF note in memory */
+struct memelfnote {
+ const char *name;
+ size_t namesz;
+ size_t namesz_rounded;
+ int type;
+ size_t datasz;
+ void *data;
+ size_t notesz;
+};
+
+struct elf_siginfo {
+ int si_signo; /* signal number */
+ int si_code; /* extra code */
+ int si_errno; /* errno */
+};
+
+struct elf_prstatus {
+ struct elf_siginfo pr_info; /* Info associated with signal */
+ short pr_cursig; /* Current signal */
+ target_ulong pr_sigpend; /* XXX */
+ target_ulong pr_sighold; /* XXX */
+ int pr_pid;
+ int pr_ppid;
+ int pr_pgrp;
+ int pr_sid;
+ struct target_timeval pr_utime; /* XXX User time */
+ struct target_timeval pr_stime; /* XXX System time */
+ struct target_timeval pr_cutime; /* XXX Cumulative user time */
+ struct target_timeval pr_cstime; /* XXX Cumulative system time */
+ elf_gregset_t pr_reg; /* GP registers */
+ abi_long pr_fpvalid; /* XXX */
+};
+
+#define ELF_PRARGSZ (80) /* Number of chars for args */
+
+struct elf_prpsinfo {
+ char pr_state; /* numeric process state */
+ char pr_sname; /* char for pr_state */
+ char pr_zomb; /* zombie */
+ char pr_nice; /* nice val */
+ target_ulong pr_flag; /* flags */
+ short pr_uid;
+ short pr_gid;
+ abi_long pr_pid, pr_ppid, pr_pgrp, pr_sid;
+ /* Lots missing */
+ char pr_fname[16]; /* filename of executable */
+ char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+/* Here is the structure in which status of each thread is captured. */
+struct elf_thread_status {
+ TAILQ_ENTRY(elf_thread_status) ets_link;
+ struct elf_prstatus prstatus; /* NT_PRSTATUS */
+#if 0
+ elf_fpregset_t fpu; /* NT_PRFPREG */
+ struct task_struct *thread;
+ elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */
+#endif
+ struct memelfnote notes[1];
+ int num_notes;
+};
+
+struct elf_note_info {
+ struct memelfnote *notes;
+ struct elf_prstatus *prstatus; /* NT_PRSTATUS */
+ struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */
+
+ TAILQ_HEAD(thread_list_head, elf_thread_status) thread_list;
+#if 0
+ /*
+ * Current version of ELF coredump doesn't support
+ * dumping fp regs etc.
+ */
+ elf_fpregset_t *fpu;
+ elf_fpxregset_t *xfpu;
+ int thread_status_size;
+#endif
+ int notes_size;
+ int numnote;
+};
+
+struct vm_area_struct {
+ abi_ulong vma_start; /* start vaddr of memory region */
+ abi_ulong vma_end; /* end vaddr of memory region */
+ abi_ulong vma_flags; /* protection etc. flags for the region */
+ TAILQ_ENTRY(vm_area_struct) vma_link;
+};
+
+struct mm_struct {
+ TAILQ_HEAD(, vm_area_struct) mm_mmap;
+ int mm_count; /* number of mappings */
+};
+
+static struct mm_struct *vma_init(void);
+static void vma_delete(struct mm_struct *);
+static int vma_add_mapping(struct mm_struct *, abi_ulong,
+ abi_ulong, abi_ulong);
+static int vma_get_mapping_count(const struct mm_struct *);
+static struct vm_area_struct *vma_first(const struct mm_struct *);
+static struct vm_area_struct *vma_next(struct vm_area_struct *);
+static abi_ulong vma_dump_size(const struct vm_area_struct *);
+static int vma_walker(void *priv, unsigned long start, unsigned long end,
+ unsigned long flags);
+
+static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t);
+static void fill_note(struct memelfnote *, const char *, int,
+ unsigned int, void *);
+static void fill_prstatus(struct elf_prstatus *, const TaskState *, int);
+static int fill_psinfo(struct elf_prpsinfo *, const TaskState *);
+static void fill_auxv_note(struct memelfnote *, const TaskState *);
+static void fill_elf_note_phdr(struct elf_phdr *, int, off_t);
+static size_t note_size(const struct memelfnote *);
+static void free_note_info(struct elf_note_info *);
+static int fill_note_info(struct elf_note_info *, long, const CPUState *);
+static void fill_thread_info(struct elf_note_info *, const CPUState *);
+static int core_dump_filename(const TaskState *, char *, size_t);
+
+static int dump_write(int, const void *, size_t);
+static int write_note(struct memelfnote *, int);
+static int write_note_info(struct elf_note_info *, int);
+
+#ifdef BSWAP_NEEDED
+static void bswap_prstatus(struct elf_prstatus *);
+static void bswap_psinfo(struct elf_prpsinfo *);
+
+static void bswap_prstatus(struct elf_prstatus *prstatus)
+{
+ prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo);
+ prstatus->pr_info.si_code = tswapl(prstatus->pr_info.si_code);
+ prstatus->pr_info.si_errno = tswapl(prstatus->pr_info.si_errno);
+ prstatus->pr_cursig = tswap16(prstatus->pr_cursig);
+ prstatus->pr_sigpend = tswapl(prstatus->pr_sigpend);
+ prstatus->pr_sighold = tswapl(prstatus->pr_sighold);
+ prstatus->pr_pid = tswapl(prstatus->pr_pid);
+ prstatus->pr_ppid = tswapl(prstatus->pr_ppid);
+ prstatus->pr_pgrp = tswapl(prstatus->pr_pgrp);
+ prstatus->pr_sid = tswapl(prstatus->pr_sid);
+ /* cpu times are not filled, so we skip them */
+ /* regs should be in correct format already */
+ prstatus->pr_fpvalid = tswapl(prstatus->pr_fpvalid);
+}
+
+static void bswap_psinfo(struct elf_prpsinfo *psinfo)
+{
+ psinfo->pr_flag = tswapl(psinfo->pr_flag);
+ psinfo->pr_uid = tswap16(psinfo->pr_uid);
+ psinfo->pr_gid = tswap16(psinfo->pr_gid);
+ psinfo->pr_pid = tswapl(psinfo->pr_pid);
+ psinfo->pr_ppid = tswapl(psinfo->pr_ppid);
+ psinfo->pr_pgrp = tswapl(psinfo->pr_pgrp);
+ psinfo->pr_sid = tswapl(psinfo->pr_sid);
+}
+#endif /* BSWAP_NEEDED */
+
+/*
+ * Minimal support for linux memory regions. These are needed
+ * when we are finding out what memory exactly belongs to
+ * emulated process. No locks needed here, as long as
+ * thread that received the signal is stopped.
+ */
+
+static struct mm_struct *vma_init(void)
+{
+ struct mm_struct *mm;
+
+ if ((mm = qemu_malloc(sizeof (*mm))) == NULL)
+ return (NULL);
+
+ mm->mm_count = 0;
+ TAILQ_INIT(&mm->mm_mmap);
+
+ return (mm);
+}
+
+static void vma_delete(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma;
+
+ while ((vma = vma_first(mm)) != NULL) {
+ TAILQ_REMOVE(&mm->mm_mmap, vma, vma_link);
+ qemu_free(vma);
+ }
+ qemu_free(mm);
+}
+
+static int vma_add_mapping(struct mm_struct *mm, abi_ulong start,
+ abi_ulong end, abi_ulong flags)
+{
+ struct vm_area_struct *vma;
+
+ if ((vma = qemu_mallocz(sizeof (*vma))) == NULL)
+ return (-1);
+
+ vma->vma_start = start;
+ vma->vma_end = end;
+ vma->vma_flags = flags;
+
+ TAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link);
+ mm->mm_count++;
+
+ return (0);
+}
+
+static struct vm_area_struct *vma_first(const struct mm_struct *mm)
+{
+ return (TAILQ_FIRST(&mm->mm_mmap));
+}
+
+static struct vm_area_struct *vma_next(struct vm_area_struct *vma)
+{
+ return (TAILQ_NEXT(vma, vma_link));
+}
+
+static int vma_get_mapping_count(const struct mm_struct *mm)
+{
+ return (mm->mm_count);
+}
+
+/*
+ * Calculate file (dump) size of given memory region.
+ */
+static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
+{
+ /* if we cannot even read the first page, skip it */
+ if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
+ return (0);
+
+ /*
+ * Usually we don't dump executable pages as they contain
+ * non-writable code that debugger can read directly from
+ * target library etc. However, thread stacks are marked
+ * also executable so we read in first page of given region
+ * and check whether it contains elf header. If there is
+ * no elf header, we dump it.
+ */
+ if (vma->vma_flags & PROT_EXEC) {
+ char page[TARGET_PAGE_SIZE];
+
+ copy_from_user(page, vma->vma_start, sizeof (page));
+ if ((page[EI_MAG0] == ELFMAG0) &&
+ (page[EI_MAG1] == ELFMAG1) &&
+ (page[EI_MAG2] == ELFMAG2) &&
+ (page[EI_MAG3] == ELFMAG3)) {
+ /*
+ * Mappings are possibly from ELF binary. Don't dump
+ * them.
+ */
+ return (0);
+ }
+ }
+
+ return (vma->vma_end - vma->vma_start);
+}
+
+static int vma_walker(void *priv, unsigned long start, unsigned long end,
+ unsigned long flags)
+{
+ struct mm_struct *mm = (struct mm_struct *)priv;
+
+ /*
+ * Don't dump anything that qemu has reserved for internal use.
+ */
+ if (flags & PAGE_RESERVED)
+ return (0);
+
+ vma_add_mapping(mm, start, end, flags);
+ return (0);
+}
+
+static void fill_note(struct memelfnote *note, const char *name, int type,
+ unsigned int sz, void *data)
+{
+ unsigned int namesz;
+
+ namesz = strlen(name) + 1;
+ note->name = name;
+ note->namesz = namesz;
+ note->namesz_rounded = roundup(namesz, sizeof (int32_t));
+ note->type = type;
+ note->datasz = roundup(sz, sizeof (int32_t));;
+ note->data = data;
+
+ note->notesz = sizeof (struct elf_note) +
+ note->namesz_rounded + note->datasz;
+}
+
+static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine,
+ uint32_t flags)
+{
+ (void) memset(elf, 0, sizeof(*elf));
+
+ (void) memcpy(elf->e_ident, ELFMAG, SELFMAG);
+ elf->e_ident[EI_CLASS] = ELF_CLASS;
+ elf->e_ident[EI_DATA] = ELF_DATA;
+ elf->e_ident[EI_VERSION] = EV_CURRENT;
+ elf->e_ident[EI_OSABI] = ELF_OSABI;
+
+ elf->e_type = ET_CORE;
+ elf->e_machine = machine;
+ elf->e_version = EV_CURRENT;
+ elf->e_phoff = sizeof(struct elfhdr);
+ elf->e_flags = flags;
+ elf->e_ehsize = sizeof(struct elfhdr);
+ elf->e_phentsize = sizeof(struct elf_phdr);
+ elf->e_phnum = segs;
+
+#ifdef BSWAP_NEEDED
+ bswap_ehdr(elf);
+#endif
+}
+
+static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
+{
+ phdr->p_type = PT_NOTE;
+ phdr->p_offset = offset;
+ phdr->p_vaddr = 0;
+ phdr->p_paddr = 0;
+ phdr->p_filesz = sz;
+ phdr->p_memsz = 0;
+ phdr->p_flags = 0;
+ phdr->p_align = 0;
+
+#ifdef BSWAP_NEEDED
+ bswap_phdr(phdr);
+#endif
+}
+
+static size_t note_size(const struct memelfnote *note)
+{
+ return (note->notesz);
+}
+
+static void fill_prstatus(struct elf_prstatus *prstatus,
+ const TaskState *ts, int signr)
+{
+ (void) memset(prstatus, 0, sizeof (*prstatus));
+ prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
+ prstatus->pr_pid = ts->ts_tid;
+ prstatus->pr_ppid = getppid();
+ prstatus->pr_pgrp = getpgrp();
+ prstatus->pr_sid = getsid(0);
+
+#ifdef BSWAP_NEEDED
+ bswap_prstatus(prstatus);
+#endif
+}
+
+static int fill_psinfo(struct elf_prpsinfo *psinfo, const TaskState *ts)
+{
+ char *filename, *base_filename;
+ unsigned int i, len;
+
+ (void) memset(psinfo, 0, sizeof (*psinfo));
+
+ len = ts->info->arg_end - ts->info->arg_start;
+ if (len >= ELF_PRARGSZ)
+ len = ELF_PRARGSZ-1;
+ if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len))
+ return -EFAULT;
+ for(i = 0; i < len; i++)
+ if (psinfo->pr_psargs[i] == 0)
+ psinfo->pr_psargs[i] = ' ';
+ psinfo->pr_psargs[len] = 0;
+
+ psinfo->pr_pid = getpid();
+ psinfo->pr_ppid = getppid();
+ psinfo->pr_pgrp = getpgrp();
+ psinfo->pr_sid = getsid(0);
+ psinfo->pr_uid = getuid();
+ psinfo->pr_gid = getgid();
+
+ filename = strdup(ts->bprm->filename);
+ base_filename = strdup(basename(filename));
+ (void) strncpy(psinfo->pr_fname, base_filename,
+ sizeof(psinfo->pr_fname));
+
+ free(base_filename);
+ free(filename);
+
+#ifdef BSWAP_NEEDED
+ bswap_psinfo(psinfo);
+#endif
+ return (0);
+}
+
+static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
+{
+ elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
+ elf_addr_t orig_auxv = auxv;
+ abi_ulong val;
+ void *ptr;
+ int i, len;
+
+ /*
+ * Auxiliary vector is stored in target process stack. It contains
+ * {type, value} pairs that we need to dump into note. This is not
+ * strictly necessary but we do it here for sake of completeness.
+ */
+
+ /* find out lenght of the vector, AT_NULL is terminator */
+ i = len = 0;
+ do {
+ get_user_ual(val, auxv);
+ i += 2;
+ auxv += 2 * sizeof (elf_addr_t);
+ } while (val != AT_NULL);
+ len = i * sizeof (elf_addr_t);
+
+ /* read in whole auxv vector and copy it to memelfnote */
+ ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
+ if (ptr != NULL) {
+ fill_note(note, "CORE", NT_AUXV, len, ptr);
+ unlock_user(ptr, auxv, len);
+ }
+}
+
+/*
+ * Constructs name of coredump file. We have following convention
+ * for the name:
+ * qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
+ *
+ * Returns 0 in case of success, -1 otherwise (errno is set).
+ */
+static int core_dump_filename(const TaskState *ts, char *buf,
+ size_t bufsize)
+{
+ char timestamp[64];
+ char *filename = NULL;
+ char *base_filename = NULL;
+ struct timeval tv;
+ struct tm tm;
+
+ assert(bufsize >= PATH_MAX);
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ (void) fprintf(stderr, "unable to get current timestamp: %s",
+ strerror(errno));
+ return (-1);
+ }
+
+ /* XXX: use qemu_malloc() */
+ filename = strdup(ts->bprm->filename);
+ base_filename = strdup(basename(filename));
+
+ (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
+ localtime_r(&tv.tv_sec, &tm));
+ (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
+ base_filename, timestamp, (int)getpid());
+
+ free(base_filename);
+ free(filename);
+
+ return (0);
+}
+
+static int dump_write(int fd, const void *ptr, size_t size)
+{
+ const char *bufp = (const char *)ptr;
+ ssize_t bytes_written, bytes_left;
+
+ bytes_written = 0;
+ bytes_left = size;
+
+ /*
+ * In normal conditions, single write(2) should do but
+ * in case of socket etc. this mechanism is more portable.
+ */
+ do {
+ bytes_written = write(fd, bufp, bytes_left);
+ if (bytes_written < 0) {
+ if (errno == EINTR)
+ continue;
+ return (-1);
+ } else if (bytes_written == 0) { /* eof */
+ return (-1);
+ }
+ bufp += bytes_written;
+ bytes_left -= bytes_written;
+ } while (bytes_left > 0);
+
+ return (0);
+}
+
+static int write_note(struct memelfnote *men, int fd)
+{
+ struct elf_note en;
+
+ en.n_namesz = men->namesz;
+ en.n_type = men->type;
+ en.n_descsz = men->datasz;
+
+#ifdef BSWAP_NEEDED
+ bswap_note(&en);
+#endif
+
+ if (dump_write(fd, &en, sizeof(en)) != 0)
+ return (-1);
+ if (dump_write(fd, men->name, men->namesz_rounded) != 0)
+ return (-1);
+ if (dump_write(fd, men->data, men->datasz) != 0)
+ return (-1);
+
+ return (0);
+}
+
+static void fill_thread_info(struct elf_note_info *info, const CPUState *env)
+{
+ TaskState *ts = (TaskState *)env->opaque;
+ struct elf_thread_status *ets;
+
+ ets = qemu_mallocz(sizeof (*ets));
+ ets->num_notes = 1; /* only prstatus is dumped */
+ fill_prstatus(&ets->prstatus, ts, 0);
+ elf_core_copy_regs(&ets->prstatus.pr_reg, env);
+ fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus),
+ &ets->prstatus);
+
+ TAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link);
+
+ /* increase size of the note segment */
+ info->notes_size += note_size(&ets->notes[0]);
+}
+
+static int fill_note_info(struct elf_note_info *info,
+ long signr, const CPUState *env)
+{
+#define NUMNOTES 3
+ CPUState *cpu = NULL;
+ TaskState *ts = (TaskState *)env->opaque;
+ int i;
+
+ (void) memset(info, 0, sizeof (*info));
+
+ TAILQ_INIT(&info->thread_list);
+
+ info->notes = qemu_mallocz(NUMNOTES * sizeof (struct memelfnote));
+ if (info->notes == NULL)
+ return (-ENOMEM);
+ info->prstatus = qemu_mallocz(sizeof (*info->prstatus));
+ if (info->prstatus == NULL)
+ return (-ENOMEM);
+ info->psinfo = qemu_mallocz(sizeof (*info->psinfo));
+ if (info->prstatus == NULL)
+ return (-ENOMEM);
+
+ /*
+ * First fill in status (and registers) of current thread
+ * including process info & aux vector.
+ */
+ fill_prstatus(info->prstatus, ts, signr);
+ elf_core_copy_regs(&info->prstatus->pr_reg, env);
+ fill_note(&info->notes[0], "CORE", NT_PRSTATUS,
+ sizeof (*info->prstatus), info->prstatus);
+ fill_psinfo(info->psinfo, ts);
+ fill_note(&info->notes[1], "CORE", NT_PRPSINFO,
+ sizeof (*info->psinfo), info->psinfo);
+ fill_auxv_note(&info->notes[2], ts);
+ info->numnote = 3;
+
+ info->notes_size = 0;
+ for (i = 0; i < info->numnote; i++)
+ info->notes_size += note_size(&info->notes[i]);
+
+ /* read and fill status of all threads */
+ cpu_list_lock();
+ for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ if (cpu == thread_env)
+ continue;
+ fill_thread_info(info, cpu);
+ }
+ cpu_list_unlock();
+
+ return (0);
+}
+
+static void free_note_info(struct elf_note_info *info)
+{
+ struct elf_thread_status *ets;
+
+ while (!TAILQ_EMPTY(&info->thread_list)) {
+ ets = TAILQ_FIRST(&info->thread_list);
+ TAILQ_REMOVE(&info->thread_list, ets, ets_link);
+ qemu_free(ets);
+ }
+
+ qemu_free(info->prstatus);
+ qemu_free(info->psinfo);
+ qemu_free(info->notes);
+}
+
+static int write_note_info(struct elf_note_info *info, int fd)
+{
+ struct elf_thread_status *ets;
+ int i, error = 0;
+
+ /* write prstatus, psinfo and auxv for current thread */
+ for (i = 0; i < info->numnote; i++)
+ if ((error = write_note(&info->notes[i], fd)) != 0)
+ return (error);
+
+ /* write prstatus for each thread */
+ for (ets = info->thread_list.tqh_first; ets != NULL;
+ ets = ets->ets_link.tqe_next) {
+ if ((error = write_note(&ets->notes[0], fd)) != 0)
+ return (error);
+ }
+
+ return (0);
+}
+
+/*
+ * Write out ELF coredump.
+ *
+ * See documentation of ELF object file format in:
+ * http://www.caldera.com/developers/devspecs/gabi41.pdf
+ *
+ * Coredump format in linux is following:
+ *
+ * 0 +----------------------+ \
+ * | ELF header | ET_CORE |
+ * +----------------------+ |
+ * | ELF program headers | |--- headers
+ * | - NOTE section | |
+ * | - PT_LOAD sections | |
+ * +----------------------+ /
+ * | NOTEs: |
+ * | - NT_PRSTATUS |
+ * | - NT_PRSINFO |
+ * | - NT_AUXV |
+ * +----------------------+ <-- aligned to target page
+ * | Process memory dump |
+ * : :
+ * . .
+ * : :
+ * | |
+ * +----------------------+
+ *
+ * NT_PRSTATUS -> struct elf_prstatus (per thread)
+ * NT_PRSINFO -> struct elf_prpsinfo
+ * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()).
+ *
+ * Format follows System V format as close as possible. Current
+ * version limitations are as follows:
+ * - no floating point registers are dumped
+ *
+ * Function returns 0 in case of success, negative errno otherwise.
+ *
+ * TODO: make this work also during runtime: it should be
+ * possible to force coredump from running process and then
+ * continue processing. For example qemu could set up SIGUSR2
+ * handler (provided that target process haven't registered
+ * handler for that) that does the dump when signal is received.
+ */
+static int elf_core_dump(int signr, const CPUState *env)
+{
+ const TaskState *ts = (const TaskState *)env->opaque;
+ struct vm_area_struct *vma = NULL;
+ char corefile[PATH_MAX];
+ struct elf_note_info info;
+ struct elfhdr elf;
+ struct elf_phdr phdr;
+ struct mm_struct *mm = NULL;
+ off_t offset = 0, data_offset = 0;
+ int segs = 0;
+ int fd = -1;
+
+ errno = 0;
+
+ if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
+ return (-errno);
+
+ if ((fd = open(corefile, O_WRONLY | O_CREAT,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
+ return (-errno);
+
+ /*
+ * Walk through target process memory mappings and
+ * set up structure containing this information. After
+ * this point vma_xxx functions can be used.
+ */
+ if ((mm = vma_init()) == NULL)
+ goto out;
+
+ walk_memory_regions(mm, vma_walker);
+ segs = vma_get_mapping_count(mm);
+
+ /*
+ * Construct valid coredump ELF header. We also
+ * add one more segment for notes.
+ */
+ fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0);
+ if (dump_write(fd, &elf, sizeof (elf)) != 0)
+ goto out;
+
+ /* fill in in-memory version of notes */
+ if (fill_note_info(&info, signr, env) < 0)
+ goto out;
+
+ offset += sizeof (elf); /* elf header */
+ offset += (segs + 1) * sizeof (struct elf_phdr); /* program headers */
+
+ /* write out notes program header */
+ fill_elf_note_phdr(&phdr, info.notes_size, offset);
+
+ offset += info.notes_size;
+ if (dump_write(fd, &phdr, sizeof (phdr)) != 0)
+ goto out;
+
+ /*
+ * ELF specification wants data to start at page boundary so
+ * we align it here.
+ */
+ offset = roundup(offset, ELF_EXEC_PAGESIZE);
+
+ /*
+ * Write program headers for memory regions mapped in
+ * the target process.
+ */
+ for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
+ (void) memset(&phdr, 0, sizeof (phdr));
+
+ phdr.p_type = PT_LOAD;
+ phdr.p_offset = offset;
+ phdr.p_vaddr = vma->vma_start;
+ phdr.p_paddr = 0;
+ phdr.p_filesz = vma_dump_size(vma);
+ offset += phdr.p_filesz;
+ phdr.p_memsz = vma->vma_end - vma->vma_start;
+ phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0;
+ if (vma->vma_flags & PROT_WRITE)
+ phdr.p_flags |= PF_W;
+ if (vma->vma_flags & PROT_EXEC)
+ phdr.p_flags |= PF_X;
+ phdr.p_align = ELF_EXEC_PAGESIZE;
+
+ dump_write(fd, &phdr, sizeof (phdr));
+ }
+
+ /*
+ * Next we write notes just after program headers. No
+ * alignment needed here.
+ */
+ if (write_note_info(&info, fd) < 0)
+ goto out;
+
+ /* align data to page boundary */
+ data_offset = lseek(fd, 0, SEEK_CUR);
+ data_offset = TARGET_PAGE_ALIGN(data_offset);
+ if (lseek(fd, data_offset, SEEK_SET) != data_offset)
+ goto out;
+
+ /*
+ * Finally we can dump process memory into corefile as well.
+ */
+ for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) {
+ abi_ulong addr;
+ abi_ulong end;
+
+ end = vma->vma_start + vma_dump_size(vma);
+
+ for (addr = vma->vma_start; addr < end;
+ addr += TARGET_PAGE_SIZE) {
+ char page[TARGET_PAGE_SIZE];
+ int error;
+
+ /*
+ * Read in page from target process memory and
+ * write it to coredump file.
+ */
+ error = copy_from_user(page, addr, sizeof (page));
+ if (error != 0) {
+ (void) fprintf(stderr, "unable to dump " TARGET_FMT_lx "\n",
+ addr);
+ errno = -error;
+ goto out;
+ }
+ if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0)
+ goto out;
+ }
+ }
+
+out:
+ free_note_info(&info);
+ if (mm != NULL)
+ vma_delete(mm);
+ (void) close(fd);
+
+ if (errno != 0)
+ return (-errno);
+ return (0);
+}
+
+#endif /* USE_ELF_CORE_DUMP */
+
static int load_aout_interp(void * exptr, int interp_fd)
{
printf("a.out interpreter not yet supported\n");
#define __USER_DS (0x2B)
struct target_pt_regs {
- long ebx;
- long ecx;
- long edx;
- long esi;
- long edi;
- long ebp;
- long eax;
- int xds;
- int xes;
- long orig_eax;
- long eip;
- int xcs;
- long eflags;
- long esp;
- int xss;
+ abi_ulong ebx;
+ abi_ulong ecx;
+ abi_ulong edx;
+ abi_ulong esi;
+ abi_ulong edi;
+ abi_ulong ebp;
+ abi_ulong eax;
+ abi_ulong xds;
+ abi_ulong xes;
+ abi_ulong xfs;
+ abi_ulong xgs;
+ abi_ulong orig_eax;
+ abi_ulong eip;
+ abi_ulong xcs;
+ abi_ulong eflags;
+ abi_ulong esp;
+ abi_ulong xss;
};
/* ioctls */
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
abi_ulong stringp, int push_ptr)
{
+ TaskState *ts = (TaskState *)thread_env->opaque;
int n = sizeof(abi_ulong);
abi_ulong envp;
abi_ulong argv;
sp -= n;
/* FIXME - handle put_user() failures */
put_user_ual(argc, sp);
-
+ ts->info->arg_start = stringp;
while (argc-- > 0) {
/* FIXME - handle put_user() failures */
put_user_ual(stringp, argv);
argv += n;
stringp += target_strlen(stringp) + 1;
}
+ ts->info->arg_end = stringp;
/* FIXME - handle put_user() failures */
put_user_ual(0, argv);
while (envc-- > 0) {
}
int loader_exec(const char * filename, char ** argv, char ** envp,
- struct target_pt_regs * regs, struct image_info *infop)
+ struct target_pt_regs * regs, struct image_info *infop,
+ struct linux_binprm *bprm)
{
- struct linux_binprm bprm;
int retval;
int i;
- bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
+ bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- bprm.page[i] = 0;
+ bprm->page[i] = 0;
retval = open(filename, O_RDONLY);
if (retval < 0)
return retval;
- bprm.fd = retval;
- bprm.filename = (char *)filename;
- bprm.argc = count(argv);
- bprm.argv = argv;
- bprm.envc = count(envp);
- bprm.envp = envp;
+ bprm->fd = retval;
+ bprm->filename = (char *)filename;
+ bprm->argc = count(argv);
+ bprm->argv = argv;
+ bprm->envc = count(envp);
+ bprm->envp = envp;
- retval = prepare_binprm(&bprm);
+ retval = prepare_binprm(bprm);
infop->host_argv = argv;
if(retval>=0) {
- if (bprm.buf[0] == 0x7f
- && bprm.buf[1] == 'E'
- && bprm.buf[2] == 'L'
- && bprm.buf[3] == 'F') {
+ if (bprm->buf[0] == 0x7f
+ && bprm->buf[1] == 'E'
+ && bprm->buf[2] == 'L'
+ && bprm->buf[3] == 'F') {
#ifndef TARGET_HAS_ELFLOAD32
- retval = load_elf_binary(&bprm,regs,infop);
+ retval = load_elf_binary(bprm,regs,infop);
#else
- retval = load_elf_binary_multi(&bprm, regs, infop);
+ retval = load_elf_binary_multi(bprm, regs, infop);
#endif
#if defined(TARGET_HAS_BFLT)
- } else if (bprm.buf[0] == 'b'
- && bprm.buf[1] == 'F'
- && bprm.buf[2] == 'L'
- && bprm.buf[3] == 'T') {
- retval = load_flt_binary(&bprm,regs,infop);
+ } else if (bprm->buf[0] == 'b'
+ && bprm->buf[1] == 'F'
+ && bprm->buf[2] == 'L'
+ && bprm->buf[3] == 'T') {
+ retval = load_flt_binary(bprm,regs,infop);
#endif
} else {
fprintf(stderr, "Unknown binary format\n");
/* Something went wrong, return the inode and free the argument pages*/
for (i=0 ; i<MAX_ARG_PAGES ; i++) {
- free(bprm.page[i]);
+ free(bprm->page[i]);
}
return(retval);
}
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
+#include <sys/syscall.h>
#include "qemu.h"
#include "qemu-common.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
-char *exec_path;
+const char *exec_path;
+
+#if defined(CONFIG_USE_GUEST_BASE)
+unsigned long mmap_min_addr = 0;
+unsigned long guest_base = 0;
+#endif
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
- exit (1);
+ _exit (1);
}
process_pending_signals (env);
}
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
- exit (1);
+ _exit (1);
}
process_pending_signals (env);
}
"-drop-ld-preload drop LD_PRELOAD for target process\n"
"-E var=value sets/modifies targets environment variable(s)\n"
"-U var unsets targets environment variable(s)\n"
+ "-0 argv0 forces target process argv[0] to be argv0\n"
+#if defined(CONFIG_USE_GUEST_BASE)
+ "-B address set guest_base address to address\n"
+#endif
"\n"
"Debug options:\n"
"-d options activate log (logfile=%s)\n"
"Environment variables:\n"
"QEMU_STRACE Print system calls and arguments similar to the\n"
" 'strace' program. Enable by setting to any value.\n"
+ "\n"
"You can use -E and -U options to set/unset environment variables\n"
"for target process. It is possible to provide several variables\n"
"by repeating the option. For example:\n"
" -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
"Note that if you provide several changes to single variable\n"
"last change will stay in effect.\n"
+#if defined(CONFIG_USE_GUEST_BASE)
+ "\n"
+ "You can use -B option to load target binary into different\n"
+ "address that is specified in elf headers. This can be useful\n"
+ "when target binary would be loaded to low addresses and\n"
+ "/proc/sys/vm/mmap_min_addr is set to higher. For example\n"
+ " qemu-" TARGET_ARCH " -B 0x100000 ...\n"
+ "loads target binary starting from the first meg.\n"
+#endif
,
TARGET_ARCH,
interp_prefix,
THREAD CPUState *thread_env;
+void task_settid(TaskState *ts)
+{
+ if (ts->ts_tid == 0) {
+#ifdef USE_NPTL
+ ts->ts_tid = (pid_t)syscall(SYS_gettid);
+#else
+ /* when no threads are used, tid becomes pid */
+ ts->ts_tid = getpid();
+#endif
+ }
+}
+
+void stop_all_tasks(void)
+{
+ /*
+ * We trust that when using NPTL, start_exclusive()
+ * handles thread stopping correctly. Note that there
+ * is no way out of this state as we don't provide
+ * any suspend routine.
+ */
+ start_exclusive();
+}
+
/* Assumes contents are already zeroed. */
void init_task_state(TaskState *ts)
{
int main(int argc, char **argv, char **envp)
{
- const char *filename;
+ const char *filename = NULL;
const char *cpu_model;
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
+ struct linux_binprm bprm;
TaskState ts1, *ts = &ts1;
CPUState *env;
int optind;
const char *r;
int gdbstub_port = 0;
char **target_environ, **wrk;
+ char **target_argv;
+ int target_argc;
+ int drop_ld_preload = 0;
envlist_t *envlist = NULL;
+ const char *argv0 = NULL;
+ int argskip = 0;
+ int i;
if (argc <= 1)
usage();
for(item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
- exit(1);
+ _exit(1);
}
cpu_set_log(mask);
} else if (!strcmp(r, "E")) {
r = argv[optind++];
if (envlist_unsetenv(envlist, r) != 0)
usage();
+ } else if (!strcmp(r, "0")) {
+ r = argv[optind++];
+ argv0 = r;
+ } else if (!strcmp(r,"-sbox-call")) {
+ argskip++;
} else if (!strcmp(r, "s")) {
if (optind >= argc)
break;
if (qemu_host_page_size == 0 ||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
fprintf(stderr, "page size must be a power of two\n");
- exit(1);
+ _exit(1);
}
} else if (!strcmp(r, "g")) {
if (optind >= argc)
#endif
exit(1);
}
+#if defined(CONFIG_USE_GUEST_BASE)
+ } else if (!strcmp(r, "B")) {
+ guest_base = strtol(argv[optind++], NULL, 0);
+#endif
} else if (!strcmp(r, "drop-ld-preload")) {
- (void) envlist_unsetenv(envlist, "LD_PRELOAD");
+ drop_ld_preload = 1;
+ } else if (!strcmp(r, "keep-ld-preload")) {
+ drop_ld_preload = 0;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
} else
}
if (optind >= argc)
usage();
- filename = argv[optind];
- exec_path = argv[optind];
+ if (filename == NULL) {
+ filename = argv[optind];
+ exec_path = argv[optind];
+ } else {
+ argv0 = argv[optind];
+ }
+ if (drop_ld_preload) {
+ (void) envlist_unsetenv(envlist, "LD_PRELOAD");
+ }
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
/* Zero out image_info */
memset(info, 0, sizeof(struct image_info));
+ memset(&bprm, 0, sizeof (bprm));
+
/* Scan interp_prefix dir for replacement files. */
init_paths(interp_prefix);
cpu_model = "qemu32";
#endif
#elif defined(TARGET_ARM)
- cpu_model = "arm926";
+ cpu_model = "any";
#elif defined(TARGET_M68K)
cpu_model = "any";
#elif defined(TARGET_SPARC)
target_environ = envlist_to_environ(envlist, NULL);
envlist_free(envlist);
- if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+#if defined(CONFIG_USE_GUEST_BASE)
+ /*
+ * Now that page sizes are configured in cpu_init() we can do
+ * proper page alignment for guest_base.
+ */
+ guest_base = HOST_PAGE_ALIGN(guest_base);
+
+ /*
+ * Read in mmap_min_addr kernel parameter and check
+ * whether it is set to some value > 0. This value is used
+ * later on when doing mmap(2)s to calculate where guest_base
+ * is to set, if needed.
+ *
+ * When user has explicitly set the quest base, we skip this
+ * test.
+ */
+ if (guest_base == 0) {
+ FILE *fp;
+
+ if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
+ unsigned long tmp;
+ if (fscanf(fp, "%lu", &tmp) == 1) {
+ mmap_min_addr = tmp;
+ qemu_log("kernel mmap_min_addr=%lu\n", mmap_min_addr);
+ }
+ fclose(fp);
+ }
+ }
+#endif /* CONFIG_USE_GUEST_BASE */
+
+ /*
+ * Prepare copy of argv vector for target.
+ */
+ target_argc = argc - optind;
+ target_argv = calloc(target_argc + 1, sizeof (char *));
+ if (target_argv == NULL) {
+ (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
+ exit(1);
+ }
+
+ /*
+ * If argv0 is specified (using '-0' switch) we replace
+ * argv[0] pointer with the given one.
+ */
+ i = 0;
+ if (argv0 != NULL) {
+ target_argv[i++] = strdup(argv0);
+ }
+ for (; i < target_argc; i++) {
+ target_argv[i] = strdup(argv[optind + i]);
+ }
+ target_argv[target_argc] = NULL;
+
+ memset(ts, 0, sizeof(TaskState));
+ init_task_state(ts);
+ /* build Task State */
+ env->opaque = ts;
+ ts->bprm = &bprm;
+ ts->info = info;
+ task_settid(ts);
+
+ if (loader_exec(filename, target_argv+argskip, target_environ, regs,
+ info, &bprm) != 0) {
printf("Error loading %s\n", filename);
_exit(1);
}
+ for (i = 0; i < target_argc; i++) {
+ free(target_argv[i]);
+ }
+ free(target_argv);
+
for (wrk = target_environ; *wrk; wrk++) {
free(*wrk);
}
free(target_environ);
if (qemu_log_enabled()) {
+#if defined(CONFIG_USE_GUEST_BASE)
+ if (guest_base > 0) {
+ qemu_log("guest_base is set to 0x%lx\n", guest_base);
+ qemu_log(
+ "==========================================================\n"
+ "Note that all target addresses below are given in target\n"
+ "address space which is different from host by guest_base.\n"
+ "For example: target address 0x%x becomes 0x%x and so on.\n"
+ "==========================================================\n",
+ (uintptr_t)0x8000, (uintptr_t)g2h(0x8000));
+ }
+#endif
log_page_dump();
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
syscall_init();
signal_init();
- /* build Task State */
- memset(ts, 0, sizeof(TaskState));
- init_task_state(ts);
- ts->info = info;
- env->opaque = ts;
-
#if defined(TARGET_I386)
cpu_x86_set_cpl(env, 3);
unsigned long last_brk;
-/* find a free memory area of size 'size'. The search starts at
- 'start'. If 'start' == 0, then a default start address is used.
- Return -1 if error.
-*/
-/* page_init() marks pages used by the host as reserved to be sure not
- to use them. */
-static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+/*
+ * Find and reserve a free memory area of size 'size'. The search
+ * starts at 'start'.
+ * It must be called with mmap_lock() held.
+ * Return -1 if error.
+ */
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
{
- abi_ulong addr, addr1, addr_start;
- int prot;
- unsigned long new_brk;
-
- new_brk = (unsigned long)sbrk(0);
- if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
- /* This is a hack to catch the host allocating memory with brk().
- If it uses mmap then we loose.
- FIXME: We really want to avoid the host allocating memory in
- the first place, and maybe leave some slack to avoid switching
- to mmap. */
- page_set_flags(last_brk & TARGET_PAGE_MASK,
- TARGET_PAGE_ALIGN(new_brk),
- PAGE_RESERVED);
- }
- last_brk = new_brk;
+ void *ptr;
+ abi_ulong addr;
size = HOST_PAGE_ALIGN(size);
- start = start & qemu_host_page_mask;
+ start &= qemu_host_page_mask;
+
+ /* If 'start' == 0, then a default start address is used. */
+ if (start == 0)
+ start = mmap_next_start;
+
addr = start;
- if (addr == 0)
- addr = mmap_next_start;
- addr_start = addr;
+
for(;;) {
- prot = 0;
- for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
- prot |= page_get_flags(addr1);
- }
- if (prot == 0)
+ /*
+ * Reserve needed memory area to avoid a race.
+ * It should be discarded using:
+ * - mmap() with MAP_FIXED flag
+ * - mremap() with MREMAP_FIXED flag
+ * - shmat() with SHM_REMAP flag
+ */
+ ptr = mmap((void *)(unsigned long)addr, size, PROT_NONE,
+ MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+
+ /* ENOMEM, if host address space has no memory */
+ if (ptr == MAP_FAILED)
+ return (abi_ulong)-1;
+
+ /* If address fits target address space we've found what we need */
+ if ((unsigned long)ptr + size - 1 <= (abi_ulong)-1)
break;
+
+ /* Unmap and try again with new page */
+ munmap(ptr, size);
addr += qemu_host_page_size;
- /* we found nothing */
- if (addr == addr_start)
+
+ /* ENOMEM if we check whole of target address space */
+ if (addr == start)
return (abi_ulong)-1;
}
- if (start == 0)
- mmap_next_start = addr + size;
- return addr;
+
+ /* Update default start address */
+ if (start == mmap_next_start)
+ mmap_next_start = (unsigned long)ptr + size;
+
+ return h2g(ptr);
}
/* NOTE: all the constants are the HOST ones */
The assumption is that this area does not change.
*/
#include <sys/types.h>
+#include <assert.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#define streq(a,b) (strcmp((a), (b)) == 0)
+/*
+ * Checks whether directory entry (dent) is valid. This
+ * means that symlinks pointing to '.' and '..' should
+ * be skipped by main recursion code. Returns 1 when
+ * entry is valid.
+ */
+static int
+is_dentry_valid(const char *path, const struct dirent *dent)
+{
+ char fullpath[PATH_MAX];
+ char linkbuf[PATH_MAX];
+ ssize_t len;
+
+ assert(path != NULL);
+ assert(dent != NULL);
+
+ if (dent->d_type != DT_LNK)
+ return (1);
+
+ (void) snprintf(fullpath, sizeof (fullpath), "%s/%s",
+ path, dent->d_name);
+
+ if ((len = readlink(fullpath, linkbuf, sizeof (linkbuf) - 1)) != -1) {
+ linkbuf[len] = '\0';
+ if (streq(linkbuf, ".") || streq(linkbuf, ".."))
+ return (0);
+ }
+
+ return (1);
+}
+
+/* TODO: add recursion count check */
static struct pathelem *add_dir_maybe(struct pathelem *path)
{
DIR *dir;
while ((dirent = readdir(dir)) != NULL) {
if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
- path = add_entry(path, dirent->d_name);
+ if (is_dentry_valid(path->pathname, dirent)) {
+ path = add_entry(path, dirent->d_name);
+ }
}
}
closedir(dir);
#ifndef QEMU_H
#define QEMU_H
+#include <sys/queue.h>
+
#include <signal.h>
#include <string.h>
abi_ulong entry;
abi_ulong code_offset;
abi_ulong data_offset;
+ abi_ulong saved_auxv;
+ abi_ulong arg_start;
+ abi_ulong arg_end;
char **host_argv;
int personality;
};
first signal, we put it here */
};
+struct process;
+
/* NOTE: we force a big alignment so that the stack stored after is
aligned too */
typedef struct TaskState {
- struct TaskState *next;
+ pid_t ts_tid; /* tid (or pid) of this task */
#ifdef TARGET_ARM
/* FPA state */
FPA11 fpa;
#endif
int used; /* non zero if used */
struct image_info *info;
+ struct linux_binprm *bprm;
struct emulated_sigtable sigtab[TARGET_NSIG];
struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
struct sigqueue *first_free; /* first free siginfo queue entry */
int signal_pending; /* non zero if a signal may be pending */
- uint8_t stack[0];
+ uint8_t stack[];
} __attribute__((aligned(16))) TaskState;
-extern char *exec_path;
+extern const char *exec_path;
void init_task_state(TaskState *ts);
+extern void task_settid(TaskState *);
+extern void stop_all_tasks(void);
extern const char *qemu_uname_release;
+#if defined(CONFIG_USE_GUEST_BASE)
+extern unsigned long mmap_min_addr;
+#endif
/* ??? See if we can avoid exposing so much of the loader internals. */
/*
char **argv;
char **envp;
char * filename; /* Name of binary */
+ int (*core_dump)(int, const CPUState *); /* coredump routine */
};
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
abi_ulong stringp, int push_ptr);
int loader_exec(const char * filename, char ** argv, char ** envp,
- struct target_pt_regs * regs, struct image_info *infop);
+ struct target_pt_regs * regs, struct image_info *infop,
+ struct linux_binprm *);
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info);
#include <unistd.h>
#include <signal.h>
#include <errno.h>
+#include <assert.h>
#include <sys/ucontext.h>
#include "qemu.h"
}
}
+/* returns 1 if given signal should dump core if not handled */
+static int core_dump_signal(int sig)
+{
+ switch (sig) {
+ case TARGET_SIGABRT:
+ case TARGET_SIGFPE:
+ case TARGET_SIGILL:
+ case TARGET_SIGQUIT:
+ case TARGET_SIGSEGV:
+ case TARGET_SIGTRAP:
+ case TARGET_SIGBUS:
+ return (1);
+ default:
+ return (0);
+ }
+}
+
void signal_init(void)
{
struct sigaction act;
/* abort execution with signal */
static void QEMU_NORETURN force_sig(int sig)
{
- int host_sig;
+ TaskState *ts = (TaskState *)thread_env->opaque;
+ int host_sig, core_dumped = 0;
+ struct sigaction act;
host_sig = target_to_host_signal(sig);
- fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
- sig, strsignal(host_sig));
-#if 1
gdb_signalled(thread_env, sig);
- _exit(-host_sig);
-#else
- {
- struct sigaction act;
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_SIGINFO;
- act.sa_sigaction = SIG_DFL;
- sigaction(SIGABRT, &act, NULL);
- abort();
+
+ /* dump core if supported by target binary format */
+ if (core_dump_signal(sig) && (ts->bprm->core_dump != NULL)) {
+ stop_all_tasks();
+ core_dumped =
+ ((*ts->bprm->core_dump)(sig, thread_env) == 0);
}
-#endif
+
+ (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
+ sig, strsignal(host_sig),
+ ((core_dumped) ? "core dumped" : "exiting"));
+
+ /* The proper exit code for dieing from an uncaught signal is
+ * -<signal>. The kernel doesn't allow exit() or _exit() to pass
+ * a negative value. To get the proper exit code we need to
+ * actually die from an uncaught signal. Here the default signal
+ * handler is installed, we send ourself a signal and we wait for
+ * it to arrive. */
+ sigfillset(&act.sa_mask);
+ act.sa_handler = SIG_DFL;
+ sigaction(host_sig, &act, NULL);
+
+ /* For some reason raise(host_sig) doesn't send the signal when
+ * statically linked on x86-64. */
+ kill(getpid(), host_sig);
+
+ /* Make sure the signal isn't masked (just reuse the mask inside
+ of act) */
+ sigdelset(&act.sa_mask, host_sig);
+ sigsuspend(&act.sa_mask);
+
+ /* unreachable */
+ assert(0);
+
}
/* queue a signal so that it will be send to the virtual CPU as soon
}
#endif
+#define LOCKED_ARG0 (1 << 0)
+#define LOCKED_ARG1 (1 << 1)
+#define LOCKED_ARG2 (1 << 2)
+#define LOCKED_ARG3 (1 << 3)
+#define LOCKED_ARG4 (1 << 4)
+#define LOCKED_ARG5 (1 << 5)
+
+struct args {
+ abi_long arg_guest; /* guest argument */
+ uintptr_t arg_host; /* host argument */
+ int arg_locked; /* is this argument locked? */
+};
+
+/*
+ * This function locks strings from guest memory and prints
+ * strace output according to format specified in strace.list.
+ *
+ * First parameter specifies, which guest arguments should be
+ * locked (LOCKED_ARG0 - LOCKED_ARG5).
+ */
+static void
+print_locked(unsigned int locked, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ struct args args[6] = {
+ { arg0, 0, (locked & LOCKED_ARG0) },
+ { arg1, 0, (locked & LOCKED_ARG1) },
+ { arg2, 0, (locked & LOCKED_ARG2) },
+ { arg3, 0, (locked & LOCKED_ARG3) },
+ { arg4, 0, (locked & LOCKED_ARG4) },
+ { arg5, 0, (locked & LOCKED_ARG5) },
+ };
+ struct args *a;
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ a = &args[i];
+ if (a->arg_locked) {
+ a->arg_host = (uintptr_t)lock_user_string(a->arg_guest);
+ if (a->arg_host == 0)
+ goto out;
+ } else {
+ a->arg_host = (uintptr_t)a->arg_guest;
+ }
+ }
+
+ /*
+ * Now we can have all strings locked and converted into host
+ * addresses.
+ */
+ gemu_log(name->format,
+ name->name,
+ args[0].arg_host,
+ args[1].arg_host,
+ args[2].arg_host,
+ args[3].arg_host,
+ args[4].arg_host,
+ args[5].arg_host);
+
+out:
+ for (i = 0; i < 6; i++) {
+ a = &args[i];
+ if (a->arg_locked)
+ unlock_user((void *)a->arg_host, a->arg_guest, 0);
+ }
+}
+
+static void
+print_1st_locked(const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_locked(LOCKED_ARG0, name, arg0, arg1, arg2, arg3, arg4, arg5);
+}
+
+static void
+print_2nd_locked(const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_locked(LOCKED_ARG1, name, arg0, arg1, arg2, arg3, arg4, arg5);
+}
+
+static void
+print_1st_and_2nd_locked(const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_locked(LOCKED_ARG0 | LOCKED_ARG1, name, arg0, arg1, arg2,
+ arg3, arg4, arg5);
+}
+
+static void
+print_1st_and_3rd_locked(const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_locked(LOCKED_ARG0 | LOCKED_ARG2, name, arg0, arg1, arg2,
+ arg3, arg4, arg5);
+}
+
+static void
+print_1st_2nd_and_3rd_locked(const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_locked(LOCKED_ARG0 | LOCKED_ARG1 | LOCKED_ARG2, name,
+ arg0, arg1, arg2, arg3, arg4, arg5);
+}
+
+static void
+print_2nd_and_4th_locked(const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_locked(LOCKED_ARG1 | LOCKED_ARG3, name, arg0, arg1, arg2,
+ arg3, arg4, arg5);
+}
+
+/*
+ * Here is list of syscalls that we support reading in (locking)
+ * strings from guest addresses. Every syscall that has "%s" in its
+ * parameter list and doesn't have specific print function, should
+ * be defined here.
+ */
+#define print_access print_1st_locked
+#define print_chdir print_1st_locked
+#define print_chmod print_1st_locked
+#define print_creat print_1st_locked
+#define print_execv print_1st_locked
+#define print_faccessat print_2nd_locked
+#define print_fchmodat print_2nd_locked
+#define print_fchown print_1st_locked
+#define print_fchownat print_2nd_locked
+#define print_futimesat print_2nd_locked
+#define print_link print_1st_and_2nd_locked
+#define print_linkat print_2nd_and_4th_locked
+#define print_lstat print_1st_locked
+#define print_lstat64 print_1st_locked
+#define print_mkdir print_1st_locked
+#define print_mkdirat print_2nd_locked
+#define print_mknod print_1st_locked
+#define print_mknodat print_2nd_locked
+#define print_mq_open print_1st_locked
+#define print_mq_unlink print_1st_locked
+#define print_fstatat64 print_2nd_locked
+#define print_newfstatat print_2nd_locked
+#define print_open print_1st_locked
+#define print_openat print_2nd_locked
+#define print_readlink print_1st_locked
+#define print_readlinkat print_2nd_locked
+#define print_rename print_1st_and_2nd_locked
+#define print_renameat print_2nd_and_4th_locked
+#define print_stat print_1st_locked
+#define print_stat64 print_1st_locked
+#define print_statfs print_1st_locked
+#define print_statfs64 print_1st_locked
+#define print_symlink print_1st_and_2nd_locked
+#define print_symlinkat print_1st_and_3rd_locked
+#define print_umount print_1st_2nd_and_3rd_locked
+#define print_unlink print_1st_locked
+#define print_unlinkat print_2nd_locked
+#define print_utime print_1st_locked
+#define print_utimensat print_2nd_locked
+
/*
* An array of all of the syscalls we know about
*/
} else {
/* XXX: this format system is broken because it uses
host types and host pointers for strings */
+ /*
+ * It now works when it has print_xxx_locked function
+ * as its printing function.
+ */
if( scnames[i].format != NULL )
format = scnames[i].format;
gemu_log(format,scnames[i].name, arg1,arg2,arg3,arg4,arg5,arg6);
+/*
+ * Note that if you change format strings in these, check also
+ * that corresponding print functions are able to handle string
+ * locking correctly (see strace.c).
+ */
#ifdef TARGET_NR_accept
{ TARGET_NR_accept, "accept" , "%s(%d,%#x,%#x)", NULL, NULL },
#endif
#ifdef TARGET_NR_access
-{ TARGET_NR_access, "access" , "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_access, "access" , "%s(\"%s\",%#o)", print_access, NULL },
#endif
#ifdef TARGET_NR_acct
{ TARGET_NR_acct, "acct" , NULL, NULL, NULL },
{ TARGET_NR_capset, "capset" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_chdir
-{ TARGET_NR_chdir, "chdir" , "%s(\"%s\")", NULL, NULL },
+{ TARGET_NR_chdir, "chdir" , "%s(\"%s\")", print_chdir, NULL },
#endif
#ifdef TARGET_NR_chmod
-{ TARGET_NR_chmod, "chmod" , "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_chmod, "chmod" , "%s(\"%s\",%#o)", print_chmod, NULL },
#endif
#ifdef TARGET_NR_chown
{ TARGET_NR_chown, "chown" , NULL, NULL, NULL },
{ TARGET_NR_connect, "connect" , "%s(%d,%#x,%d)", NULL, NULL },
#endif
#ifdef TARGET_NR_creat
-{ TARGET_NR_creat, "creat" , "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_creat, "creat" , "%s(\"%s\",%#o)", print_creat, NULL },
#endif
#ifdef TARGET_NR_create_module
{ TARGET_NR_create_module, "create_module" , NULL, NULL, NULL },
{ TARGET_NR_epoll_wait_old, "epoll_wait_old" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_execv
-{ TARGET_NR_execv, "execv" , "%s(\"%s\",%ld,%ld,%ld,%ld,%ld)\n", NULL, NULL },
+{ TARGET_NR_execv, "execv" , "%s(\"%s\",%ld,%ld,%ld,%ld,%ld)\n",
+ print_execv, NULL },
#endif
#ifdef TARGET_NR_execve
{ TARGET_NR_execve, "execve" , NULL, print_execve, NULL },
{ TARGET_NR_exit_group, "exit_group" , "%s(%d)\n", NULL, NULL },
#endif
#ifdef TARGET_NR_faccessat
-{ TARGET_NR_faccessat, "faccessat" , "%s(%d,\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_NR_faccessat, "faccessat" , "%s(%d,\"%s\",%#o,%#x)",
+ print_faccessat, NULL },
#endif
#ifdef TARGET_NR_fadvise64
{ TARGET_NR_fadvise64, "fadvise64" , NULL, NULL, NULL },
{ TARGET_NR_fchmod, "fchmod" , "%s(%d,%#o)", NULL, NULL },
#endif
#ifdef TARGET_NR_fchmodat
-{ TARGET_NR_fchmodat, "fchmodat" , "%s(%d,\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_NR_fchmodat, "fchmodat" , "%s(%d,\"%s\",%#o,%#x)",
+ print_fchmodat, NULL },
#endif
#ifdef TARGET_NR_fchown
-{ TARGET_NR_fchown, "fchown" , "%s(\"%s\",%d,%d)", NULL, NULL },
+{ TARGET_NR_fchown, "fchown" , "%s(\"%s\",%d,%d)", print_fchown, NULL },
#endif
#ifdef TARGET_NR_fchown32
{ TARGET_NR_fchown32, "fchown32" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_fchownat
-{ TARGET_NR_fchownat, "fchownat" , "%s(%d,\"%s\",%d,%d,%#x)", NULL, NULL },
+{ TARGET_NR_fchownat, "fchownat" , "%s(%d,\"%s\",%d,%d,%#x)",
+ print_fchownat, NULL },
#endif
#ifdef TARGET_NR_fcntl
{ TARGET_NR_fcntl, "fcntl" , NULL, NULL, NULL },
{ TARGET_NR_futex, "futex" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_futimesat
-{ TARGET_NR_futimesat, "futimesat" , "%s(%d,\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_futimesat, "futimesat" , "%s(%d,\"%s\",%p)",
+ print_futimesat, NULL },
#endif
#ifdef TARGET_NR_getcwd
{ TARGET_NR_getcwd, "getcwd" , "%s(%p,%d)", NULL, NULL },
{ TARGET_NR_lgetxattr, "lgetxattr" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_link
-{ TARGET_NR_link, "link" , "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_NR_link, "link" , "%s(\"%s\",\"%s\")", print_link, NULL },
#endif
#ifdef TARGET_NR_linkat
-{ TARGET_NR_linkat, "linkat" , "%s(%d,\"%s\",%d,\"%s\",%#x)", NULL, NULL },
+{ TARGET_NR_linkat, "linkat" , "%s(%d,\"%s\",%d,\"%s\",%#x)",
+ print_linkat, NULL },
#endif
#ifdef TARGET_NR_Linux
{ TARGET_NR_Linux, "Linux" , NULL, NULL, NULL },
{ TARGET_NR_lsetxattr, "lsetxattr" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_lstat
-{ TARGET_NR_lstat, "lstat" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_lstat, "lstat" , "%s(\"%s\",%p)", print_lstat, NULL },
#endif
#ifdef TARGET_NR_lstat64
-{ TARGET_NR_lstat64, "lstat64" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_lstat64, "lstat64" , "%s(\"%s\",%p)", print_lstat64, NULL },
#endif
#ifdef TARGET_NR_madvise
{ TARGET_NR_madvise, "madvise" , NULL, NULL, NULL },
{ TARGET_NR_mincore, "mincore" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_mkdir
-{ TARGET_NR_mkdir, "mkdir" , "%s(\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_mkdir, "mkdir" , "%s(\"%s\",%#o)", print_mkdir, NULL },
#endif
#ifdef TARGET_NR_mkdirat
-{ TARGET_NR_mkdirat, "mkdirat" , "%s(%d,\"%s\",%#o)", NULL, NULL },
+{ TARGET_NR_mkdirat, "mkdirat" , "%s(%d,\"%s\",%#o)", print_mkdirat, NULL },
#endif
#ifdef TARGET_NR_mknod
-{ TARGET_NR_mknod, "mknod" , "%s(\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_NR_mknod, "mknod" , "%s(\"%s\",%#o,%#x)", print_mknod, NULL },
#endif
#ifdef TARGET_NR_mknodat
-{ TARGET_NR_mknodat, "mknodat" , "%s(%d,\"%s\",%#o,%#x)", NULL, NULL },
+{ TARGET_NR_mknodat, "mknodat" , "%s(%d,\"%s\",%#o,%#x)",
+ print_mknodat, NULL },
#endif
#ifdef TARGET_NR_mlock
{ TARGET_NR_mlock, "mlock" , NULL, NULL, NULL },
{ TARGET_NR_mpx, "mpx" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_mq_getsetattr
-{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , NULL, NULL, NULL },
+{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , "%s(%d,%p,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_mq_notify
-{ TARGET_NR_mq_notify, "mq_notify" , NULL, NULL, NULL },
+{ TARGET_NR_mq_notify, "mq_notify" , "%s(%d,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_mq_open
-{ TARGET_NR_mq_open, "mq_open" , NULL, NULL, NULL },
+{ TARGET_NR_mq_open, "mq_open" , "%s(\"/%s\",%#x,%#o,%p)",
+ print_mq_open, NULL },
#endif
#ifdef TARGET_NR_mq_timedreceive
-{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , NULL, NULL, NULL },
+{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_mq_timedsend
-{ TARGET_NR_mq_timedsend, "mq_timedsend" , NULL, NULL, NULL },
+{ TARGET_NR_mq_timedsend, "mq_timedsend" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_mq_unlink
-{ TARGET_NR_mq_unlink, "mq_unlink" , NULL, NULL, NULL },
+{ TARGET_NR_mq_unlink, "mq_unlink" , "%s(%s)", print_mq_unlink, NULL },
#endif
#ifdef TARGET_NR_mremap
{ TARGET_NR_mremap, "mremap" , NULL, NULL, NULL },
{ TARGET_NR_nanosleep, "nanosleep" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_fstatat64
-{ TARGET_NR_fstatat64, "fstatat64" , "%s(%d,\"%s\",%p,%#x)", NULL, NULL },
+{ TARGET_NR_fstatat64, "fstatat64" , "%s(%d,\"%s\",%p,%#x)",
+ print_fstatat64, NULL },
#endif
#ifdef TARGET_NR_newfstatat
-{ TARGET_NR_newfstatat, "newfstatat" , "%s(%d,\"%s\",%p,%#x)", NULL, NULL },
+{ TARGET_NR_newfstatat, "newfstatat" , "%s(%d,\"%s\",%p,%#x)",
+ print_newfstatat, NULL },
#endif
#ifdef TARGET_NR__newselect
{ TARGET_NR__newselect, "_newselect" , NULL, print_newselect, print_syscall_ret_newselect },
{ TARGET_NR_olduname, "olduname" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_open
-{ TARGET_NR_open, "open" , "%s(\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_NR_open, "open" , "%s(\"%s\",%#x,%#o)", print_open, NULL },
#endif
#ifdef TARGET_NR_openat
-{ TARGET_NR_openat, "openat" , "%s(%d,\"%s\",%#x,%#o)", NULL, NULL },
+{ TARGET_NR_openat, "openat" , "%s(%d,\"%s\",%#x,%#o)",
+ print_openat, NULL },
#endif
#ifdef TARGET_NR_osf_adjtime
{ TARGET_NR_osf_adjtime, "osf_adjtime" , NULL, NULL, NULL },
{ TARGET_NR_readdir, "readdir" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_readlink
-{ TARGET_NR_readlink, "readlink" , "%s(\"%s\",%p,%d)", NULL, NULL },
+{ TARGET_NR_readlink, "readlink" , "%s(\"%s\",%p,%d)",
+ print_readlink, NULL },
#endif
#ifdef TARGET_NR_readlinkat
-{ TARGET_NR_readlinkat, "readlinkat" , "%s(%d,\"%s\",%p,%d)", NULL, NULL },
+{ TARGET_NR_readlinkat, "readlinkat" , "%s(%d,\"%s\",%p,%d)",
+ print_readlinkat, NULL },
#endif
#ifdef TARGET_NR_readv
{ TARGET_NR_readv, "readv" , NULL, NULL, NULL },
{ TARGET_NR_removexattr, "removexattr" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_rename
-{ TARGET_NR_rename, "rename" , "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_NR_rename, "rename" , "%s(\"%s\",\"%s\")", print_rename, NULL },
#endif
#ifdef TARGET_NR_renameat
-{ TARGET_NR_renameat, "renameat" , "%s(%d,\"%s\",%d,\"%s\")", NULL, NULL },
+{ TARGET_NR_renameat, "renameat" , "%s(%d,\"%s\",%d,\"%s\")",
+ print_renameat, NULL },
#endif
#ifdef TARGET_NR_request_key
{ TARGET_NR_request_key, "request_key" , NULL, NULL, NULL },
{ TARGET_NR_ssetmask, "ssetmask" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_stat
-{ TARGET_NR_stat, "stat" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_stat, "stat" , "%s(\"%s\",%p)", print_stat, NULL },
#endif
#ifdef TARGET_NR_stat64
-{ TARGET_NR_stat64, "stat64" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_stat64, "stat64" , "%s(\"%s\",%p)", print_stat64, NULL },
#endif
#ifdef TARGET_NR_statfs
-{ TARGET_NR_statfs, "statfs" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_statfs, "statfs" , "%s(\"%s\",%p)", print_statfs, NULL },
#endif
#ifdef TARGET_NR_statfs64
-{ TARGET_NR_statfs64, "statfs64" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_statfs64, "statfs64" , "%s(\"%s\",%p)", print_statfs64, NULL },
#endif
#ifdef TARGET_NR_stime
{ TARGET_NR_stime, "stime" , NULL, NULL, NULL },
{ TARGET_NR_swapon, "swapon" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_symlink
-{ TARGET_NR_symlink, "symlink" , "%s(\"%s\",\"%s\")", NULL, NULL },
+{ TARGET_NR_symlink, "symlink" , "%s(\"%s\",\"%s\")",
+ print_symlink, NULL },
#endif
#ifdef TARGET_NR_symlinkat
-{ TARGET_NR_symlinkat, "symlinkat" , "%s(\"%s\",%d,\"%s\")", NULL, NULL },
+{ TARGET_NR_symlinkat, "symlinkat" , "%s(\"%s\",%d,\"%s\")",
+ print_symlinkat, NULL },
#endif
#ifdef TARGET_NR_sync
{ TARGET_NR_sync, "sync" , NULL, NULL, NULL },
{ TARGET_NR_umask, "umask" , "%s(%#o)", NULL, NULL },
#endif
#ifdef TARGET_NR_umount
-{ TARGET_NR_umount, "umount" , "%s(\"%s\",\"%s\",\"%s\",%#x,%p)", NULL, NULL },
+{ TARGET_NR_umount, "umount" , "%s(\"%s\",\"%s\",\"%s\",%#x,%p)",
+ print_umount, NULL },
#endif
#ifdef TARGET_NR_umount2
{ TARGET_NR_umount2, "umount2" , NULL, NULL, NULL },
{ TARGET_NR_uname, "uname" , "%s(%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_unlink
-{ TARGET_NR_unlink, "unlink" , "%s(\"%s\")", NULL, NULL },
+{ TARGET_NR_unlink, "unlink" , "%s(\"%s\")", print_unlink, NULL },
#endif
#ifdef TARGET_NR_unlinkat
-{ TARGET_NR_unlinkat, "unlinkat" , "%s(%d,\"%s\",%#x)", NULL, NULL },
+{ TARGET_NR_unlinkat, "unlinkat" , "%s(%d,\"%s\",%#x)", print_unlinkat, NULL },
#endif
#ifdef TARGET_NR_unshare
{ TARGET_NR_unshare, "unshare" , NULL, NULL, NULL },
{ TARGET_NR_ustat, "ustat" , "%s(%#x,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_utime
-{ TARGET_NR_utime, "utime" , "%s(\"%s\",%p)", NULL, NULL },
+{ TARGET_NR_utime, "utime" , "%s(\"%s\",%p)", print_utime, NULL },
#endif
#ifdef TARGET_NR_utimes
{ TARGET_NR_utimes, "utimes" , NULL, NULL, NULL },
{ TARGET_NR_writev, "writev" , "%s(%d,%p,%#x)", NULL, NULL },
#endif
#ifdef TARGET_NR_utimensat
-{ TARGET_NR_utimensat, "utimensat", "%s(%d,\"%s\",%p,%#x)", NULL, NULL },
+{ TARGET_NR_utimensat, "utimensat", "%s(%d,\"%s\",%p,%#x)",
+ print_utimensat, NULL },
#endif
#include <fcntl.h>
#include <time.h>
#include <limits.h>
+#include <mqueue.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <signal.h>
#include <sched.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/uio.h>
#include <sys/poll.h>
#include <sys/times.h>
#include <sys/statfs.h>
#include <utime.h>
#include <sys/sysinfo.h>
+#include <sys/utsname.h>
//#include <sys/user.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#define __NR_sys_linkat __NR_linkat
#define __NR_sys_mkdirat __NR_mkdirat
#define __NR_sys_mknodat __NR_mknodat
+#define __NR_sys_newfstatat __NR_newfstatat
#define __NR_sys_openat __NR_openat
#define __NR_sys_readlinkat __NR_readlinkat
#define __NR_sys_renameat __NR_renameat
return -ENOSYS;
}
#endif
-_syscall1(int,sys_uname,struct new_utsname *,buf)
-#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
-_syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags)
-#endif
-#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
-_syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname,
- mode_t,mode,int,flags)
-#endif
-#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16)
-_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
- uid_t,owner,gid_t,group,int,flags)
-#endif
-#if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64)
+#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
+ defined(__NR_fstatat64)
_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
struct stat *,buf,int,flags)
#endif
_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
const struct timeval *,times)
#endif
-_syscall2(int,sys_getcwd1,char *,buf,size_t,size)
#if TARGET_ABI_BITS == 32
_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
#endif
_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
#endif
-#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
-_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
- int,newdirfd,const char *,newpath,int,flags)
-#endif
-#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
-_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
-#endif
-#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
-_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
- mode_t,mode,dev_t,dev)
-#endif
-#if defined(TARGET_NR_openat) && defined(__NR_openat)
-_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
-#endif
-#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
-_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
- char *,buf,size_t,bufsize)
-#endif
-#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
-_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
- int,newdirfd,const char *,newpath)
+#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
+ defined(__NR_newfstatat)
+_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
+ struct stat *,buf,int,flags)
#endif
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
-#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
-_syscall3(int,sys_symlinkat,const char *,oldpath,
- int,newdirfd,const char *,newpath)
-#endif
_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
_syscall1(int,set_tid_address,int *,tidptr)
#endif
-#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
-_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
-#endif
-#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
-_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
- const struct timespec *,tsp,int,flags)
-#endif
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
_syscall0(int,sys_inotify_init)
#endif
#endif
#endif
+static bitmask_transtbl fcntl_flags_tbl[] = {
+ { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
+ { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
+ { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
+ { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
+ { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
+ { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
+ { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
+ { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
+ { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
+ { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
+ { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
+ { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
+ { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
+#if defined(O_DIRECT)
+ { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
+#endif
+ { 0, 0, 0, 0 }
+};
+
+static int
+sys_uname(struct new_utsname *buf)
+{
+ struct utsname uts_buf;
+
+ if (uname(&uts_buf) < 0)
+ return (-1);
+
+ /*
+ * Just in case these have some differences, we
+ * translate utsname to new_utsname (which is the
+ * struct linux kernel uses).
+ */
+
+#define COPY_UTSNAME_FIELD(dest, src) \
+ do { \
+ /* __NEW_UTS_LEN doesn't include terminating null */ \
+ (void) strncpy((dest), (src), __NEW_UTS_LEN); \
+ (dest)[__NEW_UTS_LEN] = '\0'; \
+ } while (0)
+
+ bzero(buf, sizeof (*buf));
+ COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
+ COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
+ COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
+ COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
+ COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
+#ifdef _GNU_SOURCE
+ COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
+#endif
+ return (0);
+
+#undef COPY_UTSNAME_FIELD
+}
+
+static int
+sys_getcwd1(char *buf, size_t size)
+{
+ if (getcwd(buf, size) == NULL) {
+ /* getcwd() sets errno */
+ return (-1);
+ }
+ return (0);
+}
+
+#ifdef CONFIG_ATFILE
+
+/*
+ * Host system seems to have atfile syscall stubs available. We
+ * now enable them one by one as specified by target syscall_nr.h.
+ */
+
+#ifdef TARGET_NR_openat
+static int
+sys_openat(int dirfd, const char *pathname, int flags, ...)
+{
+ /*
+ * open(2) has extra parameter 'mode' when called with
+ * flag O_CREAT.
+ */
+ if ((flags & O_CREAT) != 0) {
+ va_list ap;
+ mode_t mode;
+
+ /*
+ * Get the 'mode' parameter and translate it to
+ * host bits.
+ */
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
+ va_end(ap);
+
+ return (openat(dirfd, pathname, flags, mode));
+ }
+ return (openat(dirfd, pathname, flags));
+}
+#endif
+
+#ifdef TARGET_NR_mkdirat
+static int
+sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
+{
+ return (mkdirat(dirfd, pathname, mode));
+}
+#endif
+
+#ifdef TARGET_NR_mknodat
+static int
+sys_mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev)
+{
+ return (mknodat(dirfd, pathname, mode, dev));
+}
+#endif
+
+#ifdef TARGET_NR_fchownat
+static int
+sys_fchownat(int dirfd, const char *pathname, uid_t owner,
+ gid_t group, int flags)
+{
+ return (fchownat(dirfd, pathname, owner, group, flags));
+}
+#endif
+
+#ifdef TARGET_NR_fstatat
+static int
+sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
+ int flags)
+{
+ return (fstatat64(dirfd, pathname, buf, flags));
+}
+#endif
+
+#ifdef TARGET_NR_unlinkat
+static int
+sys_unlinkat(int dirfd, const char *pathname, int flags)
+{
+ return (unlinkat(dirfd, pathname, flags));
+}
+#endif
+
+#ifdef TARGET_NR_renameat
+static int
+sys_renameat(int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath)
+{
+ return (renameat(olddirfd, oldpath, newdirfd, newpath));
+}
+#endif
+
+#ifdef TARGET_NR_linkat
+static int
+sys_linkat(int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath, int flags)
+{
+ return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
+}
+#endif
+
+#ifdef TARGET_NR_symlinkat
+static int
+sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
+{
+ return (symlinkat(oldpath, newdirfd, newpath));
+}
+#endif
+
+#ifdef TARGET_NR_readlinkat
+static int
+sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
+{
+ return (readlinkat(dirfd, pathname, buf, bufsiz));
+}
+#endif
+
+#ifdef TARGET_NR_fchmodat
+static int
+sys_fchmodat(int dirfd, const char *pathname, mode_t mode, int flags)
+{
+ return (fchmodat(dirfd, pathname, mode, flags));
+}
+#endif
+
+#ifdef TARGET_NR_faccessat
+static int
+sys_faccessat(int dirfd, const char *pathname, int mode, int flags)
+{
+ return (faccessat(dirfd, pathname, mode, flags));
+}
+#endif
+
+#ifdef TARGET_NR_utimensat
+static int
+sys_utimensat(int dirfd, const char *pathname,
+ const struct timespec times[2], int flags)
+{
+ return (utimensat(dirfd, pathname, times, flags));
+}
+#endif
+
+#else /* !CONFIG_ATFILE */
+
+/*
+ * Host system doesn't have these available so we don't try
+ * to implement them.
+ */
+
+#undef TARGET_NR_openat
+#undef TARGET_NR_mkdirat
+#undef TARGET_NR_mknodat
+#undef TARGET_NR_fchownat
+#undef TARGET_NR_fstatat
+#undef TARGET_NR_unlinkat
+#undef TARGET_NR_renameat
+#undef TARGET_NR_linkat
+#undef TARGET_NR_symlinkat
+#undef TARGET_NR_readlinkat
+#undef TARGET_NR_fchmodat
+#undef TARGET_NR_faccessat
+#undef TARGET_NR_utimensat
+
+#endif /* CONFIG_ATFILE */
+
+
extern int personality(int);
extern int flock(int, int);
extern int setfsuid(int);
return 0;
}
+static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
+ abi_ulong target_mq_attr_addr)
+{
+ struct target_mq_attr *target_mq_attr;
+
+ if (!lock_user_struct(VERIFY_READ, target_mq_attr,
+ target_mq_attr_addr, 1))
+ return -TARGET_EFAULT;
+
+ __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
+ __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+ __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+ __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+ unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
+
+ return 0;
+}
+
+static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
+ const struct mq_attr *attr)
+{
+ struct target_mq_attr *target_mq_attr;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
+ target_mq_attr_addr, 0))
+ return -TARGET_EFAULT;
+
+ __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
+ __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+ __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+ __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+ unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
+
+ return 0;
+}
/* do_select() must return target values and target errnos. */
static abi_long do_select(int n,
abi_ulong target_addr,
socklen_t len)
{
+ const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
+ sa_family_t sa_family;
struct target_sockaddr *target_saddr;
target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
if (!target_saddr)
return -TARGET_EFAULT;
+
+ sa_family = tswap16(target_saddr->sa_family);
+
+ /* Oops. The caller might send a incomplete sun_path; sun_path
+ * must be terminated by \0 (see the manual page), but
+ * unfortunately it is quite common to specify sockaddr_un
+ * length as "strlen(x->sun_path)" while it should be
+ * "strlen(...) + 1". We'll fix that here if needed.
+ * Linux kernel has a similar feature.
+ */
+
+ if (sa_family == AF_UNIX) {
+ if (len < unix_maxlen) {
+ char *cp = (char*)target_saddr;
+
+ if ( cp[len-1] && !cp[len] )
+ len++;
+ }
+ if (len > unix_maxlen)
+ len = unix_maxlen;
+ }
+
memcpy(addr, target_saddr, len);
- addr->sa_family = tswap16(target_saddr->sa_family);
+ addr->sa_family = sa_family;
unlock_user(target_saddr, target_addr, 0);
return 0;
return get_errno(socket(domain, type, protocol));
}
-/* MAX_SOCK_ADDR from linux/net/socket.c */
-#define MAX_SOCK_ADDR 128
-
/* do_bind() Must return target values and target errnos. */
static abi_long do_bind(int sockfd, abi_ulong target_addr,
socklen_t addrlen)
{
void *addr;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
- addr = alloca(addrlen);
+ addr = alloca(addrlen+1);
target_to_host_sockaddr(addr, target_addr, addrlen);
return get_errno(bind(sockfd, addr, addrlen));
{
void *addr;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
void *addr;
abi_long ret;
+ if (target_addr == 0)
+ return get_errno(accept(fd, NULL, NULL));
+
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
void *host_msg;
abi_long ret;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
host_msg = lock_user(VERIFY_READ, msg, len, 1);
ret = -TARGET_EFAULT;
goto fail;
}
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) {
+ if (addrlen < 0) {
ret = -TARGET_EINVAL;
goto fail;
}
}
#endif
-#ifdef TARGET_NR_ipc
#define N_SHM_REGIONS 32
static struct shm_region {
abi_ulong start;
abi_ulong size;
} shm_regions[N_SHM_REGIONS];
-#endif
struct target_ipc_perm
{
struct target_semid_ds
{
- struct target_ipc_perm sem_perm;
- abi_ulong sem_otime;
- abi_ulong __unused1;
- abi_ulong sem_ctime;
- abi_ulong __unused2;
- abi_ulong sem_nsems;
- abi_ulong __unused3;
- abi_ulong __unused4;
+ struct target_ipc_perm sem_perm;
+ abi_ulong sem_otime;
+ abi_ulong __unused1;
+ abi_ulong sem_ctime;
+ abi_ulong __unused2;
+ abi_ulong sem_nsems;
+ abi_ulong __unused3;
+ abi_ulong __unused4;
};
static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
return -TARGET_EFAULT;
- target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
+ if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
+ return -TARGET_EFAULT;
host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
host_sd->sem_otime = tswapl(target_sd->sem_otime);
host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
return -TARGET_EFAULT;
- host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
+ if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
+ return -TARGET_EFAULT;;
target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
target_sd->sem_otime = tswapl(host_sd->sem_otime);
target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
return 0;
}
+struct target_seminfo {
+ int semmap;
+ int semmni;
+ int semmns;
+ int semmnu;
+ int semmsl;
+ int semopm;
+ int semume;
+ int semusz;
+ int semvmx;
+ int semaem;
+};
+
+static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
+ struct seminfo *host_seminfo)
+{
+ struct target_seminfo *target_seminfo;
+ if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
+ return -TARGET_EFAULT;
+ __put_user(host_seminfo->semmap, &target_seminfo->semmap);
+ __put_user(host_seminfo->semmni, &target_seminfo->semmni);
+ __put_user(host_seminfo->semmns, &target_seminfo->semmns);
+ __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
+ __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
+ __put_user(host_seminfo->semopm, &target_seminfo->semopm);
+ __put_user(host_seminfo->semume, &target_seminfo->semume);
+ __put_user(host_seminfo->semusz, &target_seminfo->semusz);
+ __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
+ __put_user(host_seminfo->semaem, &target_seminfo->semaem);
+ unlock_user_struct(target_seminfo, target_addr, 1);
+ return 0;
+}
+
union semun {
- int val;
- struct semid_ds *buf;
- unsigned short *array;
+ int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+ struct seminfo *__buf;
};
union target_semun {
- int val;
- abi_long buf;
- unsigned short int *array;
+ int val;
+ abi_ulong buf;
+ abi_ulong array;
+ abi_ulong __buf;
};
-static inline abi_long target_to_host_semun(int cmd,
- union semun *host_su,
- abi_ulong target_addr,
- struct semid_ds *ds)
+static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+ abi_ulong target_addr)
{
- union target_semun *target_su;
-
- switch( cmd ) {
- case IPC_STAT:
- case IPC_SET:
- if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
- return -TARGET_EFAULT;
- target_to_host_semid_ds(ds,target_su->buf);
- host_su->buf = ds;
- unlock_user_struct(target_su, target_addr, 0);
- break;
- case GETVAL:
- case SETVAL:
- if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
- return -TARGET_EFAULT;
- host_su->val = tswapl(target_su->val);
- unlock_user_struct(target_su, target_addr, 0);
- break;
- case GETALL:
- case SETALL:
- if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
- return -TARGET_EFAULT;
- *host_su->array = tswap16(*target_su->array);
- unlock_user_struct(target_su, target_addr, 0);
- break;
- default:
- gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+ int nsems;
+ unsigned short *array;
+ union semun semun;
+ struct semid_ds semid_ds;
+ int i, ret;
+
+ semun.buf = &semid_ds;
+
+ ret = semctl(semid, 0, IPC_STAT, semun);
+ if (ret == -1)
+ return get_errno(ret);
+
+ nsems = semid_ds.sem_nsems;
+
+ *host_array = malloc(nsems*sizeof(unsigned short));
+ array = lock_user(VERIFY_READ, target_addr,
+ nsems*sizeof(unsigned short), 1);
+ if (!array)
+ return -TARGET_EFAULT;
+
+ for(i=0; i<nsems; i++) {
+ __get_user((*host_array)[i], &array[i]);
}
+ unlock_user(array, target_addr, 0);
+
return 0;
}
-static inline abi_long host_to_target_semun(int cmd,
- abi_ulong target_addr,
- union semun *host_su,
- struct semid_ds *ds)
+static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+ unsigned short **host_array)
{
- union target_semun *target_su;
-
- switch( cmd ) {
- case IPC_STAT:
- case IPC_SET:
- if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
- return -TARGET_EFAULT;
- host_to_target_semid_ds(target_su->buf,ds);
- unlock_user_struct(target_su, target_addr, 1);
- break;
- case GETVAL:
- case SETVAL:
- if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
- return -TARGET_EFAULT;
- target_su->val = tswapl(host_su->val);
- unlock_user_struct(target_su, target_addr, 1);
- break;
- case GETALL:
- case SETALL:
- if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
- return -TARGET_EFAULT;
- *target_su->array = tswap16(*host_su->array);
- unlock_user_struct(target_su, target_addr, 1);
- break;
- default:
- gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+ int nsems;
+ unsigned short *array;
+ union semun semun;
+ struct semid_ds semid_ds;
+ int i, ret;
+
+ semun.buf = &semid_ds;
+
+ ret = semctl(semid, 0, IPC_STAT, semun);
+ if (ret == -1)
+ return get_errno(ret);
+
+ nsems = semid_ds.sem_nsems;
+
+ array = lock_user(VERIFY_WRITE, target_addr,
+ nsems*sizeof(unsigned short), 0);
+ if (!array)
+ return -TARGET_EFAULT;
+
+ for(i=0; i<nsems; i++) {
+ __put_user((*host_array)[i], &array[i]);
}
+ free(*host_array);
+ unlock_user(array, target_addr, 1);
+
return 0;
}
-static inline abi_long do_semctl(int first, int second, int third,
- abi_long ptr)
+static inline abi_long do_semctl(int semid, int semnum, int cmd,
+ union target_semun target_su)
{
union semun arg;
struct semid_ds dsarg;
- int cmd = third&0xff;
- abi_long ret = 0;
+ unsigned short *array;
+ struct seminfo seminfo;
+ abi_long ret = -TARGET_EINVAL;
+ abi_long err;
- switch( cmd ) {
- case GETVAL:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
- break;
- case SETVAL:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
- break;
- case GETALL:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
- break;
- case SETALL:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
- break;
- case IPC_STAT:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
- break;
- case IPC_SET:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
- break;
- default:
- ret = get_errno(semctl(first, second, cmd, arg));
+ cmd &= 0xff;
+
+ switch (cmd) {
+ case IPC_STAT:
+ case IPC_SET:
+ case SEM_STAT:
+ err = target_to_host_semid_ds(&dsarg, target_su.buf);
+ if (err)
+ return err;
+ arg.buf = &dsarg;
+ ret = get_errno(semctl(semid, semnum, cmd, arg));
+ err = host_to_target_semid_ds(target_su.buf, &dsarg);
+ if (err)
+ return err;
+ break;
+ case GETVAL:
+ case SETVAL:
+ arg.val = tswapl(target_su.val);
+ ret = get_errno(semctl(semid, semnum, cmd, arg));
+ target_su.val = tswapl(arg.val);
+ break;
+ case GETALL:
+ case SETALL:
+ err = target_to_host_semarray(semid, &array, target_su.array);
+ if (err)
+ return err;
+ arg.array = array;
+ ret = get_errno(semctl(semid, semnum, cmd, arg));
+ err = host_to_target_semarray(semid, target_su.array, &array);
+ if (err)
+ return err;
+ break;
+ case IPC_INFO:
+ case SEM_INFO:
+ arg.__buf = &seminfo;
+ ret = get_errno(semctl(semid, semnum, cmd, arg));
+ err = host_to_target_seminfo(target_su.__buf, &seminfo);
+ if (err)
+ return err;
+ break;
+ case IPC_RMID:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ ret = get_errno(semctl(semid, semnum, cmd, NULL));
+ break;
}
return ret;
}
+struct target_sembuf {
+ unsigned short sem_num;
+ short sem_op;
+ short sem_flg;
+};
+
+static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
+ abi_ulong target_addr,
+ unsigned nsops)
+{
+ struct target_sembuf *target_sembuf;
+ int i;
+
+ target_sembuf = lock_user(VERIFY_READ, target_addr,
+ nsops*sizeof(struct target_sembuf), 1);
+ if (!target_sembuf)
+ return -TARGET_EFAULT;
+
+ for(i=0; i<nsops; i++) {
+ __put_user(target_sembuf[i].sem_num, &host_sembuf[i].sem_num);
+ __put_user(target_sembuf[i].sem_op, &host_sembuf[i].sem_op);
+ __put_user(target_sembuf[i].sem_flg, &host_sembuf[i].sem_flg);
+ }
+
+ unlock_user(target_sembuf, target_addr, 0);
+
+ return 0;
+}
+
+static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
+{
+ struct sembuf sops[nsops];
+
+ if (target_to_host_sembuf(sops, ptr, nsops))
+ return -TARGET_EFAULT;
+
+ return semop(semid, sops, nsops);
+}
+
struct target_msqid_ds
{
struct target_ipc_perm msg_perm;
return ret;
}
+struct target_shmid_ds
+{
+ struct target_ipc_perm shm_perm;
+ abi_ulong shm_segsz;
+ abi_ulong shm_atime;
+#if TARGET_ABI_BITS == 32
+ abi_ulong __unused1;
+#endif
+ abi_ulong shm_dtime;
+#if TARGET_ABI_BITS == 32
+ abi_ulong __unused2;
+#endif
+ abi_ulong shm_ctime;
+#if TARGET_ABI_BITS == 32
+ abi_ulong __unused3;
+#endif
+ int shm_cpid;
+ int shm_lpid;
+ abi_ulong shm_nattch;
+ unsigned long int __unused4;
+ unsigned long int __unused5;
+};
+
+static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+ abi_ulong target_addr)
+{
+ struct target_shmid_ds *target_sd;
+
+ if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
+ return -TARGET_EFAULT;
+ if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
+ return -TARGET_EFAULT;
+ __put_user(target_sd->shm_segsz, &host_sd->shm_segsz);
+ __put_user(target_sd->shm_atime, &host_sd->shm_atime);
+ __put_user(target_sd->shm_dtime, &host_sd->shm_dtime);
+ __put_user(target_sd->shm_ctime, &host_sd->shm_ctime);
+ __put_user(target_sd->shm_cpid, &host_sd->shm_cpid);
+ __put_user(target_sd->shm_lpid, &host_sd->shm_lpid);
+ __put_user(target_sd->shm_nattch, &host_sd->shm_nattch);
+ unlock_user_struct(target_sd, target_addr, 0);
+ return 0;
+}
+
+static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+ struct shmid_ds *host_sd)
+{
+ struct target_shmid_ds *target_sd;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
+ return -TARGET_EFAULT;
+ if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
+ return -TARGET_EFAULT;
+ __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+ __put_user(host_sd->shm_atime, &target_sd->shm_atime);
+ __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+ __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+ __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+ __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+ __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+ unlock_user_struct(target_sd, target_addr, 1);
+ return 0;
+}
+
+struct target_shminfo {
+ abi_ulong shmmax;
+ abi_ulong shmmin;
+ abi_ulong shmmni;
+ abi_ulong shmseg;
+ abi_ulong shmall;
+};
+
+static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
+ struct shminfo *host_shminfo)
+{
+ struct target_shminfo *target_shminfo;
+ if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
+ return -TARGET_EFAULT;
+ __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
+ __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
+ __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
+ __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
+ __put_user(host_shminfo->shmall, &target_shminfo->shmall);
+ unlock_user_struct(target_shminfo, target_addr, 1);
+ return 0;
+}
+
+struct target_shm_info {
+ int used_ids;
+ abi_ulong shm_tot;
+ abi_ulong shm_rss;
+ abi_ulong shm_swp;
+ abi_ulong swap_attempts;
+ abi_ulong swap_successes;
+};
+
+static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
+ struct shm_info *host_shm_info)
+{
+ struct target_shm_info *target_shm_info;
+ if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
+ return -TARGET_EFAULT;
+ __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
+ __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
+ __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
+ __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
+ __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
+ __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
+ unlock_user_struct(target_shm_info, target_addr, 1);
+ return 0;
+}
+
+static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
+{
+ struct shmid_ds dsarg;
+ struct shminfo shminfo;
+ struct shm_info shm_info;
+ abi_long ret = -TARGET_EINVAL;
+
+ cmd &= 0xff;
+
+ switch(cmd) {
+ case IPC_STAT:
+ case IPC_SET:
+ case SHM_STAT:
+ if (target_to_host_shmid_ds(&dsarg, buf))
+ return -TARGET_EFAULT;
+ ret = get_errno(shmctl(shmid, cmd, &dsarg));
+ if (host_to_target_shmid_ds(buf, &dsarg))
+ return -TARGET_EFAULT;
+ break;
+ case IPC_INFO:
+ ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
+ if (host_to_target_shminfo(buf, &shminfo))
+ return -TARGET_EFAULT;
+ break;
+ case SHM_INFO:
+ ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
+ if (host_to_target_shm_info(buf, &shm_info))
+ return -TARGET_EFAULT;
+ break;
+ case IPC_RMID:
+ case SHM_LOCK:
+ case SHM_UNLOCK:
+ ret = get_errno(shmctl(shmid, cmd, NULL));
+ break;
+ }
+
+ return ret;
+}
+
+static inline abi_long do_shmat(int shmid, abi_ulong shmaddr, int shmflg,
+ unsigned long *raddr)
+{
+ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
+ abi_long ret;
+ struct shmid_ds shm_info;
+ int i;
+
+ /* find out the length of the shared memory segment */
+ ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
+ if (is_error(ret)) {
+ /* can't get length, bail out */
+ return get_errno(ret);
+ }
+
+ mmap_lock();
+
+ if (shmaddr)
+ *raddr = (unsigned long) shmat(shmid, g2h(shmaddr), shmflg);
+ else {
+ abi_ulong mmap_start;
+
+ mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
+
+ if (mmap_start == -1) {
+ errno = ENOMEM;
+ *raddr = -1;
+ } else
+ *raddr = (unsigned long) shmat(shmid, g2h(mmap_start),
+ shmflg | SHM_REMAP);
+ }
+
+ if (*raddr == -1) {
+ mmap_unlock();
+ return get_errno(*raddr);
+ }
+
+ page_set_flags(h2g(*raddr), h2g(*raddr) + shm_info.shm_segsz,
+ PAGE_VALID | PAGE_READ |
+ ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
+
+ for (i = 0; i < N_SHM_REGIONS; i++) {
+ if (shm_regions[i].start == 0) {
+ shm_regions[i].start = h2g(*raddr);
+ shm_regions[i].size = shm_info.shm_segsz;
+ break;
+ }
+ }
+
+ *raddr = h2g(*raddr);
+
+ mmap_unlock();
+ return 0;
+}
+
+static inline abi_long do_shmdt(abi_ulong shmaddr)
+{
+ int i;
+
+ for (i = 0; i < N_SHM_REGIONS; ++i) {
+ if (shm_regions[i].start == shmaddr) {
+ shm_regions[i].start = 0;
+ page_set_flags(shmaddr, shm_regions[i].size, 0);
+ break;
+ }
+ }
+
+ return get_errno(shmdt(g2h(shmaddr)));
+}
+
#ifdef TARGET_NR_ipc
/* ??? This only works with linear mappings. */
/* do_ipc() must return target values and target errnos. */
{
int version;
abi_long ret = 0;
- struct shmid_ds shm_info;
- int i;
version = call >> 16;
call &= 0xffff;
switch (call) {
case IPCOP_semop:
- ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second));
+ ret = do_semop(first, ptr, second);
break;
case IPCOP_semget:
break;
case IPCOP_semctl:
- ret = do_semctl(first, second, third, ptr);
- break;
-
- case IPCOP_semtimedop:
- gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
- ret = -TARGET_ENOSYS;
+ ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
break;
case IPCOP_msgget:
break;
case IPCOP_shmat:
- {
- abi_ulong raddr;
- void *host_addr;
- /* SHM_* flags are the same on all linux platforms */
- host_addr = shmat(first, (void *)g2h(ptr), second);
- if (host_addr == (void *)-1) {
- ret = get_errno((long)host_addr);
- break;
- }
- raddr = h2g((unsigned long)host_addr);
- /* find out the length of the shared memory segment */
-
- ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
- if (is_error(ret)) {
- /* can't get length, bail out */
- shmdt(host_addr);
- break;
- }
- page_set_flags(raddr, raddr + shm_info.shm_segsz,
- PAGE_VALID | PAGE_READ |
- ((second & SHM_RDONLY)? 0: PAGE_WRITE));
- for (i = 0; i < N_SHM_REGIONS; ++i) {
- if (shm_regions[i].start == 0) {
- shm_regions[i].start = raddr;
- shm_regions[i].size = shm_info.shm_segsz;
+ switch (version) {
+ default:
+ {
+ unsigned long raddr;
+
+ ret = do_shmat(first, ptr, second, &raddr);
+ if (ret)
break;
- }
+
+ ret = put_user_ual(raddr, third);
+ break;
}
- if (put_user_ual(raddr, third))
- return -TARGET_EFAULT;
- ret = 0;
+ case 1:
+ ret = -TARGET_EINVAL;
+ break;
}
- break;
+ break;
+
case IPCOP_shmdt:
- for (i = 0; i < N_SHM_REGIONS; ++i) {
- if (shm_regions[i].start == ptr) {
- shm_regions[i].start = 0;
- page_set_flags(ptr, shm_regions[i].size, 0);
- break;
- }
- }
- ret = get_errno(shmdt((void *)g2h(ptr)));
- break;
+ ret = do_shmdt(ptr);
+ break;
case IPCOP_shmget:
- /* IPC_* flag values are the same on all linux platforms */
- ret = get_errno(shmget(first, second, third));
- break;
+ ret = get_errno(shmget(first, second, third));
+ break;
- /* IPC_* and SHM_* command values are the same on all linux platforms */
case IPCOP_shmctl:
- switch(second) {
- case IPC_RMID:
- case SHM_LOCK:
- case SHM_UNLOCK:
- ret = get_errno(shmctl(first, second, NULL));
- break;
- default:
- goto unimplemented;
- }
+ ret = do_shmctl(first, second, third);
break;
+
default:
- unimplemented:
- gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
- ret = -TARGET_ENOSYS;
- break;
+ gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
+ ret = -TARGET_ENOSYS;
+ break;
}
return ret;
}
{ 0, 0, 0, 0 }
};
-static bitmask_transtbl fcntl_flags_tbl[] = {
- { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
- { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
- { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
- { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
- { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
- { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
- { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
- { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
- { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
- { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
- { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
- { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
- { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
-#if defined(O_DIRECT)
- { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
-#endif
- { 0, 0, 0, 0 }
-};
-
#if defined(TARGET_I386)
/* NOTE: there is really one LDT for all the threads */
pthread_cond_t cond;
pthread_t thread;
uint32_t tid;
+ unsigned int flags;
abi_ulong child_tidptr;
abi_ulong parent_tidptr;
sigset_t sigmask;
{
new_thread_info *info = arg;
CPUState *env;
+ TaskState *ts;
env = info->env;
thread_env = env;
+ ts = (TaskState *)thread_env->opaque;
info->tid = gettid();
+ task_settid(ts);
if (info->child_tidptr)
put_user_u32(info->tid, info->child_tidptr);
if (info->parent_tidptr)
flags &= ~(CLONE_VFORK | CLONE_VM);
if (flags & CLONE_VM) {
+ TaskState *parent_ts = (TaskState *)env->opaque;
#if defined(USE_NPTL)
new_thread_info info;
pthread_attr_t attr;
/* Init regs that differ from the parent. */
cpu_clone_regs(new_env, newsp);
new_env->opaque = ts;
+ ts->bprm = parent_ts->bprm;
+ ts->info = parent_ts->info;
#if defined(USE_NPTL)
nptl_flags = flags;
flags &= ~CLONE_NPTL_FLAGS2;
return 0;
}
-#ifdef TARGET_NR_stat64
+#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
static inline abi_long host_to_target_stat64(void *cpu_env,
abi_ulong target_addr,
struct stat *host_st)
} else
#endif
{
+#if TARGET_LONG_BITS == 64
+ struct target_stat *target_st;
+#else
struct target_stat64 *target_st;
+#endif
if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
return -TARGET_EFAULT;
- memset(target_st, 0, sizeof(struct target_stat64));
+ memset(target_st, 0, sizeof(*target_st));
__put_user(host_st->st_dev, &target_st->st_dev);
__put_user(host_st->st_ino, &target_st->st_ino);
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
-
+#ifdef TARGET_NR_semget
+ case TARGET_NR_semget:
+ ret = get_errno(semget(arg1, arg2, arg3));
+ break;
+#endif
+#ifdef TARGET_NR_semop
+ case TARGET_NR_semop:
+ ret = get_errno(do_semop(arg1, arg2, arg3));
+ break;
+#endif
+#ifdef TARGET_NR_semctl
+ case TARGET_NR_semctl:
+ ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
+ break;
+#endif
#ifdef TARGET_NR_msgctl
case TARGET_NR_msgctl:
ret = do_msgctl(arg1, arg2, arg3);
ret = do_msgsnd(arg1, arg2, arg3, arg4);
break;
#endif
+#ifdef TARGET_NR_shmget
+ case TARGET_NR_shmget:
+ ret = get_errno(shmget(arg1, arg2, arg3));
+ break;
+#endif
+#ifdef TARGET_NR_shmctl
+ case TARGET_NR_shmctl:
+ ret = do_shmctl(arg1, arg2, arg3);
+ break;
+#endif
+#ifdef TARGET_NR_shmat
+ case TARGET_NR_shmat:
+ {
+ abi_long err;
+ unsigned long _ret;
+
+ err = do_shmat(arg1, arg2, arg3, &_ret);
+ ret = err ? err : _ret;
+ }
+ break;
+#endif
+#ifdef TARGET_NR_shmdt
+ case TARGET_NR_shmdt:
+ ret = do_shmdt(arg1);
+ break;
+#endif
case TARGET_NR_fsync:
ret = get_errno(fsync(arg1));
break;
ret = host_to_target_stat64(cpu_env, arg2, &st);
break;
#endif
-#if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64)
+#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
+ (defined(__NR_fstatat64) || defined(__NR_newfstatat))
+#ifdef TARGET_NR_fstatat64
case TARGET_NR_fstatat64:
+#endif
+#ifdef TARGET_NR_newfstatat
+ case TARGET_NR_newfstatat:
+#endif
if (!(p = lock_user_string(arg2)))
goto efault;
+#ifdef __NR_fstatat64
ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
+#else
+ ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
+#endif
if (!is_error(ret))
ret = host_to_target_stat64(cpu_env, arg3, &st);
break;
break;
#endif
+#ifdef TARGET_NR_mq_open
+ case TARGET_NR_mq_open:
+ {
+ struct mq_attr posix_mq_attr;
+
+ p = lock_user_string(arg1 - 1);
+ if (arg4 != 0)
+ copy_from_user_mq_attr (&posix_mq_attr, arg4);
+ ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
+ unlock_user (p, arg1, 0);
+ break;
+ }
+
+ case TARGET_NR_mq_unlink:
+ p = lock_user_string(arg1 - 1);
+ ret = get_errno(mq_unlink(p));
+ unlock_user (p, arg1, 0);
+ break;
+
+ case TARGET_NR_mq_timedsend:
+ {
+ struct timespec ts;
+
+ p = lock_user (VERIFY_READ, arg2, arg3, 1);
+ if (arg5 != 0) {
+ target_to_host_timespec(&ts, arg5);
+ ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
+ host_to_target_timespec(arg5, &ts);
+ }
+ else
+ ret = get_errno(mq_send(arg1, p, arg3, arg4));
+ unlock_user (p, arg2, arg3);
+ break;
+ }
+
+ case TARGET_NR_mq_timedreceive:
+ {
+ struct timespec ts;
+ unsigned int prio;
+
+ p = lock_user (VERIFY_READ, arg2, arg3, 1);
+ if (arg5 != 0) {
+ target_to_host_timespec(&ts, arg5);
+ ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
+ host_to_target_timespec(arg5, &ts);
+ }
+ else
+ ret = get_errno(mq_receive(arg1, p, arg3, &prio));
+ unlock_user (p, arg2, arg3);
+ if (arg4 != 0)
+ put_user_u32(prio, arg4);
+ break;
+ }
+
+ /* Not implemented for now... */
+/* case TARGET_NR_mq_notify: */
+/* break; */
+
+ case TARGET_NR_mq_getsetattr:
+ {
+ struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
+ ret = 0;
+ if (arg3 != 0) {
+ ret = mq_getattr(arg1, &posix_mq_attr_out);
+ copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
+ }
+ if (arg2 != 0) {
+ copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
+ ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
+ }
+
+ break;
+ }
+#endif
+
default:
unimplemented:
gemu_log("qemu: Unsupported syscall: %d\n", num);
char d_name[256];
};
+struct target_mq_attr {
+ abi_long mq_flags;
+ abi_long mq_maxmsg;
+ abi_long mq_msgsize;
+ abi_long mq_curmsgs;
+};
+
#include "socket.h"
#include "errno_defs.h"
#define __USER_DS (0x2B)
struct target_pt_regs {
- abi_ulong r15;
- abi_ulong r14;
- abi_ulong r13;
- abi_ulong r12;
- abi_ulong rbp;
- abi_ulong rbx;
+ abi_ulong r15;
+ abi_ulong r14;
+ abi_ulong r13;
+ abi_ulong r12;
+ abi_ulong rbp;
+ abi_ulong rbx;
/* arguments: non interrupts/non tracing syscalls only save upto here*/
- abi_ulong r11;
- abi_ulong r10;
- abi_ulong r9;
- abi_ulong r8;
- abi_ulong rax;
- abi_ulong rcx;
- abi_ulong rdx;
- abi_ulong rsi;
- abi_ulong rdi;
- abi_ulong orig_rax;
+ abi_ulong r11;
+ abi_ulong r10;
+ abi_ulong r9;
+ abi_ulong r8;
+ abi_ulong rax;
+ abi_ulong rcx;
+ abi_ulong rdx;
+ abi_ulong rsi;
+ abi_ulong rdi;
+ abi_ulong orig_rax;
/* end of arguments */
/* cpu exception frame or undefined */
- abi_ulong rip;
- abi_ulong cs;
- abi_ulong eflags;
- abi_ulong rsp;
- abi_ulong ss;
+ abi_ulong rip;
+ abi_ulong cs;
+ abi_ulong eflags;
+ abi_ulong rsp;
+ abi_ulong ss;
+ abi_ulong fs_base;
+ abi_ulong gs_base;
+ abi_ulong ds;
+ abi_ulong es;
+ abi_ulong fs;
+ abi_ulong gs;
/* top of stack page */
};
uint32_t c1_sys; /* System control register. */
uint32_t c1_coproc; /* Coprocessor access register. */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
+ uint32_t c1_secfg; /* Secure configuration register. */
+ uint32_t c1_sedbg; /* Secure debug enable register. */
+ uint32_t c1_nseac; /* Non-secure access control register. */
uint32_t c2_base0; /* MMU translation table base 0. */
uint32_t c2_base1; /* MMU translation table base 1. */
uint32_t c2_control; /* MMU translation table base control. */
ARM_FEATURE_DIV,
ARM_FEATURE_M, /* Microcontroller profile. */
ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */
- ARM_FEATURE_THUMB2EE
+ ARM_FEATURE_THUMB2EE,
+ ARM_FEATURE_TRUSTZONE /* TrustZone Security Extensions. */
};
static inline int arm_feature(CPUARMState *env, int feature)
#define IS_M(env) arm_feature(env, ARM_FEATURE_M)
#define ARM_CPUID(env) (env->cp15.c0_cpuid)
-#define ARM_CPUID_ARM1026 0x4106a262
-#define ARM_CPUID_ARM926 0x41069265
-#define ARM_CPUID_ARM946 0x41059461
-#define ARM_CPUID_TI915T 0x54029152
-#define ARM_CPUID_TI925T 0x54029252
-#define ARM_CPUID_PXA250 0x69052100
-#define ARM_CPUID_PXA255 0x69052d00
-#define ARM_CPUID_PXA260 0x69052903
-#define ARM_CPUID_PXA261 0x69052d05
-#define ARM_CPUID_PXA262 0x69052d06
-#define ARM_CPUID_PXA270 0x69054110
-#define ARM_CPUID_PXA270_A0 0x69054110
-#define ARM_CPUID_PXA270_A1 0x69054111
-#define ARM_CPUID_PXA270_B0 0x69054112
-#define ARM_CPUID_PXA270_B1 0x69054113
-#define ARM_CPUID_PXA270_C0 0x69054114
-#define ARM_CPUID_PXA270_C5 0x69054117
-#define ARM_CPUID_ARM1136 0x4117b363
-#define ARM_CPUID_ARM1136_R2 0x4107b362
-#define ARM_CPUID_ARM11MPCORE 0x410fb022
-#define ARM_CPUID_CORTEXA8 0x410fc080
-#define ARM_CPUID_CORTEXM3 0x410fc231
-#define ARM_CPUID_ANY 0xffffffff
+#define ARM_CPUID_ARM1026 0x4106a262
+#define ARM_CPUID_ARM926 0x41069265
+#define ARM_CPUID_ARM946 0x41059461
+#define ARM_CPUID_TI915T 0x54029152
+#define ARM_CPUID_TI925T 0x54029252
+#define ARM_CPUID_PXA250 0x69052100
+#define ARM_CPUID_PXA255 0x69052d00
+#define ARM_CPUID_PXA260 0x69052903
+#define ARM_CPUID_PXA261 0x69052d05
+#define ARM_CPUID_PXA262 0x69052d06
+#define ARM_CPUID_PXA270 0x69054110
+#define ARM_CPUID_PXA270_A0 0x69054110
+#define ARM_CPUID_PXA270_A1 0x69054111
+#define ARM_CPUID_PXA270_B0 0x69054112
+#define ARM_CPUID_PXA270_B1 0x69054113
+#define ARM_CPUID_PXA270_C0 0x69054114
+#define ARM_CPUID_PXA270_C5 0x69054117
+#define ARM_CPUID_ARM1136 0x4117b363
+#define ARM_CPUID_ARM1136_R2 0x4107b362
+#define ARM_CPUID_ARM11MPCORE 0x410fb022
+#define ARM_CPUID_CORTEXA8 0x411fc081
+#define ARM_CPUID_CORTEXA8_R2 0x412fc083
+#define ARM_CPUID_CORTEXM3 0x410fc231
+#define ARM_CPUID_ANY 0xffffffff
#if defined(CONFIG_USER_ONLY)
#define TARGET_PAGE_BITS 12
static uint32_t cortexa8_cp15_c0_c2[8] =
{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 };
+static uint32_t cortexa8r2_cp16_c0_c2[8] =
+{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00011142, 0, 0, 0 };
+
static uint32_t mpcore_cp15_c0_c1[8] =
{ 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 };
set_feature(env, ARM_FEATURE_VFP3);
set_feature(env, ARM_FEATURE_NEON);
set_feature(env, ARM_FEATURE_THUMB2EE);
+ set_feature(env, ARM_FEATURE_TRUSTZONE);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
break;
+ case ARM_CPUID_CORTEXA8_R2:
+ set_feature(env, ARM_FEATURE_V6);
+ set_feature(env, ARM_FEATURE_V6K);
+ set_feature(env, ARM_FEATURE_V7);
+ set_feature(env, ARM_FEATURE_AUXCR);
+ set_feature(env, ARM_FEATURE_THUMB2);
+ set_feature(env, ARM_FEATURE_VFP);
+ set_feature(env, ARM_FEATURE_VFP3);
+ set_feature(env, ARM_FEATURE_NEON);
+ set_feature(env, ARM_FEATURE_THUMB2EE);
+ set_feature(env, ARM_FEATURE_TRUSTZONE);
+ env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c2;
+ env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
+ env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100; /* should be 0x00011111 */
+ memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
+ memcpy(env->cp15.c0_c2, cortexa8r2_cp16_c0_c2, 8 * sizeof(uint32_t));
+ env->cp15.c0_cachetype = 0x82048004;
+ env->cp15.c0_clid = (1 << 27) | (2 << 24) | (4 << 3) | 3;
+ env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
+ env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
+ env->cp15.c0_ccsid[2] = 0xf03fe03a; /* 256k L2 cache. */
+ break;
case ARM_CPUID_CORTEXM3:
set_feature(env, ARM_FEATURE_V6);
set_feature(env, ARM_FEATURE_THUMB2);
{ ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
{ ARM_CPUID_CORTEXM3, "cortex-m3"},
{ ARM_CPUID_CORTEXA8, "cortex-a8"},
+ { ARM_CPUID_CORTEXA8_R2, "cortex-a8-r2"},
{ ARM_CPUID_TI925T, "ti925t" },
{ ARM_CPUID_PXA250, "pxa250" },
{ ARM_CPUID_PXA255, "pxa255" },
}
goto bad_reg;
case 1: /* System configuration. */
- if (arm_feature(env, ARM_FEATURE_OMAPCP))
- op2 = 0;
- switch (op2) {
+ switch (crm) {
case 0:
- if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0)
- env->cp15.c1_sys = val;
- /* ??? Lots of these bits are not implemented. */
- /* This may enable/disable the MMU, so do a TLB flush. */
- tlb_flush(env, 1);
- break;
- case 1: /* Auxiliary cotrol register. */
- if (arm_feature(env, ARM_FEATURE_XSCALE)) {
- env->cp15.c1_xscaleauxcr = val;
+ if (arm_feature(env, ARM_FEATURE_OMAPCP))
+ op2 = 0;
+ switch (op2) {
+ case 0:
+ if (!arm_feature(env, ARM_FEATURE_XSCALE))
+ env->cp15.c1_sys = val;
+ /* ??? Lots of these bits are not implemented. */
+ /* This may enable/disable the MMU, so do a TLB flush. */
+ tlb_flush(env, 1);
+ break;
+ case 1: /* Auxiliary cotrol register. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ env->cp15.c1_xscaleauxcr = val;
+ break;
+ }
+ /* Not implemented. */
break;
+ case 2:
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ goto bad_reg;
+ if (env->cp15.c1_coproc != val) {
+ env->cp15.c1_coproc = val;
+ /* ??? Is this safe when called from within a TB? */
+ tb_flush(env);
+ }
+ break;
+ default:
+ goto bad_reg;
}
- /* Not implemented. */
break;
- case 2:
- if (arm_feature(env, ARM_FEATURE_XSCALE))
+ case 1:
+ if (!arm_feature(env, ARM_FEATURE_TRUSTZONE)
+ || (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
+ goto bad_reg;
+ switch (op2) {
+ case 0: /* Secure configuration register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ env->cp15.c1_secfg = val;
+ break;
+ case 1: /* Secure debug enable register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ env->cp15.c1_sedbg = val;
+ break;
+ case 2: /* Nonsecure access control register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ env->cp15.c1_nseac = val;
+ break;
+ default:
goto bad_reg;
- if (env->cp15.c1_coproc != val) {
- env->cp15.c1_coproc = val;
- /* ??? Is this safe when called from within a TB? */
- tb_flush(env);
}
break;
default:
goto bad_reg;
}
} else {
- switch (op2) {
- case 0:
- env->cp15.c2_base0 = val;
- break;
- case 1:
- env->cp15.c2_base1 = val;
- break;
- case 2:
+ switch (op2) {
+ case 0:
+ env->cp15.c2_base0 = val;
+ break;
+ case 1:
+ env->cp15.c2_base1 = val;
+ break;
+ case 2:
val &= 7;
env->cp15.c2_control = val;
- env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val);
+ env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val);
env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val);
- break;
- default:
- goto bad_reg;
- }
+ break;
+ default:
+ goto bad_reg;
+ }
}
break;
case 3: /* MMU Domain access control / MPU write buffer control. */
break;
switch (crm) {
case 0: /* Cache lockdown. */
- switch (op1) {
- case 0: /* L1 cache. */
- switch (op2) {
- case 0:
- env->cp15.c9_data = val;
- break;
- case 1:
- env->cp15.c9_insn = val;
- break;
- default:
- goto bad_reg;
- }
- break;
- case 1: /* L2 cache. */
- /* Ignore writes to L2 lockdown/auxiliary registers. */
- break;
- default:
- goto bad_reg;
- }
- break;
+ switch (op1) {
+ case 0: /* L1 cache. */
+ switch (op2) {
+ case 0:
+ env->cp15.c9_data = val;
+ break;
+ case 1:
+ env->cp15.c9_insn = val;
+ break;
+ default:
+ goto bad_reg;
+ }
+ break;
+ case 1: /* L2 cache. */
+ /* Ignore writes to L2 lockdown/auxiliary registers. */
+ break;
+ default:
+ goto bad_reg;
+ }
+ break;
case 1: /* TCM memory region registers. */
/* Not implemented. */
goto bad_reg;
case 0: /* Device ID. */
return env->cp15.c0_cpuid;
case 1: /* Cache Type. */
- return env->cp15.c0_cachetype;
+ return env->cp15.c0_cachetype;
case 2: /* TCM status. */
return 0;
case 3: /* TLB type register. */
default:
goto bad_reg;
}
+ break;
case 1:
/* These registers aren't documented on arm11 cores. However
Linux looks at them anyway. */
default:
goto bad_reg;
}
+ break;
case 1: /* System configuration. */
- if (arm_feature(env, ARM_FEATURE_OMAPCP))
- op2 = 0;
- switch (op2) {
- case 0: /* Control register. */
- return env->cp15.c1_sys;
- case 1: /* Auxiliary control register. */
- if (arm_feature(env, ARM_FEATURE_XSCALE))
- return env->cp15.c1_xscaleauxcr;
- if (!arm_feature(env, ARM_FEATURE_AUXCR))
- goto bad_reg;
- switch (ARM_CPUID(env)) {
- case ARM_CPUID_ARM1026:
- return 1;
- case ARM_CPUID_ARM1136:
- case ARM_CPUID_ARM1136_R2:
- return 7;
- case ARM_CPUID_ARM11MPCORE:
- return 1;
- case ARM_CPUID_CORTEXA8:
- return 2;
+ switch (crm) {
+ case 0:
+ if (arm_feature(env, ARM_FEATURE_OMAPCP))
+ op2 = 0;
+ switch (op2) {
+ case 0: /* Control register. */
+ return env->cp15.c1_sys;
+ case 1: /* Auxiliary control register. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ return env->cp15.c1_xscaleauxcr;
+ if (!arm_feature(env, ARM_FEATURE_AUXCR))
+ goto bad_reg;
+ switch (ARM_CPUID(env)) {
+ case ARM_CPUID_ARM1026:
+ return 1;
+ case ARM_CPUID_ARM1136:
+ case ARM_CPUID_ARM1136_R2:
+ return 7;
+ case ARM_CPUID_ARM11MPCORE:
+ return 1;
+ case ARM_CPUID_CORTEXA8:
+ case ARM_CPUID_CORTEXA8_R2:
+ return 2;
+ default:
+ goto bad_reg;
+ }
+ break;
+ case 2: /* Coprocessor access register. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ goto bad_reg;
+ return env->cp15.c1_coproc;
default:
goto bad_reg;
}
- case 2: /* Coprocessor access register. */
- if (arm_feature(env, ARM_FEATURE_XSCALE))
+ break;
+ case 1:
+ if (!arm_feature(env, ARM_FEATURE_TRUSTZONE)
+ || (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
+ goto bad_reg;
+ switch (op2) {
+ case 0: /* Secure configuration register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ return env->cp15.c1_secfg;
+ case 1: /* Secure debug enable register. */
+ if (env->cp15.c1_secfg & 1)
+ goto bad_reg;
+ return env->cp15.c1_sedbg;
+ case 2: /* Nonsecure access control register. */
+ return env->cp15.c1_nseac;
+ default:
goto bad_reg;
- return env->cp15.c1_coproc;
+ }
+ break;
default:
goto bad_reg;
}
+ break;
case 2: /* MMU Page table control / MPU cache control. */
if (arm_feature(env, ARM_FEATURE_MPU)) {
switch (op2) {
goto bad_reg;
}
} else {
- switch (op2) {
- case 0:
- return env->cp15.c2_base0;
- case 1:
- return env->cp15.c2_base1;
- case 2:
+ switch (op2) {
+ case 0:
+ return env->cp15.c2_base0;
+ case 1:
+ return env->cp15.c2_base1;
+ case 2:
return env->cp15.c2_control;
- default:
- goto bad_reg;
- }
- }
+ default:
+ goto bad_reg;
+ }
+ }
case 3: /* MMU Domain access control / MPU write buffer control. */
return env->cp15.c3;
case 4: /* Reserved. */
} else {
if (arm_feature(env, ARM_FEATURE_OMAPCP))
op2 = 0;
- switch (op2) {
- case 0:
- return env->cp15.c6_data;
- case 1:
- if (arm_feature(env, ARM_FEATURE_V6)) {
- /* Watchpoint Fault Adrress. */
- return 0; /* Not implemented. */
- } else {
- /* Instruction Fault Adrress. */
- /* Arm9 doesn't have an IFAR, but implementing it anyway
- shouldn't do any harm. */
- return env->cp15.c6_insn;
- }
- case 2:
- if (arm_feature(env, ARM_FEATURE_V6)) {
- /* Instruction Fault Adrress. */
- return env->cp15.c6_insn;
- } else {
- goto bad_reg;
- }
- default:
- goto bad_reg;
- }
+ switch (op2) {
+ case 0:
+ return env->cp15.c6_data;
+ case 1:
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ /* Watchpoint Fault Adrress. */
+ return 0; /* Not implemented. */
+ }
+ /* Instruction Fault Adrress. */
+ /* Arm9 doesn't have an IFAR, but implementing it anyway
+ shouldn't do any harm. */
+ return env->cp15.c6_insn;
+ case 2:
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ /* Instruction Fault Adrress. */
+ return env->cp15.c6_insn;
+ }
+ goto bad_reg;
+ default:
+ goto bad_reg;
+ }
}
case 7: /* Cache control. */
- /* FIXME: Should only clear Z flag if destination is r15. */
- env->ZF = 0;
+ if (((insn >> 12) & 0xf) == 0xf) /* clear ZF only if destination is r15 */
+ env->ZF = 0;
return 0;
case 8: /* MMU TLB control. */
goto bad_reg;
case 9: /* Cache lockdown. */
switch (op1) {
case 0: /* L1 cache. */
- if (arm_feature(env, ARM_FEATURE_OMAPCP))
- return 0;
+ if (arm_feature(env, ARM_FEATURE_OMAPCP))
+ return 0;
switch (op2) {
case 0:
return env->cp15.c9_data;
qemu_register_machine(&mainstone2_machine);
qemu_register_machine(&musicpal_machine);
qemu_register_machine(&tosapda_machine);
+ qemu_register_machine(&beagle_machine);
}
void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, env->cp15.c1_sys);
qemu_put_be32(f, env->cp15.c1_coproc);
qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
+ qemu_put_be32(f, env->cp15.c1_secfg);
+ qemu_put_be32(f, env->cp15.c1_sedbg);
+ qemu_put_be32(f, env->cp15.c1_nseac);
qemu_put_be32(f, env->cp15.c2_base0);
qemu_put_be32(f, env->cp15.c2_base1);
qemu_put_be32(f, env->cp15.c2_mask);
env->cp15.c1_sys = qemu_get_be32(f);
env->cp15.c1_coproc = qemu_get_be32(f);
env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
+ env->cp15.c1_secfg = qemu_get_be32(f);
+ env->cp15.c1_sedbg = qemu_get_be32(f);
+ env->cp15.c1_nseac = qemu_get_be32(f);
env->cp15.c2_base0 = qemu_get_be32(f);
env->cp15.c2_base1 = qemu_get_be32(f);
env->cp15.c2_mask = qemu_get_be32(f);
uint32_t HELPER (add_cc)(uint32_t a, uint32_t b)
{
uint32_t result;
- result = T0 + T1;
+ result = a + b;
env->NF = env->ZF = result;
env->CF = result < a;
env->VF = (a ^ b ^ -1) & (a ^ result);
dead_tmp(var);
}
+/* Variant of store_reg which uses branch&exchange logic when storing
+ to r15 in ARM architecture v7 and above. The source must be a temporary
+ and will be marked as dead. */
+#define store_reg_bx(dc, reg, var) \
+ if ((reg) == 15 && ENABLE_ARCH_7) \
+ gen_bx((dc), (var)); \
+ else \
+ store_reg((dc), (reg), (var));
/* Basic operations. */
#define gen_op_movl_T0_T1() tcg_gen_mov_i32(cpu_T[0], cpu_T[1])
dead_tmp(tmp);
}
+/* dest = T0 + T1 + CF. */
+static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
+{
+ TCGv tmp;
+ tcg_gen_add_i32(dest, t0, t1);
+ tmp = load_cpu_field(CF);
+ tcg_gen_add_i32(dest, dest, tmp);
+ dead_tmp(tmp);
+}
+
/* dest = T0 - T1 + CF - 1. */
static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
{
return 0;
}
-/* Generate an old-style exception return. */
-static void gen_exception_return(DisasContext *s)
+/* Generate an old-style exception return. Marks pc as dead. */
+static void gen_exception_return(DisasContext *s, TCGv pc)
{
TCGv tmp;
- gen_movl_reg_T0(s, 15);
+ store_reg(s, 15, pc);
tmp = load_cpu_field(spsr);
gen_set_cpsr(tmp, 0xffffffff);
dead_tmp(tmp);
dead_tmp(tmp2);
store_reg(s, rd, tmp);
break;
- case 7: /* bkpt */
- gen_set_condexec(s);
- gen_set_pc_im(s->pc - 4);
- gen_exception(EXCP_BKPT);
- s->is_jmp = DISAS_JUMP;
+ case 7:
+ if (op1 == 1) {
+ /* bkpt */
+ gen_set_condexec(s);
+ gen_set_pc_im(s->pc - 4);
+ gen_exception(EXCP_BKPT);
+ s->is_jmp = DISAS_JUMP;
+ } else if (op1 == 3) {
+ /* smi/smc */
+ if (!(env->cp15.c0_c2[4] & 0xf000) || IS_USER(s))
+ goto illegal_op;
+ /* TODO: real implementation; execute as NOP for now */
+ /*fprintf(stderr, "smc [0x%08x] pc=0x%08x\n", insn, s->pc);*/
+ } else {
+ goto illegal_op;
+ }
break;
case 0x8: /* signed multiply */
case 0xa:
shift = ((insn >> 8) & 0xf) * 2;
if (shift)
val = (val >> shift) | (val << (32 - shift));
- gen_op_movl_T1_im(val);
+ tmp2 = new_tmp();
+ tcg_gen_movi_i32(tmp2, val);
if (logic_cc && shift)
- gen_set_CF_bit31(cpu_T[1]);
+ gen_set_CF_bit31(tmp2);
} else {
/* register */
rm = (insn) & 0xf;
- gen_movl_T1_reg(s, rm);
+ tmp2 = load_reg(s, rm);
shiftop = (insn >> 5) & 3;
if (!(insn & (1 << 4))) {
shift = (insn >> 7) & 0x1f;
- gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
+ gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
} else {
rs = (insn >> 8) & 0xf;
tmp = load_reg(s, rs);
- gen_arm_shift_reg(cpu_T[1], shiftop, tmp, logic_cc);
+ gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
}
}
if (op1 != 0x0f && op1 != 0x0d) {
rn = (insn >> 16) & 0xf;
- gen_movl_T0_reg(s, rn);
- }
+ tmp = load_reg(s, rn);
+ } else
+ tmp = new_tmp();
rd = (insn >> 12) & 0xf;
switch(op1) {
case 0x00:
- gen_op_andl_T0_T1();
- gen_movl_reg_T0(s, rd);
+ tcg_gen_and_i32(tmp, tmp, tmp2);
if (logic_cc)
- gen_op_logic_T0_cc();
+ gen_logic_CC(tmp);
+ store_reg_bx(s, rd, tmp);
break;
case 0x01:
- gen_op_xorl_T0_T1();
- gen_movl_reg_T0(s, rd);
+ tcg_gen_xor_i32(tmp, tmp, tmp2);
if (logic_cc)
- gen_op_logic_T0_cc();
+ gen_logic_CC(tmp);
+ store_reg_bx(s, rd, tmp);
break;
case 0x02:
if (set_cc && rd == 15) {
/* SUBS r15, ... is used for exception return. */
if (IS_USER(s))
goto illegal_op;
- gen_op_subl_T0_T1_cc();
- gen_exception_return(s);
+ gen_helper_sub_cc(tmp, tmp, tmp2);
+ gen_exception_return(s, tmp);
} else {
if (set_cc)
- gen_op_subl_T0_T1_cc();
+ gen_helper_sub_cc(tmp, tmp, tmp2);
else
- gen_op_subl_T0_T1();
- gen_movl_reg_T0(s, rd);
+ tcg_gen_sub_i32(tmp, tmp, tmp2);
+ store_reg_bx(s, rd, tmp);
}
break;
case 0x03:
if (set_cc)
- gen_op_rsbl_T0_T1_cc();
+ gen_helper_sub_cc(tmp, tmp2, tmp);
else
- gen_op_rsbl_T0_T1();
- gen_movl_reg_T0(s, rd);
+ tcg_gen_sub_i32(tmp, tmp2, tmp);
+ store_reg_bx(s, rd, tmp);
break;
case 0x04:
if (set_cc)
- gen_op_addl_T0_T1_cc();
+ gen_helper_add_cc(tmp, tmp, tmp2);
else
- gen_op_addl_T0_T1();
- gen_movl_reg_T0(s, rd);
+ tcg_gen_add_i32(tmp, tmp, tmp2);
+ store_reg_bx(s, rd, tmp);
break;
case 0x05:
if (set_cc)
- gen_op_adcl_T0_T1_cc();
+ gen_helper_adc_cc(tmp, tmp, tmp2);
else
- gen_adc_T0_T1();
- gen_movl_reg_T0(s, rd);
+ gen_add_carry(tmp, tmp, tmp2);
+ store_reg_bx(s, rd, tmp);
break;
case 0x06:
if (set_cc)
- gen_op_sbcl_T0_T1_cc();
+ gen_helper_sbc_cc(tmp, tmp, tmp2);
else
- gen_sbc_T0_T1();
- gen_movl_reg_T0(s, rd);
+ gen_sub_carry(tmp, tmp, tmp2);
+ store_reg_bx(s, rd, tmp);
break;
case 0x07:
if (set_cc)
- gen_op_rscl_T0_T1_cc();
+ gen_helper_sbc_cc(tmp, tmp2, tmp);
else
- gen_rsc_T0_T1();
- gen_movl_reg_T0(s, rd);
+ gen_sub_carry(tmp, tmp2, tmp);
+ store_reg_bx(s, rd, tmp);
break;
case 0x08:
if (set_cc) {
- gen_op_andl_T0_T1();
- gen_op_logic_T0_cc();
+ tcg_gen_and_i32(tmp, tmp, tmp2);
+ gen_logic_CC(tmp);
}
+ dead_tmp(tmp);
break;
case 0x09:
if (set_cc) {
- gen_op_xorl_T0_T1();
- gen_op_logic_T0_cc();
+ tcg_gen_xor_i32(tmp, tmp, tmp2);
+ gen_logic_CC(tmp);
}
+ dead_tmp(tmp);
break;
case 0x0a:
- if (set_cc) {
- gen_op_subl_T0_T1_cc();
- }
+ if (set_cc)
+ gen_helper_sub_cc(tmp, tmp, tmp2);
+ dead_tmp(tmp);
break;
case 0x0b:
- if (set_cc) {
- gen_op_addl_T0_T1_cc();
- }
+ if (set_cc)
+ gen_helper_add_cc(tmp, tmp, tmp2);
+ dead_tmp(tmp);
break;
case 0x0c:
- gen_op_orl_T0_T1();
- gen_movl_reg_T0(s, rd);
+ tcg_gen_or_i32(tmp, tmp, tmp2);
if (logic_cc)
- gen_op_logic_T0_cc();
+ gen_logic_CC(tmp);
+ store_reg_bx(s, rd, tmp);
break;
case 0x0d:
+ tcg_gen_mov_i32(tmp, tmp2);
if (logic_cc && rd == 15) {
/* MOVS r15, ... is used for exception return. */
if (IS_USER(s))
goto illegal_op;
- gen_op_movl_T0_T1();
- gen_exception_return(s);
+ gen_exception_return(s, tmp);
} else {
- gen_movl_reg_T1(s, rd);
+ store_reg_bx(s, rd, tmp);
if (logic_cc)
- gen_op_logic_T1_cc();
+ gen_logic_CC(tmp2);
}
break;
case 0x0e:
- gen_op_bicl_T0_T1();
- gen_movl_reg_T0(s, rd);
+ tcg_gen_bic_i32(tmp, tmp, tmp2);
if (logic_cc)
- gen_op_logic_T0_cc();
+ gen_logic_CC(tmp);
+ store_reg_bx(s, rd, tmp);
break;
default:
case 0x0f:
- gen_op_notl_T1();
- gen_movl_reg_T1(s, rd);
+ tcg_gen_not_i32(tmp, tmp2);
if (logic_cc)
- gen_op_logic_T1_cc();
+ gen_logic_CC(tmp);
+ store_reg_bx(s, rd, tmp);
break;
}
+ dead_tmp(tmp2);
} else {
/* other instructions */
op1 = (insn >> 24) & 0xf;
/* add x(r1), r0 */
tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) -
offsetof(CPUTLBEntry, addr_read));
+#elif defined(CONFIG_USE_GUEST_BASE)
+ /*
+ * Add guest_base to all loads.
+ */
+ tcg_out_mov(s, r0, addr_reg); /* movl addr_reg, r0 */
+ tcg_out_addi(s, r0, GUEST_BASE); /* addl $GUEST_BASE, r0 */
#else
r0 = addr_reg;
#endif
/* add x(r1), r0 */
tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) -
offsetof(CPUTLBEntry, addr_write));
+#elif defined(CONFIG_USE_GUEST_BASE)
+ /*
+ * Add guest_base to all stores.
+ */
+ tcg_out_mov(s, r0, addr_reg); /* movl addr_reg, r0 */
+ tcg_out_addi(s, r0, GUEST_BASE); /* addl $GUEST_BASE, r0 */
#else
r0 = addr_reg;
#endif
/* add x(r1), r0 */
tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
offsetof(CPUTLBEntry, addr_read));
+#elif defined(CONFIG_USE_GUEST_BASE)
+ /*
+ * Add guest_base to all loads.
+ */
+ tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); /* movq addr_reg, r0 */
+ tcg_out_addi(s, r0, GUEST_BASE); /* addq $GUEST_BASE, r0 */
#else
r0 = addr_reg;
#endif
/* add x(r1), r0 */
tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
offsetof(CPUTLBEntry, addr_write));
+#elif defined(CONFIG_USE_GUEST_BASE)
+ /*
+ * Add guest_base to all stores.
+ */
+ tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg); /* movq addr_reg, r0 */
+ tcg_out_addi(s, r0, GUEST_BASE); /* addq $GUEST_BASE, r0 */
#else
r0 = addr_reg;
#endif