#######################################################################
# 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
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
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
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"
fi
fi
+# check if utimensat and futimens are supported
+utimens=no
+cat > $TMPC << EOF
+#define _ATFILE_SOURCE
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <fcntl.h>
+
+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
##########################################
--- /dev/null
+/*
+ * Beagle board emulation. http://beagleboard.org/
+ *
+ * Original code Copyright (C) 2008 yajin(yajin@vm-kernel.org)
+ * Rewrite Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "omap.h"
+#include "arm-misc.h"
+#include "boards.h"
+#include "i2c.h"
+#include "net.h"
+#include "devices.h"
+#include "flash.h"
+
+#define BEAGLE_NAND_CS 0
+#define BEAGLE_SMC_CS 1
+#define BEAGLE_NAND_PAGESIZE 0x800
+#define BEAGLE_SDRAM_SIZE (128 * 1024 * 1024) /* 128MB */
+
+/* Beagle board support */
+struct beagle_s {
+ struct omap_mpu_state_s *cpu;
+
- struct nand_flash_s *nand;
++ 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);
uint16_t *ptr;
int angle;
int pitch;
- blizzard_fn_t line_fn;
} data;
- };
+ } BlizzardState;
/* Bytes(!) per pixel */
static const int blizzard_iformat_bpp[0x10] = {
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);
/* 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);
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
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
# 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;
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
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:
*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);
}
}
- 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) {
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) {
#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;
}
/* 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);
}
}
- 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;
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);
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 */
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:
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 */
--- /dev/null
+/*
+ * OMAP3 Multimedia Card/Secure Digital/Secure Digital I/O (MMC/SD/SDIO) Card Interface emulation
+ *
+ * Copyright (C) 2008 yajin <yajin@vm-kernel.org>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "hw.h"
+#include "omap.h"
+#include "sd.h"
+
+/* debug levels:
+ 0 - no debug
+ 1 - print out all commands in processing order
+ 2 - dump all register accesses and buffer management */
+#define MMC_DEBUG_LEVEL 0
+
+#if MMC_DEBUG_LEVEL>0
+#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#if MMC_DEBUG_LEVEL>1
+#define TRACE2(...) TRACE(__VA_ARGS__)
+#else
+#define TRACE2(...)
+#endif
+#else
+#define TRACE(...)
+#define TRACE2(...)
+#endif
+
+struct omap3_mmc_s
+{
+ qemu_irq irq;
+ qemu_irq *dma;
+ qemu_irq coverswitch;
+ omap_clk clk;
+ SDState *card;
+
+ uint32_t sysconfig;
+ uint32_t sysstatus;
+ uint32_t csre;
+ uint32_t systest;
+ uint32_t con;
+ uint32_t pwcnt;
+ uint32_t blk;
+ uint32_t arg;
+ uint32_t cmd;
+ uint32_t rsp10;
+ uint32_t rsp32;
+ uint32_t rsp54;
+ uint32_t rsp76;
+ uint32_t data;
+ uint32_t pstate;
+ uint32_t hctl;
+ uint32_t sysctl;
+ uint32_t stat;
+ uint32_t ie;
+ uint32_t ise;
+ uint32_t ac12;
+ uint32_t capa;
+ uint32_t cur_capa;
+ uint32_t rev;
+
+ uint16_t blen_counter;
+ uint16_t nblk_counter;
+
+ uint32_t fifo[256];
+ int fifo_start;
+ int fifo_len;
+
+ int ddir;
+ int transfer;
+ int stop;
+
+ uint32_t stat_pending;
+};
+
+
+typedef enum
+{
+ sd_nore = 0, /* no response */
+ sd_136_bits = 1, /* response length 136 bits */
+ sd_48_bits = 2, /* response length 48 bits */
+ sd_48b_bits = 3, /* response length 48 bits with busy after response */
+} omap3_sd_rsp_type_t;
+
+static void omap3_mmc_command(struct omap3_mmc_s *host);
+
+static void omap3_mmc_interrupts_update(struct omap3_mmc_s *s)
+{
+ qemu_set_irq(s->irq, !!((s->stat | s->stat_pending) & s->ie & s->ise));
+}
+
+static void omap3_mmc_fifolevel_update(struct omap3_mmc_s *host)
+{
+ enum { ongoing, ready, aborted } state = ongoing;
+
+ if ((host->cmd & (1 << 21))) { /* DP */
+ if (host->ddir) {
+ TRACE2("receive, dma=%d, fifo_len=%d bytes",
+ host->cmd & 1, host->fifo_len * 4);
+
+ /* omap3_mmc_transfer ensures we always have data in FIFO
+ during receive as long as all data has not been transferred -
+ NOTE that the actual transfer may be finished already (i.e.
+ host->transfer is cleared) but not all data has been read out
+ from FIFO yet */
+ if (host->fifo_len) {
+ if (host->cmd & 1) { /* DE */
+ if (host->fifo_len * 4 == (host->blk & 0x7ff)) { /* BLEN */
+ if (host->stop)
+ state = aborted;
+ else
+ qemu_irq_raise(host->dma[1]);
+ } else
+ qemu_irq_lower(host->dma[1]);
+ } else {
+ if (host->stop
+ && host->fifo_len * 4 == (host->blk & 0x7ff))
+ state = aborted;
+ else {
+ host->pstate |= 0x0800; /* BRE */
+ host->stat_pending |= 0x20; /* BRR */
+ }
+ }
+ }
+ else
+ state = host->stop ? aborted : ready;
+ } else {
+ /* omap3_mmc_transfer keeps FIFO empty during transmit so
+ we just check all blocks have been transferred or not */
+ if (host->transfer) {
+ if (host->cmd & 1) { /* DE */
+ if (host->blen_counter == (host->blk & 0x7ff)) { /* BLEN */
+ if (host->stop)
+ state = aborted;
+ else
+ qemu_irq_raise(host->dma[0]);
+ } else
+ qemu_irq_lower(host->dma[0]);
+ } else {
+ if (host->stop
+ && host->blen_counter == (host->blk & 0x7ff))
+ state = aborted;
+ else {
+ host->pstate |= 0x0400; /* BWE */
+ host->stat_pending |= 0x10; /* BWR */
+ }
+ }
+ } else
+ state = host->stop ? aborted : ready;
+ }
+
+ if ((host->cmd & 1) || state != ongoing) { /* DE */
+ host->pstate &= ~0x0c00; /* BRE | BWE */
+ host->stat_pending &= ~0x30; /* BRR | BWR */
+ host->stat &= ~0x30; /* BRR | BWR */
+ if (state != ongoing) {
+ TRACE2("transfer %s",
+ state == ready
+ ? "complete"
+ : "aborted --> complete");
+ host->stat_pending |= 0x2; /* TC */
+ if (host->cmd & 0x04) { /* ACEN */
+ host->stop = 0x0cc30000;
+ state = aborted;
+ }
+ if (state == aborted) {
+ host->cmd = host->stop;
+ host->stop = 0;
+ omap3_mmc_command(host);
+ }
+ }
+ }
+ }
+}
+
+static void omap3_mmc_transfer(struct omap3_mmc_s *host)
+{
+ int i;
+ uint32_t x;
+#if MMC_DEBUG_LEVEL>1
+ int j;
+ uint8_t c, sym[17];
+#endif
+
+ /* IF data transfer is inactive
+ OR block count enabled with zero block count
+ OR in receive mode and we have unread data in FIFO
+ OR in transmit mode and we have no data in FIFO,
+ THEN don't do anything */
+ if (!host->transfer
+ || ((host->cmd & 2) && !host->nblk_counter)
+ || (host->ddir && host->fifo_len)
+ || (!host->ddir && !host->fifo_len))
+ return;
+
+ if (host->ddir) {
+ TRACE2("begin, %d blocks (%d bytes/block) left to receive, %d bytes in FIFO",
+ (host->cmd & 2) ? host->nblk_counter : 1,
+ host->blk & 0x7ff,
+ host->fifo_len * 4);
+ while (host->blen_counter && host->fifo_len < 255) {
+ for (i = 0, x = 0; i < 32 && host->blen_counter; i += 8, host->blen_counter--)
+ x |= sd_read_data(host->card) << i;
+ host->fifo[(host->fifo_start + host->fifo_len) & 0xff] = x;
+ host->fifo_len++;
+ }
+ TRACE2("end, %d bytes in FIFO:", host->fifo_len * 4);
+#if MMC_DEBUG_LEVEL>1
+ for (i = 0; i < host->fifo_len; ) {
+ fprintf(stderr, "%s: [0x%03x] ", __FUNCTION__, i * 4);
+ do {
+ x = host->fifo[(host->fifo_start + i) & 0xff];
+ for (j = 0; j < 4; j++) {
+ c = (x >> (j * 8)) & 0xff;
+ fprintf(stderr, "%02x ", c);
+ sym[(i & 3) * 4 + j] = (c < 32 || c > 126) ? '.' : c;
+ }
+ } while (((++i) & 3));
+ sym[16] = 0;
+ fprintf(stderr, "%s\n", sym);
+ }
+#endif
+ } else {
+ TRACE2("%d bytes left to transmit in current block", host->blen_counter);
+ while (host->blen_counter && host->fifo_len) {
+ for (i = 0; i < 32 && host->blen_counter; i += 8, host->blen_counter--)
+ sd_write_data(host->card, (host->fifo[host->fifo_start] >> i) & 0xff);
+ host->fifo_start++;
+ host->fifo_len--;
+ host->fifo_start &= 0xff;
+ }
+ }
+
+ if (!host->blen_counter) {
+ if (host->cmd & 2) /* BCE */
+ host->nblk_counter--;
+ TRACE2("block done, %d blocks left",
+ (host->cmd & (1 << 5)) ? host->nblk_counter : 0);
+ host->blen_counter = host->blk & 0x7ff;
+ if (!(host->cmd & (1 << 5)) /* MSBS */
+ || !host->nblk_counter) {
+ host->nblk_counter = (host->blk >> 16) & 0xffff;
+ host->transfer = 0;
+ host->pstate &= ~0x0306; /* RTA | WTA | DLA | DATI */
+ }
+ }
+}
+
+static void omap3_mmc_command(struct omap3_mmc_s *host)
+{
+ uint32_t rspstatus, mask;
+ int rsplen, timeout;
- struct sd_request_s request;
++ 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);
+}
--- /dev/null
+/*
+ * TI OMAP3 High-Speed USB Host and OTG Controller emulation.
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "omap.h"
+#include "irq.h"
+#include "devices.h"
+#include "hw.h"
+
+#define OMAP3_HSUSB_OTG
+#define OMAP3_HSUSB_HOST
+
+#define OMAP3_HSUSB_DEBUG
+
+#ifdef OMAP3_HSUSB_DEBUG
+#define TRACE(fmt,...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
+#ifdef OMAP3_HSUSB_OTG
+/* usb-musb.c */
+extern CPUReadMemoryFunc *musb_read[];
+extern CPUWriteMemoryFunc *musb_write[];
+
+struct omap3_hsusb_otg_s {
+ qemu_irq mc_irq;
+ qemu_irq dma_irq;
- struct musb_s *musb;
++ 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;
+}
+
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;
+}
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;
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);
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;
}
}
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;
}
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;
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;
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)
}
/* 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:
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. */
#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;
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:
--- /dev/null
+/*
+ * TI TWL4030 emulation
+ *
+ * Copyright (C) 2008 yajin<yajin@vm-kernel.org>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Register implementation based on TPS65950 ES1.0 specification.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "i2c.h"
+#include "sysemu.h"
+#include "console.h"
+#include "cpu-all.h"
+
+//#define VERBOSE 1
+
+#ifdef VERBOSE
+#define TRACE(fmt, ...) fprintf(stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#else
+#define TRACE(...)
+#endif
+
- struct twl4030_i2c_s {
++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);
#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;
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;
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;
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]);
/* 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 */
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;
/* 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:
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:
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:
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:
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):
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):
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;
+}
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)