From: Riku Voipio Date: Mon, 8 Jun 2009 15:31:58 +0000 (+0300) Subject: Merge commit 'gnu/master' into test X-Git-Url: http://vcs.maemo.org/git/?p=qemu;a=commitdiff_plain;h=759b334a9739814df2883aa4c41b1c0f5670e90a Merge commit 'gnu/master' into test Epic merge Conflicts: Makefile block.c block.h configure hw/boards.h hw/flash.h hw/integratorcp.c hw/nand.c hw/omap2.c hw/omap_i2c.c hw/sd.c hw/smc91c111.c hw/tsc2005.c hw/tusb6010.c hw/usb-musb.c linux-user/syscall.c target-arm/machine.c target-arm/translate.c --- 759b334a9739814df2883aa4c41b1c0f5670e90a diff --cc Makefile index 6eb73c5,767d6c5..a991fbd --- a/Makefile +++ b/Makefile @@@ -63,10 -65,10 +65,10 @@@ recurse-all: $(SUBDIR_RULES ####################################################################### # BLOCK_OBJS is code used by both qemu system emulation and qemu-img - BLOCK_OBJS=cutils.o cache-utils.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-vmstate.o + BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.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 @@@ -233,10 -254,10 +254,10 @@@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-c 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 + rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d $(MAKE) -C tests clean - for d in $(TARGET_DIRS); do \ + for d in $(TARGET_DIRS) libhw32 libhw64; do \ $(MAKE) -C $$d $@ || exit 1 ; \ done diff --cc Makefile.target index 858ba3d,27de4b9..40a0599 --- a/Makefile.target +++ b/Makefile.target @@@ -669,10 -664,9 +666,10 @@@ OBJS+= arm-semi. OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o OBJS+= pflash_cfi01.o gumstix.o - OBJS+= zaurus.o ide.o serial.o nand.o ecc.o spitz.o tosa.o tc6393xb.o + OBJS+= zaurus.o ide.o serial.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+= mst_fpga.o mainstone.o diff --cc configure index c45bd75,89e7f53..4d4330c --- a/configure +++ b/configure @@@ -178,10 -180,10 +180,11 @@@ softmmu="yes linux_user="no" darwin_user="no" bsd_user="no" -build_docs="yes" +guest_base="no" +build_docs="no" uname_release="" curses="yes" + curl="yes" pthread="yes" aio="yes" io_thread="no" @@@ -1241,29 -1276,9 +1281,28 @@@ EO fi fi +# check if utimensat and futimens are supported +utimens=no +cat > $TMPC << EOF +#define _ATFILE_SOURCE +#define _GNU_SOURCE +#include +#include + +int main(void) +{ + utimensat(AT_FDCWD, "foo", NULL, 0); + futimens(0, NULL); + return 0; +} +EOF +if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then + utimens=yes +fi + # Check if tools are available to build documentation. - if [ -x "`which texi2html 2>/dev/null`" ] && \ - [ -x "`which pod2man 2>/dev/null`" ]; then - build_docs="yes" + if test "$build_docs" = "yes" -a \( ! -x "`which texi2html 2>/dev/null`" -o ! -x "`which pod2man 2>/dev/null`" \) ; then + build_docs="no" fi ########################################## diff --cc hw/beagle.c index 3e91935,0000000..d422114 mode 100644,000000..100644 --- a/hw/beagle.c +++ b/hw/beagle.c @@@ -1,87 -1,0 +1,94 @@@ +/* + * 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; ++ NANDFlashState *nand; + struct omap3_lcd_panel_s *lcd_panel; + i2c_bus *i2c; - struct twl4030_s *twl4030; ++ void *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) ++static void beagle_init(ram_addr_t 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); ++ opaque = smc91c111_init_lite(&nd_table[0], /*0x08000000,*/ ++ omap2_gpio_in_get(s->cpu->gpif, 54)[0]); + omap_gpmc_attach(s->cpu->gpmc, BEAGLE_SMC_CS, smc91c111_iomemtype(opaque), - 0, 0, opaque, 0); ++ NULL, NULL, 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, */ +}; + ++static void beagle_machine_init(void) ++{ ++ qemu_register_machine(&beagle_machine); ++} ++ ++machine_init(beagle_machine_init); diff --cc hw/blizzard.c index e75833b,40739d5..44978a1 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@@ -117,8 -118,9 +117,8 @@@ typedef struct uint16_t *ptr; int angle; int pitch; - blizzard_fn_t line_fn; } data; - }; + } BlizzardState; /* Bytes(!) per pixel */ static const int blizzard_iformat_bpp[0x10] = { @@@ -985,16 -942,23 +985,16 @@@ static void blizzard_screen_dump(void * ppm_save(filename, s->state->surface); } -#define DEPTH 8 -#include "blizzard_template.h" -#define DEPTH 15 -#include "blizzard_template.h" -#define DEPTH 16 -#include "blizzard_template.h" -#define DEPTH 24 -#include "blizzard_template.h" -#define DEPTH 32 -#include "blizzard_template.h" - void *s1d13745_init(qemu_irq gpio_int) { - struct blizzard_s *s = (struct blizzard_s *) qemu_mallocz(sizeof(*s)); + BlizzardState *s = (BlizzardState *) qemu_mallocz(sizeof(*s)); s->fb = qemu_malloc(0x180000); - + /* Fill the framebuffer with white color here because the corresponding + * code in nseries.c is broken since the DisplayState change in QEMU. + * This is supposedly ok since nseries.c is the only user of blizzard.c */ + memset(s->fb, 0xff, 0x180000); + s->state = graphic_console_init(blizzard_update_display, blizzard_invalidate_display, blizzard_screen_dump, NULL, s); diff --cc hw/devices.h index ac66ce7,156bde2..5f80a20 --- a/hw/devices.h +++ b/hw/devices.h @@@ -4,30 -4,16 +4,18 @@@ /* Devices that have nowhere better to go. */ /* smc91c111.c */ - void *smc91c111_init(NICInfo *, uint32_t, qemu_irq, int phys_alloc); -void smc91c111_init(NICInfo *, uint32_t, qemu_irq); ++void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq); ++void *smc91c111_init_lite(NICInfo *nd, qemu_irq irq); +int smc91c111_iomemtype(void *opaque); - /* ssd0323.c */ - int ssd0323_xfer_ssi(void *opaque, int data); - void *ssd0323_init(qemu_irq *cmd_p); - - /* ads7846.c */ - struct ads7846_state_s; - uint32_t ads7846_read(void *opaque); - void ads7846_write(void *opaque, uint32_t value); - struct ads7846_state_s *ads7846_init(qemu_irq penirq); - /* tsc210x.c */ - struct uwire_slave_s; - struct mouse_transform_info_s; - struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); - struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, - qemu_irq dav, AudioState *audio); - struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); + uWireSlave *tsc2102_init(qemu_irq pint); + uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav); + I2SCodec *tsc210x_codec(uWireSlave *chip); uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len); - void tsc210x_set_transform(struct uwire_slave_s *chip, - struct mouse_transform_info_s *info); - void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down); + void tsc210x_set_transform(uWireSlave *chip, + MouseTransformInfo *info); + void tsc210x_key_event(uWireSlave *chip, int key, int down); /* tsc2005.c */ void *tsc2005_init(qemu_irq pintdav); diff --cc hw/flash.h index 8cbd9e0,69aef8c..7c1d3b9 --- a/hw/flash.h +++ b/hw/flash.h @@@ -17,15 -17,14 +17,15 @@@ pflash_t *pflash_cfi02_register(target_ uint16_t unlock_addr0, uint16_t unlock_addr1); /* nand.c */ - struct nand_flash_s; - struct nand_flash_s *nand_init(int manf_id, int chip_id); - void nand_done(struct nand_flash_s *s); - void nand_setpins(struct nand_flash_s *s, + typedef struct NANDFlashState NANDFlashState; + NANDFlashState *nand_init(int manf_id, int chip_id); + void nand_done(NANDFlashState *s); + void nand_setpins(NANDFlashState *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, uint32_t value); - uint32_t nand_getio(struct nand_flash_s *s); - uint32_t nand_getbuswidth(struct nand_flash_s *s); + void nand_getpins(NANDFlashState *s, int *rb); -void nand_setio(NANDFlashState *s, uint8_t value); -uint8_t nand_getio(NANDFlashState *s); ++void nand_setio(NANDFlashState *s, uint32_t value); ++uint32_t nand_getio(NANDFlashState *s); ++uint32_t nand_getbuswidth(NANDFlashState *s); #define NAND_MFR_TOSHIBA 0x98 #define NAND_MFR_SAMSUNG 0xec diff --cc hw/i2c.h index 7a80bcb,f15c70c..26155b5 --- a/hw/i2c.h +++ b/hw/i2c.h @@@ -82,13 -79,6 +79,9 @@@ void wm8750_set_bclk_in(void *opaque, i void tmp105_set(i2c_slave *i2c, int temp); /* lm832x.c */ - struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq); - void lm832x_key_event(struct i2c_slave *i2c, int key, int state); + void lm832x_key_event(i2c_slave *i2c, int key, int state); +/* twl4030.c */ - struct twl4030_s; - struct twl4030_s *twl4030_init(i2c_bus *bus, qemu_irq irq); ++void *twl4030_init(i2c_bus *gp_bus, qemu_irq irq); + #endif diff --cc hw/nand.c index 2cadbe4,4ad77ec..d2a3cc4 --- a/hw/nand.c +++ b/hw/nand.c @@@ -52,9 -45,8 +52,9 @@@ # define MAX_PAGE 0x800 # define MAX_OOB 0x40 - struct nand_flash_s { + struct NANDFlashState { 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; @@@ -73,9 -64,9 +73,9 @@@ 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, uint64_t addr, int offset); + void (*blk_write)(NANDFlashState *s); + void (*blk_erase)(NANDFlashState *s); - void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset); ++ void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset); }; # define NAND_NO_AUTOINCR 0x00000001 @@@ -217,17 -208,9 +217,17 @@@ static void nand_reset(NANDFlashState * 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) ++static inline void nand_pushio_byte(NANDFlashState *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) + static void nand_command(NANDFlashState *s) { switch (s->cmd) { case NAND_CMD_READ0: @@@ -362,16 -344,11 +362,16 @@@ void nand_getpins(NANDFlashState *s, in *rb = 1; } - void nand_setio(struct nand_flash_s *s, uint32_t value) -void nand_setio(NANDFlashState *s, uint8_t value) ++void nand_setio(NANDFlashState *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); @@@ -458,10 -415,9 +458,10 @@@ } } - uint32_t nand_getio(struct nand_flash_s *s) -uint8_t nand_getio(NANDFlashState *s) ++uint32_t nand_getio(NANDFlashState *s) { int offset; + uint32_t x = 0; /* Allow sequential reading */ if (!s->iolen && s->cmd == NAND_CMD_READ0) { @@@ -478,28 -434,14 +478,28 @@@ 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) ++uint32_t nand_getbuswidth(NANDFlashState *s) +{ + if (!s) + return 0; + return (s->buswidth << 3); } - struct nand_flash_s *nand_init(int manf_id, int chip_id) + NANDFlashState *nand_init(int manf_id, int chip_id) { int pagesize; - struct nand_flash_s *s; + NANDFlashState *s; int index; if (nand_flash_ids[chip_id].size == 0) { @@@ -576,9 -515,9 +574,9 @@@ void nand_done(NANDFlashState *s #else /* Program a single page */ - static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s) + static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *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; @@@ -622,9 -561,9 +620,9 @@@ } /* Erase a single block */ - static void glue(nand_blk_erase_, PAGE_SIZE)(struct nand_flash_s *s) + static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *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); @@@ -667,8 -606,8 +665,8 @@@ } } - static void glue(nand_blk_load_, PAGE_SIZE)(struct nand_flash_s *s, + static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s, - uint32_t addr, int offset) + uint64_t addr, int offset) { if (PAGE(addr) >= s->pages) return; diff --cc hw/omap.h index 09ea052,231049d..6eda35f --- a/hw/omap.h +++ b/hw/omap.h @@@ -893,8 -690,15 +893,8 @@@ struct omap_uwire_s struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, qemu_irq *irq, qemu_irq dma, omap_clk clk); void omap_uwire_attach(struct omap_uwire_s *s, - struct uwire_slave_s *slave, int chipselect); + uWireSlave *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); diff --cc hw/omap2.c index 895a1c7,6fccca4..785a6d8 --- a/hw/omap2.c +++ b/hw/omap2.c @@@ -2565,10 -2638,8 +2563,10 @@@ static uint32_t omap_tap_read(void *opa 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__); + hw_error("%s: Bad mpu model\n", __FUNCTION__); } case 0x208: /* PRODUCTION_ID_reg for OMAP2 */ @@@ -2584,10 -2655,8 +2582,10 @@@ return 0x000000f0; case omap3430: return 0x000000f0; + case omap3530: + return 0x000f00f0; default: - cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__); + hw_error("%s: Bad mpu model\n", __FUNCTION__); } case 0x20c: @@@ -2599,10 -2668,9 +2597,10 @@@ 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__); + hw_error("%s: Bad mpu model\n", __FUNCTION__); } case 0x218: /* DIE_ID_reg */ diff --cc hw/omap3_mmc.c index 402db19,0000000..7897424 mode 100644,000000..100644 --- a/hw/omap3_mmc.c +++ b/hw/omap3_mmc.c @@@ -1,793 -1,0 +1,793 @@@ +/* + * OMAP3 Multimedia Card/Secure Digital/Secure Digital I/O (MMC/SD/SDIO) Card Interface emulation + * + * Copyright (C) 2008 yajin + * Copyright (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "hw.h" +#include "omap.h" +#include "sd.h" + +/* debug levels: + 0 - no debug + 1 - print out all commands in processing order + 2 - dump all register accesses and buffer management */ +#define MMC_DEBUG_LEVEL 0 + +#if MMC_DEBUG_LEVEL>0 +#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__) +#if MMC_DEBUG_LEVEL>1 +#define TRACE2(...) TRACE(__VA_ARGS__) +#else +#define TRACE2(...) +#endif +#else +#define TRACE(...) +#define TRACE2(...) +#endif + +struct omap3_mmc_s +{ + qemu_irq irq; + qemu_irq *dma; + qemu_irq coverswitch; + omap_clk clk; + SDState *card; + + uint32_t sysconfig; + uint32_t sysstatus; + uint32_t csre; + uint32_t systest; + uint32_t con; + uint32_t pwcnt; + uint32_t blk; + uint32_t arg; + uint32_t cmd; + uint32_t rsp10; + uint32_t rsp32; + uint32_t rsp54; + uint32_t rsp76; + uint32_t data; + uint32_t pstate; + uint32_t hctl; + uint32_t sysctl; + uint32_t stat; + uint32_t ie; + uint32_t ise; + uint32_t ac12; + uint32_t capa; + uint32_t cur_capa; + uint32_t rev; + + uint16_t blen_counter; + uint16_t nblk_counter; + + uint32_t fifo[256]; + int fifo_start; + int fifo_len; + + int ddir; + int transfer; + int stop; + + uint32_t stat_pending; +}; + + +typedef enum +{ + sd_nore = 0, /* no response */ + sd_136_bits = 1, /* response length 136 bits */ + sd_48_bits = 2, /* response length 48 bits */ + sd_48b_bits = 3, /* response length 48 bits with busy after response */ +} omap3_sd_rsp_type_t; + +static void omap3_mmc_command(struct omap3_mmc_s *host); + +static void omap3_mmc_interrupts_update(struct omap3_mmc_s *s) +{ + qemu_set_irq(s->irq, !!((s->stat | s->stat_pending) & s->ie & s->ise)); +} + +static void omap3_mmc_fifolevel_update(struct omap3_mmc_s *host) +{ + enum { ongoing, ready, aborted } state = ongoing; + + if ((host->cmd & (1 << 21))) { /* DP */ + if (host->ddir) { + TRACE2("receive, dma=%d, fifo_len=%d bytes", + host->cmd & 1, host->fifo_len * 4); + + /* omap3_mmc_transfer ensures we always have data in FIFO + during receive as long as all data has not been transferred - + NOTE that the actual transfer may be finished already (i.e. + host->transfer is cleared) but not all data has been read out + from FIFO yet */ + if (host->fifo_len) { + if (host->cmd & 1) { /* DE */ + if (host->fifo_len * 4 == (host->blk & 0x7ff)) { /* BLEN */ + if (host->stop) + state = aborted; + else + qemu_irq_raise(host->dma[1]); + } else + qemu_irq_lower(host->dma[1]); + } else { + if (host->stop + && host->fifo_len * 4 == (host->blk & 0x7ff)) + state = aborted; + else { + host->pstate |= 0x0800; /* BRE */ + host->stat_pending |= 0x20; /* BRR */ + } + } + } + else + state = host->stop ? aborted : ready; + } else { + /* omap3_mmc_transfer keeps FIFO empty during transmit so + we just check all blocks have been transferred or not */ + if (host->transfer) { + if (host->cmd & 1) { /* DE */ + if (host->blen_counter == (host->blk & 0x7ff)) { /* BLEN */ + if (host->stop) + state = aborted; + else + qemu_irq_raise(host->dma[0]); + } else + qemu_irq_lower(host->dma[0]); + } else { + if (host->stop + && host->blen_counter == (host->blk & 0x7ff)) + state = aborted; + else { + host->pstate |= 0x0400; /* BWE */ + host->stat_pending |= 0x10; /* BWR */ + } + } + } else + state = host->stop ? aborted : ready; + } + + if ((host->cmd & 1) || state != ongoing) { /* DE */ + host->pstate &= ~0x0c00; /* BRE | BWE */ + host->stat_pending &= ~0x30; /* BRR | BWR */ + host->stat &= ~0x30; /* BRR | BWR */ + if (state != ongoing) { + TRACE2("transfer %s", + state == ready + ? "complete" + : "aborted --> complete"); + host->stat_pending |= 0x2; /* TC */ + if (host->cmd & 0x04) { /* ACEN */ + host->stop = 0x0cc30000; + state = aborted; + } + if (state == aborted) { + host->cmd = host->stop; + host->stop = 0; + omap3_mmc_command(host); + } + } + } + } +} + +static void omap3_mmc_transfer(struct omap3_mmc_s *host) +{ + int i; + uint32_t x; +#if MMC_DEBUG_LEVEL>1 + int j; + uint8_t c, sym[17]; +#endif + + /* IF data transfer is inactive + OR block count enabled with zero block count + OR in receive mode and we have unread data in FIFO + OR in transmit mode and we have no data in FIFO, + THEN don't do anything */ + if (!host->transfer + || ((host->cmd & 2) && !host->nblk_counter) + || (host->ddir && host->fifo_len) + || (!host->ddir && !host->fifo_len)) + return; + + if (host->ddir) { + TRACE2("begin, %d blocks (%d bytes/block) left to receive, %d bytes in FIFO", + (host->cmd & 2) ? host->nblk_counter : 1, + host->blk & 0x7ff, + host->fifo_len * 4); + while (host->blen_counter && host->fifo_len < 255) { + for (i = 0, x = 0; i < 32 && host->blen_counter; i += 8, host->blen_counter--) + x |= sd_read_data(host->card) << i; + host->fifo[(host->fifo_start + host->fifo_len) & 0xff] = x; + host->fifo_len++; + } + TRACE2("end, %d bytes in FIFO:", host->fifo_len * 4); +#if MMC_DEBUG_LEVEL>1 + for (i = 0; i < host->fifo_len; ) { + fprintf(stderr, "%s: [0x%03x] ", __FUNCTION__, i * 4); + do { + x = host->fifo[(host->fifo_start + i) & 0xff]; + for (j = 0; j < 4; j++) { + c = (x >> (j * 8)) & 0xff; + fprintf(stderr, "%02x ", c); + sym[(i & 3) * 4 + j] = (c < 32 || c > 126) ? '.' : c; + } + } while (((++i) & 3)); + sym[16] = 0; + fprintf(stderr, "%s\n", sym); + } +#endif + } else { + TRACE2("%d bytes left to transmit in current block", host->blen_counter); + while (host->blen_counter && host->fifo_len) { + for (i = 0; i < 32 && host->blen_counter; i += 8, host->blen_counter--) + sd_write_data(host->card, (host->fifo[host->fifo_start] >> i) & 0xff); + host->fifo_start++; + host->fifo_len--; + host->fifo_start &= 0xff; + } + } + + if (!host->blen_counter) { + if (host->cmd & 2) /* BCE */ + host->nblk_counter--; + TRACE2("block done, %d blocks left", + (host->cmd & (1 << 5)) ? host->nblk_counter : 0); + host->blen_counter = host->blk & 0x7ff; + if (!(host->cmd & (1 << 5)) /* MSBS */ + || !host->nblk_counter) { + host->nblk_counter = (host->blk >> 16) & 0xffff; + host->transfer = 0; + host->pstate &= ~0x0306; /* RTA | WTA | DLA | DATI */ + } + } +} + +static void omap3_mmc_command(struct omap3_mmc_s *host) +{ + uint32_t rspstatus, mask; + int rsplen, timeout; - struct sd_request_s request; ++ SDRequest request; + uint8_t response[16]; + int cmd = (host->cmd >> 24) & 0x3f; /* INDX */ + + TRACE("%d type=%d arg=0x%08x blk=0x%08x, fifo=%d/%d", + cmd, (host->cmd >> 22) & 3, host->arg, host->blk, + host->fifo_start, host->fifo_len); + + if ((host->con & 2) && !cmd) { /* INIT and CMD0 */ + host->stat_pending |= 0x1; + host->pstate &= 0xfffffffe; + return; + } + + if (host->cmd & (1 << 21)) { /* DP */ + host->fifo_start = 0; + host->fifo_len = 0; + host->transfer = 1; + host->ddir = (host->cmd >> 4) & 1; + /* DLA | DATI | (RTA/WTA) */ + host->pstate |= 0x6 | (host->ddir ? 0x200 : 0x100); + } else { + host->transfer = 0; + host->pstate &= ~0x306; /* RTA | WTA | DLA | DATI */ + } + + timeout = 0; + mask = 0; + rspstatus = 0; + + request.cmd = cmd; + request.arg = host->arg; + request.crc = 0; /* FIXME */ + + rsplen = sd_do_command(host->card, &request, response); + + switch ((host->cmd >> 16) & 3) { /* RSP_TYPE */ + case sd_nore: + rsplen = 0; + break; + case sd_136_bits: + if (rsplen < 16) { + timeout = 1; + break; + } + rsplen = 16; + host->rsp76 = (response[0] << 24) | (response[1] << 16) | + (response[2] << 8) | (response[3] << 0); + host->rsp54 = (response[4] << 24) | (response[5] << 16) | + (response[6] << 8) | (response[7] << 0); + host->rsp32 = (response[8] << 24) | (response[9] << 16) | + (response[10] << 8) | (response[11] << 0); + host->rsp10 = (response[12] << 24) | (response[13] << 16) | + (response[14] << 8) | (response[15] << 0); + break; + case sd_48_bits: + case sd_48b_bits: + if (rsplen < 4) { + timeout = 1; + break; + } + rsplen = 4; + host->rsp10 = (response[0] << 24) | (response[1] << 16) | + (response[2] << 8) | (response[3] << 0); + switch (cmd) { + case 41: /* r3 */ + case 8: /* r7 */ + break; + case 3: /* r6 */ + mask = 0xe00; + rspstatus = (response[2] << 8) | response[3]; + break; + default: + mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR | + ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION | + LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND | + CARD_ECC_FAILED | CC_ERROR | SD_ERROR | + CID_CSD_OVERWRITE | WP_ERASE_SKIP; + rspstatus = (response[0] << 24) | (response[1] << 16) | + (response[2] << 8) | (response[3] << 0); + break; + } + default: + break; + } + + if (cmd == 12 || cmd == 52) { /* stop transfer commands */ + /*host->fifo_start = 0;*/ + /*host->fifo_len = 0;*/ + host->transfer = 0; + host->pstate &= ~0x0f06; /* BRE | BWE | RTA | WTA | DLA | DATI */ + host->stat_pending &= ~0x30; /* BRR | BWR */ + host->stat &= ~0x30; /* BRR | BWR */ + host->stat_pending |= 0x2; /* TC */ + qemu_irq_lower(host->dma[0]); + qemu_irq_lower(host->dma[1]); + } + + if (rspstatus & mask & host->csre) { + host->stat_pending |= 1 << 28; /* CERR */ + host->pstate &= ~0x306; /* RTA | WTA | DLA | DATI */ + host->transfer = 0; + } else { + host->stat &= ~(1 << 28); /* CERR */ + host->stat_pending &= ~(1 << 28); /* CERR */ + } + host->stat_pending |= timeout ? (1 << 16) : 0x1; /* CTO : CC */ +} + +static void omap3_mmc_reset(struct omap3_mmc_s *s) +{ + s->sysconfig = 0x00000015; + s->con = 0x00000500; + s->pstate = 0x00040000; + s->capa = 0x00e10080; + s->rev = 0x26000000; + + s->fifo_start = 0; + s->fifo_len = 0; + s->stop = 0; +} + +static uint32_t omap3_mmc_read(void *opaque, target_phys_addr_t addr) +{ + struct omap3_mmc_s *s = (struct omap3_mmc_s *) opaque; + uint32_t i ; + + switch (addr) { + case 0x10: + TRACE2("SYSCONFIG = %08x", s->sysconfig); + return s->sysconfig; + case 0x14: + TRACE2("SYSSTATUS = %08x", s->sysstatus | 0x1); + return s->sysstatus | 0x1; /*reset completed */ + case 0x24: + TRACE2("CSRE = %08x", s->csre); + return s->csre; + case 0x28: + TRACE2("SYSTEST = %08x", s->systest); + return s->systest; + case 0x2c: /* MMCHS_CON */ + TRACE2("CON = %08x", s->con); + return s->con; + case 0x30: + TRACE2("PWCNT = %08x", s->pwcnt); + return s->pwcnt; + case 0x104: /* MMCHS_BLK */ + TRACE2("BLK = %08x", s->blk); + return s->blk; + case 0x108: /* MMCHS_ARG */ + TRACE2("ARG = %08x", s->arg); + return s->arg; + case 0x10c: + TRACE2("CMD = %08x", s->cmd); + return s->cmd; + case 0x110: + TRACE2("RSP10 = %08x", s->rsp10); + return s->rsp10; + case 0x114: + TRACE2("RSP32 = %08x", s->rsp32); + return s->rsp32; + case 0x118: + TRACE2("RSP54 = %08x", s->rsp54); + return s->rsp54; + case 0x11c: + TRACE2("RSP76 = %08x", s->rsp76); + return s->rsp76; + case 0x120: + /* in PIO mode, access allowed only when BRE is set */ + if (!(s->cmd & 1) && !(s->pstate & 0x0800)) { + s->stat_pending |= 1 << 29; /* BADA */ + i = 0; + } else { + i = s->fifo[s->fifo_start]; + s->fifo[s->fifo_start] = 0; + if (s->fifo_len == 0) { + fprintf(stderr, "%s: FIFO underrun\n", __FUNCTION__); + return i; + } + s->fifo_start++; + s->fifo_len--; + s->fifo_start &= 255; + omap3_mmc_transfer(s); + omap3_mmc_fifolevel_update(s); + } + omap3_mmc_interrupts_update(s); + return i; + case 0x124: /* MMCHS_PSTATE */ + TRACE2("PSTATE = %08x", s->pstate); + return s->pstate; + case 0x128: + TRACE2("HCTL = %08x", s->hctl); + return s->hctl; + case 0x12c: /* MMCHS_SYSCTL */ + TRACE2("SYSCTL = %08x", s->sysctl); + return s->sysctl; + case 0x130: /* MMCHS_STAT */ + s->stat |= s->stat_pending; + if (s->stat & 0xffff0000) + s->stat |= 1 << 15; /* ERRI */ + else + s->stat &= ~(1 << 15); /* ERRI */ + s->stat_pending = 0; + TRACE2("STAT = %08x", s->stat); + return s->stat; + case 0x134: + TRACE2("IE = %08x", s->ie); + return s->ie; + case 0x138: + TRACE2("ISE = %08x", s->ise); + return s->ise; + case 0x13c: + TRACE2("AC12 = %08x", s->ac12); + return s->ac12; + case 0x140: /* MMCHS_CAPA */ + TRACE2("CAPA = %08x", s->capa); + return s->capa; + case 0x148: + TRACE2("CUR_CAPA = %08x", s->cur_capa); + return s->cur_capa; + case 0x1fc: + TRACE2("REV = %08x", s->rev); + return s->rev; + default: + OMAP_BAD_REG(addr); + exit(-1); + return 0; + } +} + +static void omap3_mmc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap3_mmc_s *s = (struct omap3_mmc_s *) opaque; + + switch (addr) { + case 0x014: + case 0x110: + case 0x114: + case 0x118: + case 0x11c: + case 0x124: + case 0x13c: + case 0x1fc: + OMAP_RO_REG(addr); + break; + case 0x010: + TRACE2("SYSCONFIG = %08x", value); + if (value & 2) + omap3_mmc_reset(s); + s->sysconfig = value & 0x31d; + break; + case 0x024: + TRACE2("CSRE = %08x", value); + s->csre = value; + break; + case 0x028: + TRACE2("SYSTEST = %08x", value); + s->systest = value; + break; + case 0x02c: /* MMCHS_CON */ + TRACE2("CON = %08x", value); + if (value & 0x10) /* MODE */ + fprintf(stderr, "%s: SYSTEST mode is not supported\n", + __FUNCTION__); + if (value & 0x20) /* DW8 */ + fprintf(stderr, "%s: 8-bit data width is not supported\n", + __FUNCTION__); + if (value & 0x1000) /* CEATA */ + fprintf(stderr, "%s: CE-ATA control mode not supported\n", + __FUNCTION__); + s->con = value & 0x1ffff; + break; + case 0x030: + TRACE2("PWCNT = %08x", value); + s->pwcnt = value; + break; + case 0x104: /* MMCHS_BLK */ + TRACE2("BLK = %08x", value); + s->blk = value & 0xffff07ff; + s->blen_counter = value & 0x7ff; + s->nblk_counter = (value >> 16) & 0xffff; + break; + case 0x108: /* MMCHS_ARG */ + TRACE2("ARG = %08x", value); + s->arg = value; + break; + case 0x10c: /* MMCHS_CMD */ + TRACE2("CMD = %08x", value); + if (!s->card) { + s->stat_pending |= (1 << 16); /* CTO */ + } else { + /* TODO: writing to bits 0-15 should have no effect during + an active data transfer */ + if (!s->stop + && (((value >> 24) & 0x3f) == 12 + || ((value >> 24) & 0x3f) == 52)) { + s->stop = value & 0x3ffb0037; + } else { + s->cmd = value & 0x3ffb0037; + omap3_mmc_command(s); + } + omap3_mmc_transfer(s); + omap3_mmc_fifolevel_update(s); + } + omap3_mmc_interrupts_update(s); + break; + case 0x120: + /* in PIO mode, access allowed only when BWE is set */ + if (!(s->cmd & 1) && !(s->pstate & 0x0400)) { + s->stat_pending |= 1 << 29; /* BADA */ + } else { + if (s->fifo_len == 256) { + fprintf(stderr, "%s: FIFO overrun\n", __FUNCTION__); + break; + } + s->fifo[(s->fifo_start + s->fifo_len) & 255] = value; + s->fifo_len++; + omap3_mmc_transfer(s); + omap3_mmc_fifolevel_update(s); + } + omap3_mmc_interrupts_update(s); + break; + case 0x128: /* MMCHS_HCTL */ + TRACE2("HCTL = %08x", value); + s->hctl = value & 0xf0f0f02; + if (s->hctl & (1 << 16)) /* SBGR */ + fprintf(stderr, "%s: Stop at block gap feature not implemented!\n", __FUNCTION__); + break; + case 0x12c: /* MMCHS_SYSCTL */ + TRACE2("SYSCTL = %08x", value); + if (value & 0x04000000) { /* SRD */ + s->data = 0; + s->pstate &= ~0x00000f06; /* BRE, BWE, RTA, WTA, DLA, DATI */ + s->hctl &= ~0x00030000; /* SGBR, CR */ + s->stat &= ~0x00000034; /* BRR, BWR, BGE */ + s->stat_pending &= ~0x00000034; + s->fifo_start = 0; + s->fifo_len = 0; + } + if (value & 0x02000000) { /* SRC */ + s->pstate &= ~0x00000001; /* CMDI */ + } + if (value & 0x01000000) { /* SRA */ + uint32_t capa = s->capa; + uint32_t cur_capa = s->cur_capa; + omap3_mmc_reset(s); + s->capa = capa; + s->cur_capa = cur_capa; + } + value = (value & ~2) | ((value & 1) << 1); /* copy ICE directly to ICS */ + s->sysctl = value & 0x000fffc7; + break; + case 0x130: + TRACE2("STAT = %08x", value); + value = value & 0x317f0237; + s->stat &= ~value; + /* stat_pending is NOT cleared */ + omap3_mmc_interrupts_update(s); + break; + case 0x134: /* MMCHS_IE */ + TRACE2("IE = %08x", value); + if (!(s->con & 0x4000)) /* if CON:OBIE is clear, ignore write to OBI_ENABLE */ + value = (value & ~0x200) | (s->ie & 0x200); + s->ie = value & 0x317f0337; + if (!(s->ie & 0x100)) { + s->stat &= ~0x100; + s->stat_pending &= ~0x100; + } + omap3_mmc_interrupts_update(s); + break; + case 0x138: + TRACE2("ISE = %08x", value); + s->ise = value & 0x317f0337; + omap3_mmc_interrupts_update(s); + break; + case 0x140: /* MMCHS_CAPA */ + TRACE2("CAPA = %08x", value); + s->capa &= ~0x07000000; + s->capa |= value & 0x07000000; + break; + case 0x148: + TRACE2("CUR_CAPA = %08x", value); + s->cur_capa = value & 0xffffff; + break; + default: + OMAP_BAD_REG(addr); + exit(-1); + } +} + +static CPUReadMemoryFunc *omap3_mmc_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap3_mmc_read, +}; + +static CPUWriteMemoryFunc *omap3_mmc_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap3_mmc_write, +}; + +static void omap3_mmc_save_state(QEMUFile *f, void *opaque) +{ + struct omap3_mmc_s *s = (struct omap3_mmc_s *)opaque; + int i; + + qemu_put_be32(f, s->sysconfig); + qemu_put_be32(f, s->sysstatus); + qemu_put_be32(f, s->csre); + qemu_put_be32(f, s->systest); + qemu_put_be32(f, s->con); + qemu_put_be32(f, s->pwcnt); + qemu_put_be32(f, s->blk); + qemu_put_be32(f, s->arg); + qemu_put_be32(f, s->cmd); + qemu_put_be32(f, s->rsp10); + qemu_put_be32(f, s->rsp32); + qemu_put_be32(f, s->rsp54); + qemu_put_be32(f, s->rsp76); + qemu_put_be32(f, s->data); + qemu_put_be32(f, s->pstate); + qemu_put_be32(f, s->hctl); + qemu_put_be32(f, s->sysctl); + qemu_put_be32(f, s->stat); + qemu_put_be32(f, s->ie); + qemu_put_be32(f, s->ise); + qemu_put_be32(f, s->ac12); + qemu_put_be32(f, s->capa); + qemu_put_be32(f, s->cur_capa); + qemu_put_be32(f, s->rev); + qemu_put_be16(f, s->blen_counter); + qemu_put_be16(f, s->nblk_counter); + for (i = 0; i < sizeof(s->fifo)/sizeof(uint32_t); i++) + qemu_put_be32(f, s->fifo[i]); + qemu_put_sbe32(f, s->fifo_start); + qemu_put_sbe32(f, s->fifo_len); + qemu_put_sbe32(f, s->ddir); + qemu_put_sbe32(f, s->transfer); + qemu_put_sbe32(f, s->stop); + qemu_put_be32(f, s->stat_pending); +} + +static int omap3_mmc_load_state(QEMUFile *f, void *opaque, int version_id) +{ + struct omap3_mmc_s *s = (struct omap3_mmc_s *)opaque; + int i; + + if (version_id) + return -EINVAL; + + s->sysconfig = qemu_get_be32(f); + s->sysstatus = qemu_get_be32(f); + s->csre = qemu_get_be32(f); + s->systest = qemu_get_be32(f); + s->con = qemu_get_be32(f); + s->pwcnt = qemu_get_be32(f); + s->blk = qemu_get_be32(f); + s->arg = qemu_get_be32(f); + s->cmd = qemu_get_be32(f); + s->rsp10 = qemu_get_be32(f); + s->rsp32 = qemu_get_be32(f); + s->rsp54 = qemu_get_be32(f); + s->rsp76 = qemu_get_be32(f); + s->data = qemu_get_be32(f); + s->pstate = qemu_get_be32(f); + s->hctl = qemu_get_be32(f); + s->sysctl = qemu_get_be32(f); + s->stat = qemu_get_be32(f); + s->ie = qemu_get_be32(f); + s->ise = qemu_get_be32(f); + s->ac12 = qemu_get_be32(f); + s->capa = qemu_get_be32(f); + s->cur_capa = qemu_get_be32(f); + s->rev = qemu_get_be32(f); + s->blen_counter = qemu_get_be16(f); + s->nblk_counter = qemu_get_be16(f); + for (i = 0; i < sizeof(s->fifo)/sizeof(uint32_t); i++) + s->fifo[i] = qemu_get_be32(f); + s->fifo_start = qemu_get_sbe32(f); + s->fifo_len = qemu_get_sbe32(f); + s->ddir = qemu_get_sbe32(f); + s->transfer = qemu_get_sbe32(f); + s->stop = qemu_get_sbe32(f); + s->stat_pending = qemu_get_be32(f); + + omap3_mmc_fifolevel_update(s); + omap3_mmc_interrupts_update(s); + + return 0; +} + +struct omap3_mmc_s *omap3_mmc_init(struct omap_target_agent_s *ta, + qemu_irq irq, qemu_irq dma[], + omap_clk fclk, omap_clk iclk) +{ + int iomemtype; + struct omap3_mmc_s *s = (struct omap3_mmc_s *) + qemu_mallocz(sizeof(struct omap3_mmc_s)); + + s->irq = irq; + s->dma = dma; + s->clk = fclk; + + omap3_mmc_reset(s); + + iomemtype = l4_register_io_memory(0, omap3_mmc_readfn, + omap3_mmc_writefn, s); + omap_l4_attach(ta, 0, iomemtype); + + register_savevm("omap3_mmc", (ta->base >> 12) & 0xff, 0, + omap3_mmc_save_state, omap3_mmc_load_state, s); + return s; +} + +void omap3_mmc_attach(struct omap3_mmc_s *s, + BlockDriverState *bd) +{ + if (s->card) { + fprintf(stderr, "%s: SD card already attached!\n", __FUNCTION__); + exit(-1); + } + s->card = sd_init(bd, 0); + sd_enable(s->card, 1); +} diff --cc hw/omap3_usb.c index 06eeaa3,0000000..f89c317 mode 100644,000000..100644 --- a/hw/omap3_usb.c +++ b/hw/omap3_usb.c @@@ -1,512 -1,0 +1,512 @@@ +/* + * 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; ++ MUSBState *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_read(int access, + 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[access](s->musb, addr); + if (addr < 0x400) + return musb_read[access](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_write(int access, + 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[access](s->musb, addr, value); + else if (addr < 0x400) + musb_write[access](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 uint32_t omap3_hsusb_otg_readb(void *opaque, target_phys_addr_t addr) +{ + return omap3_hsusb_otg_read(0, opaque, addr); +} + +static uint32_t omap3_hsusb_otg_readh(void *opaque, target_phys_addr_t addr) +{ + return omap3_hsusb_otg_read(1, opaque, addr); +} + +static uint32_t omap3_hsusb_otg_readw(void *opaque, target_phys_addr_t addr) +{ + return omap3_hsusb_otg_read(2, opaque, addr); +} + +static void omap3_hsusb_otg_writeb(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + omap3_hsusb_otg_write(0, opaque, addr, value); +} + +static void omap3_hsusb_otg_writeh(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + omap3_hsusb_otg_write(1, opaque, addr, value); +} + +static void omap3_hsusb_otg_writew(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + omap3_hsusb_otg_write(2, opaque, addr, value); +} + +static CPUReadMemoryFunc *omap3_hsusb_otg_readfn[] = { + omap3_hsusb_otg_readb, + omap3_hsusb_otg_readh, + omap3_hsusb_otg_readw, +}; + +static CPUWriteMemoryFunc *omap3_hsusb_otg_writefn[] = { + omap3_hsusb_otg_writeb, + omap3_hsusb_otg_writeh, + omap3_hsusb_otg_writew, +}; + +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));*/ + 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; + uint32_t tll_sysconfig; + uint32_t insnreg05_ulpi; +}; + +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); + qemu_put_be32(f, s->tll_sysconfig); + qemu_put_be32(f, s->insnreg05_ulpi); +} + +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); + s->tll_sysconfig = qemu_get_be32(f); + s->insnreg05_ulpi = 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 */ + s->tll_sysconfig = 1; +} + +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; + TRACE(OMAP_FMT_plx, addr); + + 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; + TRACE(OMAP_FMT_plx " = 0x%08x", addr, value); + + 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) +{ + struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque; + TRACE(OMAP_FMT_plx, addr); + switch (addr) { + case 0xa4: /* INSNREG05_ULPI */ + return s->insnreg05_ulpi; + default: + break; + } + return 0; +} + +static void omap3_hsusb_ehci_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque; + TRACE(OMAP_FMT_plx " = 0x%08x", addr, value); + + switch (addr) { + case 0xa4: /* INSNREG05_ULPI */ + s->insnreg05_ulpi = value & 0xF0000000; + default: + break; + } +} + +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) +{ + struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque; + TRACE(OMAP_FMT_plx, addr); + + switch (addr) { + case 0x00: /* USBTLL_REVISION */ + return 0x1; + case 0x10: /* USBTLL_SYSCONFIG */ + return s->tll_sysconfig; + case 0x14: /* USBTLL_SYSSTATUS */ + return 0x1; /* RESETDONE */ + case 0x18: /* USBTLL_IRQSTATUS */ + return 0; + case 0x1C: /* USBTLL_IRQENABLE */ + return 0; + default: + break; + } + return 0; +} + +static void omap3_hsusb_tll_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap3_hsusb_host_s *s = (struct omap3_hsusb_host_s *)opaque; + TRACE(OMAP_FMT_plx " = 0x%08x", addr, value); + + switch (addr) { + case 0x00: /* USBTLL_REVISION */ + case 0x14: /* USBTLL_SYSSTATUS */ + OMAP_RO_REGV(addr, value); + case 0x10: /* USBTLL_SYSCONFIG */ + s->tll_sysconfig = value & 0xFFFFFEE0;; + default: + OMAP_BAD_REGV(addr, value); + break; + } +} + +static CPUReadMemoryFunc *omap3_hsusb_tll_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap3_hsusb_tll_read, +}; + +static CPUWriteMemoryFunc *omap3_hsusb_tll_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap3_hsusb_tll_write, +}; + +static void omap3_hsusb_host_init(struct omap_target_agent_s *host_ta, + struct omap_target_agent_s *tll_ta, + qemu_irq ohci_irq, + qemu_irq ehci_irq, + qemu_irq tll_irq, + struct omap3_hsusb_host_s *s) +{ + s->ehci_irq = ehci_irq; + s->tll_irq = tll_irq; + + omap_l4_attach(tll_ta, 0, l4_register_io_memory(0, + omap3_hsusb_tll_readfn, + omap3_hsusb_tll_writefn, + s)); + omap_l4_attach(host_ta, 0, l4_register_io_memory(0, + omap3_hsusb_host_readfn, + omap3_hsusb_host_writefn, + s)); +/* omap_l4_attach(host_ta, 1, usb_ohci_init_omap(omap_l4_base(host_ta, 1), + omap_l4_size(host_ta, 1), + 3, ohci_irq));*/ + omap_l4_attach(host_ta, 2, l4_register_io_memory(0, + omap3_hsusb_ehci_readfn, + omap3_hsusb_ehci_writefn, + s)); + + omap3_hsusb_host_reset(s); + + register_savevm("omap3_hsusb_host", -1, 0, + omap3_hsusb_host_save_state, + omap3_hsusb_host_load_state, s); +} +#endif + +struct omap3_hsusb_s { +#ifdef OMAP3_HSUSB_OTG + struct omap3_hsusb_otg_s otg; +#endif +#ifdef OMAP3_HSUSB_HOST + struct omap3_hsusb_host_s host; +#endif +}; + +struct omap3_hsusb_s *omap3_hsusb_init(struct omap_target_agent_s *otg_ta, + struct omap_target_agent_s *host_ta, + struct omap_target_agent_s *tll_ta, + qemu_irq mc_irq, + qemu_irq dma_irq, + qemu_irq ohci_irq, + qemu_irq ehci_irq, + qemu_irq tll_irq) +{ + struct omap3_hsusb_s *s = qemu_mallocz(sizeof(struct omap3_hsusb_s)); +#ifdef OMAP3_HSUSB_HOST + omap3_hsusb_host_init(host_ta, tll_ta, + ohci_irq, ehci_irq, tll_irq, + &s->host); +#endif +#ifdef OMAP3_HSUSB_OTG + omap3_hsusb_otg_init(otg_ta, mc_irq, dma_irq, &s->otg); +#endif + return s; +} + diff --cc hw/omap_dss.c index a65f5f0,d8c2977..3a92d0a --- a/hw/omap_dss.c +++ b/hw/omap_dss.c @@@ -2190,163 -1064,6 +2190,163 @@@ struct omap_dss_s *omap_dss_init(struc void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip) { if (cs < 0 || cs > 1) - cpu_abort(cpu_single_env, "%s: wrong CS %i\n", __FUNCTION__, cs); + hw_error("%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*/ + +#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" + +/* 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; + target_phys_addr_t size; + + 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 (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; + } + int gf = dss->dispc.l[0].gfx_format; + if (!(dss->dispc.l[0].rotation_flag)) { /* rotation*/ + switch (ds_get_bits_per_pixel(s->state)) { + case 8: s->line_fn = omap3_lcd_panel_draw_fn_8[gf]; break; + case 15: s->line_fn = omap3_lcd_panel_draw_fn_15[gf]; break; + case 16: s->line_fn = omap3_lcd_panel_draw_fn_16[gf]; break; + case 24: s->line_fn = omap3_lcd_panel_draw_fn_24[gf]; break; + case 32: s->line_fn = omap3_lcd_panel_draw_fn_32[gf]; break; + default: s->line_fn = 0; break; + } + } else { + switch (ds_get_bits_per_pixel(s->state)) { + case 8: s->line_fn = omap3_lcd_panel_draw_fn_r_8[gf]; break; + case 15: s->line_fn = omap3_lcd_panel_draw_fn_r_15[gf]; break; + case 16: s->line_fn = omap3_lcd_panel_draw_fn_r_16[gf]; break; + case 24: s->line_fn = omap3_lcd_panel_draw_fn_r_24[gf]; break; + case 32: s->line_fn = omap3_lcd_panel_draw_fn_r_32[gf]; break; + default: s->line_fn = 0; break; + } + } + } + if (!s->line_fn) { + fprintf(stderr, + "%s: line_fn is NULL - host bpp=%d, omap3 lcd gfx_format=%d\n", + __FUNCTION__, + ds_get_bits_per_pixel(s->state), + dss->dispc.l[0].gfx_format); + exit(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; + + 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; + + size = copy_height * copy_width * lcd_Bpp; + src = cpu_physical_memory_map(dss->dispc.l[0].addr[0], &size, 0); + if (src) { + if (size == copy_height * copy_width * lcd_Bpp) { + 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); + } + cpu_physical_memory_unmap(src, size, 0, size); + } + s->invalidate = 0; + + dss->dispc.irqst |= 1; /* FRAMEDONE */ + omap_dss_interrupt_update(dss); +} + +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); + return s; +} diff --cc hw/omap_i2c.c index 9982762,c0dd3a5..c4ee7dc --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@@ -65,95 -47,16 +64,20 @@@ struct omap_i2c_s 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) - { - 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) - { - 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) - { - 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; @@@ -272,127 -148,91 +196,127 @@@ static uint32_t omap_i2c_read(void *opa 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)) { ++ if (s->fifolen <= ((s->dma >> 8) & 0x3f)) { + 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); @@@ -407,195 -247,137 +331,195 @@@ static void omap_i2c_write(void *opaque 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], ++ /*i2c_set_slave_address(&s->slave[0], + value & (s->revision >= OMAP3_INTR_REV + && (s->control & 0x80) - ? 0x3ff: 0x7f)); ++ ? 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", (int)addr, value); + s->own_addr[addr] = value & 0x3ff; - i2c_set_slave_address(&s->slave[addr], ++ /*i2c_set_slave_address(&s->slave[addr], + value & ((s->control & (0x80 >> addr)) - ? 0x3ff: 0x7f)); ++ ? 0x3ff: 0x7f));*/ } - omap_i2c_interrupts_update(s); - } - break; - - case 0x28: /* I2C_OA */ - s->addr[0] = value & 0x3ff; - 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; } } @@@ -721,26 -433,13 +645,20 @@@ static struct omap_i2c_s *omap_i2c_comm s->irq = irq; s->drq[0] = dma[0]; s->drq[1] = dma[1]; - 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->bus = i2c_init_bus(NULL, "i2c"); + 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; } diff --cc hw/onenand.c index 35865d8,9803a07..bc8107c --- a/hw/onenand.c +++ b/hw/onenand.c @@@ -130,87 -129,8 +130,87 @@@ static void onenand_intr_update(OneNAND 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; ++ OneNANDState *s = (OneNANDState *)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; ++ OneNANDState *s = (OneNANDState *)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) + static void onenand_reset(OneNANDState *s, int cold) { memset(&s->addr, 0, sizeof(s->addr)); s->command = 0; diff --cc hw/smc91c111.c index a9904d9,38cbd01..d8a2599 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@@ -691,78 -690,6 +690,73 @@@ static CPUWriteMemoryFunc *smc91c111_wr smc91c111_writel }; - int smc91c111_iomemtype(void *opaque) { - smc91c111_state *s=(smc91c111_state *) opaque; - return s->mmio_index; - } - +static void smc91c111_save_state(QEMUFile *f, void *opaque) +{ + smc91c111_state *s = (smc91c111_state *)opaque; + int i; + + qemu_put_be16(f, s->tcr); + qemu_put_be16(f, s->rcr); + qemu_put_be16(f, s->cr); + qemu_put_be16(f, s->ctr); + qemu_put_be16(f, s->gpr); + qemu_put_be16(f, s->ptr); + qemu_put_be16(f, s->ercv); + qemu_put_sbe32(f, s->bank); + qemu_put_sbe32(f, s->packet_num); + qemu_put_sbe32(f, s->tx_alloc); + qemu_put_sbe32(f, s->allocated); + qemu_put_sbe32(f, s->tx_fifo_len); + qemu_put_sbe32(f, s->rx_fifo_len); + qemu_put_sbe32(f, s->tx_fifo_done_len); + qemu_put_byte(f, s->int_level); + qemu_put_byte(f, s->int_mask); + qemu_put_buffer(f, s->macaddr, sizeof(s->macaddr)); + for (i = 0; i < NUM_PACKETS; i++) { + qemu_put_sbe32(f, s->tx_fifo[i]); + qemu_put_sbe32(f, s->rx_fifo[i]); + qemu_put_sbe32(f, s->tx_fifo_done[i]); + qemu_put_buffer(f, s->data[i], sizeof(s->data[i])); + } +} + +static int smc91c111_load_state(QEMUFile *f, void *opaque, int version_id) +{ + smc91c111_state *s = (smc91c111_state *)opaque; + int i; + + if (version_id) + return -EINVAL; + + s->tcr = qemu_get_be16(f); + s->rcr = qemu_get_be16(f); + s->cr = qemu_get_be16(f); + s->ctr = qemu_get_be16(f); + s->gpr = qemu_get_be16(f); + s->ptr = qemu_get_be16(f); + s->ercv = qemu_get_be16(f); + s->bank = qemu_get_sbe32(f); + s->packet_num = qemu_get_sbe32(f); + s->tx_alloc = qemu_get_sbe32(f); + s->allocated = qemu_get_sbe32(f); + s->tx_fifo_len = qemu_get_sbe32(f); + s->rx_fifo_len = qemu_get_sbe32(f); + s->tx_fifo_done_len = qemu_get_sbe32(f); + s->int_level = qemu_get_byte(f); + s->int_mask = qemu_get_byte(f); + qemu_get_buffer(f, s->macaddr, sizeof(s->macaddr)); + for (i = 0; i < NUM_PACKETS; i++) { + s->tx_fifo[i] = qemu_get_sbe32(f); + s->rx_fifo[i] = qemu_get_sbe32(f); + s->tx_fifo_done[i] = qemu_get_sbe32(f); + qemu_get_buffer(f, s->data[i], sizeof(s->data[i])); + } + + smc91c111_update(s); + + return 0; +} + static void smc91c111_cleanup(VLANClientState *vc) { smc91c111_state *s = vc->opaque; @@@ -792,7 -715,27 +782,51 @@@ static void smc91c111_init1(SysBusDevic smc91c111_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); /* ??? Save/restore. */ + register_savevm("smc91c111", -1, 0, + smc91c111_save_state, smc91c111_load_state, s); ++ /*return s;*/ + } + + static void smc91c111_register_devices(void) + { + sysbus_register_dev("smc91c111", sizeof(smc91c111_state), smc91c111_init1); + } + + /* Legacy helper function. Should go away when machine config files are + implemented. */ + void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) + { + DeviceState *dev; + SysBusDevice *s; + + qemu_check_nic_model(nd, "smc91c111"); + dev = qdev_create(NULL, "smc91c111"); + qdev_set_netdev(dev, nd); + qdev_init(dev); + s = sysbus_from_qdev(dev); + sysbus_mmio_map(s, 0, base); + sysbus_connect_irq(s, 0, irq); + } + ++void *smc91c111_init_lite(NICInfo *nd, qemu_irq irq) ++{ ++ DeviceState *dev; ++ SysBusDevice *s; ++ ++ qemu_check_nic_model(nd, "smc91c111"); ++ dev = qdev_create(NULL, "smc91c111"); ++ qdev_set_netdev(dev, nd); ++ qdev_init(dev); ++ s = sysbus_from_qdev(dev); ++ //sysbus_mmio_map(s, 0, base); ++ sysbus_connect_irq(s, 0, irq); + return s; +} ++ ++int smc91c111_iomemtype(void *opaque) ++{ ++ SysBusDevice *s = (SysBusDevice *)opaque; ++ return (FROM_SYSBUS(smc91c111_state, s))->mmio_index; ++} ++ + device_init(smc91c111_register_devices) diff --cc hw/tsc2005.c index 68b18c4,36d6b53..40aee0a --- a/hw/tsc2005.c +++ b/hw/tsc2005.c @@@ -226,9 -226,28 +226,9 @@@ static void tsc2005_write(TSC2005State } /* This handles most of the chip's logic. */ - static void tsc2005_pin_update(struct tsc2005_state_s *s) + static void tsc2005_pin_update(TSC2005State *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: @@@ -380,8 -399,7 +380,8 @@@ uint32_t tsc2005_txrx(void *opaque, uin static void tsc2005_timer_tick(void *opaque) { - struct tsc2005_state_s *s = opaque; + TSC2005State *s = opaque; + int pin_state; /* Timer ticked -- a set of conversions has been finished. */ diff --cc hw/tusb6010.c index dfd2824,f3aa7b1..4a8e75c --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@@ -26,19 -26,10 +26,19 @@@ #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 { + struct TUSBState { int iomemtype[2]; qemu_irq irq; - struct musb_s *musb; + MUSBState *musb; QEMUTimer *otg_timer; QEMUTimer *pwr_timer; @@@ -693,9 -683,8 +692,9 @@@ static void tusb_power_tick(void *opaqu static void tusb_musb_core_intr(void *opaque, int source, int level) { - struct tusb_s *s = (struct tusb_s *) opaque; + TUSBState *s = (TUSBState *) 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: diff --cc hw/twl4030.c index a60b438,0000000..9be8c21 mode 100644,000000..100644 --- a/hw/twl4030.c +++ b/hw/twl4030.c @@@ -1,947 -1,0 +1,888 @@@ +/* + * TI TWL4030 emulation + * + * Copyright (C) 2008 yajin + * Copyright (C) 2009 Nokia Corporation + * + * Register implementation based on TPS65950 ES1.0 specification. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "hw.h" +#include "qemu-timer.h" +#include "i2c.h" +#include "sysemu.h" +#include "console.h" +#include "cpu-all.h" + +//#define VERBOSE 1 + +#ifdef VERBOSE +#define TRACE(fmt, ...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__) +#else +#define TRACE(...) +#endif + - struct twl4030_i2c_s { ++typedef struct TWL4030State TWL4030State; ++typedef struct TWL4030NodeState TWL4030NodeState; ++ ++typedef uint8_t (*twl4030_read_func)(TWL4030NodeState *s, ++ uint8_t addr); ++typedef void (*twl4030_write_func)(TWL4030NodeState *s, ++ uint8_t addr, uint8_t value); ++ ++struct TWL4030NodeState { + i2c_slave i2c; + int firstbyte; + uint8_t reg; - qemu_irq irq; ++ ++ twl4030_read_func read_func; ++ twl4030_write_func write_func; ++ TWL4030State *twl4030; ++ + uint8 reg_data[256]; - struct twl4030_s *twl4030; +}; + - struct twl4030_s { - struct twl4030_i2c_s *i2c[5]; - ++struct TWL4030State { ++ qemu_irq irq; ++ + int key_cfg; + int key_tst; + ++ TWL4030NodeState *i2c[5]; ++ + 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, 0x60, 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) ++static uint8_t twl4030_48_read(TWL4030NodeState *s, 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_STS */ + if (s->reg_data[0xfd] & 1) /* PHY_PWR_CTRL */ + return 0; + if (s->reg_data[0xfe] & 1) /* REQ_PHY_DPLL_CLK */ + return 1; + return (s->reg_data[0x04] >> 6) & 1; /* SUSPENDM */ + default: - fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n", - __FUNCTION__, addr, cpu_single_env->regs[15]); ++ fprintf(stderr, "%s: unknown register 0x%02x\n", ++ __FUNCTION__, addr); + break; + } + return 0; +} + - static void twl4030_48_write(void *opaque, uint8_t addr, uint8_t value) ++static void twl4030_48_write(TWL4030NodeState *s, 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: /* FUNC_CTRL */ + s->reg_data[0x04] = value & 0x7f; + break; + case 0x05: /* FUNC_CRTL_SET */ + s->reg_data[0x04] = (s->reg_data[0x04] | value) & 0x7f; + break; + case 0x06: /* FUNC_CTRL_CLEAR */ + s->reg_data[0x04] = (s->reg_data[0x04] & ~value) & 0x7f; + break; + case 0x07: /* IFC_CTRL */ + s->reg_data[0x07] = value & 0x9e; + break; + case 0x08: /* IFC_CRTL_SET */ + s->reg_data[0x07] = (s->reg_data[0x07] | value) & 0x9e; + break; + case 0x09: /* IFC_CRTL_CLEAR */ + s->reg_data[0x07] = (s->reg_data[0x07] & ~value) & 0x9e; + break; + case 0xa1: /* CARKIT_SM_CTRL */ + s->reg_data[0xa1] = value & 0x3f; + break; + case 0xa2: /* CARKIT_SM_CTRL_SET */ + s->reg_data[0xa1] = (s->reg_data[0xa1] | value) & 0x3f; + break; + case 0xa3: /* CARKIT_SM_CTRL_CLR */ + s->reg_data[0xa1] = (s->reg_data[0xa1] & ~value) & 0x3f; + 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 0xbb: /* CARKIT_ANA_CTRL */ + s->reg_data[0xbb] = value; + break; + case 0xbc: /* CARKIT_ANA_CTRL_SET */ + s->reg_data[0xbb] |= value; + break; + case 0xbd: /* CARKIT_ANA_CTRL_CLR */ + s->reg_data[0xbb] &= ~value; + 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 0x%x\n", - __FUNCTION__, addr, cpu_single_env->regs[15]); ++ fprintf(stderr, "%s: unknown register 0x%02x\n", ++ __FUNCTION__, addr); + 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) ++static uint8_t twl4030_49_read(TWL4030NodeState *s, 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 ... 0x49: + return s->reg_data[addr]; + /* Test region */ + case 0x4c ... 0x60: + return s->reg_data[addr]; + /* PIH region */ + case 0x81: /* PIH_ISR_P1 */ + case 0x82: /* PIH_ISR_P2 */ + case 0x83: /* PIH_SIR */ + return s->reg_data[addr]; + /* INTBR region */ + case 0x85 ... 0x97: + return s->reg_data[addr]; + /* GPIO region */ + case 0x98 ... 0xc5: + return s->reg_data[addr]; + default: - fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n", - __FUNCTION__, addr, cpu_single_env->regs[15]); ++ fprintf(stderr, "%s: unknown register 0x%02x\n", ++ __FUNCTION__, addr); + break; + } + return 0; +} + - static void twl4030_49_write(void *opaque, uint8_t addr, uint8_t value) ++static void twl4030_49_write(TWL4030NodeState *s, 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 ... 0x49: + s->reg_data[addr] = value; + break; + /* Test region */ + case 0x4c ... 0x59: + s->reg_data[addr] = value; + break; + case 0x5a ... 0x60: + /* 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 ... 0x90: + /* read-only, ignore */ + break; + case 0x91 ... 0x97: + s->reg_data[addr] = value; + break; + /* GPIO region */ + case 0x98 ... 0x9a: + /* read-only, ignore */ + break; + case 0x9b ... 0xae: + s->reg_data[addr] = value; + break; + case 0xaf: /* GPIOPUPDCTR5 */ + s->reg_data[addr] = value & 0x0f; + break; + case 0xb0 ... 0xb5: + s->reg_data[addr] = value; + break; + case 0xb6: /* GPIO_IMR3A */ + s->reg_data[addr] = value & 0x03; + break; + case 0xb7 ... 0xc4: + 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 0x%x\n", - __FUNCTION__, addr, cpu_single_env->regs[15]); ++ fprintf(stderr, "%s: unknown register 0x%02x\n", ++ __FUNCTION__, addr); + 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) ++static uint8_t twl4030_4a_read(TWL4030NodeState *s, uint8_t addr) +{ - 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) { + /* MADC region */ + case 0x00 ... 0x13: + case 0x61 ... 0x67: + return s->reg_data[addr]; + case 0x17 ... 0x36: /* RT conversion registers */ + case 0x37 ... 0x56: /* GP conversion registers */ + case 0x57 ... 0x60: /* BCI conversion registers */ + return (addr & 1) ? 0 : 0x60; + /* MAIN_CHARGE region */ + case 0x74 ... 0xa6: + return s->reg_data[addr]; + /* Interrupt region */ + case 0xb9 ... 0xc6: + return s->reg_data[addr]; + /* KEYPAD region */ + case 0xd2 ... 0xe9: + return s->reg_data[addr]; + /* LED region */ + case 0xee: /* LEDEN */ + return s->reg_data[addr]; + /* PWMA region */ + case 0xef: /* PWMAON */ + case 0xf0: /* PWMAOFF */ + return s->reg_data[addr]; + /* PWMB region */ + case 0xf1: /* PWMBON */ + case 0xf2: /* PWMBOFF */ + return s->reg_data[addr]; + /* PWM0 region */ + case 0xf8: /* PWM0ON */ + case 0xf9: /* PWM0OFF */ + return s->reg_data[addr]; + /* PWM1 region */ + case 0xfb: /* PWM1ON */ + case 0xfc: /* PWM1OFF */ + return s->reg_data[addr]; + default: - fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n", - __FUNCTION__, addr, cpu_single_env->regs[15] ); ++ fprintf(stderr, "%s: unknown register 0x%02x\n", ++ __FUNCTION__, addr); + break; + } + return 0; +} + - static void twl4030_4a_write(void *opaque, uint8_t addr, uint8_t value) ++static void twl4030_4a_write(TWL4030NodeState *s, 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 0x00: /* CTRL1 */ + s->reg_data[addr] = value; + break; + case 0x06: /* SW1SELECT_LSB */ + case 0x07: /* SW1SELECT_MSB */ + case 0x08: /* SW1AVERAGE_LSB */ + case 0x09: /* SW1AVERAGE_MSB */ + s->reg_data[addr] = value; + break; + case 0x12: /* CTRL_SW1 */ + s->reg_data[addr] = 0xde; + break; + case 0x61: /* MADC_ISR1 */ + s->reg_data[addr] &= ~(value & 0x0f); + break; + case 0x62: /* MADC_IMR1 */ + s->reg_data[addr] = value & 0x0f; + break; + case 0x97: /* BCICTL1 */ + s->reg_data[addr] = value; + break; + case 0xb9: /* BCIISR1A */ + s->reg_data[addr] &= ~value; + break; + case 0xba: /* BCIISR2A */ + s->reg_data[addr] &= ~(value & 0x0f); + break; + case 0xbb: /* BCIIMR1A */ + s->reg_data[addr] = value; + break; + case 0xbc: /* BCIIMR2A */ + s->reg_data[addr] = value & 0x0f; + break; + case 0xd2: /* KEYP_CTRL_REG */ + s->reg_data[addr] = value & 0x7f; + 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 */ + case 0xf8: /* PWM0ON */ + case 0xfb: /* PWM1ON */ + s->reg_data[addr] = value; + break; + case 0xf0: /* PWMAOFF */ + case 0xf9: /* PWM0OFF */ + case 0xfc: /* PWM1OFF */ + s->reg_data[addr] = value & 0x7f; + break; + default: - fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n", - __FUNCTION__, addr, cpu_single_env->regs[15]); ++ fprintf(stderr, "%s: unknown register 0x%02x\n", ++ __FUNCTION__, addr); + 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) ++static uint8_t twl4030_4b_read(TWL4030NodeState *s, uint8_t addr) +{ - 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) { + /* SECURED_REG region */ + case 0x00 ... 0x13: + return s->reg_data[addr]; + /* BACKUP_REG region */ + case 0x14 ... 0x1b: + return s->reg_data[addr]; + /* RTC region */ + case 0x1c ... 0x2d: + return s->reg_data[addr]; + /* INT region */ + case 0x2e ... 0x35: + return s->reg_data[addr]; + /* PM_MASTER region */ + case 0x36 ... 0x44: + return s->reg_data[addr]; + case 0x45: /* STS_HW_CONDITIONS - USB plugged, no VBUS -> host usb */ + return 0x4; + case 0x46 ... 0x5a: + return s->reg_data[addr]; + /* PM_RECEIVER region */ + case 0x5b ... 0xf1: + return s->reg_data[addr]; + default: - fprintf(stderr, "%s: unknown register 0x%02x pc 0x%x\n", - __FUNCTION__, addr, cpu_single_env->regs[15] ); ++ fprintf(stderr, "%s: unknown register 0x%02x\n", ++ __FUNCTION__, addr); + break; + } + return 0; +} + + - static void twl4030_4b_write(void *opaque, uint8_t addr, uint8_t value) ++static void twl4030_4b_write(TWL4030NodeState *s, 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 0x2e: /* PWR_ISR1 */ + case 0x2f: /* PWR_IMR1 */ + s->reg_data[addr] = value; + break; + case 0x33: /* PWR_EDR1 */ + case 0x34: /* PWR_EDR2 */ + 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 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; + } + /* TODO: check if autoincrement is write-protected as well */ + s->reg_data[0x59]++; + break; + case 0x68: /* MISC_CFG */ + s->reg_data[addr] = value; + 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 0x75: /* VAUX1_DEDICATED */ + 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 0x79: /* VAUX2_DEDICATED */ + case 0x81: /* VAUX4_DEDICATED */ + 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 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 0x74: /* VAUX1_REMAP */ + case 0x78: /* VAUX2_REMAP */ + case 0x7c: /* VAUX3_REMAP */ + case 0x80: /* VAUX4_REMAP */ + case 0x90: /* VPLL2_REMAP */ + s->reg_data[addr] = value; + 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 0x%02x value 0x%02x pc 0x%x\n", - __FUNCTION__, addr, value, cpu_single_env->regs[15]); ++ "%s: unknown register 0x%02x value 0x%02x\n", ++ __FUNCTION__, addr, value); + break; + } +} + - static int twl4030_4b_tx(i2c_slave *i2c, uint8_t data) ++static void twl4030_node_init(TWL4030NodeState *s, ++ twl4030_read_func read, ++ twl4030_write_func write, ++ const uint8_t *reset_values) +{ - 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; ++ s->read_func = read; ++ s->write_func = write; ++ s->reg = 0x00; ++ memcpy(s->reg_data, reset_values, 256); +} + - static int twl4030_4b_rx(i2c_slave *i2c) ++static void twl4030_48_init(i2c_slave *i2c) +{ - struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c; - - return twl4030_4b_read(s, s->reg++); ++ twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c), ++ twl4030_48_read, twl4030_48_write, ++ addr_48_reset_values); +} + - static void twl4030_4b_reset(i2c_slave *i2c) ++static void twl4030_49_init(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; ++ twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c), ++ twl4030_49_read, twl4030_49_write, ++ addr_49_reset_values); +} + - static void twl4030_4b_event(i2c_slave *i2c, enum i2c_event event) ++static void twl4030_4a_init(i2c_slave *i2c) +{ - struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c; - - if (event == I2C_START_SEND) ++ twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c), ++ twl4030_4a_read, twl4030_4a_write, ++ addr_4a_reset_values); ++} ++ ++static void twl4030_4b_init(i2c_slave *i2c) ++{ ++ twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c), ++ twl4030_4b_read, twl4030_4b_write, ++ addr_4b_reset_values); ++} ++ ++static void twl4030_event(i2c_slave *i2c, enum i2c_event event) ++{ ++ if (event == I2C_START_SEND) { ++ TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c); + s->firstbyte = 1; ++ } ++} ++ ++static int twl4030_rx(i2c_slave *i2c) ++{ ++ TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c); ++ return s->read_func(s, s->reg++); ++} ++ ++static int twl4030_tx(i2c_slave *i2c, uint8_t data) ++{ ++ TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c); ++ if (s->firstbyte) { ++ s->reg = data; ++ s->firstbyte = 0; ++ } else { ++ s->write_func(s, s->reg++, data); ++ } ++ return 1; +} + +static void twl4030_save_state(QEMUFile *f, void *opaque) +{ - struct twl4030_s *s = (struct twl4030_s *)opaque; ++ TWL4030State *s = (TWL4030State *)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; ++ TWL4030State *s = (TWL4030State *)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) ++void *twl4030_init(i2c_bus *gp_bus, qemu_irq irq) +{ - int i; ++ TWL4030State *s = (TWL4030State *)qemu_mallocz(sizeof(*s)); + - 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->irq = irq; ++ s->key_cfg = 0; ++ s->key_tst = 0; ++ ++ int i; ++ for (i = 0; i < 4; i++) { ++ char name[16]; ++ sprintf(name, "twl4030_id%d", i + 1); ++ DeviceState *ds = i2c_create_slave(gp_bus, name, 0x48 + i); ++ s->i2c[i] = FROM_I2C_SLAVE(TWL4030NodeState, I2C_SLAVE_FROM_QDEV(ds)); + 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; +} ++ ++static I2CSlaveInfo twl4030_info[4] = { ++ { ++ .init = twl4030_48_init, ++ .event = twl4030_event, ++ .recv = twl4030_rx, ++ .send = twl4030_tx ++ }, ++ { ++ .init = twl4030_49_init, ++ .event = twl4030_event, ++ .recv = twl4030_rx, ++ .send = twl4030_tx ++ }, ++ { ++ .init = twl4030_4a_init, ++ .event = twl4030_event, ++ .recv = twl4030_rx, ++ .send = twl4030_tx ++ }, ++ { ++ .init = twl4030_4b_init, ++ .event = twl4030_event, ++ .recv = twl4030_rx, ++ .send = twl4030_tx ++ }, ++}; ++ ++static void twl4030_register_devices(void) ++{ ++ I2CSlaveInfo *p = twl4030_info; ++ int i; ++ for (i = 0; i < 4; p++, i++) { ++ char name[16]; ++ sprintf(name, "twl4030_id%d", i + 1); ++ i2c_register_slave(name, sizeof(TWL4030NodeState), p); ++ } ++} ++ ++device_init(twl4030_register_devices); diff --cc hw/usb-musb.c index 5fe25ce,451bc8d..dbcfe83 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@@ -250,18 -249,38 +250,47 @@@ #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 { + typedef struct { + uint16_t faddr[2]; + uint8_t haddr[2]; + uint8_t hport[2]; + uint16_t csr[2]; + uint16_t maxp[2]; + uint16_t rxcount; + uint8_t type[2]; + uint8_t interval[2]; + uint8_t config; + 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]; + USBPacket packey[2]; + int status[2]; + int ext_size[2]; + + /* For callbacks' use */ + int epnum; + int interrupt[2]; + MUSBState *musb; + USBCallback *delayed_cb[2]; + QEMUTimer *intv_timer[2]; + } MUSBEndPoint; + + struct MUSBState { qemu_irq *irqs; USBPort port; @@@ -280,41 -299,44 +309,14 @@@ int setup_len; int session; - uint32_t buf[0x2000]; + uint8_t buf[0x8000]; - struct musb_ep_s { - uint16_t faddr[2]; - uint8_t haddr[2]; - uint8_t hport[2]; - uint16_t csr[2]; - uint16_t maxp[2]; - uint16_t rxcount; - uint8_t type[2]; - uint8_t interval[2]; - uint8_t config; - uint8_t fifosize; - int timeout[2]; /* Always in microframes */ - - uint8_t *buf[2]; - int fifolen[2]; - int fifostart[2]; - int fifoaddr[2]; - USBPacket packey[2]; - int status[2]; - int ext_size[2]; - - /* For callbacks' use */ - int epnum; - int interrupt[2]; - struct musb_s *musb; - USBCallback *delayed_cb[2]; - QEMUTimer *intv_timer[2]; /* Duplicating the world since 2008!... probably we should have 32 * logical, single endpoints instead. */ - } ep[16]; + MUSBEndPoint ep[16]; -} *musb_init(qemu_irq *irqs) -{ - MUSBState *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) + static void musb_vbus_set(MUSBState *s, int level) { if (level) s->devctl |= 3 << MGC_S_DEVCTL_VBUS; @@@ -746,12 -768,12 +748,12 @@@ static void musb_rx_packet_complete(USB musb_rx_intr_set(s, epnum, 1); } - static void musb_tx_rdy(struct musb_s *s, int epnum) + static void musb_tx_rdy(MUSBState *s, int epnum) { - struct musb_ep_s *ep = s->ep + epnum; + MUSBEndPoint *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; @@@ -850,39 -871,7 +852,39 @@@ static void musb_rx_req(MUSBState *s, i total, musb_rx_packet_complete, 1); } - static uint8_t musb_read_fifo(struct musb_ep_s *ep) ++static uint8_t musb_read_fifo(MUSBEndPoint *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) ++static void musb_write_fifo(MUSBEndPoint *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) + static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir) { if (ep->intv_timer[dir]) qemu_del_timer(ep->intv_timer[dir]); @@@ -891,8 -880,7 +893,8 @@@ /* Bus control */ 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); + MUSBState *s = (MUSBState *) opaque; ++ // TRACE("ADDR = 0x%08x", addr); switch (addr) { /* For USB2.0 HS hubs only */ @@@ -913,15 -901,9 +915,15 @@@ static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value) { - struct musb_s *s = (struct musb_s *) opaque; + MUSBState *s = (MUSBState *) 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; @@@ -1162,10 -1143,9 +1164,10 @@@ static void musb_ep_writeh(void *opaque /* Generic control */ static uint32_t musb_readb(void *opaque, target_phys_addr_t addr) { - struct musb_s *s = (struct musb_s *) opaque; + MUSBState *s = (MUSBState *) opaque; int ep, i; uint8_t ret; +// TRACE("ADDR = 0x%08x", addr); switch (addr) { case MUSB_HDRC_FADDR: @@@ -1225,9 -1201,8 +1227,9 @@@ static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) { - struct musb_s *s = (struct musb_s *) opaque; + MUSBState *s = (MUSBState *) opaque; int ep; +// TRACE("ADDR = 0x%08x = %08x", addr, value); switch (addr) { case MUSB_HDRC_FADDR: @@@ -1312,10 -1282,9 +1314,10 @@@ static uint32_t musb_readh(void *opaque, target_phys_addr_t addr) { - struct musb_s *s = (struct musb_s *) opaque; + MUSBState *s = (MUSBState *) opaque; int ep, i; uint16_t ret; +// TRACE("ADDR = 0x%08x", addr); switch (addr) { case MUSB_HDRC_INTRTX: @@@ -1367,9 -1332,8 +1369,9 @@@ static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) { - struct musb_s *s = (struct musb_s *) opaque; + MUSBState *s = (MUSBState *) opaque; int ep; + //TRACE("ADDR = 0x%08x = %08x", addr, value); switch (addr) { case MUSB_HDRC_INTRTXE: @@@ -1426,8 -1382,9 +1428,8 @@@ static uint32_t musb_readw(void *opaque, target_phys_addr_t addr) { - struct musb_s *s = (struct musb_s *) opaque; + MUSBState *s = (MUSBState *) opaque; - MUSBEndPoint *ep; - int epnum; + int ep; switch (addr) { case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): @@@ -1444,9 -1411,9 +1446,9 @@@ static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value) { - struct musb_s *s = (struct musb_s *) opaque; + MUSBState *s = (MUSBState *) opaque; - MUSBEndPoint *ep; - int epnum; + int ep; +// TRACE("ADDR = 0x%08x = %08x", addr, value); switch (addr) { case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f): @@@ -1472,182 -1448,3 +1474,182 @@@ CPUWriteMemoryFunc *musb_write[] = musb_writeh, musb_writew, }; + +static void musb_save_state(QEMUFile *f, void *opaque) +{ - struct musb_s *s = (struct musb_s *)opaque; ++ MUSBState *s = (MUSBState *)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; ++ MUSBState *s = (MUSBState *)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) ++MUSBState *musb_init(qemu_irq *irqs) +{ - struct musb_s *s = qemu_mallocz(sizeof(*s)); ++ MUSBState *s = qemu_mallocz(sizeof(*s)); + int i; + + s->irqs = irqs; + + s->faddr = 0x00; + s->power = MGC_M_POWER_HSENAB; + s->tx_intr = 0x0000; + s->rx_intr = 0x0000; + s->tx_mask = 0xffff; + s->rx_mask = 0xffff; + s->intr = 0x00; + s->mask = 0x06; + s->idx = 0; + + /* TODO: _DW */ + s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO; + for (i = 0; i < 16; i ++) { + s->ep[i].fifosize = 64; + s->ep[i].maxp[0] = 0x40; + s->ep[i].maxp[1] = 0x40; + s->ep[i].musb = s; + s->ep[i].epnum = i; + } + + qemu_register_usb_port(&s->port, s, 0, musb_attach); + register_savevm("musb", -1, 0, musb_save_state, musb_load_state, s); + return s; +} diff --cc linux-user/syscall.c index 9787ec1,59c91f8..2087226 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@@ -3468,9 -3201,8 +3468,10 @@@ static void *clone_func(void *arg env = info->env; thread_env = env; + ts = (TaskState *)thread_env->opaque; - info->tid = gettid(); + task_settid(ts); + info->tid = gettid(); + env->host_tid = info->tid; if (info->child_tidptr) put_user_u32(info->tid, info->child_tidptr); if (info->parent_tidptr)