diff options
author | Richard Purdie <richard@openedhand.com> | 2008-04-10 09:50:09 +0000 |
---|---|---|
committer | Richard Purdie <richard@openedhand.com> | 2008-04-10 09:50:09 +0000 |
commit | 5091c0bd8842b2a5f94e47c391dc6fe73eac8901 (patch) | |
tree | 48288911ebbed8f7b557a3a828b340f06e155056 /meta/packages | |
parent | 37ddd0087fac5868851113d3d7b11c262653f782 (diff) | |
download | openembedded-core-5091c0bd8842b2a5f94e47c391dc6fe73eac8901.tar.gz openembedded-core-5091c0bd8842b2a5f94e47c391dc6fe73eac8901.tar.bz2 openembedded-core-5091c0bd8842b2a5f94e47c391dc6fe73eac8901.tar.xz openembedded-core-5091c0bd8842b2a5f94e47c391dc6fe73eac8901.zip |
qemu-cvs: Add nokia800 emulation
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@4225 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'meta/packages')
-rw-r--r-- | meta/packages/qemu/qemu-native-0.9.1+cvs20080307/qemu-n800-support.patch | 13970 | ||||
-rw-r--r-- | meta/packages/qemu/qemu-native-0.9.1+cvs20080307/series | 1 | ||||
-rw-r--r-- | meta/packages/qemu/qemu_cvs.bb | 5 |
3 files changed, 13974 insertions, 2 deletions
diff --git a/meta/packages/qemu/qemu-native-0.9.1+cvs20080307/qemu-n800-support.patch b/meta/packages/qemu/qemu-native-0.9.1+cvs20080307/qemu-n800-support.patch new file mode 100644 index 000000000..b1b6649ef --- /dev/null +++ b/meta/packages/qemu/qemu-native-0.9.1+cvs20080307/qemu-n800-support.patch @@ -0,0 +1,13970 @@ +diff --git a/Makefile b/Makefile +index c36a978..cb0cf7b 100644 +--- a/Makefile ++++ b/Makefile +@@ -51,7 +51,8 @@ OBJS+=block.o + + OBJS+=irq.o + OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o +-OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o ++OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o ++OBJS+=tmp105.o + OBJS+=scsi-disk.o cdrom.o + OBJS+=scsi-generic.o + OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o usb-serial.o +diff --git a/Makefile.target b/Makefile.target +index d1deda1..48f31bc 100644 +--- a/Makefile.target ++++ b/Makefile.target +@@ -593,7 +593,9 @@ OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o + OBJS+= pflash_cfi01.o gumstix.o + OBJS+= spitz.o ide.o serial.o nand.o ecc.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 + OBJS+= palm.o tsc210x.o ++OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o + OBJS+= mst_fpga.o mainstone.o + CPPFLAGS += -DHAS_AUDIO + endif +diff --git a/console.h b/console.h +index b8a5c6d..b45974e 100644 +--- a/console.h ++++ b/console.h +@@ -32,6 +32,12 @@ void kbd_put_keycode(int keycode); + void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); + int kbd_mouse_is_absolute(void); + ++struct mouse_transform_info_s { ++ int x; ++ int y; ++ int a[7]; ++}; ++ + void do_info_mice(void); + void do_mouse_set(int index); + +diff --git a/cpu-all.h b/cpu-all.h +index 7a7e655..c7c9611 100644 +--- a/cpu-all.h ++++ b/cpu-all.h +@@ -810,7 +810,7 @@ extern uint8_t *phys_ram_dirty; + /* physical memory access */ + #define TLB_INVALID_MASK (1 << 3) + #define IO_MEM_SHIFT 4 +-#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT)) ++#define IO_MEM_NB_ENTRIES (16 << (TARGET_PAGE_BITS - IO_MEM_SHIFT)) + + #define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */ + #define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ +diff --git a/exec.c b/exec.c +index e9a5918..c69f742 100644 +--- a/exec.c ++++ b/exec.c +@@ -1658,7 +1658,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { + /* IO memory case */ +- address = vaddr | pd; ++ address = vaddr | (pd & ~TARGET_PAGE_MASK); + addend = paddr; + } else { + /* standard memory */ +@@ -1692,7 +1692,9 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + } else { + te->addr_read = -1; + } +- if (prot & PAGE_EXEC) { ++ if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { ++ te->addr_code = pd; ++ } else if (prot & PAGE_EXEC) { + te->addr_code = address; + } else { + te->addr_code = -1; +@@ -2487,7 +2489,9 @@ int cpu_register_io_memory(int io_index, + if (io_index <= 0) { + if (io_mem_nb >= IO_MEM_NB_ENTRIES) + return -1; +- io_index = io_mem_nb++; ++ do io_index = io_mem_nb++; ++ while (((io_index << IO_MEM_SHIFT) & ~TARGET_PAGE_MASK) ++ <= IO_MEM_NOTDIRTY); + } else { + if (io_index >= IO_MEM_NB_ENTRIES) + return -1; +diff --git a/hw/arm-misc.h b/hw/arm-misc.h +index 7914ff1..a1e0061 100644 +--- a/hw/arm-misc.h ++++ b/hw/arm-misc.h +@@ -21,10 +21,7 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, + const char *kernel_filename, const char *cpu_model); + + /* arm_boot.c */ +- +-void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, +- const char *kernel_cmdline, const char *initrd_filename, +- int board_id, target_phys_addr_t loader_start); ++void arm_load_kernel(CPUState *env, struct arm_boot_info *info); + + /* armv7m_nvic.c */ + int system_clock_scale; +diff --git a/hw/arm_boot.c b/hw/arm_boot.c +index 8335e69..20b1512 100644 +--- a/hw/arm_boot.c ++++ b/hw/arm_boot.c +@@ -47,21 +47,18 @@ static void main_cpu_reset(void *opaque) + CPUState *env = opaque; + + cpu_reset(env); +- if (env->kernel_filename) +- arm_load_kernel(env, env->ram_size, env->kernel_filename, +- env->kernel_cmdline, env->initrd_filename, +- env->board_id, env->loader_start); ++ if (env->boot_info) ++ arm_load_kernel(env, env->boot_info); + + /* TODO: Reset secondary CPUs. */ + } + +-static void set_kernel_args(uint32_t ram_size, int initrd_size, +- const char *kernel_cmdline, +- target_phys_addr_t loader_start) ++static void set_kernel_args(struct arm_boot_info *info, ++ int initrd_size, void *base) + { + uint32_t *p; + +- p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); ++ p = (uint32_t *)(base + KERNEL_ARGS_ADDR); + /* ATAG_CORE */ + stl_raw(p++, 5); + stl_raw(p++, 0x54410001); +@@ -69,46 +66,55 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size, + stl_raw(p++, 0x1000); + stl_raw(p++, 0); + /* ATAG_MEM */ ++ /* TODO: multiple chips */ + stl_raw(p++, 4); + stl_raw(p++, 0x54410002); +- stl_raw(p++, ram_size); +- stl_raw(p++, loader_start); ++ stl_raw(p++, info->ram_size); ++ stl_raw(p++, info->loader_start); + if (initrd_size) { + /* ATAG_INITRD2 */ + stl_raw(p++, 4); + stl_raw(p++, 0x54420005); +- stl_raw(p++, loader_start + INITRD_LOAD_ADDR); ++ stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR); + stl_raw(p++, initrd_size); + } +- if (kernel_cmdline && *kernel_cmdline) { ++ if (info->kernel_cmdline && *info->kernel_cmdline) { + /* ATAG_CMDLINE */ + int cmdline_size; + +- cmdline_size = strlen(kernel_cmdline); +- memcpy (p + 2, kernel_cmdline, cmdline_size + 1); ++ cmdline_size = strlen(info->kernel_cmdline); ++ memcpy(p + 2, info->kernel_cmdline, cmdline_size + 1); + cmdline_size = (cmdline_size >> 2) + 1; + stl_raw(p++, cmdline_size + 2); + stl_raw(p++, 0x54410009); + p += cmdline_size; + } ++ if (info->atag_board) { ++ /* ATAG_BOARD */ ++ int atag_board_len; ++ ++ atag_board_len = (info->atag_board(info, p + 2) + 3) >> 2; ++ stl_raw(p++, 2 + atag_board_len); ++ stl_raw(p++, 0x414f4d50); ++ p += atag_board_len; ++ } + /* ATAG_END */ + stl_raw(p++, 0); + stl_raw(p++, 0); + } + +-static void set_kernel_args_old(uint32_t ram_size, int initrd_size, +- const char *kernel_cmdline, +- target_phys_addr_t loader_start) ++static void set_kernel_args_old(struct arm_boot_info *info, ++ int initrd_size, void *base) + { + uint32_t *p; + unsigned char *s; + + /* see linux/include/asm-arm/setup.h */ +- p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); ++ p = (uint32_t *)(base + KERNEL_ARGS_ADDR); + /* page_size */ + stl_raw(p++, 4096); + /* nr_pages */ +- stl_raw(p++, ram_size / 4096); ++ stl_raw(p++, info->ram_size / 4096); + /* ramdisk_size */ + stl_raw(p++, 0); + #define FLAG_READONLY 1 +@@ -142,7 +148,7 @@ static void set_kernel_args_old(uint32_t ram_size, int initrd_size, + stl_raw(p++, 0); + /* initrd_start */ + if (initrd_size) +- stl_raw(p++, loader_start + INITRD_LOAD_ADDR); ++ stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR); + else + stl_raw(p++, 0); + /* initrd_size */ +@@ -159,17 +165,15 @@ static void set_kernel_args_old(uint32_t ram_size, int initrd_size, + stl_raw(p++, 0); + /* zero unused fields */ + memset(p, 0, 256 + 1024 - +- (p - ((uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR)))); +- s = phys_ram_base + KERNEL_ARGS_ADDR + 256 + 1024; +- if (kernel_cmdline) +- strcpy (s, kernel_cmdline); ++ (p - ((uint32_t *)(base + KERNEL_ARGS_ADDR)))); ++ s = base + KERNEL_ARGS_ADDR + 256 + 1024; ++ if (info->kernel_cmdline) ++ strcpy (s, info->kernel_cmdline); + else + stb_raw(s, 0); + } + +-void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, +- const char *kernel_cmdline, const char *initrd_filename, +- int board_id, target_phys_addr_t loader_start) ++void arm_load_kernel(CPUState *env, struct arm_boot_info *info) + { + int kernel_size; + int initrd_size; +@@ -177,36 +181,41 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, + int is_linux = 0; + uint64_t elf_entry; + target_ulong entry; ++ uint32_t pd; ++ void *loader_phys; + + /* Load the kernel. */ +- if (!kernel_filename) { ++ if (!info->kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + +- if (!env->kernel_filename) { +- env->ram_size = ram_size; +- env->kernel_filename = kernel_filename; +- env->kernel_cmdline = kernel_cmdline; +- env->initrd_filename = initrd_filename; +- env->board_id = board_id; +- env->loader_start = loader_start; ++ if (!env->boot_info) { ++ if (info->nb_cpus == 0) ++ info->nb_cpus = 1; ++ env->boot_info = info; + qemu_register_reset(main_cpu_reset, env); + } ++ ++ pd = cpu_get_physical_page_desc(info->loader_start); ++ loader_phys = phys_ram_base + (pd & TARGET_PAGE_MASK) + ++ (info->loader_start & ~TARGET_PAGE_MASK); ++ + /* Assume that raw images are linux kernels, and ELF images are not. */ +- kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); ++ kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL); + entry = elf_entry; + if (kernel_size < 0) { +- kernel_size = load_uboot(kernel_filename, &entry, &is_linux); ++ kernel_size = load_uboot(info->kernel_filename, &entry, &is_linux); + } + if (kernel_size < 0) { +- kernel_size = load_image(kernel_filename, +- phys_ram_base + KERNEL_LOAD_ADDR); +- entry = loader_start + KERNEL_LOAD_ADDR; ++ kernel_size = load_image(info->kernel_filename, ++ loader_phys + KERNEL_LOAD_ADDR); ++ entry = info->loader_start + KERNEL_LOAD_ADDR; + is_linux = 1; + } + if (kernel_size < 0) { +- fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); ++ fprintf(stderr, "qemu: could not load kernel '%s'\n", ++ info->kernel_filename); + exit(1); + } + if (!is_linux) { +@@ -214,30 +223,29 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, + env->regs[15] = entry & 0xfffffffe; + env->thumb = entry & 1; + } else { +- if (initrd_filename) { +- initrd_size = load_image(initrd_filename, +- phys_ram_base + INITRD_LOAD_ADDR); ++ if (info->initrd_filename) { ++ initrd_size = load_image(info->initrd_filename, ++ loader_phys + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initrd '%s'\n", +- initrd_filename); ++ info->initrd_filename); + exit(1); + } + } else { + initrd_size = 0; + } +- bootloader[1] |= board_id & 0xff; +- bootloader[2] |= (board_id >> 8) & 0xff; +- bootloader[5] = loader_start + KERNEL_ARGS_ADDR; ++ bootloader[1] |= info->board_id & 0xff; ++ bootloader[2] |= (info->board_id >> 8) & 0xff; ++ bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR; + bootloader[6] = entry; + for (n = 0; n < sizeof(bootloader) / 4; n++) +- stl_raw(phys_ram_base + (n * 4), bootloader[n]); +- for (n = 0; n < sizeof(smpboot) / 4; n++) +- stl_raw(phys_ram_base + ram_size + (n * 4), smpboot[n]); ++ stl_raw(loader_phys + (n * 4), bootloader[n]); ++ if (info->nb_cpus > 1) ++ for (n = 0; n < sizeof(smpboot) / 4; n++) ++ stl_raw(loader_phys + info->ram_size + (n * 4), smpboot[n]); + if (old_param) +- set_kernel_args_old(ram_size, initrd_size, +- kernel_cmdline, loader_start); ++ set_kernel_args_old(info, initrd_size, loader_phys); + else +- set_kernel_args(ram_size, initrd_size, +- kernel_cmdline, loader_start); ++ set_kernel_args(info, initrd_size, loader_phys); + } + } +diff --git a/hw/blizzard.c b/hw/blizzard.c +new file mode 100644 +index 0000000..9046b5d +--- /dev/null ++++ b/hw/blizzard.c +@@ -0,0 +1,1001 @@ ++/* ++ * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller. ++ * ++ * Copyright (C) 2008 Nokia Corporation ++ * Written by Andrzej Zaborowski <andrew@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * 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 "console.h" ++#include "devices.h" ++#include "vga_int.h" ++#include "pixel_ops.h" ++ ++typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int); ++ ++struct blizzard_s { ++ uint8_t reg; ++ uint32_t addr; ++ int swallow; ++ ++ int pll; ++ int pll_range; ++ int pll_ctrl; ++ uint8_t pll_mode; ++ uint8_t clksel; ++ int memenable; ++ int memrefresh; ++ uint8_t timing[3]; ++ int priority; ++ ++ uint8_t lcd_config; ++ int x; ++ int y; ++ int skipx; ++ int skipy; ++ uint8_t hndp; ++ uint8_t vndp; ++ uint8_t hsync; ++ uint8_t vsync; ++ uint8_t pclk; ++ uint8_t u; ++ uint8_t v; ++ uint8_t yrc[2]; ++ int ix[2]; ++ int iy[2]; ++ int ox[2]; ++ int oy[2]; ++ ++ int enable; ++ int blank; ++ int bpp; ++ int invalidate; ++ int mx[2]; ++ int my[2]; ++ uint8_t mode; ++ uint8_t effect; ++ uint8_t iformat; ++ uint8_t source; ++ DisplayState *state; ++ blizzard_fn_t *line_fn_tab[2]; ++ void *fb; ++ ++ uint8_t hssi_config[3]; ++ uint8_t tv_config; ++ uint8_t tv_timing[4]; ++ uint8_t vbi; ++ uint8_t tv_x; ++ uint8_t tv_y; ++ uint8_t tv_test; ++ uint8_t tv_filter_config; ++ uint8_t tv_filter_idx; ++ uint8_t tv_filter_coeff[0x20]; ++ uint8_t border_r; ++ uint8_t border_g; ++ uint8_t border_b; ++ uint8_t gamma_config; ++ uint8_t gamma_idx; ++ uint8_t gamma_lut[0x100]; ++ uint8_t matrix_ena; ++ uint8_t matrix_coeff[0x12]; ++ uint8_t matrix_r; ++ uint8_t matrix_g; ++ uint8_t matrix_b; ++ uint8_t pm; ++ uint8_t status; ++ uint8_t rgbgpio_dir; ++ uint8_t rgbgpio; ++ uint8_t gpio_dir; ++ uint8_t gpio; ++ uint8_t gpio_edge[2]; ++ uint8_t gpio_irq; ++ uint8_t gpio_pdown; ++ ++ struct { ++ int x; ++ int y; ++ int dx; ++ int dy; ++ int len; ++ int buflen; ++ void *buf; ++ void *data; ++ uint16_t *ptr; ++ int angle; ++ int pitch; ++ blizzard_fn_t line_fn; ++ } data; ++}; ++ ++/* Bytes(!) per pixel */ ++static const int blizzard_iformat_bpp[0x10] = { ++ 0, ++ 2, /* RGB 5:6:5*/ ++ 3, /* RGB 6:6:6 mode 1 */ ++ 3, /* RGB 8:8:8 mode 1 */ ++ 0, 0, ++ 4, /* RGB 6:6:6 mode 2 */ ++ 4, /* RGB 8:8:8 mode 2 */ ++ 0, /* YUV 4:2:2 */ ++ 0, /* YUV 4:2:0 */ ++ 0, 0, 0, 0, 0, 0, ++}; ++ ++static inline void blizzard_rgb2yuv(int r, int g, int b, ++ int *y, int *u, int *v) ++{ ++ *y = 0x10 + ((0x838 * r + 0x1022 * g + 0x322 * b) >> 13); ++ *u = 0x80 + ((0xe0e * b - 0x04c1 * r - 0x94e * g) >> 13); ++ *v = 0x80 + ((0xe0e * r - 0x0bc7 * g - 0x247 * b) >> 13); ++} ++ ++static void blizzard_window(struct blizzard_s *s) ++{ ++ uint8_t *src, *dst; ++ int bypp[2]; ++ int bypl[3]; ++ int y; ++ blizzard_fn_t fn = s->data.line_fn; ++ ++ if (!fn) ++ return; ++ if (s->mx[0] > s->data.x) ++ s->mx[0] = s->data.x; ++ if (s->my[0] > s->data.y) ++ s->my[0] = s->data.y; ++ if (s->mx[1] < s->data.x + s->data.dx) ++ s->mx[1] = s->data.x + s->data.dx; ++ if (s->my[1] < s->data.y + s->data.dy) ++ s->my[1] = s->data.y + s->data.dy; ++ ++ bypp[0] = s->bpp; ++ bypp[1] = (s->state->depth + 7) >> 3; ++ bypl[0] = bypp[0] * s->data.pitch; ++ bypl[1] = bypp[1] * s->x; ++ bypl[2] = bypp[0] * s->data.dx; ++ ++ src = s->data.data; ++ dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x; ++ for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1]) ++ fn(dst, src, bypl[2]); ++} ++ ++static int blizzard_transfer_setup(struct blizzard_s *s) ++{ ++ if (s->source > 3 || !s->bpp || ++ s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0]) ++ return 0; ++ ++ s->data.angle = s->effect & 3; ++ s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat]; ++ s->data.x = s->ix[0]; ++ s->data.y = s->iy[0]; ++ s->data.dx = s->ix[1] - s->ix[0] + 1; ++ s->data.dy = s->iy[1] - s->iy[0] + 1; ++ s->data.len = s->bpp * s->data.dx * s->data.dy; ++ s->data.pitch = s->data.dx; ++ if (s->data.len > s->data.buflen) { ++ s->data.buf = realloc(s->data.buf, s->data.len); ++ s->data.buflen = s->data.len; ++ } ++ s->data.ptr = s->data.buf; ++ s->data.data = s->data.buf; ++ s->data.len /= 2; ++ return 1; ++} ++ ++static void blizzard_reset(struct blizzard_s *s) ++{ ++ s->reg = 0; ++ s->swallow = 0; ++ ++ s->pll = 9; ++ s->pll_range = 1; ++ s->pll_ctrl = 0x14; ++ s->pll_mode = 0x32; ++ s->clksel = 0x00; ++ s->memenable = 0; ++ s->memrefresh = 0x25c; ++ s->timing[0] = 0x3f; ++ s->timing[1] = 0x13; ++ s->timing[2] = 0x21; ++ s->priority = 0; ++ ++ s->lcd_config = 0x74; ++ s->x = 8; ++ s->y = 1; ++ s->skipx = 0; ++ s->skipy = 0; ++ s->hndp = 3; ++ s->vndp = 2; ++ s->hsync = 1; ++ s->vsync = 1; ++ s->pclk = 0x80; ++ ++ s->ix[0] = 0; ++ s->ix[1] = 0; ++ s->iy[0] = 0; ++ s->iy[1] = 0; ++ s->ox[0] = 0; ++ s->ox[1] = 0; ++ s->oy[0] = 0; ++ s->oy[1] = 0; ++ ++ s->yrc[0] = 0x00; ++ s->yrc[1] = 0x30; ++ s->u = 0; ++ s->v = 0; ++ ++ s->iformat = 3; ++ s->source = 0; ++ s->bpp = blizzard_iformat_bpp[s->iformat]; ++ ++ s->hssi_config[0] = 0x00; ++ s->hssi_config[1] = 0x00; ++ s->hssi_config[2] = 0x01; ++ s->tv_config = 0x00; ++ s->tv_timing[0] = 0x00; ++ s->tv_timing[1] = 0x00; ++ s->tv_timing[2] = 0x00; ++ s->tv_timing[3] = 0x00; ++ s->vbi = 0x10; ++ s->tv_x = 0x14; ++ s->tv_y = 0x03; ++ s->tv_test = 0x00; ++ s->tv_filter_config = 0x80; ++ s->tv_filter_idx = 0x00; ++ s->border_r = 0x10; ++ s->border_g = 0x80; ++ s->border_b = 0x80; ++ s->gamma_config = 0x00; ++ s->gamma_idx = 0x00; ++ s->matrix_ena = 0x00; ++ memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff)); ++ s->matrix_r = 0x00; ++ s->matrix_g = 0x00; ++ s->matrix_b = 0x00; ++ s->pm = 0x02; ++ s->status = 0x00; ++ s->rgbgpio_dir = 0x00; ++ s->gpio_dir = 0x00; ++ s->gpio_edge[0] = 0x00; ++ s->gpio_edge[1] = 0x00; ++ s->gpio_irq = 0x00; ++ s->gpio_pdown = 0xff; ++} ++ ++static inline void blizzard_invalidate_display(void *opaque) { ++ struct blizzard_s *s = (struct blizzard_s *) opaque; ++ ++ s->invalidate = 1; ++} ++ ++static uint16_t blizzard_reg_read(void *opaque, uint8_t reg) ++{ ++ struct blizzard_s *s = (struct blizzard_s *) opaque; ++ ++ switch (reg) { ++ case 0x00: /* Revision Code */ ++ return 0xa5; ++ ++ case 0x02: /* Configuration Readback */ ++ return 0x83; /* Macrovision OK, CNF[2:0] = 3 */ ++ ++ case 0x04: /* PLL M-Divider */ ++ return (s->pll - 1) | (1 << 7); ++ case 0x06: /* PLL Lock Range Control */ ++ return s->pll_range; ++ case 0x08: /* PLL Lock Synthesis Control 0 */ ++ return s->pll_ctrl & 0xff; ++ case 0x0a: /* PLL Lock Synthesis Control 1 */ ++ return s->pll_ctrl >> 8; ++ case 0x0c: /* PLL Mode Control 0 */ ++ return s->pll_mode; ++ ++ case 0x0e: /* Clock-Source Select */ ++ return s->clksel; ++ ++ case 0x10: /* Memory Controller Activate */ ++ case 0x14: /* Memory Controller Bank 0 Status Flag */ ++ return s->memenable; ++ ++ case 0x18: /* Auto-Refresh Interval Setting 0 */ ++ return s->memrefresh & 0xff; ++ case 0x1a: /* Auto-Refresh Interval Setting 1 */ ++ return s->memrefresh >> 8; ++ ++ case 0x1c: /* Power-On Sequence Timing Control */ ++ return s->timing[0]; ++ case 0x1e: /* Timing Control 0 */ ++ return s->timing[1]; ++ case 0x20: /* Timing Control 1 */ ++ return s->timing[2]; ++ ++ case 0x24: /* Arbitration Priority Control */ ++ return s->priority; ++ ++ case 0x28: /* LCD Panel Configuration */ ++ return s->lcd_config; ++ ++ case 0x2a: /* LCD Horizontal Display Width */ ++ return s->x >> 3; ++ case 0x2c: /* LCD Horizontal Non-display Period */ ++ return s->hndp; ++ case 0x2e: /* LCD Vertical Display Height 0 */ ++ return s->y & 0xff; ++ case 0x30: /* LCD Vertical Display Height 1 */ ++ return s->y >> 8; ++ case 0x32: /* LCD Vertical Non-display Period */ ++ return s->vndp; ++ case 0x34: /* LCD HS Pulse-width */ ++ return s->hsync; ++ case 0x36: /* LCd HS Pulse Start Position */ ++ return s->skipx >> 3; ++ case 0x38: /* LCD VS Pulse-width */ ++ return s->vsync; ++ case 0x3a: /* LCD VS Pulse Start Position */ ++ return s->skipy; ++ ++ case 0x3c: /* PCLK Polarity */ ++ return s->pclk; ++ ++ case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ ++ return s->hssi_config[0]; ++ case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ ++ return s->hssi_config[1]; ++ case 0x42: /* High-speed Serial Interface Tx Mode */ ++ return s->hssi_config[2]; ++ case 0x44: /* TV Display Configuration */ ++ return s->tv_config; ++ case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */ ++ return s->tv_timing[(reg - 0x46) >> 1]; ++ case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ ++ return s->vbi; ++ case 0x50: /* TV Horizontal Start Position */ ++ return s->tv_x; ++ case 0x52: /* TV Vertical Start Position */ ++ return s->tv_y; ++ case 0x54: /* TV Test Pattern Setting */ ++ return s->tv_test; ++ case 0x56: /* TV Filter Setting */ ++ return s->tv_filter_config; ++ case 0x58: /* TV Filter Coefficient Index */ ++ return s->tv_filter_idx; ++ case 0x5a: /* TV Filter Coefficient Data */ ++ if (s->tv_filter_idx < 0x20) ++ return s->tv_filter_coeff[s->tv_filter_idx ++]; ++ return 0; ++ ++ case 0x60: /* Input YUV/RGB Translate Mode 0 */ ++ return s->yrc[0]; ++ case 0x62: /* Input YUV/RGB Translate Mode 1 */ ++ return s->yrc[1]; ++ case 0x64: /* U Data Fix */ ++ return s->u; ++ case 0x66: /* V Data Fix */ ++ return s->v; ++ ++ case 0x68: /* Display Mode */ ++ return s->mode; ++ ++ case 0x6a: /* Special Effects */ ++ return s->effect; ++ ++ case 0x6c: /* Input Window X Start Position 0 */ ++ return s->ix[0] & 0xff; ++ case 0x6e: /* Input Window X Start Position 1 */ ++ return s->ix[0] >> 3; ++ case 0x70: /* Input Window Y Start Position 0 */ ++ return s->ix[0] & 0xff; ++ case 0x72: /* Input Window Y Start Position 1 */ ++ return s->ix[0] >> 3; ++ case 0x74: /* Input Window X End Position 0 */ ++ return s->ix[1] & 0xff; ++ case 0x76: /* Input Window X End Position 1 */ ++ return s->ix[1] >> 3; ++ case 0x78: /* Input Window Y End Position 0 */ ++ return s->ix[1] & 0xff; ++ case 0x7a: /* Input Window Y End Position 1 */ ++ return s->ix[1] >> 3; ++ case 0x7c: /* Output Window X Start Position 0 */ ++ return s->ox[0] & 0xff; ++ case 0x7e: /* Output Window X Start Position 1 */ ++ return s->ox[0] >> 3; ++ case 0x80: /* Output Window Y Start Position 0 */ ++ return s->oy[0] & 0xff; ++ case 0x82: /* Output Window Y Start Position 1 */ ++ return s->oy[0] >> 3; ++ case 0x84: /* Output Window X End Position 0 */ ++ return s->ox[1] & 0xff; ++ case 0x86: /* Output Window X End Position 1 */ ++ return s->ox[1] >> 3; ++ case 0x88: /* Output Window Y End Position 0 */ ++ return s->oy[1] & 0xff; ++ case 0x8a: /* Output Window Y End Position 1 */ ++ return s->oy[1] >> 3; ++ ++ case 0x8c: /* Input Data Format */ ++ return s->iformat; ++ case 0x8e: /* Data Source Select */ ++ return s->source; ++ case 0x90: /* Display Memory Data Port */ ++ return 0; ++ ++ case 0xa8: /* Border Color 0 */ ++ return s->border_r; ++ case 0xaa: /* Border Color 1 */ ++ return s->border_g; ++ case 0xac: /* Border Color 2 */ ++ return s->border_b; ++ ++ case 0xb4: /* Gamma Correction Enable */ ++ return s->gamma_config; ++ case 0xb6: /* Gamma Correction Table Index */ ++ return s->gamma_idx; ++ case 0xb8: /* Gamma Correction Table Data */ ++ return s->gamma_lut[s->gamma_idx ++]; ++ ++ case 0xba: /* 3x3 Matrix Enable */ ++ return s->matrix_ena; ++ case 0xbc ... 0xde: /* Coefficient Registers */ ++ return s->matrix_coeff[(reg - 0xbc) >> 1]; ++ case 0xe0: /* 3x3 Matrix Red Offset */ ++ return s->matrix_r; ++ case 0xe2: /* 3x3 Matrix Green Offset */ ++ return s->matrix_g; ++ case 0xe4: /* 3x3 Matrix Blue Offset */ ++ return s->matrix_b; ++ ++ case 0xe6: /* Power-save */ ++ return s->pm; ++ case 0xe8: /* Non-display Period Control / Status */ ++ return s->status | (1 << 5); ++ case 0xea: /* RGB Interface Control */ ++ return s->rgbgpio_dir; ++ case 0xec: /* RGB Interface Status */ ++ return s->rgbgpio; ++ case 0xee: /* General-purpose IO Pins Configuration */ ++ return s->gpio_dir; ++ case 0xf0: /* General-purpose IO Pins Status / Control */ ++ return s->gpio; ++ case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ ++ return s->gpio_edge[0]; ++ case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ ++ return s->gpio_edge[1]; ++ case 0xf6: /* GPIO Interrupt Status */ ++ return s->gpio_irq; ++ case 0xf8: /* GPIO Pull-down Control */ ++ return s->gpio_pdown; ++ ++ default: ++ fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg); ++ return 0; ++ } ++} ++ ++static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value) ++{ ++ struct blizzard_s *s = (struct blizzard_s *) opaque; ++ ++ switch (reg) { ++ case 0x04: /* PLL M-Divider */ ++ s->pll = (value & 0x3f) + 1; ++ break; ++ case 0x06: /* PLL Lock Range Control */ ++ s->pll_range = value & 3; ++ break; ++ case 0x08: /* PLL Lock Synthesis Control 0 */ ++ s->pll_ctrl &= 0xf00; ++ s->pll_ctrl |= (value << 0) & 0x0ff; ++ break; ++ case 0x0a: /* PLL Lock Synthesis Control 1 */ ++ s->pll_ctrl &= 0x0ff; ++ s->pll_ctrl |= (value << 8) & 0xf00; ++ break; ++ case 0x0c: /* PLL Mode Control 0 */ ++ s->pll_mode = value & 0x77; ++ if ((value & 3) == 0 || (value & 3) == 3) ++ fprintf(stderr, "%s: wrong PLL Control bits (%i)\n", ++ __FUNCTION__, value & 3); ++ break; ++ ++ case 0x0e: /* Clock-Source Select */ ++ s->clksel = value & 0xff; ++ break; ++ ++ case 0x10: /* Memory Controller Activate */ ++ s->memenable = value & 1; ++ break; ++ case 0x14: /* Memory Controller Bank 0 Status Flag */ ++ break; ++ ++ case 0x18: /* Auto-Refresh Interval Setting 0 */ ++ s->memrefresh &= 0xf00; ++ s->memrefresh |= (value << 0) & 0x0ff; ++ break; ++ case 0x1a: /* Auto-Refresh Interval Setting 1 */ ++ s->memrefresh &= 0x0ff; ++ s->memrefresh |= (value << 8) & 0xf00; ++ break; ++ ++ case 0x1c: /* Power-On Sequence Timing Control */ ++ s->timing[0] = value & 0x7f; ++ break; ++ case 0x1e: /* Timing Control 0 */ ++ s->timing[1] = value & 0x17; ++ break; ++ case 0x20: /* Timing Control 1 */ ++ s->timing[2] = value & 0x35; ++ break; ++ ++ case 0x24: /* Arbitration Priority Control */ ++ s->priority = value & 1; ++ break; ++ ++ case 0x28: /* LCD Panel Configuration */ ++ s->lcd_config = value & 0xff; ++ if (value & (1 << 7)) ++ fprintf(stderr, "%s: data swap not supported!\n", __FUNCTION__); ++ break; ++ ++ case 0x2a: /* LCD Horizontal Display Width */ ++ s->x = value << 3; ++ break; ++ case 0x2c: /* LCD Horizontal Non-display Period */ ++ s->hndp = value & 0xff; ++ break; ++ case 0x2e: /* LCD Vertical Display Height 0 */ ++ s->y &= 0x300; ++ s->y |= (value << 0) & 0x0ff; ++ break; ++ case 0x30: /* LCD Vertical Display Height 1 */ ++ s->y &= 0x0ff; ++ s->y |= (value << 8) & 0x300; ++ break; ++ case 0x32: /* LCD Vertical Non-display Period */ ++ s->vndp = value & 0xff; ++ break; ++ case 0x34: /* LCD HS Pulse-width */ ++ s->hsync = value & 0xff; ++ break; ++ case 0x36: /* LCD HS Pulse Start Position */ ++ s->skipx = value & 0xff; ++ break; ++ case 0x38: /* LCD VS Pulse-width */ ++ s->vsync = value & 0xbf; ++ break; ++ case 0x3a: /* LCD VS Pulse Start Position */ ++ s->skipy = value & 0xff; ++ break; ++ ++ case 0x3c: /* PCLK Polarity */ ++ s->pclk = value & 0x82; ++ /* Affects calculation of s->hndp, s->hsync and s->skipx. */ ++ break; ++ ++ case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */ ++ s->hssi_config[0] = value; ++ break; ++ case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */ ++ s->hssi_config[1] = value; ++ if (((value >> 4) & 3) == 3) ++ fprintf(stderr, "%s: Illegal active-data-links value\n", ++ __FUNCTION__); ++ break; ++ case 0x42: /* High-speed Serial Interface Tx Mode */ ++ s->hssi_config[2] = value & 0xbd; ++ break; ++ ++ case 0x44: /* TV Display Configuration */ ++ s->tv_config = value & 0xfe; ++ break; ++ case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */ ++ s->tv_timing[(reg - 0x46) >> 1] = value; ++ break; ++ case 0x4e: /* VBI: Closed Caption / XDS Control / Status */ ++ s->vbi = value; ++ break; ++ case 0x50: /* TV Horizontal Start Position */ ++ s->tv_x = value; ++ break; ++ case 0x52: /* TV Vertical Start Position */ ++ s->tv_y = value & 0x7f; ++ break; ++ case 0x54: /* TV Test Pattern Setting */ ++ s->tv_test = value; ++ break; ++ case 0x56: /* TV Filter Setting */ ++ s->tv_filter_config = value & 0xbf; ++ break; ++ case 0x58: /* TV Filter Coefficient Index */ ++ s->tv_filter_idx = value & 0x1f; ++ break; ++ case 0x5a: /* TV Filter Coefficient Data */ ++ if (s->tv_filter_idx < 0x20) ++ s->tv_filter_coeff[s->tv_filter_idx ++] = value; ++ break; ++ ++ case 0x60: /* Input YUV/RGB Translate Mode 0 */ ++ s->yrc[0] = value & 0xb0; ++ break; ++ case 0x62: /* Input YUV/RGB Translate Mode 1 */ ++ s->yrc[1] = value & 0x30; ++ break; ++ case 0x64: /* U Data Fix */ ++ s->u = value & 0xff; ++ break; ++ case 0x66: /* V Data Fix */ ++ s->v = value & 0xff; ++ break; ++ ++ case 0x68: /* Display Mode */ ++ if ((s->mode ^ value) & 3) ++ s->invalidate = 1; ++ s->mode = value & 0xb7; ++ s->enable = value & 1; ++ s->blank = (value >> 1) & 1; ++ if (value & (1 << 4)) ++ fprintf(stderr, "%s: Macrovision enable attempt!\n", __FUNCTION__); ++ break; ++ ++ case 0x6a: /* Special Effects */ ++ s->effect = value & 0xfb; ++ break; ++ ++ case 0x6c: /* Input Window X Start Position 0 */ ++ s->ix[0] &= 0x300; ++ s->ix[0] |= (value << 0) & 0x0ff; ++ break; ++ case 0x6e: /* Input Window X Start Position 1 */ ++ s->ix[0] &= 0x0ff; ++ s->ix[0] |= (value << 8) & 0x300; ++ break; ++ case 0x70: /* Input Window Y Start Position 0 */ ++ s->iy[0] &= 0x300; ++ s->iy[0] |= (value << 0) & 0x0ff; ++ break; ++ case 0x72: /* Input Window Y Start Position 1 */ ++ s->iy[0] &= 0x0ff; ++ s->iy[0] |= (value << 8) & 0x300; ++ break; ++ case 0x74: /* Input Window X End Position 0 */ ++ s->ix[1] &= 0x300; ++ s->ix[1] |= (value << 0) & 0x0ff; ++ break; ++ case 0x76: /* Input Window X End Position 1 */ ++ s->ix[1] &= 0x0ff; ++ s->ix[1] |= (value << 8) & 0x300; ++ break; ++ case 0x78: /* Input Window Y End Position 0 */ ++ s->iy[1] &= 0x300; ++ s->iy[1] |= (value << 0) & 0x0ff; ++ break; ++ case 0x7a: /* Input Window Y End Position 1 */ ++ s->iy[1] &= 0x0ff; ++ s->iy[1] |= (value << 8) & 0x300; ++ break; ++ case 0x7c: /* Output Window X Start Position 0 */ ++ s->ox[0] &= 0x300; ++ s->ox[0] |= (value << 0) & 0x0ff; ++ break; ++ case 0x7e: /* Output Window X Start Position 1 */ ++ s->ox[0] &= 0x0ff; ++ s->ox[0] |= (value << 8) & 0x300; ++ break; ++ case 0x80: /* Output Window Y Start Position 0 */ ++ s->oy[0] &= 0x300; ++ s->oy[0] |= (value << 0) & 0x0ff; ++ break; ++ case 0x82: /* Output Window Y Start Position 1 */ ++ s->oy[0] &= 0x0ff; ++ s->oy[0] |= (value << 8) & 0x300; ++ break; ++ case 0x84: /* Output Window X End Position 0 */ ++ s->ox[1] &= 0x300; ++ s->ox[1] |= (value << 0) & 0x0ff; ++ break; ++ case 0x86: /* Output Window X End Position 1 */ ++ s->ox[1] &= 0x0ff; ++ s->ox[1] |= (value << 8) & 0x300; ++ break; ++ case 0x88: /* Output Window Y End Position 0 */ ++ s->oy[1] &= 0x300; ++ s->oy[1] |= (value << 0) & 0x0ff; ++ break; ++ case 0x8a: /* Output Window Y End Position 1 */ ++ s->oy[1] &= 0x0ff; ++ s->oy[1] |= (value << 8) & 0x300; ++ break; ++ ++ case 0x8c: /* Input Data Format */ ++ s->iformat = value & 0xf; ++ s->bpp = blizzard_iformat_bpp[s->iformat]; ++ if (!s->bpp) ++ fprintf(stderr, "%s: Illegal or unsupported input format %x\n", ++ __FUNCTION__, s->iformat); ++ break; ++ case 0x8e: /* Data Source Select */ ++ s->source = value & 7; ++ /* Currently all windows will be "destructive overlays". */ ++ if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] || ++ s->iy[0] != s->oy[0] || ++ s->ix[1] != s->ox[1] || ++ s->iy[1] != s->oy[1])) || ++ !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) & ++ (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1)) ++ fprintf(stderr, "%s: Illegal input/output window positions\n", ++ __FUNCTION__); ++ ++ blizzard_transfer_setup(s); ++ break; ++ ++ case 0x90: /* Display Memory Data Port */ ++ if (!s->data.len && !blizzard_transfer_setup(s)) ++ break; ++ ++ *s->data.ptr ++ = value; ++ if (-- s->data.len == 0) ++ blizzard_window(s); ++ break; ++ ++ case 0xa8: /* Border Color 0 */ ++ s->border_r = value; ++ break; ++ case 0xaa: /* Border Color 1 */ ++ s->border_g = value; ++ break; ++ case 0xac: /* Border Color 2 */ ++ s->border_b = value; ++ break; ++ ++ case 0xb4: /* Gamma Correction Enable */ ++ s->gamma_config = value & 0x87; ++ break; ++ case 0xb6: /* Gamma Correction Table Index */ ++ s->gamma_idx = value; ++ break; ++ case 0xb8: /* Gamma Correction Table Data */ ++ s->gamma_lut[s->gamma_idx ++] = value; ++ break; ++ ++ case 0xba: /* 3x3 Matrix Enable */ ++ s->matrix_ena = value & 1; ++ break; ++ case 0xbc ... 0xde: /* Coefficient Registers */ ++ s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff); ++ break; ++ case 0xe0: /* 3x3 Matrix Red Offset */ ++ s->matrix_r = value; ++ break; ++ case 0xe2: /* 3x3 Matrix Green Offset */ ++ s->matrix_g = value; ++ break; ++ case 0xe4: /* 3x3 Matrix Blue Offset */ ++ s->matrix_b = value; ++ break; ++ ++ case 0xe6: /* Power-save */ ++ s->pm = value & 0x83; ++ if (value & s->mode & 1) ++ fprintf(stderr, "%s: The display must be disabled before entering " ++ "Standby Mode\n", __FUNCTION__); ++ break; ++ case 0xe8: /* Non-display Period Control / Status */ ++ s->status = value & 0x1b; ++ break; ++ case 0xea: /* RGB Interface Control */ ++ s->rgbgpio_dir = value & 0x8f; ++ break; ++ case 0xec: /* RGB Interface Status */ ++ s->rgbgpio = value & 0xcf; ++ break; ++ case 0xee: /* General-purpose IO Pins Configuration */ ++ s->gpio_dir = value; ++ break; ++ case 0xf0: /* General-purpose IO Pins Status / Control */ ++ s->gpio = value; ++ break; ++ case 0xf2: /* GPIO Positive Edge Interrupt Trigger */ ++ s->gpio_edge[0] = value; ++ break; ++ case 0xf4: /* GPIO Negative Edge Interrupt Trigger */ ++ s->gpio_edge[1] = value; ++ break; ++ case 0xf6: /* GPIO Interrupt Status */ ++ s->gpio_irq &= value; ++ break; ++ case 0xf8: /* GPIO Pull-down Control */ ++ s->gpio_pdown = value; ++ break; ++ ++ default: ++ fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg); ++ break; ++ } ++} ++ ++uint16_t s1d13745_read(void *opaque, int dc) ++{ ++ struct blizzard_s *s = (struct blizzard_s *) opaque; ++ uint16_t value = blizzard_reg_read(s, s->reg); ++ ++ if (s->swallow -- > 0) ++ return 0; ++ if (dc) ++ s->reg ++; ++ ++ return value; ++} ++ ++void s1d13745_write(void *opaque, int dc, uint16_t value) ++{ ++ struct blizzard_s *s = (struct blizzard_s *) opaque; ++ ++ if (s->swallow -- > 0) ++ return; ++ if (dc) { ++ blizzard_reg_write(s, s->reg, value); ++ ++ if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8) ++ s->reg += 2; ++ } else ++ s->reg = value & 0xff; ++} ++ ++void s1d13745_write_block(void *opaque, int dc, ++ void *buf, size_t len, int pitch) ++{ ++ struct blizzard_s *s = (struct blizzard_s *) opaque; ++ ++ while (len > 0) { ++ if (s->reg == 0x90 && dc && ++ (s->data.len || blizzard_transfer_setup(s)) && ++ len >= (s->data.len << 1)) { ++ len -= s->data.len << 1; ++ s->data.len = 0; ++ s->data.data = buf; ++ if (pitch) ++ s->data.pitch = pitch; ++ blizzard_window(s); ++ s->data.data = s->data.buf; ++ continue; ++ } ++ ++ s1d13745_write(opaque, dc, *(uint16_t *) buf); ++ len -= 2; ++ buf += 2; ++ } ++ ++ return; ++} ++ ++static void blizzard_update_display(void *opaque) ++{ ++ struct blizzard_s *s = (struct blizzard_s *) opaque; ++ int y, bypp, bypl, bwidth; ++ uint8_t *src, *dst; ++ ++ if (!s->enable) ++ return; ++ ++ if (s->x != s->state->width || s->y != s->state->height) { ++ s->invalidate = 1; ++ dpy_resize(s->state, s->x, s->y); ++ } ++ ++ if (s->invalidate) { ++ s->invalidate = 0; ++ ++ if (s->blank) { ++ bypp = (s->state->depth + 7) >> 3; ++ memset(s->state->data, 0, bypp * s->x * s->y); ++ return; ++ } ++ ++ s->mx[0] = 0; ++ s->mx[1] = s->x; ++ s->my[0] = 0; ++ s->my[1] = s->y; ++ } ++ ++ if (s->mx[1] <= s->mx[0]) ++ return; ++ ++ bypp = (s->state->depth + 7) >> 3; ++ bypl = bypp * s->x; ++ bwidth = bypp * (s->mx[1] - s->mx[0]); ++ y = s->my[0]; ++ src = s->fb + bypl * y + bypp * s->mx[0]; ++ dst = s->state->data + bypl * y + bypp * s->mx[0]; ++ for (; y < s->my[1]; y ++, src += bypl, dst += bypl) ++ memcpy(dst, src, bwidth); ++ ++ dpy_update(s->state, s->mx[0], s->my[0], ++ s->mx[1] - s->mx[0], y - s->my[0]); ++ ++ s->mx[0] = s->x; ++ s->mx[1] = 0; ++ s->my[0] = s->y; ++ s->my[1] = 0; ++} ++ ++static void blizzard_screen_dump(void *opaque, const char *filename) { ++ struct blizzard_s *s = (struct blizzard_s *) opaque; ++ ++ blizzard_update_display(opaque); ++ if (s && s->state->data) ++ ppm_save(filename, s->state->data, s->x, s->y, s->state->linesize); ++} ++ ++#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, DisplayState *ds) ++{ ++ struct blizzard_s *s = (struct blizzard_s *) qemu_mallocz(sizeof(*s)); ++ ++ s->state = ds; ++ s->fb = qemu_malloc(0x180000); ++ ++ switch (s->state->depth) { ++ case 0: ++ s->line_fn_tab[0] = s->line_fn_tab[1] = ++ qemu_mallocz(sizeof(blizzard_fn_t) * 0x10); ++ break; ++ case 8: ++ s->line_fn_tab[0] = blizzard_draw_fn_8; ++ s->line_fn_tab[1] = blizzard_draw_fn_r_8; ++ break; ++ case 15: ++ s->line_fn_tab[0] = blizzard_draw_fn_15; ++ s->line_fn_tab[1] = blizzard_draw_fn_r_15; ++ break; ++ case 16: ++ s->line_fn_tab[0] = blizzard_draw_fn_16; ++ s->line_fn_tab[1] = blizzard_draw_fn_r_16; ++ break; ++ case 24: ++ s->line_fn_tab[0] = blizzard_draw_fn_24; ++ s->line_fn_tab[1] = blizzard_draw_fn_r_24; ++ break; ++ case 32: ++ s->line_fn_tab[0] = blizzard_draw_fn_32; ++ s->line_fn_tab[1] = blizzard_draw_fn_r_32; ++ break; ++ default: ++ fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__); ++ exit(1); ++ } ++ ++ blizzard_reset(s); ++ ++ graphic_console_init(s->state, blizzard_update_display, ++ blizzard_invalidate_display, blizzard_screen_dump, ++ NULL, s); ++ ++ return s; ++} +diff --git a/hw/blizzard_template.h b/hw/blizzard_template.h +new file mode 100644 +index 0000000..8c6451d +--- /dev/null ++++ b/hw/blizzard_template.h +@@ -0,0 +1,138 @@ ++/* ++ * QEMU Epson S1D13744/S1D13745 templates ++ * ++ * Copyright (C) 2008 Nokia Corporation ++ * Written by Andrzej Zaborowski <andrew@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++#define SKIP_PIXEL(to) to += deststep ++#if DEPTH == 8 ++# define PIXEL_TYPE uint8_t ++# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to) ++# define COPY_PIXEL1(to, from) *to ++ = from ++#elif DEPTH == 15 || DEPTH == 16 ++# define PIXEL_TYPE uint16_t ++# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to) ++# define COPY_PIXEL1(to, from) *to ++ = from ++#elif DEPTH == 24 ++# define PIXEL_TYPE uint8_t ++# define COPY_PIXEL(to, from) \ ++ to[0] = from; to[1] = (from) >> 8; to[2] = (from) >> 16; SKIP_PIXEL(to) ++# define COPY_PIXEL1(to, from) \ ++ *to ++ = from; *to ++ = (from) >> 8; *to ++ = (from) >> 16 ++#elif DEPTH == 32 ++# define PIXEL_TYPE uint32_t ++# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to) ++# define COPY_PIXEL1(to, from) *to ++ = from ++#else ++# error unknown bit depth ++#endif ++ ++#ifdef WORDS_BIGENDIAN ++# define SWAP_WORDS 1 ++#endif ++ ++static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest, ++ const uint16_t *src, unsigned int width) ++{ ++#if !defined(SWAP_WORDS) && DEPTH == 16 ++ memcpy(dest, src, width << 1); ++#else ++ uint16_t data; ++ unsigned int r, g, b; ++ const uint16_t *end = (void *) src + width; ++ while (src < end) { ++ data = lduw_raw(src ++); ++ b = (data & 0x1f) << 3; ++ data >>= 5; ++ g = (data & 0x3f) << 2; ++ data >>= 6; ++ r = (data & 0x1f) << 3; ++ data >>= 5; ++ COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b)); ++ } ++#endif ++} ++ ++static void glue(blizzard_draw_line24mode1_, DEPTH)(PIXEL_TYPE *dest, ++ const uint8_t *src, unsigned int width) ++{ ++ /* TODO: check if SDL 24-bit planes are not in the same format and ++ * if so, use memcpy */ ++ unsigned int r[2], g[2], b[2]; ++ const uint8_t *end = src + width; ++ while (src < end) { ++ g[0] = *src ++; ++ r[0] = *src ++; ++ r[1] = *src ++; ++ b[0] = *src ++; ++ COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[0], g[0], b[0])); ++ b[1] = *src ++; ++ g[1] = *src ++; ++ COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[1], g[1], b[1])); ++ } ++} ++ ++static void glue(blizzard_draw_line24mode2_, DEPTH)(PIXEL_TYPE *dest, ++ const uint8_t *src, unsigned int width) ++{ ++ unsigned int r, g, b; ++ const uint8_t *end = src + width; ++ while (src < end) { ++ r = *src ++; ++ src ++; ++ b = *src ++; ++ g = *src ++; ++ COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b)); ++ } ++} ++ ++/* No rotation */ ++static blizzard_fn_t glue(blizzard_draw_fn_, DEPTH)[0x10] = { ++ NULL, ++ /* RGB 5:6:5*/ ++ (blizzard_fn_t) glue(blizzard_draw_line16_, DEPTH), ++ /* RGB 6:6:6 mode 1 */ ++ (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH), ++ /* RGB 8:8:8 mode 1 */ ++ (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH), ++ NULL, NULL, ++ /* RGB 6:6:6 mode 2 */ ++ (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH), ++ /* RGB 8:8:8 mode 2 */ ++ (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH), ++ /* YUV 4:2:2 */ ++ NULL, ++ /* YUV 4:2:0 */ ++ NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, ++}; ++ ++/* 90deg, 180deg and 270deg rotation */ ++static blizzard_fn_t glue(blizzard_draw_fn_r_, DEPTH)[0x10] = { ++ /* TODO */ ++ [0 ... 0xf] = NULL, ++}; ++ ++#undef DEPTH ++#undef SKIP_PIXEL ++#undef COPY_PIXEL ++#undef COPY_PIXEL1 ++#undef PIXEL_TYPE ++ ++#undef SWAP_WORDS +diff --git a/hw/boards.h b/hw/boards.h +index affcaa6..408d1e8 100644 +--- a/hw/boards.h ++++ b/hw/boards.h +@@ -80,6 +80,9 @@ extern QEMUMachine terrierpda_machine; + /* palm.c */ + extern QEMUMachine palmte_machine; + ++/* nseries.c */ ++extern QEMUMachine n800_machine; ++ + /* gumstix.c */ + extern QEMUMachine connex_machine; + extern QEMUMachine verdex_machine; +diff --git a/hw/cbus.c b/hw/cbus.c +new file mode 100644 +index 0000000..001b007 +--- /dev/null ++++ b/hw/cbus.c +@@ -0,0 +1,565 @@ ++/* ++ * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma / ++ * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms. ++ * ++ * Copyright (C) 2008 Nokia Corporation ++ * Written by Andrzej Zaborowski <andrew@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * 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 "irq.h" ++#include "devices.h" ++#include "sysemu.h" ++ ++//#define DEBUG ++ ++struct cbus_slave_s; ++struct cbus_priv_s { ++ struct cbus_s cbus; ++ ++ int sel; ++ int dat; ++ int clk; ++ int bit; ++ int dir; ++ uint16_t val; ++ qemu_irq dat_out; ++ ++ int addr; ++ int reg; ++ int rw; ++ enum { ++ cbus_address, ++ cbus_value, ++ } cycle; ++ ++ struct cbus_slave_s *slave[8]; ++}; ++ ++struct cbus_slave_s { ++ void *opaque; ++ void (*io)(void *opaque, int rw, int reg, uint16_t *val); ++ int addr; ++}; ++ ++static void cbus_io(struct cbus_priv_s *s) ++{ ++ if (s->slave[s->addr]) ++ s->slave[s->addr]->io(s->slave[s->addr]->opaque, ++ s->rw, s->reg, &s->val); ++ else ++ cpu_abort(cpu_single_env, "%s: bad slave address %i\n", ++ __FUNCTION__, s->addr); ++} ++ ++static void cbus_cycle(struct cbus_priv_s *s) ++{ ++ switch (s->cycle) { ++ case cbus_address: ++ s->addr = (s->val >> 6) & 7; ++ s->rw = (s->val >> 5) & 1; ++ s->reg = (s->val >> 0) & 0x1f; ++ ++ s->cycle = cbus_value; ++ s->bit = 15; ++ s->dir = !s->rw; ++ s->val = 0; ++ ++ if (s->rw) ++ cbus_io(s); ++ break; ++ ++ case cbus_value: ++ if (!s->rw) ++ cbus_io(s); ++ ++ s->cycle = cbus_address; ++ s->bit = 8; ++ s->dir = 1; ++ s->val = 0; ++ break; ++ } ++} ++ ++static void cbus_clk(void *opaque, int line, int level) ++{ ++ struct cbus_priv_s *s = (struct cbus_priv_s *) opaque; ++ ++ if (!s->sel && level && !s->clk) { ++ if (s->dir) ++ s->val |= s->dat << (s->bit --); ++ else ++ qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1); ++ ++ if (s->bit < 0) ++ cbus_cycle(s); ++ } ++ ++ s->clk = level; ++} ++ ++static void cbus_dat(void *opaque, int line, int level) ++{ ++ struct cbus_priv_s *s = (struct cbus_priv_s *) opaque; ++ ++ s->dat = level; ++} ++ ++static void cbus_sel(void *opaque, int line, int level) ++{ ++ struct cbus_priv_s *s = (struct cbus_priv_s *) opaque; ++ ++ if (!level) { ++ s->dir = 1; ++ s->bit = 8; ++ s->val = 0; ++ } ++ ++ s->sel = level; ++} ++ ++struct cbus_s *cbus_init(qemu_irq dat) ++{ ++ struct cbus_priv_s *s = (struct cbus_priv_s *) qemu_mallocz(sizeof(*s)); ++ ++ s->dat_out = dat; ++ s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0]; ++ s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0]; ++ s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0]; ++ ++ s->sel = 1; ++ s->clk = 0; ++ s->dat = 0; ++ ++ return &s->cbus; ++} ++ ++void cbus_attach(struct cbus_s *bus, void *slave_opaque) ++{ ++ struct cbus_slave_s *slave = (struct cbus_slave_s *) slave_opaque; ++ struct cbus_priv_s *s = (struct cbus_priv_s *) bus; ++ ++ s->slave[slave->addr] = slave; ++} ++ ++/* Retu/Vilma */ ++struct cbus_retu_s { ++ uint16_t irqst; ++ uint16_t irqen; ++ uint16_t cc[2]; ++ int channel; ++ uint16_t result[16]; ++ uint16_t sample; ++ ++ struct { ++ uint16_t cal; ++ } rtc; ++ ++ int is_vilma; ++ qemu_irq irq; ++ struct cbus_slave_s cbus; ++}; ++ ++static void retu_interrupt_update(struct cbus_retu_s *s) ++{ ++ qemu_set_irq(s->irq, s->irqst & ~s->irqen); ++} ++ ++#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */ ++#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */ ++#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */ ++#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */ ++#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */ ++#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */ ++#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */ ++#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */ ++#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */ ++#define RETU_REG_AFCR 0x0a /* (RW) AFC register */ ++#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */ ++#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/ ++#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */ ++#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */ ++#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */ ++#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */ ++#define RETU_REG_TXCR 0x11 /* (RW) TxC register */ ++#define RETU_REG_STATUS 0x16 /* (RO) Status register */ ++#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */ ++#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */ ++#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */ ++#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */ ++#define RETU_REG_AUDRXR2 0x1b /* (RW) Autio receive register 2 */ ++#define RETU_REG_SGR1 0x1c /* (RW) */ ++#define RETU_REG_SCR1 0x1d /* (RW) */ ++#define RETU_REG_SGR2 0x1e /* (RW) */ ++#define RETU_REG_SCR2 0x1f /* (RW) */ ++ ++/* Retu Interrupt sources */ ++enum { ++ retu_int_pwr = 0, /* Power */ ++ retu_int_char = 1, /* Charger */ ++ retu_int_rtcs = 2, /* Seconds */ ++ retu_int_rtcm = 3, /* Minutes */ ++ retu_int_rtcd = 4, /* Days */ ++ retu_int_rtca = 5, /* Alarm */ ++ retu_int_hook = 6, /* Hook */ ++ retu_int_head = 7, /* Headset */ ++ retu_int_adcs = 8, /* ADC sample */ ++}; ++ ++/* Retu ADC channel wiring */ ++enum { ++ retu_adc_bsi = 1, /* BSI */ ++ retu_adc_batt_temp = 2, /* Battery temperature */ ++ retu_adc_chg_volt = 3, /* Charger voltage */ ++ retu_adc_head_det = 4, /* Headset detection */ ++ retu_adc_hook_det = 5, /* Hook detection */ ++ retu_adc_rf_gp = 6, /* RF GP */ ++ retu_adc_tx_det = 7, /* Wideband Tx detection */ ++ retu_adc_batt_volt = 8, /* Battery voltage */ ++ retu_adc_sens = 10, /* Light sensor */ ++ retu_adc_sens_temp = 11, /* Light sensor temperature */ ++ retu_adc_bbatt_volt = 12, /* Backup battery voltage */ ++ retu_adc_self_temp = 13, /* RETU temperature */ ++}; ++ ++static inline uint16_t retu_read(struct cbus_retu_s *s, int reg) ++{ ++#ifdef DEBUG ++ printf("RETU read at %02x\n", reg); ++#endif ++ ++ switch (reg) { ++ case RETU_REG_ASICR: ++ return 0x0015 | (s->is_vilma << 7); ++ ++ case RETU_REG_IDR: ++ return s->irqst; ++ ++ case RETU_REG_IMR: ++ return s->irqen; ++ ++ case RETU_REG_RTCDSR: ++ case RETU_REG_RTCHMR: ++ case RETU_REG_RTCHMAR: ++ /* TODO */ ++ return 0x0000; ++ ++ case RETU_REG_RTCCALR: ++ return s->rtc.cal; ++ ++ case RETU_REG_ADCR: ++ return (s->channel << 10) | s->result[s->channel]; ++ case RETU_REG_ADCSCR: ++ return s->sample; ++ ++ case RETU_REG_AFCR: ++ case RETU_REG_ANTIFR: ++ case RETU_REG_CALIBR: ++ /* TODO */ ++ return 0x0000; ++ ++ case RETU_REG_CCR1: ++ return s->cc[0]; ++ case RETU_REG_CCR2: ++ return s->cc[1]; ++ ++ case RETU_REG_RCTRL_CLR: ++ case RETU_REG_RCTRL_SET: ++ case RETU_REG_TXCR: ++ case RETU_REG_STATUS: ++ case RETU_REG_WATCHDOG: ++ case RETU_REG_AUDTXR: ++ case RETU_REG_AUDPAR: ++ case RETU_REG_AUDRXR1: ++ case RETU_REG_AUDRXR2: ++ case RETU_REG_SGR1: ++ case RETU_REG_SCR1: ++ case RETU_REG_SGR2: ++ case RETU_REG_SCR2: ++ /* TODO */ ++ return 0x0000; ++ ++ default: ++ cpu_abort(cpu_single_env, "%s: bad register %02x\n", ++ __FUNCTION__, reg); ++ } ++} ++ ++static inline void retu_write(struct cbus_retu_s *s, int reg, uint16_t val) ++{ ++#ifdef DEBUG ++ printf("RETU write of %04x at %02x\n", val, reg); ++#endif ++ ++ switch (reg) { ++ case RETU_REG_IDR: ++ s->irqst ^= val; ++ retu_interrupt_update(s); ++ break; ++ ++ case RETU_REG_IMR: ++ s->irqen = val; ++ retu_interrupt_update(s); ++ break; ++ ++ case RETU_REG_RTCDSR: ++ case RETU_REG_RTCHMAR: ++ /* TODO */ ++ break; ++ ++ case RETU_REG_RTCCALR: ++ s->rtc.cal = val; ++ break; ++ ++ case RETU_REG_ADCR: ++ s->channel = (val >> 10) & 0xf; ++ s->irqst |= 1 << retu_int_adcs; ++ retu_interrupt_update(s); ++ break; ++ case RETU_REG_ADCSCR: ++ s->sample &= ~val; ++ break; ++ ++ case RETU_REG_AFCR: ++ case RETU_REG_ANTIFR: ++ case RETU_REG_CALIBR: ++ ++ case RETU_REG_CCR1: ++ s->cc[0] = val; ++ break; ++ case RETU_REG_CCR2: ++ s->cc[1] = val; ++ ++ break; ++ case RETU_REG_RCTRL_CLR: ++ case RETU_REG_RCTRL_SET: ++ case RETU_REG_STATUS: ++ /* TODO */ ++ break; ++ ++ case RETU_REG_WATCHDOG: ++ if (val == 0 && (s->cc[0] & 2)) ++ qemu_system_shutdown_request(); ++ break; ++ ++ case RETU_REG_TXCR: ++ case RETU_REG_AUDTXR: ++ case RETU_REG_AUDPAR: ++ case RETU_REG_AUDRXR1: ++ case RETU_REG_AUDRXR2: ++ case RETU_REG_SGR1: ++ case RETU_REG_SCR1: ++ case RETU_REG_SGR2: ++ case RETU_REG_SCR2: ++ /* TODO */ ++ break; ++ ++ default: ++ cpu_abort(cpu_single_env, "%s: bad register %02x\n", ++ __FUNCTION__, reg); ++ } ++} ++ ++static void retu_io(void *opaque, int rw, int reg, uint16_t *val) ++{ ++ struct cbus_retu_s *s = (struct cbus_retu_s *) opaque; ++ ++ if (rw) ++ *val = retu_read(s, reg); ++ else ++ retu_write(s, reg, *val); ++} ++ ++void *retu_init(qemu_irq irq, int vilma) ++{ ++ struct cbus_retu_s *s = (struct cbus_retu_s *) qemu_mallocz(sizeof(*s)); ++ ++ s->irq = irq; ++ s->irqen = 0xffff; ++ s->irqst = 0x0000; ++ s->is_vilma = !!vilma; ++ s->rtc.cal = 0x01; ++ s->result[retu_adc_bsi] = 0x100; ++ s->result[retu_adc_batt_temp] = 0x100; ++ s->result[retu_adc_chg_volt] = 0x200; ++ s->result[retu_adc_batt_volt] = 0x240; ++ s->result[retu_adc_sens] = 0x100; ++ s->result[retu_adc_sens_temp] = 0x100; ++ s->result[retu_adc_bbatt_volt] = 0x200; ++ s->result[retu_adc_self_temp] = 0x100; ++ ++ s->cbus.opaque = s; ++ s->cbus.io = retu_io; ++ s->cbus.addr = 1; ++ ++ return &s->cbus; ++} ++ ++/* Tahvo/Betty */ ++struct cbus_tahvo_s { ++ uint16_t irqst; ++ uint16_t irqen; ++ uint8_t charger; ++ uint8_t backlight; ++ uint16_t usbr; ++ uint16_t power; ++ ++ int is_betty; ++ qemu_irq irq; ++ struct cbus_slave_s cbus; ++}; ++ ++static void tahvo_interrupt_update(struct cbus_tahvo_s *s) ++{ ++ qemu_set_irq(s->irq, s->irqst & ~s->irqen); ++} ++ ++#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */ ++#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */ ++#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */ ++#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */ ++#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */ ++#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */ ++#define TAHVO_REG_USBR 0x06 /* (RW) USB control */ ++#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */ ++#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */ ++#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */ ++#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */ ++#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */ ++#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */ ++#define TAHVO_REG_FRR 0x0d /* (RO) FR */ ++ ++static inline uint16_t tahvo_read(struct cbus_tahvo_s *s, int reg) ++{ ++#ifdef DEBUG ++ printf("TAHVO read at %02x\n", reg); ++#endif ++ ++ switch (reg) { ++ case TAHVO_REG_ASICR: ++ return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); ++ ++ case TAHVO_REG_IDR: ++ case TAHVO_REG_IDSR: /* XXX: what does this do? */ ++ return s->irqst; ++ ++ case TAHVO_REG_IMR: ++ return s->irqen; ++ ++ case TAHVO_REG_CHAPWMR: ++ return s->charger; ++ ++ case TAHVO_REG_LEDPWMR: ++ return s->backlight; ++ ++ case TAHVO_REG_USBR: ++ return s->usbr; ++ ++ case TAHVO_REG_RCR: ++ return s->power; ++ ++ case TAHVO_REG_CCR1: ++ case TAHVO_REG_CCR2: ++ case TAHVO_REG_TESTR1: ++ case TAHVO_REG_TESTR2: ++ case TAHVO_REG_NOPR: ++ case TAHVO_REG_FRR: ++ return 0x0000; ++ ++ default: ++ cpu_abort(cpu_single_env, "%s: bad register %02x\n", ++ __FUNCTION__, reg); ++ } ++} ++ ++static inline void tahvo_write(struct cbus_tahvo_s *s, int reg, uint16_t val) ++{ ++#ifdef DEBUG ++ printf("TAHVO write of %04x at %02x\n", val, reg); ++#endif ++ ++ switch (reg) { ++ case TAHVO_REG_IDR: ++ s->irqst ^= val; ++ tahvo_interrupt_update(s); ++ break; ++ ++ case TAHVO_REG_IMR: ++ s->irqen = val; ++ tahvo_interrupt_update(s); ++ break; ++ ++ case TAHVO_REG_CHAPWMR: ++ s->charger = val; ++ break; ++ ++ case TAHVO_REG_LEDPWMR: ++ if (s->backlight != (val & 0x7f)) { ++ s->backlight = val & 0x7f; ++ printf("%s: LCD backlight now at %i / 127\n", ++ __FUNCTION__, s->backlight); ++ } ++ break; ++ ++ case TAHVO_REG_USBR: ++ s->usbr = val; ++ break; ++ ++ case TAHVO_REG_RCR: ++ s->power = val; ++ break; ++ ++ case TAHVO_REG_CCR1: ++ case TAHVO_REG_CCR2: ++ case TAHVO_REG_TESTR1: ++ case TAHVO_REG_TESTR2: ++ case TAHVO_REG_NOPR: ++ case TAHVO_REG_FRR: ++ break; ++ ++ default: ++ cpu_abort(cpu_single_env, "%s: bad register %02x\n", ++ __FUNCTION__, reg); ++ } ++} ++ ++static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val) ++{ ++ struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) opaque; ++ ++ if (rw) ++ *val = tahvo_read(s, reg); ++ else ++ tahvo_write(s, reg, *val); ++} ++ ++void *tahvo_init(qemu_irq irq, int betty) ++{ ++ struct cbus_tahvo_s *s = (struct cbus_tahvo_s *) qemu_mallocz(sizeof(*s)); ++ ++ s->irq = irq; ++ s->irqen = 0xffff; ++ s->irqst = 0x0000; ++ s->is_betty = !!betty; ++ ++ s->cbus.opaque = s; ++ s->cbus.io = tahvo_io; ++ s->cbus.addr = 2; ++ ++ return &s->cbus; ++} +diff --git a/hw/devices.h b/hw/devices.h +index 07c673b..6f1d27b 100644 +--- a/hw/devices.h ++++ b/hw/devices.h +@@ -16,7 +16,38 @@ 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); ++uint32_t tsc210x_txrx(void *opaque, uint32_t value); ++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); ++ + /* stellaris_input.c */ + void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode); + ++/* blizzard.c */ ++void *s1d13745_init(qemu_irq gpio_int, DisplayState *ds); ++void s1d13745_write(void *opaque, int dc, uint16_t value); ++void s1d13745_write_block(void *opaque, int dc, ++ void *buf, size_t len, int pitch); ++uint16_t s1d13745_read(void *opaque, int dc); ++ ++/* cbus.c */ ++struct cbus_s { ++ qemu_irq clk; ++ qemu_irq dat; ++ qemu_irq sel; ++}; ++struct cbus_s *cbus_init(qemu_irq dat_out); ++void cbus_attach(struct cbus_s *bus, void *slave_opaque); ++ ++void *retu_init(qemu_irq irq, int vilma); ++void *tahvo_init(qemu_irq irq, int betty); ++ + #endif +diff --git a/hw/flash.h b/hw/flash.h +index 42d25fe..c000d33 100644 +--- a/hw/flash.h ++++ b/hw/flash.h +@@ -34,6 +34,11 @@ uint8_t nand_getio(struct nand_flash_s *s); + #define NAND_MFR_HYNIX 0xad + #define NAND_MFR_MICRON 0x2c + ++/* onenand.c */ ++void onenand_base_update(void *opaque, target_phys_addr_t new); ++void onenand_base_unmap(void *opaque); ++void *onenand_init(uint32_t id, int regshift, qemu_irq irq); ++ + /* ecc.c */ + struct ecc_state_s { + uint8_t cp; /* Column parity */ +diff --git a/hw/i2c.h b/hw/i2c.h +index 2897036..fae46b7 100644 +--- a/hw/i2c.h ++++ b/hw/i2c.h +@@ -71,4 +71,14 @@ uint32_t wm8750_adc_dat(void *opaque); + /* ssd0303.c */ + void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address); + ++/* twl92230.c */ ++i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq); ++qemu_irq *twl92230_gpio_in_get(i2c_slave *i2c); ++void twl92230_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler); ++ ++/* tmp105.c */ ++struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm); ++void tmp105_reset(i2c_slave *i2c); ++void tmp105_set(i2c_slave *i2c, int temp); ++ + #endif +diff --git a/hw/integratorcp.c b/hw/integratorcp.c +index 549cc25..f6e6364 100644 +--- a/hw/integratorcp.c ++++ b/hw/integratorcp.c +@@ -469,6 +469,11 @@ static void icp_control_init(uint32_t base) + + /* Board init. */ + ++static struct arm_boot_info integrator_binfo = { ++ .loader_start = 0x0, ++ .board_id = 0x113, ++}; ++ + static void integratorcp_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, +@@ -527,8 +532,11 @@ static void integratorcp_init(int ram_size, int vga_ram_size, + } + pl110_init(ds, 0xc0000000, pic[22], 0); + +- arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, +- initrd_filename, 0x113, 0x0); ++ integrator_binfo.ram_size = ram_size; ++ integrator_binfo.kernel_filename = kernel_filename; ++ integrator_binfo.kernel_cmdline = kernel_cmdline; ++ integrator_binfo.initrd_filename = initrd_filename; ++ arm_load_kernel(env, &integrator_binfo); + } + + QEMUMachine integratorcp_machine = { +diff --git a/hw/mainstone.c b/hw/mainstone.c +index 5856791..9564fc3 100644 +--- a/hw/mainstone.c ++++ b/hw/mainstone.c +@@ -59,12 +59,17 @@ static struct keymap map[0xE0] = { + + enum mainstone_model_e { mainstone }; + ++static struct arm_boot_info mainstone_binfo = { ++ .loader_start = PXA2XX_SDRAM_BASE, ++ .ram_size = 0x04000000, ++}; ++ + static void mainstone_common_init(int ram_size, int vga_ram_size, + DisplayState *ds, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + const char *cpu_model, enum mainstone_model_e model, int arm_id) + { +- uint32_t mainstone_ram = 0x04000000; ++ uint32_t mainstone_ram = mainstone_binfo.ram_size; + uint32_t mainstone_rom = 0x00800000; + uint32_t mainstone_flash = 0x02000000; + uint32_t sector_len = 256 * 1024; +@@ -90,7 +95,7 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, + qemu_ram_alloc(mainstone_rom) | IO_MEM_ROM); + + /* Setup initial (reset) machine state */ +- cpu->env->regs[15] = PXA2XX_SDRAM_BASE; ++ cpu->env->regs[15] = mainstone_binfo.loader_start; + + /* There are two 32MiB flash devices on the board */ + for (i = 0; i < 2; i ++) { +@@ -121,8 +126,11 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, + + smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]); + +- arm_load_kernel(cpu->env, mainstone_ram, kernel_filename, kernel_cmdline, +- initrd_filename, arm_id, PXA2XX_SDRAM_BASE); ++ mainstone_binfo.kernel_filename = kernel_filename; ++ mainstone_binfo.kernel_cmdline = kernel_cmdline; ++ mainstone_binfo.initrd_filename = initrd_filename; ++ mainstone_binfo.board_id = arm_id; ++ arm_load_kernel(cpu->env, &mainstone_binfo); + } + + static void mainstone_init(int ram_size, int vga_ram_size, +diff --git a/hw/max7310.c b/hw/max7310.c +index 75e56c7..397950a 100644 +--- a/hw/max7310.c ++++ b/hw/max7310.c +@@ -134,8 +134,8 @@ static void max7310_event(i2c_slave *i2c, enum i2c_event event) + s->i2c_command_byte = 1; + break; + case I2C_FINISH: +- if (s->len == 1) + #ifdef VERBOSE ++ if (s->len == 1) + printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len); + #endif + break; +diff --git a/hw/nseries.c b/hw/nseries.c +new file mode 100644 +index 0000000..0425d46 +--- /dev/null ++++ b/hw/nseries.c +@@ -0,0 +1,870 @@ ++/* ++ * Nokia N-series internet tablets. ++ * ++ * Copyright (C) 2007 Nokia Corporation ++ * Written by Andrzej Zaborowski <andrew@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * 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 "irq.h" ++#include "console.h" ++#include "boards.h" ++#include "i2c.h" ++#include "devices.h" ++#include "flash.h" ++#include "hw.h" ++ ++/* Nokia N800 support */ ++struct n800_s { ++ struct omap_mpu_state_s *cpu; ++ ++ struct rfbi_chip_s blizzard; ++ struct uwire_slave_s *ts; ++ i2c_bus *i2c; ++ ++ int keymap[0x80]; ++}; ++ ++#define N800_MMC2_WP_GPIO 8 ++#define N800_CAM_TURN_GPIO 12 ++#define N800_BLIZZARD_POWERDOWN_GPIO 15 ++#define N800_MMC1_WP_GPIO 23 ++#define N800_ONENAND_GPIO 26 ++#define N800_BT_WKUP_GPIO 61 ++#define N800_STI_GPIO 62 ++#define N800_CBUS_SEL_GPIO 64 ++#define N800_CBUS_CLK_GPIO 65 ++#define N800_CBUS_DAT_GPIO 66 ++#define N800_WLAN_IRQ_GPIO 87 ++#define N800_BT_RESET_GPIO 92 ++#define N800_TEA5761_CS_GPIO 93 ++#define N800_UNKNOWN_GPIO 94 ++#define N800_CAM_ACT_GPIO 95 ++#define N800_MMC_CS_GPIO 96 ++#define N800_WLAN_PWR_GPIO 97 ++#define N800_BT_HOST_WKUP_GPIO 98 ++#define N800_TSC_TS_GPIO 103 ++#define N800_HEADPHONE_GPIO 107 ++#define N800_RETU_GPIO 108 ++#define N800_TSC_KP_IRQ_GPIO 109 ++#define N800_BAT_COVER_GPIO 110 ++#define N800_TAHVO_GPIO 111 ++#define N800_TSC_RESET_GPIO 119 ++#define N800_TMP105_GPIO 125 ++ ++#define XLDR_LL_UART 1 ++ ++#define N800_TMP105_ADDR 0x48 ++#define N800_MENELAUS_ADDR 0x72 ++ ++static void n800_mmc_cs_cb(void *opaque, int line, int level) ++{ ++ /* TODO: this seems to actually be connected to the menelaus, to ++ * which also both MMC slots connect. */ ++ omap_mmc_enable((struct omap_mmc_s *) opaque, !level); ++ ++ printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1); ++} ++ ++static void n800_gpio_setup(struct n800_s *s) ++{ ++ qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->cpu->mmc, 1); ++ omap2_gpio_out_set(s->cpu->gpif, N800_MMC_CS_GPIO, mmc_cs[0]); ++ ++ qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N800_BAT_COVER_GPIO)[0]); ++} ++ ++static void n800_nand_setup(struct n800_s *s) ++{ ++ /* Either ec40xx or ec48xx are OK for the ID */ ++ omap_gpmc_attach(s->cpu->gpmc, 0, 0, onenand_base_update, ++ onenand_base_unmap, ++ onenand_init(0xec4800, 1, ++ omap2_gpio_in_get(s->cpu->gpif, ++ N800_ONENAND_GPIO)[0])); ++} ++ ++static void n800_i2c_setup(struct n800_s *s) ++{ ++ qemu_irq tmp_irq = omap2_gpio_in_get(s->cpu->gpif, N800_TMP105_GPIO)[0]; ++ ++ /* Attach the CPU on one end of our I2C bus. */ ++ s->i2c = omap_i2c_bus(s->cpu->i2c[0]); ++ ++ /* Attach a menelaus PM chip */ ++ i2c_set_slave_address( ++ twl92230_init(s->i2c, ++ s->cpu->irq[0][OMAP_INT_24XX_SYS_NIRQ]), ++ N800_MENELAUS_ADDR); ++ ++ /* Attach a TMP105 PM chip (A0 wired to ground) */ ++ i2c_set_slave_address(tmp105_init(s->i2c, tmp_irq), N800_TMP105_ADDR); ++} ++ ++/* Touchscreen and keypad controller */ ++static void n800_key_event(void *opaque, int keycode) ++{ ++ struct n800_s *s = (struct n800_s *) opaque; ++ int code = s->keymap[keycode & 0x7f]; ++ ++ if (code == -1) ++ return; ++ ++ tsc210x_key_event(s->ts, code, !(keycode & 0x80)); ++} ++ ++static const int n800_keys[16] = { ++ -1, ++ 72, /* Up */ ++ 63, /* Home (F5) */ ++ -1, ++ 75, /* Left */ ++ 28, /* Enter */ ++ 77, /* Right */ ++ -1, ++ 1, /* Cycle (ESC) */ ++ 80, /* Down */ ++ 62, /* Menu (F4) */ ++ -1, ++ 66, /* Zoom- (F8) */ ++ 64, /* FS (F6) */ ++ 65, /* Zoom+ (F7) */ ++ -1, ++}; ++ ++static struct mouse_transform_info_s n800_pointercal = { ++ .x = 800, ++ .y = 480, ++ .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 }, ++}; ++ ++static void n800_tsc_setup(struct n800_s *s) ++{ ++ int i; ++ ++ /* XXX: are the three pins inverted inside the chip between the ++ * tsc and the cpu (N4111)? */ ++ qemu_irq penirq = 0; /* NC */ ++ qemu_irq kbirq = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_KP_IRQ_GPIO)[0]; ++ qemu_irq dav = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_TS_GPIO)[0]; ++ ++ s->ts = tsc2301_init(penirq, kbirq, dav, 0); ++ ++ for (i = 0; i < 0x80; i ++) ++ s->keymap[i] = -1; ++ for (i = 0; i < 0x10; i ++) ++ if (n800_keys[i] >= 0) ++ s->keymap[n800_keys[i]] = i; ++ ++ qemu_add_kbd_event_handler(n800_key_event, s); ++ ++ tsc210x_set_transform(s->ts, &n800_pointercal); ++} ++ ++/* LCD MIPI DBI-C controller (URAL) */ ++struct mipid_s { ++ int resp[4]; ++ int param[4]; ++ int p; ++ int pm; ++ int cmd; ++ ++ int sleep; ++ int booster; ++ int te; ++ int selfcheck; ++ int partial; ++ int normal; ++ int vscr; ++ int invert; ++ int onoff; ++ int gamma; ++ uint32_t id; ++}; ++ ++static void mipid_reset(struct mipid_s *s) ++{ ++ if (!s->sleep) ++ fprintf(stderr, "%s: Display off\n", __FUNCTION__); ++ ++ s->pm = 0; ++ s->cmd = 0; ++ ++ s->sleep = 1; ++ s->booster = 0; ++ s->selfcheck = ++ (1 << 7) | /* Register loading OK. */ ++ (1 << 5) | /* The chip is attached. */ ++ (1 << 4); /* Display glass still in one piece. */ ++ s->te = 0; ++ s->partial = 0; ++ s->normal = 1; ++ s->vscr = 0; ++ s->invert = 0; ++ s->onoff = 1; ++ s->gamma = 0; ++} ++ ++static uint32_t mipid_txrx(void *opaque, uint32_t cmd) ++{ ++ struct mipid_s *s = (struct mipid_s *) opaque; ++ uint8_t ret; ++ ++ if (s->p >= sizeof(s->resp) / sizeof(*s->resp)) ++ ret = 0; ++ else ++ ret = s->resp[s->p ++]; ++ if (s->pm --> 0) ++ s->param[s->pm] = cmd; ++ else ++ s->cmd = cmd; ++ ++ switch (s->cmd) { ++ case 0x00: /* NOP */ ++ break; ++ ++ case 0x01: /* SWRESET */ ++ mipid_reset(s); ++ break; ++ ++ case 0x02: /* BSTROFF */ ++ s->booster = 0; ++ break; ++ case 0x03: /* BSTRON */ ++ s->booster = 1; ++ break; ++ ++ case 0x04: /* RDDID */ ++ s->p = 0; ++ s->resp[0] = (s->id >> 16) & 0xff; ++ s->resp[1] = (s->id >> 8) & 0xff; ++ s->resp[2] = (s->id >> 0) & 0xff; ++ break; ++ ++ case 0x06: /* RD_RED */ ++ case 0x07: /* RD_GREEN */ ++ /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so ++ * for the bootloader one needs to change this. */ ++ case 0x08: /* RD_BLUE */ ++ s->p = 0; ++ /* TODO: return first pixel components */ ++ s->resp[0] = 0x01; ++ break; ++ ++ case 0x09: /* RDDST */ ++ s->p = 0; ++ s->resp[0] = s->booster << 7; ++ s->resp[1] = (5 << 4) | (s->partial << 2) | ++ (s->sleep << 1) | s->normal; ++ s->resp[2] = (s->vscr << 7) | (s->invert << 5) | ++ (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2); ++ s->resp[3] = s->gamma << 6; ++ break; ++ ++ case 0x0a: /* RDDPM */ ++ s->p = 0; ++ s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) | ++ (s->partial << 5) | (s->sleep << 6) | (s->booster << 7); ++ break; ++ case 0x0b: /* RDDMADCTR */ ++ s->p = 0; ++ s->resp[0] = 0; ++ break; ++ case 0x0c: /* RDDCOLMOD */ ++ s->p = 0; ++ s->resp[0] = 5; /* 65K colours */ ++ break; ++ case 0x0d: /* RDDIM */ ++ s->p = 0; ++ s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma; ++ break; ++ case 0x0e: /* RDDSM */ ++ s->p = 0; ++ s->resp[0] = s->te << 7; ++ break; ++ case 0x0f: /* RDDSDR */ ++ s->p = 0; ++ s->resp[0] = s->selfcheck; ++ break; ++ ++ case 0x10: /* SLPIN */ ++ s->sleep = 1; ++ break; ++ case 0x11: /* SLPOUT */ ++ s->sleep = 0; ++ s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */ ++ break; ++ ++ case 0x12: /* PTLON */ ++ s->partial = 1; ++ s->normal = 0; ++ s->vscr = 0; ++ break; ++ case 0x13: /* NORON */ ++ s->partial = 0; ++ s->normal = 1; ++ s->vscr = 0; ++ break; ++ ++ case 0x20: /* INVOFF */ ++ s->invert = 0; ++ break; ++ case 0x21: /* INVON */ ++ s->invert = 1; ++ break; ++ ++ case 0x22: /* APOFF */ ++ case 0x23: /* APON */ ++ goto bad_cmd; ++ ++ case 0x25: /* WRCNTR */ ++ if (s->pm < 0) ++ s->pm = 1; ++ goto bad_cmd; ++ ++ case 0x26: /* GAMSET */ ++ if (!s->pm) ++ s->gamma = ffs(s->param[0] & 0xf) - 1; ++ else if (s->pm < 0) ++ s->pm = 1; ++ break; ++ ++ case 0x28: /* DISPOFF */ ++ s->onoff = 0; ++ fprintf(stderr, "%s: Display off\n", __FUNCTION__); ++ break; ++ case 0x29: /* DISPON */ ++ s->onoff = 1; ++ fprintf(stderr, "%s: Display on\n", __FUNCTION__); ++ break; ++ ++ case 0x2a: /* CASET */ ++ case 0x2b: /* RASET */ ++ case 0x2c: /* RAMWR */ ++ case 0x2d: /* RGBSET */ ++ case 0x2e: /* RAMRD */ ++ case 0x30: /* PTLAR */ ++ case 0x33: /* SCRLAR */ ++ goto bad_cmd; ++ ++ case 0x34: /* TEOFF */ ++ s->te = 0; ++ break; ++ case 0x35: /* TEON */ ++ if (!s->pm) ++ s->te = 1; ++ else if (s->pm < 0) ++ s->pm = 1; ++ break; ++ ++ case 0x36: /* MADCTR */ ++ goto bad_cmd; ++ ++ case 0x37: /* VSCSAD */ ++ s->partial = 0; ++ s->normal = 0; ++ s->vscr = 1; ++ break; ++ ++ case 0x38: /* IDMOFF */ ++ case 0x39: /* IDMON */ ++ case 0x3a: /* COLMOD */ ++ goto bad_cmd; ++ ++ case 0xb0: /* CLKINT / DISCTL */ ++ case 0xb1: /* CLKEXT */ ++ if (s->pm < 0) ++ s->pm = 2; ++ break; ++ ++ case 0xb4: /* FRMSEL */ ++ break; ++ ++ case 0xb5: /* FRM8SEL */ ++ case 0xb6: /* TMPRNG / INIESC */ ++ case 0xb7: /* TMPHIS / NOP2 */ ++ case 0xb8: /* TMPREAD / MADCTL */ ++ case 0xba: /* DISTCTR */ ++ case 0xbb: /* EPVOL */ ++ goto bad_cmd; ++ ++ case 0xbd: /* Unknown */ ++ s->p = 0; ++ s->resp[0] = 0; ++ s->resp[1] = 1; ++ break; ++ ++ case 0xc2: /* IFMOD */ ++ if (s->pm < 0) ++ s->pm = 2; ++ break; ++ ++ case 0xc6: /* PWRCTL */ ++ case 0xc7: /* PPWRCTL */ ++ case 0xd0: /* EPWROUT */ ++ case 0xd1: /* EPWRIN */ ++ case 0xd4: /* RDEV */ ++ case 0xd5: /* RDRR */ ++ goto bad_cmd; ++ ++ case 0xda: /* RDID1 */ ++ s->p = 0; ++ s->resp[0] = (s->id >> 16) & 0xff; ++ break; ++ case 0xdb: /* RDID2 */ ++ s->p = 0; ++ s->resp[0] = (s->id >> 8) & 0xff; ++ break; ++ case 0xdc: /* RDID3 */ ++ s->p = 0; ++ s->resp[0] = (s->id >> 0) & 0xff; ++ break; ++ ++ default: ++ bad_cmd: ++ fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd); ++ break; ++ } ++ ++ return ret; ++} ++ ++static void *mipid_init(void) ++{ ++ struct mipid_s *s = (struct mipid_s *) qemu_mallocz(sizeof(*s)); ++ ++ s->id = 0x838f03; ++ mipid_reset(s); ++ ++ return s; ++} ++ ++static void n800_spi_setup(struct n800_s *s) ++{ ++ void *tsc2301 = s->ts->opaque; ++ void *mipid = mipid_init(); ++ ++ omap_mcspi_attach(s->cpu->mcspi[0], tsc210x_txrx, tsc2301, 0); ++ omap_mcspi_attach(s->cpu->mcspi[0], mipid_txrx, mipid, 1); ++} ++ ++/* This task is normally performed by the bootloader. If we're loading ++ * a kernel directly, we need to enable the Blizzard ourselves. */ ++static void n800_dss_init(struct rfbi_chip_s *chip) ++{ ++ chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */ ++ chip->write(chip->opaque, 1, 0x64); ++ chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */ ++ chip->write(chip->opaque, 1, 0x1e); ++ chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */ ++ chip->write(chip->opaque, 1, 0xe0); ++ chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */ ++ chip->write(chip->opaque, 1, 0x01); ++ chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */ ++ chip->write(chip->opaque, 1, 0x06); ++ chip->write(chip->opaque, 0, 0x68); /* Display Mode register */ ++ chip->write(chip->opaque, 1, 1); /* Enable bit */ ++} ++ ++static void n800_dss_setup(struct n800_s *s, DisplayState *ds) ++{ ++ s->blizzard.opaque = s1d13745_init(0, ds); ++ s->blizzard.block = s1d13745_write_block; ++ s->blizzard.write = s1d13745_write; ++ s->blizzard.read = s1d13745_read; ++ ++ omap_rfbi_attach(s->cpu->dss, 0, &s->blizzard); ++} ++ ++static void n800_cbus_setup(struct n800_s *s) ++{ ++ qemu_irq dat_out = omap2_gpio_in_get(s->cpu->gpif, N800_CBUS_DAT_GPIO)[0]; ++ qemu_irq retu_irq = omap2_gpio_in_get(s->cpu->gpif, N800_RETU_GPIO)[0]; ++ qemu_irq tahvo_irq = omap2_gpio_in_get(s->cpu->gpif, N800_TAHVO_GPIO)[0]; ++ ++ struct cbus_s *cbus = cbus_init(dat_out); ++ ++ omap2_gpio_out_set(s->cpu->gpif, N800_CBUS_CLK_GPIO, cbus->clk); ++ omap2_gpio_out_set(s->cpu->gpif, N800_CBUS_DAT_GPIO, cbus->dat); ++ omap2_gpio_out_set(s->cpu->gpif, N800_CBUS_SEL_GPIO, cbus->sel); ++ ++ cbus_attach(cbus, retu_init(retu_irq, 1)); ++ cbus_attach(cbus, tahvo_init(tahvo_irq, 1)); ++} ++ ++/* This task is normally performed by the bootloader. If we're loading ++ * a kernel directly, we need to set up GPMC mappings ourselves. */ ++static void n800_gpmc_init(struct n800_s *s) ++{ ++ uint32_t config7 = ++ (0xf << 8) | /* MASKADDRESS */ ++ (1 << 6) | /* CSVALID */ ++ (4 << 0); /* BASEADDRESS */ ++ ++ cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */ ++ (void *) &config7, sizeof(config7)); ++} ++ ++#if 0 ++static uint32_t n800_pinout[104] = { ++ 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0, ++ 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808, ++ 0x08080808, 0x180800c4, 0x00b80000, 0x08080808, ++ 0x080800bc, 0x00cc0808, 0x08081818, 0x18180128, ++ 0x01241800, 0x18181818, 0x000000f0, 0x01300000, ++ 0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b, ++ 0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080, ++ 0x007c0000, 0x00000000, 0x00000088, 0x00840000, ++ 0x00000000, 0x00000094, 0x00980300, 0x0f180003, ++ 0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c, ++ 0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008, ++ 0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f, ++ 0x181800f4, 0x00f81818, 0x00000018, 0x000000fc, ++ 0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008, ++ 0x00000000, 0x00000038, 0x00340000, 0x00000000, ++ 0x1a080070, 0x00641a1a, 0x08080808, 0x08080060, ++ 0x005c0808, 0x08080808, 0x08080058, 0x00540808, ++ 0x08080808, 0x0808006c, 0x00680808, 0x08080808, ++ 0x000000a8, 0x00b00000, 0x08080808, 0x000000a0, ++ 0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808, ++ 0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff, ++ 0x000000ac, 0x01040800, 0x08080b0f, 0x18180100, ++ 0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a, ++ 0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00, ++ 0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118, ++ 0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b, ++}; ++#endif ++ ++/* Setup sequence done by the bootloader */ ++static void n800_boot_init(void *opaque) ++{ ++ struct n800_s *s = (struct n800_s *) opaque; ++ uint32_t buf; ++ ++ /* PRCM setup */ ++#define omap_writel(addr, val) \ ++ buf = (val); \ ++ cpu_physical_memory_write(addr, (void *) &buf, sizeof(buf)) ++ ++ omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */ ++ omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */ ++ omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */ ++ omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */ ++ omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */ ++ omap_writel(0x48008098, 0); /* PRCM_POLCTRL */ ++ omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */ ++ omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */ ++ omap_writel(0x48008158, 1); /* RM_RSTST_MPU */ ++ omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */ ++ omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */ ++ omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */ ++ omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */ ++ omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */ ++ omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */ ++ omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */ ++ omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */ ++ omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */ ++ omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */ ++ omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */ ++ omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */ ++ omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */ ++ omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */ ++ omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */ ++ omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */ ++ omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */ ++ omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */ ++ omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */ ++ omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */ ++ omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */ ++ omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */ ++ omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */ ++ omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */ ++ omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */ ++ omap_writel(0x48008540, /* CM_CLKSEL1_PLL */ ++ (0x78 << 12) | (6 << 8)); ++ omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */ ++ ++ /* GPMC setup */ ++ n800_gpmc_init(s); ++ ++ /* Video setup */ ++ n800_dss_init(&s->blizzard); ++ ++ /* CPU setup */ ++ s->cpu->env->regs[15] = s->cpu->env->boot_info->loader_start; ++} ++ ++#define OMAP_TAG_NOKIA_BT 0x4e01 ++#define OMAP_TAG_WLAN_CX3110X 0x4e02 ++#define OMAP_TAG_CBUS 0x4e03 ++#define OMAP_TAG_EM_ASIC_BB5 0x4e04 ++ ++static int n800_atag_setup(struct arm_boot_info *info, void *p) ++{ ++ uint8_t *b; ++ uint16_t *w; ++ uint32_t *l; ++ ++ w = p; ++ ++ stw_raw(w ++, OMAP_TAG_UART); /* u16 tag */ ++ stw_raw(w ++, 4); /* u16 len */ ++ stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */ ++ w ++; ++ ++ stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */ ++ stw_raw(w ++, 4); /* u16 len */ ++ stw_raw(w ++, N800_RETU_GPIO); /* s16 retu_irq_gpio */ ++ stw_raw(w ++, N800_TAHVO_GPIO); /* s16 tahvo_irq_gpio */ ++ ++ stw_raw(w ++, OMAP_TAG_CBUS); /* u16 tag */ ++ stw_raw(w ++, 8); /* u16 len */ ++ stw_raw(w ++, N800_CBUS_CLK_GPIO); /* s16 clk_gpio */ ++ stw_raw(w ++, N800_CBUS_DAT_GPIO); /* s16 dat_gpio */ ++ stw_raw(w ++, N800_CBUS_SEL_GPIO); /* s16 sel_gpio */ ++ w ++; ++ ++ stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */ ++ stw_raw(w ++, 20); /* u16 len */ ++ strcpy((void *) w, "bat_cover"); /* char name[12] */ ++ w += 6; ++ stw_raw(w ++, N800_BAT_COVER_GPIO); /* u16 gpio */ ++ stw_raw(w ++, 0x01); ++ stw_raw(w ++, 0); ++ stw_raw(w ++, 0); ++ ++ stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */ ++ stw_raw(w ++, 20); /* u16 len */ ++ strcpy((void *) w, "cam_act"); /* char name[12] */ ++ w += 6; ++ stw_raw(w ++, N800_CAM_ACT_GPIO); /* u16 gpio */ ++ stw_raw(w ++, 0x20); ++ stw_raw(w ++, 0); ++ stw_raw(w ++, 0); ++ ++ stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */ ++ stw_raw(w ++, 20); /* u16 len */ ++ strcpy((void *) w, "cam_turn"); /* char name[12] */ ++ w += 6; ++ stw_raw(w ++, N800_CAM_TURN_GPIO); /* u16 gpio */ ++ stw_raw(w ++, 0x21); ++ stw_raw(w ++, 0); ++ stw_raw(w ++, 0); ++ ++ stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */ ++ stw_raw(w ++, 20); /* u16 len */ ++ strcpy((void *) w, "headphone"); /* char name[12] */ ++ w += 6; ++ stw_raw(w ++, N800_HEADPHONE_GPIO); /* u16 gpio */ ++ stw_raw(w ++, 0x11); ++ stw_raw(w ++, 0); ++ stw_raw(w ++, 0); ++ ++ stw_raw(w ++, OMAP_TAG_NOKIA_BT); /* u16 tag */ ++ stw_raw(w ++, 12); /* u16 len */ ++ b = (void *) w; ++ stb_raw(b ++, 0x01); /* u8 chip_type (CSR) */ ++ stb_raw(b ++, N800_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */ ++ stb_raw(b ++, N800_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */ ++ stb_raw(b ++, N800_BT_RESET_GPIO); /* u8 reset_gpio */ ++ stb_raw(b ++, 1); /* u8 bt_uart */ ++ memset(b, 0, 6); /* u8 bd_addr[6] */ ++ b += 6; ++ stb_raw(b ++, 0x02); /* u8 bt_sysclk (38.4) */ ++ w = (void *) b; ++ ++ stw_raw(w ++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */ ++ stw_raw(w ++, 8); /* u16 len */ ++ stw_raw(w ++, 0x25); /* u8 chip_type */ ++ stw_raw(w ++, N800_WLAN_PWR_GPIO); /* s16 power_gpio */ ++ stw_raw(w ++, N800_WLAN_IRQ_GPIO); /* s16 irq_gpio */ ++ stw_raw(w ++, -1); /* s16 spi_cs_gpio */ ++ ++ stw_raw(w ++, OMAP_TAG_MMC); /* u16 tag */ ++ stw_raw(w ++, 16); /* u16 len */ ++ stw_raw(w ++, 0xf); /* unsigned flags */ ++ stw_raw(w ++, -1); /* s16 power_pin */ ++ stw_raw(w ++, -1); /* s16 switch_pin */ ++ stw_raw(w ++, -1); /* s16 wp_pin */ ++ stw_raw(w ++, 0); /* unsigned flags */ ++ stw_raw(w ++, 0); /* s16 power_pin */ ++ stw_raw(w ++, 0); /* s16 switch_pin */ ++ stw_raw(w ++, 0); /* s16 wp_pin */ ++ ++ stw_raw(w ++, OMAP_TAG_TEA5761); /* u16 tag */ ++ stw_raw(w ++, 4); /* u16 len */ ++ stw_raw(w ++, N800_TEA5761_CS_GPIO); /* u16 enable_gpio */ ++ w ++; ++ ++ stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */ ++ stw_raw(w ++, 28); /* u16 len */ ++ strcpy((void *) w, "bootloader"); /* char name[16] */ ++ l = (void *) (w + 8); ++ stl_raw(l ++, 0x00020000); /* unsigned int size */ ++ stl_raw(l ++, 0x00000000); /* unsigned int offset */ ++ stl_raw(l ++, 0x3); /* unsigned int mask_flags */ ++ w = (void *) l; ++ ++ stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */ ++ stw_raw(w ++, 28); /* u16 len */ ++ strcpy((void *) w, "config"); /* char name[16] */ ++ l = (void *) (w + 8); ++ stl_raw(l ++, 0x00060000); /* unsigned int size */ ++ stl_raw(l ++, 0x00020000); /* unsigned int offset */ ++ stl_raw(l ++, 0x0); /* unsigned int mask_flags */ ++ w = (void *) l; ++ ++ stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */ ++ stw_raw(w ++, 28); /* u16 len */ ++ strcpy((void *) w, "kernel"); /* char name[16] */ ++ l = (void *) (w + 8); ++ stl_raw(l ++, 0x00200000); /* unsigned int size */ ++ stl_raw(l ++, 0x00080000); /* unsigned int offset */ ++ stl_raw(l ++, 0x0); /* unsigned int mask_flags */ ++ w = (void *) l; ++ ++ stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */ ++ stw_raw(w ++, 28); /* u16 len */ ++ strcpy((void *) w, "initfs"); /* char name[16] */ ++ l = (void *) (w + 8); ++ stl_raw(l ++, 0x00200000); /* unsigned int size */ ++ stl_raw(l ++, 0x00280000); /* unsigned int offset */ ++ stl_raw(l ++, 0x3); /* unsigned int mask_flags */ ++ w = (void *) l; ++ ++ stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */ ++ stw_raw(w ++, 28); /* u16 len */ ++ strcpy((void *) w, "rootfs"); /* char name[16] */ ++ l = (void *) (w + 8); ++ stl_raw(l ++, 0x0fb80000); /* unsigned int size */ ++ stl_raw(l ++, 0x00480000); /* unsigned int offset */ ++ stl_raw(l ++, 0x3); /* unsigned int mask_flags */ ++ w = (void *) l; ++ ++ stw_raw(w ++, OMAP_TAG_BOOT_REASON); /* u16 tag */ ++ stw_raw(w ++, 12); /* u16 len */ ++#if 0 ++ strcpy((void *) w, "por"); /* char reason_str[12] */ ++ strcpy((void *) w, "charger"); /* char reason_str[12] */ ++ strcpy((void *) w, "32wd_to"); /* char reason_str[12] */ ++ strcpy((void *) w, "sw_rst"); /* char reason_str[12] */ ++ strcpy((void *) w, "mbus"); /* char reason_str[12] */ ++ strcpy((void *) w, "unknown"); /* char reason_str[12] */ ++ strcpy((void *) w, "swdg_to"); /* char reason_str[12] */ ++ strcpy((void *) w, "sec_vio"); /* char reason_str[12] */ ++ strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ ++ strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */ ++#else ++ strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ ++#endif ++ w += 6; ++ ++ stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ ++ stw_raw(w ++, 24); /* u16 len */ ++ strcpy((void *) w, "product"); /* char component[12] */ ++ w += 6; ++ strcpy((void *) w, "RX-34"); /* char version[12] */ ++ w += 6; ++ ++ stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ ++ stw_raw(w ++, 24); /* u16 len */ ++ strcpy((void *) w, "hw-build"); /* char component[12] */ ++ w += 6; ++ strcpy((void *) w, "QEMU"); /* char version[12] */ ++ w += 6; ++ ++ stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ ++ stw_raw(w ++, 24); /* u16 len */ ++ strcpy((void *) w, "nolo"); /* char component[12] */ ++ w += 6; ++ strcpy((void *) w, "1.1.6-qemu"); /* char version[12] */ ++ w += 6; ++ ++ stw_raw(w ++, OMAP_TAG_LCD); /* u16 tag */ ++ stw_raw(w ++, 36); /* u16 len */ ++ strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */ ++ w += 8; ++ strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */ ++ w += 8; ++ stw_raw(w ++, 5); /* TODO s16 nreset_gpio */ ++ stw_raw(w ++, 16); /* u8 data_lines */ ++ ++ return (void *) w - p; ++} ++ ++static struct arm_boot_info n800_binfo = { ++ .loader_start = OMAP2_Q2_BASE, ++ /* Actually two chips of 0x4000000 bytes each */ ++ .ram_size = 0x08000000, ++ .board_id = 0x4f7, ++ .atag_board = n800_atag_setup, ++}; ++ ++static void n800_init(int ram_size, int vga_ram_size, ++ const char *boot_device, DisplayState *ds, ++ const char *kernel_filename, const char *kernel_cmdline, ++ const char *initrd_filename, const char *cpu_model) ++{ ++ struct n800_s *s = (struct n800_s *) qemu_mallocz(sizeof(*s)); ++ int sdram_size = n800_binfo.ram_size; ++ int onenandram_size = 0x00010000; ++ ++ if (ram_size < sdram_size + onenandram_size + OMAP242X_SRAM_SIZE) { ++ fprintf(stderr, "This architecture uses %i bytes of memory\n", ++ sdram_size + onenandram_size + OMAP242X_SRAM_SIZE); ++ exit(1); ++ } ++ ++ s->cpu = omap2420_mpu_init(sdram_size, NULL, cpu_model); ++ ++ n800_gpio_setup(s); ++ n800_nand_setup(s); ++ n800_i2c_setup(s); ++ n800_tsc_setup(s); ++ n800_spi_setup(s); ++ n800_dss_setup(s, ds); ++ n800_cbus_setup(s); ++ ++ /* Setup initial (reset) machine state */ ++ ++ /* Start at the OneNAND bootloader. */ ++ s->cpu->env->regs[15] = 0; ++ ++ if (kernel_filename) { ++ /* Or at the linux loader. */ ++ n800_binfo.kernel_filename = kernel_filename; ++ n800_binfo.kernel_cmdline = kernel_cmdline; ++ n800_binfo.initrd_filename = initrd_filename; ++ arm_load_kernel(s->cpu->env, &n800_binfo); ++ ++ qemu_register_reset(n800_boot_init, s); ++ n800_boot_init(s); ++ } ++ ++ dpy_resize(ds, 800, 480); ++} ++ ++QEMUMachine n800_machine = { ++ "n800", ++ "Nokia N800 aka. RX-34 tablet (OMAP2420)", ++ n800_init, ++}; +diff --git a/hw/omap.h b/hw/omap.h +index ecfd54d..de838c9 100644 +--- a/hw/omap.h ++++ b/hw/omap.h +@@ -22,6 +22,7 @@ + # define hw_omap_h "omap.h" + + # define OMAP_EMIFS_BASE 0x00000000 ++# define OMAP2_Q0_BASE 0x00000000 + # define OMAP_CS0_BASE 0x00000000 + # define OMAP_CS1_BASE 0x04000000 + # define OMAP_CS2_BASE 0x08000000 +@@ -29,18 +30,26 @@ + # define OMAP_EMIFF_BASE 0x10000000 + # define OMAP_IMIF_BASE 0x20000000 + # define OMAP_LOCALBUS_BASE 0x30000000 ++# define OMAP2_Q1_BASE 0x40000000 ++# define OMAP2_L4_BASE 0x48000000 ++# define OMAP2_SRAM_BASE 0x40200000 ++# define OMAP2_L3_BASE 0x68000000 ++# define OMAP2_Q2_BASE 0x80000000 ++# define OMAP2_Q3_BASE 0xc0000000 + # define OMAP_MPUI_BASE 0xe1000000 + + # define OMAP730_SRAM_SIZE 0x00032000 + # define OMAP15XX_SRAM_SIZE 0x00030000 + # define OMAP16XX_SRAM_SIZE 0x00004000 + # define OMAP1611_SRAM_SIZE 0x0003e800 ++# define OMAP242X_SRAM_SIZE 0x000a0000 ++# define OMAP243X_SRAM_SIZE 0x00010000 + # define OMAP_CS0_SIZE 0x04000000 + # define OMAP_CS1_SIZE 0x04000000 + # define OMAP_CS2_SIZE 0x04000000 + # define OMAP_CS3_SIZE 0x04000000 + +-/* omap1_clk.c */ ++/* omap_clk.c */ + struct omap_mpu_state_s; + typedef struct clk *omap_clk; + omap_clk omap_findclk(struct omap_mpu_state_s *mpu, const char *name); +@@ -55,14 +64,41 @@ int64_t omap_clk_getrate(omap_clk clk); + void omap_clk_reparent(omap_clk clk, omap_clk parent); + + /* omap[123].c */ ++struct omap_l4_s; ++struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num); ++ ++struct omap_target_agent_s; ++struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs); ++target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region, ++ int iotype); ++ + struct omap_intr_handler_s; + struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, +- unsigned long size, unsigned char nbanks, ++ unsigned long size, unsigned char nbanks, qemu_irq **pins, + qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk); +- +-struct omap_target_agent_s; +-static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, +- int region, int iotype) { return 0; } ++struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base, ++ int size, int nbanks, qemu_irq **pins, ++ qemu_irq parent_irq, qemu_irq parent_fiq, ++ omap_clk fclk, omap_clk iclk); ++void omap_inth_reset(struct omap_intr_handler_s *s); ++ ++struct omap_prcm_s; ++struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta, ++ qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int, ++ struct omap_mpu_state_s *mpu); ++ ++struct omap_sysctl_s; ++struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, ++ omap_clk iclk, struct omap_mpu_state_s *mpu); ++ ++struct omap_sdrc_s; ++struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base); ++ ++struct omap_gpmc_s; ++struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq); ++void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype, ++ void (*base_upd)(void *opaque, target_phys_addr_t new), ++ void (*unmap)(void *opaque), void *opaque); + + /* + * Common IRQ numbers for level 1 interrupt handler +@@ -295,10 +331,20 @@ static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, + * OMAP-24xx common IRQ numbers + */ + # define OMAP_INT_24XX_SYS_NIRQ 7 ++# define OMAP_INT_24XX_L3_IRQ 10 ++# define OMAP_INT_24XX_PRCM_MPU_IRQ 11 + # define OMAP_INT_24XX_SDMA_IRQ0 12 + # define OMAP_INT_24XX_SDMA_IRQ1 13 + # define OMAP_INT_24XX_SDMA_IRQ2 14 + # define OMAP_INT_24XX_SDMA_IRQ3 15 ++# define OMAP_INT_243X_MCBSP2_IRQ 16 ++# define OMAP_INT_243X_MCBSP3_IRQ 17 ++# define OMAP_INT_243X_MCBSP4_IRQ 18 ++# define OMAP_INT_243X_MCBSP5_IRQ 19 ++# define OMAP_INT_24XX_GPMC_IRQ 20 ++# define OMAP_INT_24XX_GUFFAW_IRQ 21 ++# define OMAP_INT_24XX_IVA_IRQ 22 ++# define OMAP_INT_24XX_EAC_IRQ 23 + # define OMAP_INT_24XX_CAM_IRQ 24 + # define OMAP_INT_24XX_DSS_IRQ 25 + # define OMAP_INT_24XX_MAIL_U0_MPU 26 +@@ -308,8 +354,10 @@ static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, + # define OMAP_INT_24XX_GPIO_BANK2 30 + # define OMAP_INT_24XX_GPIO_BANK3 31 + # define OMAP_INT_24XX_GPIO_BANK4 32 +-# define OMAP_INT_24XX_GPIO_BANK5 33 ++# define OMAP_INT_243X_GPIO_BANK5 33 + # define OMAP_INT_24XX_MAIL_U3_MPU 34 ++# define OMAP_INT_24XX_WDT3 35 ++# define OMAP_INT_24XX_WDT4 36 + # define OMAP_INT_24XX_GPTIMER1 37 + # define OMAP_INT_24XX_GPTIMER2 38 + # define OMAP_INT_24XX_GPTIMER3 39 +@@ -322,10 +370,24 @@ static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, + # define OMAP_INT_24XX_GPTIMER10 46 + # define OMAP_INT_24XX_GPTIMER11 47 + # define OMAP_INT_24XX_GPTIMER12 48 ++# define OMAP_INT_24XX_PKA_IRQ 50 ++# define OMAP_INT_24XX_SHA1MD5_IRQ 51 ++# define OMAP_INT_24XX_RNG_IRQ 52 ++# define OMAP_INT_24XX_MG_IRQ 53 ++# define OMAP_INT_24XX_I2C1_IRQ 56 ++# define OMAP_INT_24XX_I2C2_IRQ 57 + # define OMAP_INT_24XX_MCBSP1_IRQ_TX 59 + # define OMAP_INT_24XX_MCBSP1_IRQ_RX 60 + # define OMAP_INT_24XX_MCBSP2_IRQ_TX 62 + # define OMAP_INT_24XX_MCBSP2_IRQ_RX 63 ++# define OMAP_INT_243X_MCBSP1_IRQ 64 ++# define OMAP_INT_24XX_MCSPI1_IRQ 65 ++# define OMAP_INT_24XX_MCSPI2_IRQ 66 ++# define OMAP_INT_24XX_SSI1_IRQ0 67 ++# define OMAP_INT_24XX_SSI1_IRQ1 68 ++# define OMAP_INT_24XX_SSI2_IRQ0 69 ++# define OMAP_INT_24XX_SSI2_IRQ1 70 ++# define OMAP_INT_24XX_SSI_GDD_IRQ 71 + # define OMAP_INT_24XX_UART1_IRQ 72 + # define OMAP_INT_24XX_UART2_IRQ 73 + # define OMAP_INT_24XX_UART3_IRQ 74 +@@ -335,10 +397,15 @@ static inline target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, + # define OMAP_INT_24XX_USB_IRQ_HGEN 78 + # define OMAP_INT_24XX_USB_IRQ_HSOF 79 + # define OMAP_INT_24XX_USB_IRQ_OTG 80 ++# define OMAP_INT_24XX_VLYNQ_IRQ 81 + # define OMAP_INT_24XX_MMC_IRQ 83 ++# define OMAP_INT_24XX_MS_IRQ 84 ++# define OMAP_INT_24XX_FAC_IRQ 85 ++# define OMAP_INT_24XX_MCSPI3_IRQ 91 + # define OMAP_INT_243X_HS_USB_MC 92 + # define OMAP_INT_243X_HS_USB_DMA 93 + # define OMAP_INT_243X_CARKIT 94 ++# define OMAP_INT_34XX_GPTIMER12 95 + + /* omap_dma.c */ + enum omap_dma_model { +@@ -352,6 +419,9 @@ struct omap_dma_s; + struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, + qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, + enum omap_dma_model model); ++struct omap_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs, ++ struct omap_mpu_state_s *mpu, int fifo, ++ int chans, omap_clk iclk, omap_clk fclk); + void omap_dma_reset(struct omap_dma_s *s); + + struct dma_irq_map { +@@ -367,7 +437,7 @@ enum omap_dma_port { + tipb, + local, /* omap16xx: ocp_t2 */ + tipb_mpui, +- omap_dma_port_last, ++ __omap_dma_port_last, + }; + + typedef enum { +@@ -488,11 +558,83 @@ struct omap_dma_lcd_channel_s { + # define OMAP_DMA_MMC2_RX 55 + # define OMAP_DMA_CRYPTO_DES_OUT 56 + ++/* ++ * DMA request numbers for the OMAP2 ++ */ ++# define OMAP24XX_DMA_NO_DEVICE 0 ++# define OMAP24XX_DMA_XTI_DMA 1 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_EXT_DMAREQ0 2 ++# define OMAP24XX_DMA_EXT_DMAREQ1 3 ++# define OMAP24XX_DMA_GPMC 4 ++# define OMAP24XX_DMA_GFX 5 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_DSS 6 ++# define OMAP24XX_DMA_VLYNQ_TX 7 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_CWT 8 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_AES_TX 9 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_AES_RX 10 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_DES_TX 11 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_DES_RX 12 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_SHA1MD5_RX 13 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_EXT_DMAREQ2 14 ++# define OMAP24XX_DMA_EXT_DMAREQ3 15 ++# define OMAP24XX_DMA_EXT_DMAREQ4 16 ++# define OMAP24XX_DMA_EAC_AC_RD 17 ++# define OMAP24XX_DMA_EAC_AC_WR 18 ++# define OMAP24XX_DMA_EAC_MD_UL_RD 19 ++# define OMAP24XX_DMA_EAC_MD_UL_WR 20 ++# define OMAP24XX_DMA_EAC_MD_DL_RD 21 ++# define OMAP24XX_DMA_EAC_MD_DL_WR 22 ++# define OMAP24XX_DMA_EAC_BT_UL_RD 23 ++# define OMAP24XX_DMA_EAC_BT_UL_WR 24 ++# define OMAP24XX_DMA_EAC_BT_DL_RD 25 ++# define OMAP24XX_DMA_EAC_BT_DL_WR 26 ++# define OMAP24XX_DMA_I2C1_TX 27 ++# define OMAP24XX_DMA_I2C1_RX 28 ++# define OMAP24XX_DMA_I2C2_TX 29 ++# define OMAP24XX_DMA_I2C2_RX 30 ++# define OMAP24XX_DMA_MCBSP1_TX 31 ++# define OMAP24XX_DMA_MCBSP1_RX 32 ++# define OMAP24XX_DMA_MCBSP2_TX 33 ++# define OMAP24XX_DMA_MCBSP2_RX 34 ++# define OMAP24XX_DMA_SPI1_TX0 35 ++# define OMAP24XX_DMA_SPI1_RX0 36 ++# define OMAP24XX_DMA_SPI1_TX1 37 ++# define OMAP24XX_DMA_SPI1_RX1 38 ++# define OMAP24XX_DMA_SPI1_TX2 39 ++# define OMAP24XX_DMA_SPI1_RX2 40 ++# define OMAP24XX_DMA_SPI1_TX3 41 ++# define OMAP24XX_DMA_SPI1_RX3 42 ++# define OMAP24XX_DMA_SPI2_TX0 43 ++# define OMAP24XX_DMA_SPI2_RX0 44 ++# define OMAP24XX_DMA_SPI2_TX1 45 ++# define OMAP24XX_DMA_SPI2_RX1 46 ++ ++# define OMAP24XX_DMA_UART1_TX 49 ++# define OMAP24XX_DMA_UART1_RX 50 ++# define OMAP24XX_DMA_UART2_TX 51 ++# define OMAP24XX_DMA_UART2_RX 52 ++# define OMAP24XX_DMA_UART3_TX 53 ++# define OMAP24XX_DMA_UART3_RX 54 ++# define OMAP24XX_DMA_USB_W2FC_TX0 55 ++# define OMAP24XX_DMA_USB_W2FC_RX0 56 ++# define OMAP24XX_DMA_USB_W2FC_TX1 57 ++# define OMAP24XX_DMA_USB_W2FC_RX1 58 ++# define OMAP24XX_DMA_USB_W2FC_TX2 59 ++# define OMAP24XX_DMA_USB_W2FC_RX2 60 ++# define OMAP24XX_DMA_MMC1_TX 61 ++# define OMAP24XX_DMA_MMC1_RX 62 ++# define OMAP24XX_DMA_MS 63 /* Not in OMAP2420 */ ++# define OMAP24XX_DMA_EXT_DMAREQ5 64 ++ + /* omap[123].c */ + struct omap_mpu_timer_s; + struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk); + ++struct omap_gp_timer_s; ++struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, ++ qemu_irq irq, omap_clk fclk, omap_clk iclk); ++ + struct omap_watchdog_timer_s; + struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk); +@@ -501,13 +643,21 @@ struct omap_32khz_timer_s; + struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk); + ++void omap_synctimer_init(struct omap_target_agent_s *ta, ++ struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk); ++ + struct omap_tipb_bridge_s; + struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base, + qemu_irq abort_irq, omap_clk clk); + + struct omap_uart_s; + struct omap_uart_s *omap_uart_init(target_phys_addr_t base, +- qemu_irq irq, omap_clk clk, CharDriverState *chr); ++ qemu_irq irq, omap_clk fclk, omap_clk iclk, ++ qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr); ++struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta, ++ qemu_irq irq, omap_clk fclk, omap_clk iclk, ++ qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr); ++void omap_uart_reset(struct omap_uart_s *s); + + struct omap_mpuio_s; + struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, +@@ -523,6 +673,12 @@ struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, + qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s); + void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler); + ++struct omap_gpif_s; ++struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta, ++ qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules); ++qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start); ++void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler); ++ + struct uwire_slave_s { + uint16_t (*receive)(void *opaque); + void (*send)(void *opaque, uint16_t data); +@@ -534,6 +690,13 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, + void omap_uwire_attach(struct omap_uwire_s *s, + struct uwire_slave_s *slave, int chipselect); + ++struct omap_mcspi_s; ++struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum, ++ qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk); ++void omap_mcspi_attach(struct omap_mcspi_s *s, ++ uint32_t (*txrx)(void *opaque, uint32_t), 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); +@@ -570,6 +733,9 @@ void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave); + struct omap_lpg_s; + struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk); + ++void omap_tap_init(struct omap_target_agent_s *ta, ++ struct omap_mpu_state_s *mpu); ++ + /* omap_lcdc.c */ + struct omap_lcd_panel_s; + void omap_lcdc_reset(struct omap_lcd_panel_s *s); +@@ -577,13 +743,33 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, + struct omap_dma_lcd_channel_s *dma, DisplayState *ds, + ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk); + ++/* omap_dss.c */ ++struct rfbi_chip_s { ++ void *opaque; ++ void (*write)(void *opaque, int dc, uint16_t value); ++ void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch); ++ uint16_t (*read)(void *opaque, int dc); ++}; ++struct omap_dss_s; ++void omap_dss_reset(struct omap_dss_s *s); ++struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta, ++ target_phys_addr_t l3_base, DisplayState *ds, ++ qemu_irq irq, qemu_irq drq, ++ omap_clk fck1, omap_clk fck2, omap_clk ck54m, ++ omap_clk ick1, omap_clk ick2); ++void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip); ++ + /* omap_mmc.c */ + struct omap_mmc_s; + struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, + BlockDriverState *bd, + qemu_irq irq, qemu_irq dma[], omap_clk clk); ++struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, ++ BlockDriverState *bd, qemu_irq irq, qemu_irq dma[], ++ omap_clk fclk, omap_clk iclk); + void omap_mmc_reset(struct omap_mmc_s *s); + void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover); ++void omap_mmc_enable(struct omap_mmc_s *s, int enable); + + /* omap_i2c.c */ + struct omap_i2c_s; +@@ -596,14 +782,37 @@ i2c_bus *omap_i2c_bus(struct omap_i2c_s *s); + + # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) + # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) ++# define cpu_is_omap1610(cpu) (cpu->mpu_model == omap1610) ++# define cpu_is_omap1710(cpu) (cpu->mpu_model == omap1710) ++# define cpu_is_omap2410(cpu) (cpu->mpu_model == omap2410) ++# define cpu_is_omap2420(cpu) (cpu->mpu_model == omap2420) ++# define cpu_is_omap2430(cpu) (cpu->mpu_model == omap2430) ++# define cpu_is_omap3430(cpu) (cpu->mpu_model == omap3430) ++ + # define cpu_is_omap15xx(cpu) \ + (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu)) +-# define cpu_class_omap1(cpu) 1 ++# define cpu_is_omap16xx(cpu) \ ++ (cpu_is_omap1610(cpu) || cpu_is_omap1710(cpu)) ++# define cpu_is_omap24xx(cpu) \ ++ (cpu_is_omap2410(cpu) || cpu_is_omap2420(cpu) || cpu_is_omap2430(cpu)) ++ ++# define cpu_class_omap1(cpu) \ ++ (cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu)) ++# define cpu_class_omap2(cpu) cpu_is_omap24xx(cpu) ++# define cpu_class_omap3(cpu) cpu_is_omap3430(cpu) + + struct omap_mpu_state_s { +- enum omap1_mpu_model { ++ enum omap_mpu_model { + omap310, + omap1510, ++ omap1610, ++ omap1710, ++ omap2410, ++ omap2420, ++ omap2422, ++ omap2423, ++ omap2430, ++ omap3430, + } mpu_model; + + CPUState *env; +@@ -620,7 +829,7 @@ struct omap_mpu_state_s { + target_phys_addr_t offset, uint32_t value); + int (*addr_valid)(struct omap_mpu_state_s *s, + target_phys_addr_t addr); +- } port[omap_dma_port_last]; ++ } port[__omap_dma_port_last]; + + unsigned long sdram_size; + unsigned long sram_size; +@@ -656,7 +865,7 @@ struct omap_mpu_state_s { + omap_clk clk; + } pwt; + +- struct omap_i2c_s *i2c; ++ struct omap_i2c_s *i2c[2]; + + struct omap_rtc_s *rtc; + +@@ -722,7 +931,38 @@ struct omap_mpu_state_s { + uint16_t dsp_idlect2; + uint16_t dsp_rstct2; + } clkm; +-} *omap310_mpu_init(unsigned long sdram_size, ++ ++ /* OMAP2-only peripherals */ ++ struct omap_l4_s *l4; ++ ++ struct omap_gp_timer_s *gptimer[12]; ++ ++ target_phys_addr_t tap_base; ++ ++ struct omap_synctimer_s { ++ target_phys_addr_t base; ++ uint32_t val; ++ uint16_t readh; ++ } synctimer; ++ ++ struct omap_prcm_s *prcm; ++ struct omap_sdrc_s *sdrc; ++ struct omap_gpmc_s *gpmc; ++ struct omap_sysctl_s *sysc; ++ ++ struct omap_gpif_s *gpif; ++ ++ struct omap_mcspi_s *mcspi[2]; ++ ++ struct omap_dss_s *dss; ++}; ++ ++/* omap1.c */ ++struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, ++ DisplayState *ds, const char *core); ++ ++/* omap2.c */ ++struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, + DisplayState *ds, const char *core); + + # if TARGET_PHYS_ADDR_BITS == 32 +@@ -743,24 +983,46 @@ uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr); + void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, + uint32_t value); + ++void omap_mpu_wakeup(void *opaque, int irq, int req); ++ + # define OMAP_BAD_REG(paddr) \ +- printf("%s: Bad register " OMAP_FMT_plx "\n", __FUNCTION__, paddr) ++ fprintf(stderr, "%s: Bad register " OMAP_FMT_plx "\n", \ ++ __FUNCTION__, paddr) + # define OMAP_RO_REG(paddr) \ +- printf("%s: Read-only register " OMAP_FMT_plx "\n", \ ++ fprintf(stderr, "%s: Read-only register " OMAP_FMT_plx "\n", \ + __FUNCTION__, paddr) + ++/* OMAP-specific Linux bootloader tags for the ATAG_BOARD area ++ (Board-specifc tags are not here) */ ++#define OMAP_TAG_CLOCK 0x4f01 ++#define OMAP_TAG_MMC 0x4f02 ++#define OMAP_TAG_SERIAL_CONSOLE 0x4f03 ++#define OMAP_TAG_USB 0x4f04 ++#define OMAP_TAG_LCD 0x4f05 ++#define OMAP_TAG_GPIO_SWITCH 0x4f06 ++#define OMAP_TAG_UART 0x4f07 ++#define OMAP_TAG_FBMEM 0x4f08 ++#define OMAP_TAG_STI_CONSOLE 0x4f09 ++#define OMAP_TAG_CAMERA_SENSOR 0x4f0a ++#define OMAP_TAG_PARTITION 0x4f0b ++#define OMAP_TAG_TEA5761 0x4f10 ++#define OMAP_TAG_TMP105 0x4f11 ++#define OMAP_TAG_BOOT_REASON 0x4f80 ++#define OMAP_TAG_FLASH_PART_STR 0x4f81 ++#define OMAP_TAG_VERSION_STR 0x4f82 ++ + # define TCMI_VERBOSE 1 + //# define MEM_VERBOSE 1 + + # ifdef TCMI_VERBOSE + # define OMAP_8B_REG(paddr) \ +- printf("%s: 8-bit register " OMAP_FMT_plx "\n", \ ++ fprintf(stderr, "%s: 8-bit register " OMAP_FMT_plx "\n", \ + __FUNCTION__, paddr) + # define OMAP_16B_REG(paddr) \ +- printf("%s: 16-bit register " OMAP_FMT_plx "\n", \ ++ fprintf(stderr, "%s: 16-bit register " OMAP_FMT_plx "\n", \ + __FUNCTION__, paddr) + # define OMAP_32B_REG(paddr) \ +- printf("%s: 32-bit register " OMAP_FMT_plx "\n", \ ++ fprintf(stderr, "%s: 32-bit register " OMAP_FMT_plx "\n", \ + __FUNCTION__, paddr) + # else + # define OMAP_8B_REG(paddr) +@@ -863,10 +1125,4 @@ inline static int debug_register_io_memory(int io_index, + # define cpu_register_io_memory debug_register_io_memory + # endif + +-/* Not really omap specific, but is the only thing that uses the +- uwire interface. */ +-/* tsc210x.c */ +-struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); +-struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); +- + #endif /* hw_omap_h */ +diff --git a/hw/omap1.c b/hw/omap1.c +index 3888e80..d81cbce 100644 +--- a/hw/omap1.c ++++ b/hw/omap1.c +@@ -23,10 +23,11 @@ + #include "omap.h" + #include "sysemu.h" + #include "qemu-timer.h" ++#include "qemu-char.h" + /* We use pc-style serial ports. */ + #include "pc.h" + +-/* Should signal the TCMI */ ++/* Should signal the TCMI/GPMC */ + uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) + { + uint8_t ret; +@@ -86,6 +87,7 @@ struct omap_intr_handler_bank_s { + uint32_t mask; + uint32_t fiq; + uint32_t sens_edge; ++ uint32_t swi; + unsigned char priority[32]; + }; + +@@ -94,11 +96,14 @@ struct omap_intr_handler_s { + qemu_irq parent_intr[2]; + target_phys_addr_t base; + unsigned char nbanks; ++ int level_only; + + /* state */ + uint32_t new_agr[2]; + int sir_intr[2]; +- struct omap_intr_handler_bank_s banks[]; ++ int autoidle; ++ uint32_t mask; ++ struct omap_intr_handler_bank_s bank[]; + }; + + static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) +@@ -113,11 +118,11 @@ static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) + * If all interrupts have the same priority, the default order is IRQ_N, + * IRQ_N-1,...,IRQ_0. */ + for (j = 0; j < s->nbanks; ++j) { +- level = s->banks[j].irqs & ~s->banks[j].mask & +- (is_fiq ? s->banks[j].fiq : ~s->banks[j].fiq); ++ level = s->bank[j].irqs & ~s->bank[j].mask & ++ (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq); + for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, + level >>= f) { +- p = s->banks[j].priority[i]; ++ p = s->bank[j].priority[i]; + if (p <= p_intr) { + p_intr = p; + sir_intr = 32 * j + i; +@@ -134,10 +139,10 @@ static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq) + uint32_t has_intr = 0; + + for (i = 0; i < s->nbanks; ++i) +- has_intr |= s->banks[i].irqs & ~s->banks[i].mask & +- (is_fiq ? s->banks[i].fiq : ~s->banks[i].fiq); ++ has_intr |= s->bank[i].irqs & ~s->bank[i].mask & ++ (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq); + +- if (s->new_agr[is_fiq] && has_intr) { ++ if (s->new_agr[is_fiq] & has_intr & s->mask) { + s->new_agr[is_fiq] = 0; + omap_inth_sir_update(s, is_fiq); + qemu_set_irq(s->parent_intr[is_fiq], 1); +@@ -152,13 +157,13 @@ static void omap_set_intr(void *opaque, int irq, int req) + struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; + uint32_t rise; + +- struct omap_intr_handler_bank_s *bank = &ih->banks[irq >> 5]; ++ struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; + int n = irq & 31; + + if (req) { + rise = ~bank->irqs & (1 << n); + if (~bank->sens_edge & (1 << n)) +- rise &= ~bank->inputs & (1 << n); ++ rise &= ~bank->inputs; + + bank->inputs |= (1 << n); + if (rise) { +@@ -173,13 +178,33 @@ static void omap_set_intr(void *opaque, int irq, int req) + } + } + ++/* Simplified version with no edge detection */ ++static void omap_set_intr_noedge(void *opaque, int irq, int req) ++{ ++ struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; ++ uint32_t rise; ++ ++ struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; ++ int n = irq & 31; ++ ++ if (req) { ++ rise = ~bank->inputs & (1 << n); ++ if (rise) { ++ bank->irqs |= bank->inputs |= rise; ++ omap_inth_update(ih, 0); ++ omap_inth_update(ih, 1); ++ } ++ } else ++ bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi; ++} ++ + static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr) + { + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + int i, offset = addr - s->base; + int bank_no = offset >> 8; + int line_no; +- struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; ++ struct omap_intr_handler_bank_s *bank = &s->bank[bank_no]; + offset &= 0xff; + + switch (offset) { +@@ -194,7 +219,7 @@ static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr) + if (bank_no != 0) + break; + line_no = s->sir_intr[(offset - 0x10) >> 2]; +- bank = &s->banks[line_no >> 5]; ++ bank = &s->bank[line_no >> 5]; + i = line_no & 31; + if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE) + bank->irqs &= ~(1 << i); +@@ -256,7 +281,7 @@ static void omap_inth_write(void *opaque, target_phys_addr_t addr, + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + int i, offset = addr - s->base; + int bank_no = offset >> 8; +- struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; ++ struct omap_intr_handler_bank_s *bank = &s->bank[bank_no]; + offset &= 0xff; + + switch (offset) { +@@ -360,25 +385,31 @@ void omap_inth_reset(struct omap_intr_handler_s *s) + int i; + + for (i = 0; i < s->nbanks; ++i){ +- s->banks[i].irqs = 0x00000000; +- s->banks[i].mask = 0xffffffff; +- s->banks[i].sens_edge = 0x00000000; +- s->banks[i].fiq = 0x00000000; +- s->banks[i].inputs = 0x00000000; +- memset(s->banks[i].priority, 0, sizeof(s->banks[i].priority)); ++ s->bank[i].irqs = 0x00000000; ++ s->bank[i].mask = 0xffffffff; ++ s->bank[i].sens_edge = 0x00000000; ++ s->bank[i].fiq = 0x00000000; ++ s->bank[i].inputs = 0x00000000; ++ s->bank[i].swi = 0x00000000; ++ memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority)); ++ ++ if (s->level_only) ++ s->bank[i].sens_edge = 0xffffffff; + } + + s->new_agr[0] = ~0; + s->new_agr[1] = ~0; + s->sir_intr[0] = 0; + s->sir_intr[1] = 0; ++ s->autoidle = 0; ++ s->mask = ~0; + + qemu_set_irq(s->parent_intr[0], 0); + qemu_set_irq(s->parent_intr[1], 0); + } + + struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, +- unsigned long size, unsigned char nbanks, ++ unsigned long size, unsigned char nbanks, qemu_irq **pins, + qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk) + { + int iomemtype; +@@ -391,6 +422,8 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, + s->base = base; + s->nbanks = nbanks; + s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32); ++ if (pins) ++ *pins = s->pins; + + omap_inth_reset(s); + +@@ -401,6 +434,227 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, + return s; + } + ++static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; ++ int offset = addr - s->base; ++ int bank_no, line_no; ++ struct omap_intr_handler_bank_s *bank = 0; ++ ++ if ((offset & 0xf80) == 0x80) { ++ bank_no = (offset & 0x60) >> 5; ++ if (bank_no < s->nbanks) { ++ offset &= ~0x60; ++ bank = &s->bank[bank_no]; ++ } ++ } ++ ++ switch (offset) { ++ case 0x00: /* INTC_REVISION */ ++ return 0x21; ++ ++ case 0x10: /* INTC_SYSCONFIG */ ++ return (s->autoidle >> 2) & 1; ++ ++ case 0x14: /* INTC_SYSSTATUS */ ++ return 1; /* RESETDONE */ ++ ++ case 0x40: /* INTC_SIR_IRQ */ ++ return s->sir_intr[0]; ++ ++ case 0x44: /* INTC_SIR_FIQ */ ++ return s->sir_intr[1]; ++ ++ case 0x48: /* INTC_CONTROL */ ++ return (!s->mask) << 2; /* GLOBALMASK */ ++ ++ case 0x4c: /* INTC_PROTECTION */ ++ return 0; ++ ++ case 0x50: /* INTC_IDLE */ ++ return s->autoidle & 3; ++ ++ /* Per-bank registers */ ++ case 0x80: /* INTC_ITR */ ++ return bank->inputs; ++ ++ case 0x84: /* INTC_MIR */ ++ return bank->mask; ++ ++ case 0x88: /* INTC_MIR_CLEAR */ ++ case 0x8c: /* INTC_MIR_SET */ ++ return 0; ++ ++ case 0x90: /* INTC_ISR_SET */ ++ return bank->swi; ++ ++ case 0x94: /* INTC_ISR_CLEAR */ ++ return 0; ++ ++ case 0x98: /* INTC_PENDING_IRQ */ ++ return bank->irqs & ~bank->mask & ~bank->fiq; ++ ++ case 0x9c: /* INTC_PENDING_FIQ */ ++ return bank->irqs & ~bank->mask & bank->fiq; ++ ++ /* Per-line registers */ ++ case 0x100 ... 0x300: /* INTC_ILR */ ++ bank_no = (offset - 0x100) >> 7; ++ if (bank_no > s->nbanks) ++ break; ++ bank = &s->bank[bank_no]; ++ line_no = (offset & 0x7f) >> 2; ++ return (bank->priority[line_no] << 2) | ++ ((bank->fiq >> line_no) & 1); ++ } ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap2_inth_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; ++ int offset = addr - s->base; ++ int bank_no, line_no; ++ struct omap_intr_handler_bank_s *bank = 0; ++ ++ if ((offset & 0xf80) == 0x80) { ++ bank_no = (offset & 0x60) >> 5; ++ if (bank_no < s->nbanks) { ++ offset &= ~0x60; ++ bank = &s->bank[bank_no]; ++ } ++ } ++ ++ switch (offset) { ++ case 0x10: /* INTC_SYSCONFIG */ ++ s->autoidle &= 4; ++ s->autoidle |= (value & 1) << 2; ++ if (value & 2) /* SOFTRESET */ ++ omap_inth_reset(s); ++ return; ++ ++ case 0x48: /* INTC_CONTROL */ ++ s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */ ++ if (value & 2) { /* NEWFIQAGR */ ++ qemu_set_irq(s->parent_intr[1], 0); ++ s->new_agr[1] = ~0; ++ omap_inth_update(s, 1); ++ } ++ if (value & 1) { /* NEWIRQAGR */ ++ qemu_set_irq(s->parent_intr[0], 0); ++ s->new_agr[0] = ~0; ++ omap_inth_update(s, 0); ++ } ++ return; ++ ++ case 0x4c: /* INTC_PROTECTION */ ++ /* TODO: Make a bitmap (or sizeof(char)map) of access privileges ++ * for every register, see Chapter 3 and 4 for privileged mode. */ ++ if (value & 1) ++ fprintf(stderr, "%s: protection mode enable attempt\n", ++ __FUNCTION__); ++ return; ++ ++ case 0x50: /* INTC_IDLE */ ++ s->autoidle &= ~3; ++ s->autoidle |= value & 3; ++ return; ++ ++ /* Per-bank registers */ ++ case 0x84: /* INTC_MIR */ ++ bank->mask = value; ++ omap_inth_update(s, 0); ++ omap_inth_update(s, 1); ++ return; ++ ++ case 0x88: /* INTC_MIR_CLEAR */ ++ bank->mask &= ~value; ++ omap_inth_update(s, 0); ++ omap_inth_update(s, 1); ++ return; ++ ++ case 0x8c: /* INTC_MIR_SET */ ++ bank->mask |= value; ++ return; ++ ++ case 0x90: /* INTC_ISR_SET */ ++ bank->irqs |= bank->swi |= value; ++ omap_inth_update(s, 0); ++ omap_inth_update(s, 1); ++ return; ++ ++ case 0x94: /* INTC_ISR_CLEAR */ ++ bank->swi &= ~value; ++ bank->irqs = bank->swi & bank->inputs; ++ return; ++ ++ /* Per-line registers */ ++ case 0x100 ... 0x300: /* INTC_ILR */ ++ bank_no = (offset - 0x100) >> 7; ++ if (bank_no > s->nbanks) ++ break; ++ bank = &s->bank[bank_no]; ++ line_no = (offset & 0x7f) >> 2; ++ bank->priority[line_no] = (value >> 2) & 0x3f; ++ bank->fiq &= ~(1 << line_no); ++ bank->fiq |= (value & 1) << line_no; ++ return; ++ ++ case 0x00: /* INTC_REVISION */ ++ case 0x14: /* INTC_SYSSTATUS */ ++ case 0x40: /* INTC_SIR_IRQ */ ++ case 0x44: /* INTC_SIR_FIQ */ ++ case 0x80: /* INTC_ITR */ ++ case 0x98: /* INTC_PENDING_IRQ */ ++ case 0x9c: /* INTC_PENDING_FIQ */ ++ OMAP_RO_REG(addr); ++ return; ++ } ++ OMAP_BAD_REG(addr); ++} ++ ++static CPUReadMemoryFunc *omap2_inth_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap2_inth_read, ++}; ++ ++static CPUWriteMemoryFunc *omap2_inth_writefn[] = { ++ omap2_inth_write, ++ omap2_inth_write, ++ omap2_inth_write, ++}; ++ ++struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base, ++ int size, int nbanks, qemu_irq **pins, ++ qemu_irq parent_irq, qemu_irq parent_fiq, ++ omap_clk fclk, omap_clk iclk) ++{ ++ int iomemtype; ++ struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) ++ qemu_mallocz(sizeof(struct omap_intr_handler_s) + ++ sizeof(struct omap_intr_handler_bank_s) * nbanks); ++ ++ s->parent_intr[0] = parent_irq; ++ s->parent_intr[1] = parent_fiq; ++ s->base = base; ++ s->nbanks = nbanks; ++ s->level_only = 1; ++ s->pins = qemu_allocate_irqs(omap_set_intr_noedge, s, nbanks * 32); ++ if (pins) ++ *pins = s->pins; ++ ++ omap_inth_reset(s); ++ ++ iomemtype = cpu_register_io_memory(0, omap2_inth_readfn, ++ omap2_inth_writefn, s); ++ cpu_register_physical_memory(s->base, size, iomemtype); ++ ++ return s; ++} ++ + /* MPU OS timers */ + struct omap_mpu_timer_s { + qemu_irq irq; +@@ -1289,6 +1543,8 @@ static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr) + return 0x03310315; + case omap1510: + return 0x03310115; ++ default: ++ cpu_abort(cpu_single_env, "%s: bad mpu model\n", __FUNCTION__); + } + break; + +@@ -1298,6 +1554,8 @@ static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr) + return 0xfb57402f; + case omap1510: + return 0xfb47002f; ++ default: ++ cpu_abort(cpu_single_env, "%s: bad mpu model\n", __FUNCTION__); + } + break; + } +@@ -1722,19 +1980,116 @@ static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base, + /* UARTs */ + struct omap_uart_s { + SerialState *serial; /* TODO */ ++ struct omap_target_agent_s *ta; ++ target_phys_addr_t base; ++ ++ uint8_t eblr; ++ uint8_t syscontrol; ++ uint8_t wkup; ++ uint8_t cfps; + }; + +-static void omap_uart_reset(struct omap_uart_s *s) ++void omap_uart_reset(struct omap_uart_s *s) + { ++ s->eblr = 0x00; ++ s->syscontrol = 0; ++ s->wkup = 0x3f; ++ s->cfps = 0x69; + } + + struct omap_uart_s *omap_uart_init(target_phys_addr_t base, +- qemu_irq irq, omap_clk clk, CharDriverState *chr) ++ qemu_irq irq, omap_clk fclk, omap_clk iclk, ++ qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr) + { + struct omap_uart_s *s = (struct omap_uart_s *) + qemu_mallocz(sizeof(struct omap_uart_s)); +- if (chr) +- s->serial = serial_mm_init(base, 2, irq, chr, 1); ++ ++ s->serial = serial_mm_init(base, 2, irq, chr ?: qemu_chr_open("null"), 1); ++ ++ return s; ++} ++ ++static uint32_t omap_uart_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_uart_s *s = (struct omap_uart_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x48: /* EBLR */ ++ return s->eblr; ++ case 0x50: /* MVR */ ++ return 0x30; ++ case 0x54: /* SYSC */ ++ return s->syscontrol; ++ case 0x58: /* SYSS */ ++ return 1; ++ case 0x5c: /* WER */ ++ return s->wkup; ++ case 0x60: /* CFPS */ ++ return s->cfps; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_uart_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_uart_s *s = (struct omap_uart_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x48: /* EBLR */ ++ s->eblr = value & 0xff; ++ break; ++ case 0x50: /* MVR */ ++ case 0x58: /* SYSS */ ++ OMAP_RO_REG(addr); ++ break; ++ case 0x54: /* SYSC */ ++ s->syscontrol = value & 0x1d; ++ if (value & 2) ++ omap_uart_reset(s); ++ break; ++ case 0x5c: /* WER */ ++ s->wkup = value & 0x7f; ++ break; ++ case 0x60: /* CFPS */ ++ s->cfps = value & 0xff; ++ break; ++ default: ++ OMAP_BAD_REG(addr); ++ } ++} ++ ++static CPUReadMemoryFunc *omap_uart_readfn[] = { ++ omap_uart_read, ++ omap_uart_read, ++ omap_badwidth_read8, ++}; ++ ++static CPUWriteMemoryFunc *omap_uart_writefn[] = { ++ omap_uart_write, ++ omap_uart_write, ++ omap_badwidth_write8, ++}; ++ ++struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta, ++ qemu_irq irq, omap_clk fclk, omap_clk iclk, ++ qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr) ++{ ++ target_phys_addr_t base = omap_l4_attach(ta, 0, 0); ++ struct omap_uart_s *s = omap_uart_init(base, irq, ++ fclk, iclk, txdma, rxdma, chr); ++ int iomemtype = cpu_register_io_memory(0, omap_uart_readfn, ++ omap_uart_writefn, s); ++ ++ s->ta = ta; ++ s->base = base; ++ ++ cpu_register_physical_memory(s->base + 0x20, 0x100, iomemtype); ++ + return s; + } + +@@ -2778,9 +3133,11 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, + void omap_uwire_attach(struct omap_uwire_s *s, + struct uwire_slave_s *slave, int chipselect) + { +- if (chipselect < 0 || chipselect > 3) +- cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n", __FUNCTION__, +- chipselect); ++ if (chipselect < 0 || chipselect > 3) { ++ fprintf(stderr, "%s: Bad chipselect %i\n", ++ __FUNCTION__, chipselect); ++ exit(-1); ++ } + + s->chip[chipselect] = slave; + } +@@ -4123,7 +4481,7 @@ static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu) + } + + /* General chip reset */ +-static void omap_mpu_reset(void *opaque) ++static void omap1_mpu_reset(void *opaque) + { + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + +@@ -4153,7 +4511,7 @@ static void omap_mpu_reset(void *opaque) + omap_uwire_reset(mpu->microwire); + omap_pwl_reset(mpu); + omap_pwt_reset(mpu); +- omap_i2c_reset(mpu->i2c); ++ omap_i2c_reset(mpu->i2c[0]); + omap_rtc_reset(mpu->rtc); + omap_mcbsp_reset(mpu->mcbsp1); + omap_mcbsp_reset(mpu->mcbsp2); +@@ -4205,7 +4563,7 @@ static void omap_setup_dsp_mapping(const struct omap_map_s *map) + } + } + +-static void omap_mpu_wakeup(void *opaque, int irq, int req) ++void omap_mpu_wakeup(void *opaque, int irq, int req) + { + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + +@@ -4213,7 +4571,7 @@ static void omap_mpu_wakeup(void *opaque, int irq, int req) + cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); + } + +-static const struct dma_irq_map omap_dma_irq_map[] = { ++static const struct dma_irq_map omap1_dma_irq_map[] = { + { 0, OMAP_INT_DMA_CH0_6 }, + { 0, OMAP_INT_DMA_CH1_7 }, + { 0, OMAP_INT_DMA_CH2_8 }, +@@ -4307,17 +4665,16 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, + omap_clkm_init(0xfffece00, 0xe1008000, s); + + cpu_irq = arm_pic_init_cpu(s->env); +- s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, ++ s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, &s->irq[0], + cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ], + omap_findclk(s, "arminth_ck")); +- s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, ++ s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, &s->irq[1], + s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ], NULL, + omap_findclk(s, "arminth_ck")); +- s->irq[0] = s->ih[0]->pins; +- s->irq[1] = s->ih[1]->pins; + + for (i = 0; i < 6; i ++) +- dma_irqs[i] = s->irq[omap_dma_irq_map[i].ih][omap_dma_irq_map[i].intr]; ++ dma_irqs[i] = ++ s->irq[omap1_dma_irq_map[i].ih][omap1_dma_irq_map[i].intr]; + s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD], + s, omap_findclk(s, "dma_ck"), omap_dma_3_1); + +@@ -4367,12 +4724,18 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, + + s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1], + omap_findclk(s, "uart1_ck"), ++ omap_findclk(s, "uart1_ck"), ++ s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX], + serial_hds[0]); + s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2], + omap_findclk(s, "uart2_ck"), ++ omap_findclk(s, "uart2_ck"), ++ s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX], + serial_hds[0] ? serial_hds[1] : 0); + s->uart[2] = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3], + omap_findclk(s, "uart3_ck"), ++ omap_findclk(s, "uart3_ck"), ++ s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX], + serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0); + + omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1")); +@@ -4401,7 +4764,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, + omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck")); + omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck")); + +- s->i2c = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], ++ s->i2c[0] = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], + &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); + + s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], +@@ -4435,7 +4798,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, + omap_setup_dsp_mapping(omap15xx_dsp_mm); + omap_setup_mpui_io(s); + +- qemu_register_reset(omap_mpu_reset, s); ++ qemu_register_reset(omap1_mpu_reset, s); + + return s; + } +diff --git a/hw/omap2.c b/hw/omap2.c +new file mode 100644 +index 0000000..1e51197 +--- /dev/null ++++ b/hw/omap2.c +@@ -0,0 +1,3872 @@ ++/* ++ * TI OMAP processors emulation. ++ * ++ * Copyright (C) 2007-2008 Nokia Corporation ++ * Written by Andrzej Zaborowski <andrew@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++#include "hw.h" ++#include "arm-misc.h" ++#include "omap.h" ++#include "sysemu.h" ++#include "qemu-timer.h" ++#include "qemu-char.h" ++#include "flash.h" ++/* We use pc-style serial ports. */ ++#include "pc.h" ++ ++/* GP timers */ ++struct omap_gp_timer_s { ++ qemu_irq irq; ++ qemu_irq wkup; ++ qemu_irq in; ++ qemu_irq out; ++ omap_clk clk; ++ target_phys_addr_t base; ++ QEMUTimer *timer; ++ QEMUTimer *match; ++ struct omap_target_agent_s *ta; ++ ++ int in_val; ++ int out_val; ++ int64_t time; ++ int64_t rate; ++ int64_t ticks_per_sec; ++ ++ int16_t config; ++ int status; ++ int it_ena; ++ int wu_ena; ++ int enable; ++ int inout; ++ int capt2; ++ int pt; ++ enum { ++ gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both ++ } trigger; ++ enum { ++ gpt_capture_none, gpt_capture_rising, ++ gpt_capture_falling, gpt_capture_both ++ } capture; ++ int scpwm; ++ int ce; ++ int pre; ++ int ptv; ++ int ar; ++ int st; ++ int posted; ++ uint32_t val; ++ uint32_t load_val; ++ uint32_t capture_val[2]; ++ uint32_t match_val; ++ int capt_num; ++ ++ uint16_t writeh; /* LSB */ ++ uint16_t readh; /* MSB */ ++}; ++ ++#define GPT_TCAR_IT (1 << 2) ++#define GPT_OVF_IT (1 << 1) ++#define GPT_MAT_IT (1 << 0) ++ ++static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it) ++{ ++ if (timer->it_ena & it) { ++ if (!timer->status) ++ qemu_irq_raise(timer->irq); ++ ++ timer->status |= it; ++ /* Or are the status bits set even when masked? ++ * i.e. is masking applied before or after the status register? */ ++ } ++ ++ if (timer->wu_ena & it) ++ qemu_irq_pulse(timer->wkup); ++} ++ ++static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level) ++{ ++ if (!timer->inout && timer->out_val != level) { ++ timer->out_val = level; ++ qemu_set_irq(timer->out, level); ++ } ++} ++ ++static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer) ++{ ++ uint64_t distance; ++ ++ if (timer->st && timer->rate) { ++ distance = qemu_get_clock(vm_clock) - timer->time; ++ distance = muldiv64(distance, timer->rate, timer->ticks_per_sec); ++ ++ if (distance >= 0xffffffff - timer->val) ++ return 0xffffffff; ++ else ++ return timer->val + distance; ++ } else ++ return timer->val; ++} ++ ++static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer) ++{ ++ if (timer->st) { ++ timer->val = omap_gp_timer_read(timer); ++ timer->time = qemu_get_clock(vm_clock); ++ } ++} ++ ++static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer) ++{ ++ int64_t expires, matches; ++ ++ if (timer->st && timer->rate) { ++ expires = muldiv64(0x100000000ll - timer->val, ++ timer->ticks_per_sec, timer->rate); ++ qemu_mod_timer(timer->timer, timer->time + expires); ++ ++ if (timer->ce && timer->match_val >= timer->val) { ++ matches = muldiv64(timer->match_val - timer->val, ++ timer->ticks_per_sec, timer->rate); ++ qemu_mod_timer(timer->match, timer->time + matches); ++ } else ++ qemu_del_timer(timer->match); ++ } else { ++ qemu_del_timer(timer->timer); ++ qemu_del_timer(timer->match); ++ omap_gp_timer_out(timer, timer->scpwm); ++ } ++} ++ ++static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer) ++{ ++ if (timer->pt) ++ /* TODO in overflow-and-match mode if the first event to ++ * occurs is the match, don't toggle. */ ++ omap_gp_timer_out(timer, !timer->out_val); ++ else ++ /* TODO inverted pulse on timer->out_val == 1? */ ++ qemu_irq_pulse(timer->out); ++} ++ ++static void omap_gp_timer_tick(void *opaque) ++{ ++ struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; ++ ++ if (!timer->ar) { ++ timer->st = 0; ++ timer->val = 0; ++ } else { ++ timer->val = timer->load_val; ++ timer->time = qemu_get_clock(vm_clock); ++ } ++ ++ if (timer->trigger == gpt_trigger_overflow || ++ timer->trigger == gpt_trigger_both) ++ omap_gp_timer_trigger(timer); ++ ++ omap_gp_timer_intr(timer, GPT_OVF_IT); ++ omap_gp_timer_update(timer); ++} ++ ++static void omap_gp_timer_match(void *opaque) ++{ ++ struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; ++ ++ if (timer->trigger == gpt_trigger_both) ++ omap_gp_timer_trigger(timer); ++ ++ omap_gp_timer_intr(timer, GPT_MAT_IT); ++} ++ ++static void omap_gp_timer_input(void *opaque, int line, int on) ++{ ++ struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; ++ int trigger; ++ ++ switch (s->capture) { ++ default: ++ case gpt_capture_none: ++ trigger = 0; ++ break; ++ case gpt_capture_rising: ++ trigger = !s->in_val && on; ++ break; ++ case gpt_capture_falling: ++ trigger = s->in_val && !on; ++ break; ++ case gpt_capture_both: ++ trigger = (s->in_val == !on); ++ break; ++ } ++ s->in_val = on; ++ ++ if (s->inout && trigger && s->capt_num < 2) { ++ s->capture_val[s->capt_num] = omap_gp_timer_read(s); ++ ++ if (s->capt2 == s->capt_num ++) ++ omap_gp_timer_intr(s, GPT_TCAR_IT); ++ } ++} ++ ++static void omap_gp_timer_clk_update(void *opaque, int line, int on) ++{ ++ struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; ++ ++ omap_gp_timer_sync(timer); ++ timer->rate = on ? omap_clk_getrate(timer->clk) : 0; ++ omap_gp_timer_update(timer); ++} ++ ++static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer) ++{ ++ omap_clk_adduser(timer->clk, ++ qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]); ++ timer->rate = omap_clk_getrate(timer->clk); ++} ++ ++static void omap_gp_timer_reset(struct omap_gp_timer_s *s) ++{ ++ s->config = 0x000; ++ s->status = 0; ++ s->it_ena = 0; ++ s->wu_ena = 0; ++ s->inout = 0; ++ s->capt2 = 0; ++ s->capt_num = 0; ++ s->pt = 0; ++ s->trigger = gpt_trigger_none; ++ s->capture = gpt_capture_none; ++ s->scpwm = 0; ++ s->ce = 0; ++ s->pre = 0; ++ s->ptv = 0; ++ s->ar = 0; ++ s->st = 0; ++ s->posted = 1; ++ s->val = 0x00000000; ++ s->load_val = 0x00000000; ++ s->capture_val[0] = 0x00000000; ++ s->capture_val[1] = 0x00000000; ++ s->match_val = 0x00000000; ++ omap_gp_timer_update(s); ++} ++ ++static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x00: /* TIDR */ ++ return 0x21; ++ ++ case 0x10: /* TIOCP_CFG */ ++ return s->config; ++ ++ case 0x14: /* TISTAT */ ++ /* ??? When's this bit reset? */ ++ return 1; /* RESETDONE */ ++ ++ case 0x18: /* TISR */ ++ return s->status; ++ ++ case 0x1c: /* TIER */ ++ return s->it_ena; ++ ++ case 0x20: /* TWER */ ++ return s->wu_ena; ++ ++ case 0x24: /* TCLR */ ++ return (s->inout << 14) | ++ (s->capt2 << 13) | ++ (s->pt << 12) | ++ (s->trigger << 10) | ++ (s->capture << 8) | ++ (s->scpwm << 7) | ++ (s->ce << 6) | ++ (s->pre << 5) | ++ (s->ptv << 2) | ++ (s->ar << 1) | ++ (s->st << 0); ++ ++ case 0x28: /* TCRR */ ++ return omap_gp_timer_read(s); ++ ++ case 0x2c: /* TLDR */ ++ return s->load_val; ++ ++ case 0x30: /* TTGR */ ++ return 0xffffffff; ++ ++ case 0x34: /* TWPS */ ++ return 0x00000000; /* No posted writes pending. */ ++ ++ case 0x38: /* TMAR */ ++ return s->match_val; ++ ++ case 0x3c: /* TCAR1 */ ++ return s->capture_val[0]; ++ ++ case 0x40: /* TSICR */ ++ return s->posted << 2; ++ ++ case 0x44: /* TCAR2 */ ++ return s->capture_val[1]; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; ++ uint32_t ret; ++ ++ if (addr & 2) ++ return s->readh; ++ else { ++ ret = omap_gp_timer_readw(opaque, addr); ++ s->readh = ret >> 16; ++ return ret & 0xffff; ++ } ++} ++ ++static CPUReadMemoryFunc *omap_gp_timer_readfn[] = { ++ omap_badwidth_read32, ++ omap_gp_timer_readh, ++ omap_gp_timer_readw, ++}; ++ ++static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x00: /* TIDR */ ++ case 0x14: /* TISTAT */ ++ case 0x34: /* TWPS */ ++ case 0x3c: /* TCAR1 */ ++ case 0x44: /* TCAR2 */ ++ OMAP_RO_REG(addr); ++ break; ++ ++ case 0x10: /* TIOCP_CFG */ ++ s->config = value & 0x33d; ++ if (((value >> 3) & 3) == 3) /* IDLEMODE */ ++ fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n", ++ __FUNCTION__); ++ if (value & 2) /* SOFTRESET */ ++ omap_gp_timer_reset(s); ++ break; ++ ++ case 0x18: /* TISR */ ++ if (value & GPT_TCAR_IT) ++ s->capt_num = 0; ++ if (s->status && !(s->status &= ~value)) ++ qemu_irq_lower(s->irq); ++ break; ++ ++ case 0x1c: /* TIER */ ++ s->it_ena = value & 7; ++ break; ++ ++ case 0x20: /* TWER */ ++ s->wu_ena = value & 7; ++ break; ++ ++ case 0x24: /* TCLR */ ++ omap_gp_timer_sync(s); ++ s->inout = (value >> 14) & 1; ++ s->capt2 = (value >> 13) & 1; ++ s->pt = (value >> 12) & 1; ++ s->trigger = (value >> 10) & 3; ++ if (s->capture == gpt_capture_none && ++ ((value >> 8) & 3) != gpt_capture_none) ++ s->capt_num = 0; ++ s->capture = (value >> 8) & 3; ++ s->scpwm = (value >> 7) & 1; ++ s->ce = (value >> 6) & 1; ++ s->pre = (value >> 5) & 1; ++ s->ptv = (value >> 2) & 7; ++ s->ar = (value >> 1) & 1; ++ s->st = (value >> 0) & 1; ++ if (s->inout && s->trigger != gpt_trigger_none) ++ fprintf(stderr, "%s: GP timer pin must be an output " ++ "for this trigger mode\n", __FUNCTION__); ++ if (!s->inout && s->capture != gpt_capture_none) ++ fprintf(stderr, "%s: GP timer pin must be an input " ++ "for this capture mode\n", __FUNCTION__); ++ if (s->trigger == gpt_trigger_none) ++ omap_gp_timer_out(s, s->scpwm); ++ /* TODO: make sure this doesn't overflow 32-bits */ ++ s->ticks_per_sec = ticks_per_sec << (s->pre ? s->ptv + 1 : 0); ++ omap_gp_timer_update(s); ++ break; ++ ++ case 0x28: /* TCRR */ ++ s->time = qemu_get_clock(vm_clock); ++ s->val = value; ++ omap_gp_timer_update(s); ++ break; ++ ++ case 0x2c: /* TLDR */ ++ s->load_val = value; ++ break; ++ ++ case 0x30: /* TTGR */ ++ s->time = qemu_get_clock(vm_clock); ++ s->val = s->load_val; ++ omap_gp_timer_update(s); ++ break; ++ ++ case 0x38: /* TMAR */ ++ omap_gp_timer_sync(s); ++ s->match_val = value; ++ omap_gp_timer_update(s); ++ break; ++ ++ case 0x40: /* TSICR */ ++ s->posted = (value >> 2) & 1; ++ if (value & 2) /* How much exactly are we supposed to reset? */ ++ omap_gp_timer_reset(s); ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ } ++} ++ ++static void omap_gp_timer_writeh(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; ++ ++ if (addr & 2) ++ return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh); ++ else ++ s->writeh = (uint16_t) value; ++} ++ ++static CPUWriteMemoryFunc *omap_gp_timer_writefn[] = { ++ omap_badwidth_write32, ++ omap_gp_timer_writeh, ++ omap_gp_timer_write, ++}; ++ ++struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, ++ qemu_irq irq, omap_clk fclk, omap_clk iclk) ++{ ++ int iomemtype; ++ struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) ++ qemu_mallocz(sizeof(struct omap_gp_timer_s)); ++ ++ s->ta = ta; ++ s->irq = irq; ++ s->clk = fclk; ++ s->timer = qemu_new_timer(vm_clock, omap_gp_timer_tick, s); ++ s->match = qemu_new_timer(vm_clock, omap_gp_timer_match, s); ++ s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0]; ++ omap_gp_timer_reset(s); ++ omap_gp_timer_clk_setup(s); ++ ++ iomemtype = cpu_register_io_memory(0, omap_gp_timer_readfn, ++ omap_gp_timer_writefn, s); ++ s->base = omap_l4_attach(ta, 0, iomemtype); ++ ++ return s; ++} ++ ++/* 32-kHz Sync Timer of the OMAP2 */ ++static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) { ++ return muldiv64(qemu_get_clock(vm_clock), 0x8000, ticks_per_sec); ++} ++ ++static void omap_synctimer_reset(struct omap_synctimer_s *s) ++{ ++ s->val = omap_synctimer_read(s); ++} ++ ++static uint32_t omap_synctimer_readw(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x00: /* 32KSYNCNT_REV */ ++ return 0x21; ++ ++ case 0x10: /* CR */ ++ return omap_synctimer_read(s) - s->val; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static uint32_t omap_synctimer_readh(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; ++ uint32_t ret; ++ ++ if (addr & 2) ++ return s->readh; ++ else { ++ ret = omap_synctimer_readw(opaque, addr); ++ s->readh = ret >> 16; ++ return ret & 0xffff; ++ } ++} ++ ++static CPUReadMemoryFunc *omap_synctimer_readfn[] = { ++ omap_badwidth_read32, ++ omap_synctimer_readh, ++ omap_synctimer_readw, ++}; ++ ++static void omap_synctimer_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ OMAP_BAD_REG(addr); ++} ++ ++static CPUWriteMemoryFunc *omap_synctimer_writefn[] = { ++ omap_badwidth_write32, ++ omap_synctimer_write, ++ omap_synctimer_write, ++}; ++ ++void omap_synctimer_init(struct omap_target_agent_s *ta, ++ struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk) ++{ ++ struct omap_synctimer_s *s = &mpu->synctimer; ++ ++ omap_synctimer_reset(s); ++ s->base = omap_l4_attach(ta, 0, cpu_register_io_memory(0, ++ omap_synctimer_readfn, omap_synctimer_writefn, s)); ++} ++ ++/* General-Purpose Interface of OMAP2 */ ++struct omap2_gpio_s { ++ target_phys_addr_t base; ++ qemu_irq irq[2]; ++ qemu_irq wkup; ++ qemu_irq *in; ++ qemu_irq handler[32]; ++ ++ uint8_t config[2]; ++ uint32_t inputs; ++ uint32_t outputs; ++ uint32_t dir; ++ uint32_t level[2]; ++ uint32_t edge[2]; ++ uint32_t mask[2]; ++ uint32_t wumask; ++ uint32_t ints[2]; ++ uint32_t debounce; ++ uint8_t delay; ++}; ++ ++static inline void omap_gpio_module_int_update(struct omap2_gpio_s *s, ++ int line) ++{ ++ qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]); ++} ++ ++static void omap_gpio_module_wake(struct omap2_gpio_s *s, int line) ++{ ++ if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */ ++ return; ++ if (!(s->config[0] & (3 << 3))) /* Force Idle */ ++ return; ++ if (!(s->wumask & (1 << line))) ++ return; ++ ++ qemu_irq_raise(s->wkup); ++} ++ ++static inline void omap_gpio_module_out_update(struct omap2_gpio_s *s, ++ uint32_t diff) ++{ ++ int ln; ++ ++ s->outputs ^= diff; ++ diff &= ~s->dir; ++ while ((ln = ffs(diff))) { ++ ln --; ++ qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1); ++ diff &= ~(1 << ln); ++ } ++} ++ ++static void omap_gpio_module_level_update(struct omap2_gpio_s *s, int line) ++{ ++ s->ints[line] |= s->dir & ++ ((s->inputs & s->level[1]) | (~s->inputs & s->level[0])); ++ omap_gpio_module_int_update(s, line); ++} ++ ++static inline void omap_gpio_module_int(struct omap2_gpio_s *s, int line) ++{ ++ s->ints[0] |= 1 << line; ++ omap_gpio_module_int_update(s, 0); ++ s->ints[1] |= 1 << line; ++ omap_gpio_module_int_update(s, 1); ++ omap_gpio_module_wake(s, line); ++} ++ ++static void omap_gpio_module_set(void *opaque, int line, int level) ++{ ++ struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; ++ ++ if (level) { ++ if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1])) ++ omap_gpio_module_int(s, line); ++ s->inputs |= 1 << line; ++ } else { ++ if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0])) ++ omap_gpio_module_int(s, line); ++ s->inputs &= ~(1 << line); ++ } ++} ++ ++static void omap_gpio_module_reset(struct omap2_gpio_s *s) ++{ ++ s->config[0] = 0; ++ s->config[1] = 2; ++ s->ints[0] = 0; ++ s->ints[1] = 0; ++ s->mask[0] = 0; ++ s->mask[1] = 0; ++ s->wumask = 0; ++ s->dir = ~0; ++ s->level[0] = 0; ++ s->level[1] = 0; ++ s->edge[0] = 0; ++ s->edge[1] = 0; ++ s->debounce = 0; ++ s->delay = 0; ++} ++ ++static uint32_t omap_gpio_module_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x00: /* GPIO_REVISION */ ++ return 0x18; ++ ++ case 0x10: /* GPIO_SYSCONFIG */ ++ return s->config[0]; ++ ++ case 0x14: /* GPIO_SYSSTATUS */ ++ return 0x01; ++ ++ case 0x18: /* GPIO_IRQSTATUS1 */ ++ return s->ints[0]; ++ ++ case 0x1c: /* GPIO_IRQENABLE1 */ ++ case 0x60: /* GPIO_CLEARIRQENABLE1 */ ++ case 0x64: /* GPIO_SETIRQENABLE1 */ ++ return s->mask[0]; ++ ++ case 0x20: /* GPIO_WAKEUPENABLE */ ++ case 0x80: /* GPIO_CLEARWKUENA */ ++ case 0x84: /* GPIO_SETWKUENA */ ++ return s->wumask; ++ ++ case 0x28: /* GPIO_IRQSTATUS2 */ ++ return s->ints[1]; ++ ++ case 0x2c: /* GPIO_IRQENABLE2 */ ++ case 0x70: /* GPIO_CLEARIRQENABLE2 */ ++ case 0x74: /* GPIO_SETIREQNEABLE2 */ ++ return s->mask[1]; ++ ++ case 0x30: /* GPIO_CTRL */ ++ return s->config[1]; ++ ++ case 0x34: /* GPIO_OE */ ++ return s->dir; ++ ++ case 0x38: /* GPIO_DATAIN */ ++ return s->inputs; ++ ++ case 0x3c: /* GPIO_DATAOUT */ ++ case 0x90: /* GPIO_CLEARDATAOUT */ ++ case 0x94: /* GPIO_SETDATAOUT */ ++ return s->outputs; ++ ++ case 0x40: /* GPIO_LEVELDETECT0 */ ++ return s->level[0]; ++ ++ case 0x44: /* GPIO_LEVELDETECT1 */ ++ return s->level[1]; ++ ++ case 0x48: /* GPIO_RISINGDETECT */ ++ return s->edge[0]; ++ ++ case 0x4c: /* GPIO_FALLINGDETECT */ ++ return s->edge[1]; ++ ++ case 0x50: /* GPIO_DEBOUNCENABLE */ ++ return s->debounce; ++ ++ case 0x54: /* GPIO_DEBOUNCINGTIME */ ++ return s->delay; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_gpio_module_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; ++ int offset = addr - s->base; ++ uint32_t diff; ++ int ln; ++ ++ switch (offset) { ++ case 0x00: /* GPIO_REVISION */ ++ case 0x14: /* GPIO_SYSSTATUS */ ++ case 0x38: /* GPIO_DATAIN */ ++ OMAP_RO_REG(addr); ++ break; ++ ++ case 0x10: /* GPIO_SYSCONFIG */ ++ if (((value >> 3) & 3) == 3) ++ fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__); ++ if (value & 2) ++ omap_gpio_module_reset(s); ++ s->config[0] = value & 0x1d; ++ break; ++ ++ case 0x18: /* GPIO_IRQSTATUS1 */ ++ if (s->ints[0] & value) { ++ s->ints[0] &= ~value; ++ omap_gpio_module_level_update(s, 0); ++ } ++ break; ++ ++ case 0x1c: /* GPIO_IRQENABLE1 */ ++ s->mask[0] = value; ++ omap_gpio_module_int_update(s, 0); ++ break; ++ ++ case 0x20: /* GPIO_WAKEUPENABLE */ ++ s->wumask = value; ++ break; ++ ++ case 0x28: /* GPIO_IRQSTATUS2 */ ++ if (s->ints[1] & value) { ++ s->ints[1] &= ~value; ++ omap_gpio_module_level_update(s, 1); ++ } ++ break; ++ ++ case 0x2c: /* GPIO_IRQENABLE2 */ ++ s->mask[1] = value; ++ omap_gpio_module_int_update(s, 1); ++ break; ++ ++ case 0x30: /* GPIO_CTRL */ ++ s->config[1] = value & 7; ++ break; ++ ++ case 0x34: /* GPIO_OE */ ++ diff = s->outputs & (s->dir ^ value); ++ s->dir = value; ++ ++ value = s->outputs & ~s->dir; ++ while ((ln = ffs(diff))) { ++ diff &= ~(1 <<-- ln); ++ qemu_set_irq(s->handler[ln], (value >> ln) & 1); ++ } ++ ++ omap_gpio_module_level_update(s, 0); ++ omap_gpio_module_level_update(s, 1); ++ break; ++ ++ case 0x3c: /* GPIO_DATAOUT */ ++ omap_gpio_module_out_update(s, s->outputs ^ value); ++ break; ++ ++ case 0x40: /* GPIO_LEVELDETECT0 */ ++ s->level[0] = value; ++ omap_gpio_module_level_update(s, 0); ++ omap_gpio_module_level_update(s, 1); ++ break; ++ ++ case 0x44: /* GPIO_LEVELDETECT1 */ ++ s->level[1] = value; ++ omap_gpio_module_level_update(s, 0); ++ omap_gpio_module_level_update(s, 1); ++ break; ++ ++ case 0x48: /* GPIO_RISINGDETECT */ ++ s->edge[0] = value; ++ break; ++ ++ case 0x4c: /* GPIO_FALLINGDETECT */ ++ s->edge[1] = value; ++ break; ++ ++ case 0x50: /* GPIO_DEBOUNCENABLE */ ++ s->debounce = value; ++ break; ++ ++ case 0x54: /* GPIO_DEBOUNCINGTIME */ ++ s->delay = value; ++ break; ++ ++ case 0x60: /* GPIO_CLEARIRQENABLE1 */ ++ s->mask[0] &= ~value; ++ omap_gpio_module_int_update(s, 0); ++ break; ++ ++ case 0x64: /* GPIO_SETIRQENABLE1 */ ++ s->mask[0] |= value; ++ omap_gpio_module_int_update(s, 0); ++ break; ++ ++ case 0x70: /* GPIO_CLEARIRQENABLE2 */ ++ s->mask[1] &= ~value; ++ omap_gpio_module_int_update(s, 1); ++ break; ++ ++ case 0x74: /* GPIO_SETIREQNEABLE2 */ ++ s->mask[1] |= value; ++ omap_gpio_module_int_update(s, 1); ++ break; ++ ++ case 0x80: /* GPIO_CLEARWKUENA */ ++ s->wumask &= ~value; ++ break; ++ ++ case 0x84: /* GPIO_SETWKUENA */ ++ s->wumask |= value; ++ break; ++ ++ case 0x90: /* GPIO_CLEARDATAOUT */ ++ omap_gpio_module_out_update(s, s->outputs & value); ++ break; ++ ++ case 0x94: /* GPIO_SETDATAOUT */ ++ omap_gpio_module_out_update(s, ~s->outputs & value); ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return; ++ } ++} ++ ++static uint32_t omap_gpio_module_readp(void *opaque, target_phys_addr_t addr) ++{ ++ return omap_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3); ++} ++ ++static void omap_gpio_module_writep(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; ++ int offset = addr - s->base; ++ uint32_t cur = 0; ++ uint32_t mask = 0xffff; ++ ++ switch (offset & ~3) { ++ case 0x00: /* GPIO_REVISION */ ++ case 0x14: /* GPIO_SYSSTATUS */ ++ case 0x38: /* GPIO_DATAIN */ ++ OMAP_RO_REG(addr); ++ break; ++ ++ case 0x10: /* GPIO_SYSCONFIG */ ++ case 0x1c: /* GPIO_IRQENABLE1 */ ++ case 0x20: /* GPIO_WAKEUPENABLE */ ++ case 0x2c: /* GPIO_IRQENABLE2 */ ++ case 0x30: /* GPIO_CTRL */ ++ case 0x34: /* GPIO_OE */ ++ case 0x3c: /* GPIO_DATAOUT */ ++ case 0x40: /* GPIO_LEVELDETECT0 */ ++ case 0x44: /* GPIO_LEVELDETECT1 */ ++ case 0x48: /* GPIO_RISINGDETECT */ ++ case 0x4c: /* GPIO_FALLINGDETECT */ ++ case 0x50: /* GPIO_DEBOUNCENABLE */ ++ case 0x54: /* GPIO_DEBOUNCINGTIME */ ++ cur = omap_gpio_module_read(opaque, addr & ~3) & ++ ~(mask << ((addr & 3) << 3)); ++ ++ /* Fall through. */ ++ case 0x18: /* GPIO_IRQSTATUS1 */ ++ case 0x28: /* GPIO_IRQSTATUS2 */ ++ case 0x60: /* GPIO_CLEARIRQENABLE1 */ ++ case 0x64: /* GPIO_SETIRQENABLE1 */ ++ case 0x70: /* GPIO_CLEARIRQENABLE2 */ ++ case 0x74: /* GPIO_SETIREQNEABLE2 */ ++ case 0x80: /* GPIO_CLEARWKUENA */ ++ case 0x84: /* GPIO_SETWKUENA */ ++ case 0x90: /* GPIO_CLEARDATAOUT */ ++ case 0x94: /* GPIO_SETDATAOUT */ ++ value <<= (addr & 3) << 3; ++ omap_gpio_module_write(opaque, addr, cur | value); ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return; ++ } ++} ++ ++static CPUReadMemoryFunc *omap_gpio_module_readfn[] = { ++ omap_gpio_module_readp, ++ omap_gpio_module_readp, ++ omap_gpio_module_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_gpio_module_writefn[] = { ++ omap_gpio_module_writep, ++ omap_gpio_module_writep, ++ omap_gpio_module_write, ++}; ++ ++static void omap_gpio_module_init(struct omap2_gpio_s *s, ++ struct omap_target_agent_s *ta, int region, ++ qemu_irq mpu, qemu_irq dsp, qemu_irq wkup, ++ omap_clk fclk, omap_clk iclk) ++{ ++ int iomemtype; ++ ++ s->irq[0] = mpu; ++ s->irq[1] = dsp; ++ s->wkup = wkup; ++ s->in = qemu_allocate_irqs(omap_gpio_module_set, s, 32); ++ ++ iomemtype = cpu_register_io_memory(0, omap_gpio_module_readfn, ++ omap_gpio_module_writefn, s); ++ s->base = omap_l4_attach(ta, region, iomemtype); ++} ++ ++struct omap_gpif_s { ++ struct omap2_gpio_s module[5]; ++ int modules; ++ ++ target_phys_addr_t topbase; ++ int autoidle; ++ int gpo; ++}; ++ ++static void omap_gpif_reset(struct omap_gpif_s *s) ++{ ++ int i; ++ ++ for (i = 0; i < s->modules; i ++) ++ omap_gpio_module_reset(s->module + i); ++ ++ s->autoidle = 0; ++ s->gpo = 0; ++} ++ ++static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; ++ int offset = addr - s->topbase; ++ ++ switch (offset) { ++ case 0x00: /* IPGENERICOCPSPL_REVISION */ ++ return 0x18; ++ ++ case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ ++ return s->autoidle; ++ ++ case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ ++ return 0x01; ++ ++ case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ ++ return 0x00; ++ ++ case 0x40: /* IPGENERICOCPSPL_GPO */ ++ return s->gpo; ++ ++ case 0x50: /* IPGENERICOCPSPL_GPI */ ++ return 0x00; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; ++ int offset = addr - s->topbase; ++ ++ switch (offset) { ++ case 0x00: /* IPGENERICOCPSPL_REVISION */ ++ case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ ++ case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ ++ case 0x50: /* IPGENERICOCPSPL_GPI */ ++ OMAP_RO_REG(addr); ++ break; ++ ++ case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ ++ if (value & (1 << 1)) /* SOFTRESET */ ++ omap_gpif_reset(s); ++ s->autoidle = value & 1; ++ break; ++ ++ case 0x40: /* IPGENERICOCPSPL_GPO */ ++ s->gpo = value & 1; ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return; ++ } ++} ++ ++static CPUReadMemoryFunc *omap_gpif_top_readfn[] = { ++ omap_gpif_top_read, ++ omap_gpif_top_read, ++ omap_gpif_top_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_gpif_top_writefn[] = { ++ omap_gpif_top_write, ++ omap_gpif_top_write, ++ omap_gpif_top_write, ++}; ++ ++struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta, ++ qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules) ++{ ++ int iomemtype, i; ++ struct omap_gpif_s *s = (struct omap_gpif_s *) ++ qemu_mallocz(sizeof(struct omap_gpif_s)); ++ int region[4] = { 0, 2, 4, 5 }; ++ ++ s->modules = modules; ++ for (i = 0; i < modules; i ++) ++ omap_gpio_module_init(s->module + i, ta, region[i], ++ irq[i], 0, 0, fclk[i], iclk); ++ ++ omap_gpif_reset(s); ++ ++ iomemtype = cpu_register_io_memory(0, omap_gpif_top_readfn, ++ omap_gpif_top_writefn, s); ++ s->topbase = omap_l4_attach(ta, 1, iomemtype); ++ ++ return s; ++} ++ ++qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start) ++{ ++ if (start >= s->modules * 32 || start < 0) ++ cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", ++ __FUNCTION__, start); ++ return s->module[start >> 5].in + (start & 31); ++} ++ ++void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler) ++{ ++ if (line >= s->modules * 32 || line < 0) ++ cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); ++ s->module[line >> 5].handler[line & 31] = handler; ++} ++ ++/* Multichannel SPI */ ++struct omap_mcspi_s { ++ target_phys_addr_t base; ++ qemu_irq irq; ++ int chnum; ++ ++ uint32_t sysconfig; ++ uint32_t systest; ++ uint32_t irqst; ++ uint32_t irqen; ++ uint32_t wken; ++ uint32_t control; ++ ++ struct omap_mcspi_ch_s { ++ qemu_irq txdrq; ++ qemu_irq rxdrq; ++ uint32_t (*txrx)(void *opaque, uint32_t); ++ void *opaque; ++ ++ uint32_t tx; ++ uint32_t rx; ++ ++ uint32_t config; ++ uint32_t status; ++ uint32_t control; ++ } ch[4]; ++}; ++ ++static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s) ++{ ++ qemu_set_irq(s->irq, s->irqst & s->irqen); ++} ++ ++static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch) ++{ ++ qemu_set_irq(ch->txdrq, ++ (ch->control & 1) && /* EN */ ++ (ch->config & (1 << 14)) && /* DMAW */ ++ (ch->status & (1 << 1)) && /* TXS */ ++ ((ch->config >> 12) & 3) != 1); /* TRM */ ++ qemu_set_irq(ch->rxdrq, ++ (ch->control & 1) && /* EN */ ++ (ch->config & (1 << 15)) && /* DMAW */ ++ (ch->status & (1 << 0)) && /* RXS */ ++ ((ch->config >> 12) & 3) != 2); /* TRM */ ++} ++ ++static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum) ++{ ++ struct omap_mcspi_ch_s *ch = s->ch + chnum; ++ ++ if (!(ch->control & 1)) /* EN */ ++ return; ++ if ((ch->status & (1 << 0)) && /* RXS */ ++ ((ch->config >> 12) & 3) != 2 && /* TRM */ ++ !(ch->config & (1 << 19))) /* TURBO */ ++ goto intr_update; ++ if ((ch->status & (1 << 1)) && /* TXS */ ++ ((ch->config >> 12) & 3) != 1) /* TRM */ ++ goto intr_update; ++ ++ if (!(s->control & 1) || /* SINGLE */ ++ (ch->config & (1 << 20))) { /* FORCE */ ++ if (ch->txrx) ++ ch->rx = ch->txrx(ch->opaque, ch->tx); ++ } ++ ++ ch->tx = 0; ++ ch->status |= 1 << 2; /* EOT */ ++ ch->status |= 1 << 1; /* TXS */ ++ if (((ch->config >> 12) & 3) != 2) /* TRM */ ++ ch->status |= 1 << 0; /* RXS */ ++ ++intr_update: ++ if ((ch->status & (1 << 0)) && /* RXS */ ++ ((ch->config >> 12) & 3) != 2 && /* TRM */ ++ !(ch->config & (1 << 19))) /* TURBO */ ++ s->irqst |= 1 << (2 + 4 * chnum); /* RX_FULL */ ++ if ((ch->status & (1 << 1)) && /* TXS */ ++ ((ch->config >> 12) & 3) != 1) /* TRM */ ++ s->irqst |= 1 << (0 + 4 * chnum); /* TX_EMPTY */ ++ omap_mcspi_interrupt_update(s); ++ omap_mcspi_dmarequest_update(ch); ++} ++ ++static void omap_mcspi_reset(struct omap_mcspi_s *s) ++{ ++ int ch; ++ ++ s->sysconfig = 0; ++ s->systest = 0; ++ s->irqst = 0; ++ s->irqen = 0; ++ s->wken = 0; ++ s->control = 4; ++ ++ for (ch = 0; ch < 4; ch ++) { ++ s->ch[ch].config = 0x060000; ++ s->ch[ch].status = 2; /* TXS */ ++ s->ch[ch].control = 0; ++ ++ omap_mcspi_dmarequest_update(s->ch + ch); ++ } ++ ++ omap_mcspi_interrupt_update(s); ++} ++ ++static uint32_t omap_mcspi_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque; ++ int offset = addr - s->base; ++ int ch = 0; ++ uint32_t ret; ++ ++ switch (offset) { ++ case 0x00: /* MCSPI_REVISION */ ++ return 0x91; ++ ++ case 0x10: /* MCSPI_SYSCONFIG */ ++ return s->sysconfig; ++ ++ case 0x14: /* MCSPI_SYSSTATUS */ ++ return 1; /* RESETDONE */ ++ ++ case 0x18: /* MCSPI_IRQSTATUS */ ++ return s->irqst; ++ ++ case 0x1c: /* MCSPI_IRQENABLE */ ++ return s->irqen; ++ ++ case 0x20: /* MCSPI_WAKEUPENABLE */ ++ return s->wken; ++ ++ case 0x24: /* MCSPI_SYST */ ++ return s->systest; ++ ++ case 0x28: /* MCSPI_MODULCTRL */ ++ return s->control; ++ ++ case 0x68: ch ++; ++ case 0x54: ch ++; ++ case 0x40: ch ++; ++ case 0x2c: /* MCSPI_CHCONF */ ++ return s->ch[ch].config; ++ ++ case 0x6c: ch ++; ++ case 0x58: ch ++; ++ case 0x44: ch ++; ++ case 0x30: /* MCSPI_CHSTAT */ ++ return s->ch[ch].status; ++ ++ case 0x70: ch ++; ++ case 0x5c: ch ++; ++ case 0x48: ch ++; ++ case 0x34: /* MCSPI_CHCTRL */ ++ return s->ch[ch].control; ++ ++ case 0x74: ch ++; ++ case 0x60: ch ++; ++ case 0x4c: ch ++; ++ case 0x38: /* MCSPI_TX */ ++ return s->ch[ch].tx; ++ ++ case 0x78: ch ++; ++ case 0x64: ch ++; ++ case 0x50: ch ++; ++ case 0x3c: /* MCSPI_RX */ ++ s->ch[ch].status &= ~(1 << 0); /* RXS */ ++ ret = s->ch[ch].rx; ++ omap_mcspi_transfer_run(s, ch); ++ return ret; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_mcspi_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque; ++ int offset = addr - s->base; ++ int ch = 0; ++ ++ switch (offset) { ++ case 0x00: /* MCSPI_REVISION */ ++ case 0x14: /* MCSPI_SYSSTATUS */ ++ case 0x30: /* MCSPI_CHSTAT0 */ ++ case 0x3c: /* MCSPI_RX0 */ ++ case 0x44: /* MCSPI_CHSTAT1 */ ++ case 0x50: /* MCSPI_RX1 */ ++ case 0x58: /* MCSPI_CHSTAT2 */ ++ case 0x64: /* MCSPI_RX2 */ ++ case 0x6c: /* MCSPI_CHSTAT3 */ ++ case 0x78: /* MCSPI_RX3 */ ++ OMAP_RO_REG(addr); ++ return; ++ ++ case 0x10: /* MCSPI_SYSCONFIG */ ++ if (value & (1 << 1)) /* SOFTRESET */ ++ omap_mcspi_reset(s); ++ s->sysconfig = value & 0x31d; ++ break; ++ ++ case 0x18: /* MCSPI_IRQSTATUS */ ++ if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) { ++ s->irqst &= ~value; ++ omap_mcspi_interrupt_update(s); ++ } ++ break; ++ ++ case 0x1c: /* MCSPI_IRQENABLE */ ++ s->irqen = value & 0x1777f; ++ omap_mcspi_interrupt_update(s); ++ break; ++ ++ case 0x20: /* MCSPI_WAKEUPENABLE */ ++ s->wken = value & 1; ++ break; ++ ++ case 0x24: /* MCSPI_SYST */ ++ if (s->control & (1 << 3)) /* SYSTEM_TEST */ ++ if (value & (1 << 11)) { /* SSB */ ++ s->irqst |= 0x1777f; ++ omap_mcspi_interrupt_update(s); ++ } ++ s->systest = value & 0xfff; ++ break; ++ ++ case 0x28: /* MCSPI_MODULCTRL */ ++ if (value & (1 << 3)) /* SYSTEM_TEST */ ++ if (s->systest & (1 << 11)) { /* SSB */ ++ s->irqst |= 0x1777f; ++ omap_mcspi_interrupt_update(s); ++ } ++ s->control = value & 0xf; ++ break; ++ ++ case 0x68: ch ++; ++ case 0x54: ch ++; ++ case 0x40: ch ++; ++ case 0x2c: /* MCSPI_CHCONF */ ++ if ((value ^ s->ch[ch].config) & (3 << 14)) /* DMAR | DMAW */ ++ omap_mcspi_dmarequest_update(s->ch + ch); ++ if (((value >> 12) & 3) == 3) /* TRM */ ++ fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__); ++ if (((value >> 7) & 0x1f) < 3) /* WL */ ++ fprintf(stderr, "%s: invalid WL value (%i)\n", ++ __FUNCTION__, (value >> 7) & 0x1f); ++ s->ch[ch].config = value & 0x7fffff; ++ break; ++ ++ case 0x70: ch ++; ++ case 0x5c: ch ++; ++ case 0x48: ch ++; ++ case 0x34: /* MCSPI_CHCTRL */ ++ if (value & ~s->ch[ch].control & 1) { /* EN */ ++ s->ch[ch].control |= 1; ++ omap_mcspi_transfer_run(s, ch); ++ } else ++ s->ch[ch].control = value & 1; ++ break; ++ ++ case 0x74: ch ++; ++ case 0x60: ch ++; ++ case 0x4c: ch ++; ++ case 0x38: /* MCSPI_TX */ ++ s->ch[ch].tx = value; ++ s->ch[ch].status &= ~(1 << 1); /* TXS */ ++ omap_mcspi_transfer_run(s, ch); ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return; ++ } ++} ++ ++static CPUReadMemoryFunc *omap_mcspi_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap_mcspi_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_mcspi_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_mcspi_write, ++}; ++ ++struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum, ++ qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk) ++{ ++ int iomemtype; ++ struct omap_mcspi_s *s = (struct omap_mcspi_s *) ++ qemu_mallocz(sizeof(struct omap_mcspi_s)); ++ struct omap_mcspi_ch_s *ch = s->ch; ++ ++ s->irq = irq; ++ s->chnum = chnum; ++ while (chnum --) { ++ ch->txdrq = *drq ++; ++ ch->rxdrq = *drq ++; ++ ch ++; ++ } ++ omap_mcspi_reset(s); ++ ++ iomemtype = cpu_register_io_memory(0, omap_mcspi_readfn, ++ omap_mcspi_writefn, s); ++ s->base = omap_l4_attach(ta, 0, iomemtype); ++ ++ return s; ++} ++ ++void omap_mcspi_attach(struct omap_mcspi_s *s, ++ uint32_t (*txrx)(void *opaque, uint32_t), void *opaque, ++ int chipselect) ++{ ++ if (chipselect < 0 || chipselect >= s->chnum) ++ cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n", ++ __FUNCTION__, chipselect); ++ ++ s->ch[chipselect].txrx = txrx; ++ s->ch[chipselect].opaque = opaque; ++} ++ ++/* L4 Interconnect */ ++struct omap_target_agent_s { ++ struct omap_l4_s *bus; ++ int regions; ++ struct omap_l4_region_s *start; ++ target_phys_addr_t base; ++ uint32_t component; ++ uint32_t control; ++ uint32_t status; ++}; ++ ++struct omap_l4_s { ++ target_phys_addr_t base; ++ int ta_num; ++ struct omap_target_agent_s ta[0]; ++}; ++ ++struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num) ++{ ++ struct omap_l4_s *bus = qemu_mallocz( ++ sizeof(*bus) + ta_num * sizeof(*bus->ta)); ++ ++ bus->ta_num = ta_num; ++ bus->base = base; ++ ++ return bus; ++} ++ ++static uint32_t omap_l4ta_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; ++ target_phys_addr_t reg = addr - s->base; ++ ++ switch (reg) { ++ case 0x00: /* COMPONENT */ ++ return s->component; ++ ++ case 0x20: /* AGENT_CONTROL */ ++ return s->control; ++ ++ case 0x28: /* AGENT_STATUS */ ++ return s->status; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_l4ta_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; ++ target_phys_addr_t reg = addr - s->base; ++ ++ switch (reg) { ++ case 0x00: /* COMPONENT */ ++ case 0x28: /* AGENT_STATUS */ ++ OMAP_RO_REG(addr); ++ break; ++ ++ case 0x20: /* AGENT_CONTROL */ ++ s->control = value & 0x01000700; ++ if (value & 1) /* OCP_RESET */ ++ s->status &= ~1; /* REQ_TIMEOUT */ ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ } ++} ++ ++static CPUReadMemoryFunc *omap_l4ta_readfn[] = { ++ omap_badwidth_read16, ++ omap_l4ta_read, ++ omap_badwidth_read16, ++}; ++ ++static CPUWriteMemoryFunc *omap_l4ta_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_l4ta_write, ++}; ++ ++#define L4TA(n) (n) ++#define L4TAO(n) ((n) + 39) ++ ++static struct omap_l4_region_s { ++ target_phys_addr_t offset; ++ size_t size; ++ int access; ++} omap_l4_region[125] = { ++ [ 1] = { 0x40800, 0x800, 32 }, /* Initiator agent */ ++ [ 2] = { 0x41000, 0x1000, 32 }, /* Link agent */ ++ [ 0] = { 0x40000, 0x800, 32 }, /* Address and protection */ ++ [ 3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */ ++ [ 4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */ ++ [ 5] = { 0x04000, 0x1000, 32 | 16 }, /* 32K Timer */ ++ [ 6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */ ++ [ 7] = { 0x08000, 0x800, 32 }, /* PRCM Region A */ ++ [ 8] = { 0x08800, 0x800, 32 }, /* PRCM Region B */ ++ [ 9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */ ++ [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */ ++ [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */ ++ [ 12] = { 0x14000, 0x1000, 32 }, /* Test/emulation (TAP) */ ++ [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */ ++ [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */ ++ [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */ ++ [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */ ++ [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */ ++ [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */ ++ [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */ ++ [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */ ++ [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */ ++ [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */ ++ [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */ ++ [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */ ++ [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */ ++ [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */ ++ [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */ ++ [ 28] = { 0x50000, 0x400, 32 | 16 | 8 }, /* Display top */ ++ [ 29] = { 0x50400, 0x400, 32 | 16 | 8 }, /* Display control */ ++ [ 30] = { 0x50800, 0x400, 32 | 16 | 8 }, /* Display RFBI */ ++ [ 31] = { 0x50c00, 0x400, 32 | 16 | 8 }, /* Display encoder */ ++ [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */ ++ [ 33] = { 0x52000, 0x400, 32 | 16 | 8 }, /* Camera top */ ++ [ 34] = { 0x52400, 0x400, 32 | 16 | 8 }, /* Camera core */ ++ [ 35] = { 0x52800, 0x400, 32 | 16 | 8 }, /* Camera DMA */ ++ [ 36] = { 0x52c00, 0x400, 32 | 16 | 8 }, /* Camera MMU */ ++ [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */ ++ [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */ ++ [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */ ++ [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */ ++ [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */ ++ [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */ ++ [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */ ++ [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */ ++ [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */ ++ [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */ ++ [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */ ++ [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */ ++ [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */ ++ [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */ ++ [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */ ++ [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */ ++ [ 53] = { 0x66000, 0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */ ++ [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */ ++ [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */ ++ [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */ ++ [ 57] = { 0x6a000, 0x1000, 16 | 8 }, /* UART1 */ ++ [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */ ++ [ 59] = { 0x6c000, 0x1000, 16 | 8 }, /* UART2 */ ++ [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */ ++ [ 61] = { 0x6e000, 0x1000, 16 | 8 }, /* UART3 */ ++ [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */ ++ [ 63] = { 0x70000, 0x1000, 16 }, /* I2C1 */ ++ [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */ ++ [ 65] = { 0x72000, 0x1000, 16 }, /* I2C2 */ ++ [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */ ++ [ 67] = { 0x74000, 0x1000, 16 }, /* McBSP1 */ ++ [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */ ++ [ 69] = { 0x76000, 0x1000, 16 }, /* McBSP2 */ ++ [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */ ++ [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */ ++ [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */ ++ [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */ ++ [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */ ++ [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */ ++ [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */ ++ [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */ ++ [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */ ++ [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */ ++ [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */ ++ [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */ ++ [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */ ++ [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */ ++ [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */ ++ [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */ ++ [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */ ++ [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */ ++ [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */ ++ [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */ ++ [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */ ++ [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */ ++ [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */ ++ [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */ ++ [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */ ++ [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */ ++ [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */ ++ [ 97] = { 0x90000, 0x1000, 16 }, /* EAC */ ++ [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */ ++ [ 99] = { 0x92000, 0x1000, 16 }, /* FAC */ ++ [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */ ++ [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */ ++ [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */ ++ [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */ ++ [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */ ++ [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */ ++ [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */ ++ [107] = { 0x9c000, 0x1000, 16 | 8 }, /* MMC SDIO */ ++ [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */ ++ [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */ ++ [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */ ++ [111] = { 0xa0000, 0x1000, 32 }, /* RNG */ ++ [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */ ++ [113] = { 0xa2000, 0x1000, 32 }, /* DES3DES */ ++ [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */ ++ [115] = { 0xa4000, 0x1000, 32 }, /* SHA1MD5 */ ++ [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */ ++ [117] = { 0xa6000, 0x1000, 32 }, /* AES */ ++ [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */ ++ [119] = { 0xa8000, 0x2000, 32 }, /* PKA */ ++ [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */ ++ [121] = { 0xb0000, 0x1000, 32 }, /* MG */ ++ [122] = { 0xb1000, 0x1000, 32 | 16 | 8 }, ++ [123] = { 0xb2000, 0x1000, 32 }, /* HDQ/1-Wire */ ++ [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */ ++}; ++ ++static struct omap_l4_agent_info_s { ++ int ta; ++ int region; ++ int regions; ++ int ta_region; ++} omap_l4_agent_info[54] = { ++ { 0, 0, 3, 2 }, /* L4IA initiatior agent */ ++ { L4TAO(1), 3, 2, 1 }, /* Control and pinout module */ ++ { L4TAO(2), 5, 2, 1 }, /* 32K timer */ ++ { L4TAO(3), 7, 3, 2 }, /* PRCM */ ++ { L4TA(1), 10, 2, 1 }, /* BCM */ ++ { L4TA(2), 12, 2, 1 }, /* Test JTAG */ ++ { L4TA(3), 14, 6, 3 }, /* Quad GPIO */ ++ { L4TA(4), 20, 4, 3 }, /* WD timer 1/2 */ ++ { L4TA(7), 24, 2, 1 }, /* GP timer 1 */ ++ { L4TA(9), 26, 2, 1 }, /* ATM11 ETB */ ++ { L4TA(10), 28, 5, 4 }, /* Display subsystem */ ++ { L4TA(11), 33, 5, 4 }, /* Camera subsystem */ ++ { L4TA(12), 38, 2, 1 }, /* sDMA */ ++ { L4TA(13), 40, 5, 4 }, /* SSI */ ++ { L4TAO(4), 45, 2, 1 }, /* USB */ ++ { L4TA(14), 47, 2, 1 }, /* Win Tracer1 */ ++ { L4TA(15), 49, 2, 1 }, /* Win Tracer2 */ ++ { L4TA(16), 51, 2, 1 }, /* Win Tracer3 */ ++ { L4TA(17), 53, 2, 1 }, /* Win Tracer4 */ ++ { L4TA(18), 55, 2, 1 }, /* XTI */ ++ { L4TA(19), 57, 2, 1 }, /* UART1 */ ++ { L4TA(20), 59, 2, 1 }, /* UART2 */ ++ { L4TA(21), 61, 2, 1 }, /* UART3 */ ++ { L4TAO(5), 63, 2, 1 }, /* I2C1 */ ++ { L4TAO(6), 65, 2, 1 }, /* I2C2 */ ++ { L4TAO(7), 67, 2, 1 }, /* McBSP1 */ ++ { L4TAO(8), 69, 2, 1 }, /* McBSP2 */ ++ { L4TA(5), 71, 2, 1 }, /* WD Timer 3 (DSP) */ ++ { L4TA(6), 73, 2, 1 }, /* WD Timer 4 (IVA) */ ++ { L4TA(8), 75, 2, 1 }, /* GP Timer 2 */ ++ { L4TA(22), 77, 2, 1 }, /* GP Timer 3 */ ++ { L4TA(23), 79, 2, 1 }, /* GP Timer 4 */ ++ { L4TA(24), 81, 2, 1 }, /* GP Timer 5 */ ++ { L4TA(25), 83, 2, 1 }, /* GP Timer 6 */ ++ { L4TA(26), 85, 2, 1 }, /* GP Timer 7 */ ++ { L4TA(27), 87, 2, 1 }, /* GP Timer 8 */ ++ { L4TA(28), 89, 2, 1 }, /* GP Timer 9 */ ++ { L4TA(29), 91, 2, 1 }, /* GP Timer 10 */ ++ { L4TA(30), 93, 2, 1 }, /* GP Timer 11 */ ++ { L4TA(31), 95, 2, 1 }, /* GP Timer 12 */ ++ { L4TA(32), 97, 2, 1 }, /* EAC */ ++ { L4TA(33), 99, 2, 1 }, /* FAC */ ++ { L4TA(34), 101, 2, 1 }, /* IPC */ ++ { L4TA(35), 103, 2, 1 }, /* SPI1 */ ++ { L4TA(36), 105, 2, 1 }, /* SPI2 */ ++ { L4TAO(9), 107, 2, 1 }, /* MMC SDIO */ ++ { L4TAO(10), 109, 2, 1 }, ++ { L4TAO(11), 111, 2, 1 }, /* RNG */ ++ { L4TAO(12), 113, 2, 1 }, /* DES3DES */ ++ { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */ ++ { L4TA(37), 117, 2, 1 }, /* AES */ ++ { L4TA(38), 119, 2, 1 }, /* PKA */ ++ { -1, 121, 2, 1 }, ++ { L4TA(39), 123, 2, 1 }, /* HDQ/1-Wire */ ++}; ++ ++#define omap_l4ta(bus, cs) omap_l4ta_get(bus, L4TA(cs)) ++#define omap_l4tao(bus, cs) omap_l4ta_get(bus, L4TAO(cs)) ++ ++struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs) ++{ ++ int i, iomemtype; ++ struct omap_target_agent_s *ta = 0; ++ struct omap_l4_agent_info_s *info = 0; ++ ++ for (i = 0; i < bus->ta_num; i ++) ++ if (omap_l4_agent_info[i].ta == cs) { ++ ta = &bus->ta[i]; ++ info = &omap_l4_agent_info[i]; ++ break; ++ } ++ if (!ta) { ++ fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs); ++ exit(-1); ++ } ++ ++ ta->bus = bus; ++ ta->start = &omap_l4_region[info->region]; ++ ta->regions = info->regions; ++ ta->base = bus->base + ta->start[info->ta_region].offset; ++ ++ ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); ++ ta->status = 0x00000000; ++ ta->control = 0x00000200; /* XXX 01000200 for L4TAO */ ++ ++ iomemtype = cpu_register_io_memory(0, omap_l4ta_readfn, ++ omap_l4ta_writefn, ta); ++ cpu_register_physical_memory(ta->base, 0x200, iomemtype); ++ ++ return ta; ++} ++ ++target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region, ++ int iotype) ++{ ++ target_phys_addr_t base; ++ size_t size; ++ ++ if (region < 0 || region >= ta->regions) { ++ fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region); ++ exit(-1); ++ } ++ ++ base = ta->bus->base + ta->start[region].offset; ++ size = ta->start[region].size; ++ if (iotype) ++ cpu_register_physical_memory(base, size, iotype); ++ ++ return base; ++} ++ ++/* TEST-Chip-level TAP */ ++static uint32_t omap_tap_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; ++ target_phys_addr_t reg = addr - s->tap_base; ++ ++ switch (reg) { ++ case 0x204: /* IDCODE_reg */ ++ switch (s->mpu_model) { ++ case omap2420: ++ case omap2422: ++ case omap2423: ++ return 0x5b5d902f; /* ES 2.2 */ ++ case omap2430: ++ return 0x5b68a02f; /* ES 2.2 */ ++ case omap3430: ++ return 0x1b7ae02f; /* ES 2 */ ++ default: ++ cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__); ++ } ++ ++ case 0x208: /* PRODUCTION_ID_reg for OMAP2 */ ++ case 0x210: /* PRODUCTION_ID_reg for OMAP3 */ ++ switch (s->mpu_model) { ++ case omap2420: ++ return 0x000200f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */ ++ case omap2422: ++ return 0x000400f0; ++ case omap2423: ++ return 0x000800f0; ++ case omap2430: ++ return 0x000000f0; ++ case omap3430: ++ return 0x000000f0; ++ default: ++ cpu_abort(cpu_single_env, "%s: Bad mpu model\n", __FUNCTION__); ++ } ++ ++ case 0x218: /* DIE_ID_reg */ ++ return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); ++ case 0x21c: /* DIE_ID_reg */ ++ return ( 5 << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); ++ case 0x220: /* DIE_ID_reg */ ++ return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); ++ case 0x224: /* DIE_ID_reg */ ++ return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0); ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_tap_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ OMAP_BAD_REG(addr); ++} ++ ++static CPUReadMemoryFunc *omap_tap_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap_tap_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_tap_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_tap_write, ++}; ++ ++void omap_tap_init(struct omap_target_agent_s *ta, ++ struct omap_mpu_state_s *mpu) ++{ ++ mpu->tap_base = omap_l4_attach(ta, 0, cpu_register_io_memory(0, ++ omap_tap_readfn, omap_tap_writefn, mpu)); ++} ++ ++/* Power, Reset, and Clock Management */ ++struct omap_prcm_s { ++ target_phys_addr_t base; ++ qemu_irq irq[3]; ++ struct omap_mpu_state_s *mpu; ++ ++ uint32_t irqst[3]; ++ uint32_t irqen[3]; ++ ++ uint32_t sysconfig; ++ uint32_t voltctrl; ++ uint32_t scratch[20]; ++ ++ uint32_t clksrc[1]; ++ uint32_t clkout[1]; ++ uint32_t clkemul[1]; ++ uint32_t clkpol[1]; ++ uint32_t clksel[8]; ++ uint32_t clken[12]; ++ uint32_t clkctrl[4]; ++ uint32_t clkidle[7]; ++ uint32_t setuptime[2]; ++ ++ uint32_t wkup[3]; ++ uint32_t wken[3]; ++ uint32_t wkst[3]; ++ uint32_t rst[4]; ++ uint32_t rstctrl[1]; ++ uint32_t power[4]; ++ uint32_t rsttime_wkup; ++ ++ uint32_t ev; ++ uint32_t evtime[2]; ++}; ++ ++static void omap_prcm_int_update(struct omap_prcm_s *s, int dom) ++{ ++ qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]); ++ /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */ ++} ++ ++static uint32_t omap_prcm_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x000: /* PRCM_REVISION */ ++ return 0x10; ++ ++ case 0x010: /* PRCM_SYSCONFIG */ ++ return s->sysconfig; ++ ++ case 0x018: /* PRCM_IRQSTATUS_MPU */ ++ return s->irqst[0]; ++ ++ case 0x01c: /* PRCM_IRQENABLE_MPU */ ++ return s->irqen[0]; ++ ++ case 0x050: /* PRCM_VOLTCTRL */ ++ return s->voltctrl; ++ case 0x054: /* PRCM_VOLTST */ ++ return s->voltctrl & 3; ++ ++ case 0x060: /* PRCM_CLKSRC_CTRL */ ++ return s->clksrc[0]; ++ case 0x070: /* PRCM_CLKOUT_CTRL */ ++ return s->clkout[0]; ++ case 0x078: /* PRCM_CLKEMUL_CTRL */ ++ return s->clkemul[0]; ++ case 0x080: /* PRCM_CLKCFG_CTRL */ ++ case 0x084: /* PRCM_CLKCFG_STATUS */ ++ return 0; ++ ++ case 0x090: /* PRCM_VOLTSETUP */ ++ return s->setuptime[0]; ++ ++ case 0x094: /* PRCM_CLKSSETUP */ ++ return s->setuptime[1]; ++ ++ case 0x098: /* PRCM_POLCTRL */ ++ return s->clkpol[0]; ++ ++ case 0x0b0: /* GENERAL_PURPOSE1 */ ++ case 0x0b4: /* GENERAL_PURPOSE2 */ ++ case 0x0b8: /* GENERAL_PURPOSE3 */ ++ case 0x0bc: /* GENERAL_PURPOSE4 */ ++ case 0x0c0: /* GENERAL_PURPOSE5 */ ++ case 0x0c4: /* GENERAL_PURPOSE6 */ ++ case 0x0c8: /* GENERAL_PURPOSE7 */ ++ case 0x0cc: /* GENERAL_PURPOSE8 */ ++ case 0x0d0: /* GENERAL_PURPOSE9 */ ++ case 0x0d4: /* GENERAL_PURPOSE10 */ ++ case 0x0d8: /* GENERAL_PURPOSE11 */ ++ case 0x0dc: /* GENERAL_PURPOSE12 */ ++ case 0x0e0: /* GENERAL_PURPOSE13 */ ++ case 0x0e4: /* GENERAL_PURPOSE14 */ ++ case 0x0e8: /* GENERAL_PURPOSE15 */ ++ case 0x0ec: /* GENERAL_PURPOSE16 */ ++ case 0x0f0: /* GENERAL_PURPOSE17 */ ++ case 0x0f4: /* GENERAL_PURPOSE18 */ ++ case 0x0f8: /* GENERAL_PURPOSE19 */ ++ case 0x0fc: /* GENERAL_PURPOSE20 */ ++ return s->scratch[(offset - 0xb0) >> 2]; ++ ++ case 0x140: /* CM_CLKSEL_MPU */ ++ return s->clksel[0]; ++ case 0x148: /* CM_CLKSTCTRL_MPU */ ++ return s->clkctrl[0]; ++ ++ case 0x158: /* RM_RSTST_MPU */ ++ return s->rst[0]; ++ case 0x1c8: /* PM_WKDEP_MPU */ ++ return s->wkup[0]; ++ case 0x1d4: /* PM_EVGENCTRL_MPU */ ++ return s->ev; ++ case 0x1d8: /* PM_EVEGENONTIM_MPU */ ++ return s->evtime[0]; ++ case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ ++ return s->evtime[1]; ++ case 0x1e0: /* PM_PWSTCTRL_MPU */ ++ return s->power[0]; ++ case 0x1e4: /* PM_PWSTST_MPU */ ++ return 0; ++ ++ case 0x200: /* CM_FCLKEN1_CORE */ ++ return s->clken[0]; ++ case 0x204: /* CM_FCLKEN2_CORE */ ++ return s->clken[1]; ++ case 0x210: /* CM_ICLKEN1_CORE */ ++ return s->clken[2]; ++ case 0x214: /* CM_ICLKEN2_CORE */ ++ return s->clken[3]; ++ case 0x21c: /* CM_ICLKEN4_CORE */ ++ return s->clken[4]; ++ ++ case 0x220: /* CM_IDLEST1_CORE */ ++ /* TODO: check the actual iclk status */ ++ return 0x7ffffff9; ++ case 0x224: /* CM_IDLEST2_CORE */ ++ /* TODO: check the actual iclk status */ ++ return 0x00000007; ++ case 0x22c: /* CM_IDLEST4_CORE */ ++ /* TODO: check the actual iclk status */ ++ return 0x0000001f; ++ ++ case 0x230: /* CM_AUTOIDLE1_CORE */ ++ return s->clkidle[0]; ++ case 0x234: /* CM_AUTOIDLE2_CORE */ ++ return s->clkidle[1]; ++ case 0x238: /* CM_AUTOIDLE3_CORE */ ++ return s->clkidle[2]; ++ case 0x23c: /* CM_AUTOIDLE4_CORE */ ++ return s->clkidle[3]; ++ ++ case 0x240: /* CM_CLKSEL1_CORE */ ++ return s->clksel[1]; ++ case 0x244: /* CM_CLKSEL2_CORE */ ++ return s->clksel[2]; ++ ++ case 0x248: /* CM_CLKSTCTRL_CORE */ ++ return s->clkctrl[1]; ++ ++ case 0x2a0: /* PM_WKEN1_CORE */ ++ return s->wken[0]; ++ case 0x2a4: /* PM_WKEN2_CORE */ ++ return s->wken[1]; ++ ++ case 0x2b0: /* PM_WKST1_CORE */ ++ return s->wkst[0]; ++ case 0x2b4: /* PM_WKST2_CORE */ ++ return s->wkst[1]; ++ case 0x2c8: /* PM_WKDEP_CORE */ ++ return 0x1e; ++ ++ case 0x2e0: /* PM_PWSTCTRL_CORE */ ++ return s->power[1]; ++ case 0x2e4: /* PM_PWSTST_CORE */ ++ return 0x000030 | (s->power[1] & 0xfc00); ++ ++ case 0x300: /* CM_FCLKEN_GFX */ ++ return s->clken[5]; ++ case 0x310: /* CM_ICLKEN_GFX */ ++ return s->clken[6]; ++ case 0x320: /* CM_IDLEST_GFX */ ++ /* TODO: check the actual iclk status */ ++ return 0x00000001; ++ case 0x340: /* CM_CLKSEL_GFX */ ++ return s->clksel[3]; ++ case 0x348: /* CM_CLKSTCTRL_GFX */ ++ return s->clkctrl[2]; ++ case 0x350: /* RM_RSTCTRL_GFX */ ++ return s->rstctrl[0]; ++ case 0x358: /* RM_RSTST_GFX */ ++ return s->rst[1]; ++ case 0x3c8: /* PM_WKDEP_GFX */ ++ return s->wkup[1]; ++ ++ case 0x3e0: /* PM_PWSTCTRL_GFX */ ++ return s->power[2]; ++ case 0x3e4: /* PM_PWSTST_GFX */ ++ return s->power[2] & 3; ++ ++ case 0x400: /* CM_FCLKEN_WKUP */ ++ return s->clken[7]; ++ case 0x410: /* CM_ICLKEN_WKUP */ ++ return s->clken[8]; ++ case 0x420: /* CM_IDLEST_WKUP */ ++ /* TODO: check the actual iclk status */ ++ return 0x0000003f; ++ case 0x430: /* CM_AUTOIDLE_WKUP */ ++ return s->clkidle[4]; ++ case 0x440: /* CM_CLKSEL_WKUP */ ++ return s->clksel[4]; ++ case 0x450: /* RM_RSTCTRL_WKUP */ ++ return 0; ++ case 0x454: /* RM_RSTTIME_WKUP */ ++ return s->rsttime_wkup; ++ case 0x458: /* RM_RSTST_WKUP */ ++ return s->rst[2]; ++ case 0x4a0: /* PM_WKEN_WKUP */ ++ return s->wken[2]; ++ case 0x4b0: /* PM_WKST_WKUP */ ++ return s->wkst[2]; ++ ++ case 0x500: /* CM_CLKEN_PLL */ ++ return s->clken[9]; ++ case 0x520: /* CM_IDLEST_CKGEN */ ++ /* Core uses 32-kHz clock */ ++ if (!(s->clksel[6] & 3)) ++ return 0x00000377; ++ /* DPLL not in lock mode, core uses ref_clk */ ++ if ((s->clken[9] & 3) != 3) ++ return 0x00000375; ++ /* Core uses DPLL */ ++ return 0x00000376; ++ case 0x530: /* CM_AUTOIDLE_PLL */ ++ return s->clkidle[5]; ++ case 0x540: /* CM_CLKSEL1_PLL */ ++ return s->clksel[5]; ++ case 0x544: /* CM_CLKSEL2_PLL */ ++ return s->clksel[6]; ++ ++ case 0x800: /* CM_FCLKEN_DSP */ ++ return s->clken[10]; ++ case 0x810: /* CM_ICLKEN_DSP */ ++ return s->clken[11]; ++ case 0x820: /* CM_IDLEST_DSP */ ++ /* TODO: check the actual iclk status */ ++ return 0x00000103; ++ case 0x830: /* CM_AUTOIDLE_DSP */ ++ return s->clkidle[6]; ++ case 0x840: /* CM_CLKSEL_DSP */ ++ return s->clksel[7]; ++ case 0x848: /* CM_CLKSTCTRL_DSP */ ++ return s->clkctrl[3]; ++ case 0x850: /* RM_RSTCTRL_DSP */ ++ return 0; ++ case 0x858: /* RM_RSTST_DSP */ ++ return s->rst[3]; ++ case 0x8c8: /* PM_WKDEP_DSP */ ++ return s->wkup[2]; ++ case 0x8e0: /* PM_PWSTCTRL_DSP */ ++ return s->power[3]; ++ case 0x8e4: /* PM_PWSTST_DSP */ ++ return 0x008030 | (s->power[3] & 0x3003); ++ ++ case 0x8f0: /* PRCM_IRQSTATUS_DSP */ ++ return s->irqst[1]; ++ case 0x8f4: /* PRCM_IRQENABLE_DSP */ ++ return s->irqen[1]; ++ ++ case 0x8f8: /* PRCM_IRQSTATUS_IVA */ ++ return s->irqst[2]; ++ case 0x8fc: /* PRCM_IRQENABLE_IVA */ ++ return s->irqen[2]; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_prcm_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x000: /* PRCM_REVISION */ ++ case 0x054: /* PRCM_VOLTST */ ++ case 0x084: /* PRCM_CLKCFG_STATUS */ ++ case 0x1e4: /* PM_PWSTST_MPU */ ++ case 0x220: /* CM_IDLEST1_CORE */ ++ case 0x224: /* CM_IDLEST2_CORE */ ++ case 0x22c: /* CM_IDLEST4_CORE */ ++ case 0x2c8: /* PM_WKDEP_CORE */ ++ case 0x2e4: /* PM_PWSTST_CORE */ ++ case 0x320: /* CM_IDLEST_GFX */ ++ case 0x3e4: /* PM_PWSTST_GFX */ ++ case 0x420: /* CM_IDLEST_WKUP */ ++ case 0x520: /* CM_IDLEST_CKGEN */ ++ case 0x820: /* CM_IDLEST_DSP */ ++ case 0x8e4: /* PM_PWSTST_DSP */ ++ OMAP_RO_REG(addr); ++ return; ++ ++ case 0x010: /* PRCM_SYSCONFIG */ ++ s->sysconfig = value & 1; ++ break; ++ ++ case 0x018: /* PRCM_IRQSTATUS_MPU */ ++ s->irqst[0] &= ~value; ++ omap_prcm_int_update(s, 0); ++ break; ++ case 0x01c: /* PRCM_IRQENABLE_MPU */ ++ s->irqen[0] = value & 0x3f; ++ omap_prcm_int_update(s, 0); ++ break; ++ ++ case 0x050: /* PRCM_VOLTCTRL */ ++ s->voltctrl = value & 0xf1c3; ++ break; ++ ++ case 0x060: /* PRCM_CLKSRC_CTRL */ ++ s->clksrc[0] = value & 0xdb; ++ /* TODO update clocks */ ++ break; ++ ++ case 0x070: /* PRCM_CLKOUT_CTRL */ ++ s->clkout[0] = value & 0xbbbb; ++ /* TODO update clocks */ ++ break; ++ ++ case 0x078: /* PRCM_CLKEMUL_CTRL */ ++ s->clkemul[0] = value & 1; ++ /* TODO update clocks */ ++ break; ++ ++ case 0x080: /* PRCM_CLKCFG_CTRL */ ++ break; ++ ++ case 0x090: /* PRCM_VOLTSETUP */ ++ s->setuptime[0] = value & 0xffff; ++ break; ++ case 0x094: /* PRCM_CLKSSETUP */ ++ s->setuptime[1] = value & 0xffff; ++ break; ++ ++ case 0x098: /* PRCM_POLCTRL */ ++ s->clkpol[0] = value & 0x701; ++ break; ++ ++ case 0x0b0: /* GENERAL_PURPOSE1 */ ++ case 0x0b4: /* GENERAL_PURPOSE2 */ ++ case 0x0b8: /* GENERAL_PURPOSE3 */ ++ case 0x0bc: /* GENERAL_PURPOSE4 */ ++ case 0x0c0: /* GENERAL_PURPOSE5 */ ++ case 0x0c4: /* GENERAL_PURPOSE6 */ ++ case 0x0c8: /* GENERAL_PURPOSE7 */ ++ case 0x0cc: /* GENERAL_PURPOSE8 */ ++ case 0x0d0: /* GENERAL_PURPOSE9 */ ++ case 0x0d4: /* GENERAL_PURPOSE10 */ ++ case 0x0d8: /* GENERAL_PURPOSE11 */ ++ case 0x0dc: /* GENERAL_PURPOSE12 */ ++ case 0x0e0: /* GENERAL_PURPOSE13 */ ++ case 0x0e4: /* GENERAL_PURPOSE14 */ ++ case 0x0e8: /* GENERAL_PURPOSE15 */ ++ case 0x0ec: /* GENERAL_PURPOSE16 */ ++ case 0x0f0: /* GENERAL_PURPOSE17 */ ++ case 0x0f4: /* GENERAL_PURPOSE18 */ ++ case 0x0f8: /* GENERAL_PURPOSE19 */ ++ case 0x0fc: /* GENERAL_PURPOSE20 */ ++ s->scratch[(offset - 0xb0) >> 2] = value; ++ break; ++ ++ case 0x140: /* CM_CLKSEL_MPU */ ++ s->clksel[0] = value & 0x1f; ++ /* TODO update clocks */ ++ break; ++ case 0x148: /* CM_CLKSTCTRL_MPU */ ++ s->clkctrl[0] = value & 0x1f; ++ break; ++ ++ case 0x158: /* RM_RSTST_MPU */ ++ s->rst[0] &= ~value; ++ break; ++ case 0x1c8: /* PM_WKDEP_MPU */ ++ s->wkup[0] = value & 0x15; ++ break; ++ ++ case 0x1d4: /* PM_EVGENCTRL_MPU */ ++ s->ev = value & 0x1f; ++ break; ++ case 0x1d8: /* PM_EVEGENONTIM_MPU */ ++ s->evtime[0] = value; ++ break; ++ case 0x1dc: /* PM_EVEGENOFFTIM_MPU */ ++ s->evtime[1] = value; ++ break; ++ ++ case 0x1e0: /* PM_PWSTCTRL_MPU */ ++ s->power[0] = value & 0xc0f; ++ break; ++ ++ case 0x200: /* CM_FCLKEN1_CORE */ ++ s->clken[0] = value & 0xbfffffff; ++ /* TODO update clocks */ ++ break; ++ case 0x204: /* CM_FCLKEN2_CORE */ ++ s->clken[1] = value & 0x00000007; ++ /* TODO update clocks */ ++ break; ++ case 0x210: /* CM_ICLKEN1_CORE */ ++ s->clken[2] = value & 0xfffffff9; ++ /* TODO update clocks */ ++ break; ++ case 0x214: /* CM_ICLKEN2_CORE */ ++ s->clken[3] = value & 0x00000007; ++ /* TODO update clocks */ ++ break; ++ case 0x21c: /* CM_ICLKEN4_CORE */ ++ s->clken[4] = value & 0x0000001f; ++ /* TODO update clocks */ ++ break; ++ ++ case 0x230: /* CM_AUTOIDLE1_CORE */ ++ s->clkidle[0] = value & 0xfffffff9; ++ /* TODO update clocks */ ++ break; ++ case 0x234: /* CM_AUTOIDLE2_CORE */ ++ s->clkidle[1] = value & 0x00000007; ++ /* TODO update clocks */ ++ break; ++ case 0x238: /* CM_AUTOIDLE3_CORE */ ++ s->clkidle[2] = value & 0x00000007; ++ /* TODO update clocks */ ++ break; ++ case 0x23c: /* CM_AUTOIDLE4_CORE */ ++ s->clkidle[3] = value & 0x0000001f; ++ /* TODO update clocks */ ++ break; ++ ++ case 0x240: /* CM_CLKSEL1_CORE */ ++ s->clksel[1] = value & 0x0fffbf7f; ++ /* TODO update clocks */ ++ break; ++ ++ case 0x244: /* CM_CLKSEL2_CORE */ ++ s->clksel[2] = value & 0x00fffffc; ++ /* TODO update clocks */ ++ break; ++ ++ case 0x248: /* CM_CLKSTCTRL_CORE */ ++ s->clkctrl[1] = value & 0x7; ++ break; ++ ++ case 0x2a0: /* PM_WKEN1_CORE */ ++ s->wken[0] = value & 0x04667ff8; ++ break; ++ case 0x2a4: /* PM_WKEN2_CORE */ ++ s->wken[1] = value & 0x00000005; ++ break; ++ ++ case 0x2b0: /* PM_WKST1_CORE */ ++ s->wkst[0] &= ~value; ++ break; ++ case 0x2b4: /* PM_WKST2_CORE */ ++ s->wkst[1] &= ~value; ++ break; ++ ++ case 0x2e0: /* PM_PWSTCTRL_CORE */ ++ s->power[1] = (value & 0x00fc3f) | (1 << 2); ++ break; ++ ++ case 0x300: /* CM_FCLKEN_GFX */ ++ s->clken[5] = value & 6; ++ /* TODO update clocks */ ++ break; ++ case 0x310: /* CM_ICLKEN_GFX */ ++ s->clken[6] = value & 1; ++ /* TODO update clocks */ ++ break; ++ case 0x340: /* CM_CLKSEL_GFX */ ++ s->clksel[3] = value & 7; ++ /* TODO update clocks */ ++ break; ++ case 0x348: /* CM_CLKSTCTRL_GFX */ ++ s->clkctrl[2] = value & 1; ++ break; ++ case 0x350: /* RM_RSTCTRL_GFX */ ++ s->rstctrl[0] = value & 1; ++ /* TODO: reset */ ++ break; ++ case 0x358: /* RM_RSTST_GFX */ ++ s->rst[1] &= ~value; ++ break; ++ case 0x3c8: /* PM_WKDEP_GFX */ ++ s->wkup[1] = value & 0x13; ++ break; ++ case 0x3e0: /* PM_PWSTCTRL_GFX */ ++ s->power[2] = (value & 0x00c0f) | (3 << 2); ++ break; ++ ++ case 0x400: /* CM_FCLKEN_WKUP */ ++ s->clken[7] = value & 0xd; ++ /* TODO update clocks */ ++ break; ++ case 0x410: /* CM_ICLKEN_WKUP */ ++ s->clken[8] = value & 0x3f; ++ /* TODO update clocks */ ++ break; ++ case 0x430: /* CM_AUTOIDLE_WKUP */ ++ s->clkidle[4] = value & 0x0000003f; ++ /* TODO update clocks */ ++ break; ++ case 0x440: /* CM_CLKSEL_WKUP */ ++ s->clksel[4] = value & 3; ++ /* TODO update clocks */ ++ break; ++ case 0x450: /* RM_RSTCTRL_WKUP */ ++ /* TODO: reset */ ++ if (value & 2) ++ qemu_system_reset_request(); ++ break; ++ case 0x454: /* RM_RSTTIME_WKUP */ ++ s->rsttime_wkup = value & 0x1fff; ++ break; ++ case 0x458: /* RM_RSTST_WKUP */ ++ s->rst[2] &= ~value; ++ break; ++ case 0x4a0: /* PM_WKEN_WKUP */ ++ s->wken[2] = value & 0x00000005; ++ break; ++ case 0x4b0: /* PM_WKST_WKUP */ ++ s->wkst[2] &= ~value; ++ break; ++ ++ case 0x500: /* CM_CLKEN_PLL */ ++ s->clken[9] = value & 0xcf; ++ /* TODO update clocks */ ++ break; ++ case 0x530: /* CM_AUTOIDLE_PLL */ ++ s->clkidle[5] = value & 0x000000cf; ++ /* TODO update clocks */ ++ break; ++ case 0x540: /* CM_CLKSEL1_PLL */ ++ s->clksel[5] = value & 0x03bfff28; ++ /* TODO update clocks */ ++ break; ++ case 0x544: /* CM_CLKSEL2_PLL */ ++ s->clksel[6] = value & 3; ++ /* TODO update clocks */ ++ break; ++ ++ case 0x800: /* CM_FCLKEN_DSP */ ++ s->clken[10] = value & 0x501; ++ /* TODO update clocks */ ++ break; ++ case 0x810: /* CM_ICLKEN_DSP */ ++ s->clken[11] = value & 0x2; ++ /* TODO update clocks */ ++ break; ++ case 0x830: /* CM_AUTOIDLE_DSP */ ++ s->clkidle[6] = value & 0x2; ++ /* TODO update clocks */ ++ break; ++ case 0x840: /* CM_CLKSEL_DSP */ ++ s->clksel[7] = value & 0x3fff; ++ /* TODO update clocks */ ++ break; ++ case 0x848: /* CM_CLKSTCTRL_DSP */ ++ s->clkctrl[3] = value & 0x101; ++ break; ++ case 0x850: /* RM_RSTCTRL_DSP */ ++ /* TODO: reset */ ++ break; ++ case 0x858: /* RM_RSTST_DSP */ ++ s->rst[3] &= ~value; ++ break; ++ case 0x8c8: /* PM_WKDEP_DSP */ ++ s->wkup[2] = value & 0x13; ++ break; ++ case 0x8e0: /* PM_PWSTCTRL_DSP */ ++ s->power[3] = (value & 0x03017) | (3 << 2); ++ break; ++ ++ case 0x8f0: /* PRCM_IRQSTATUS_DSP */ ++ s->irqst[1] &= ~value; ++ omap_prcm_int_update(s, 1); ++ break; ++ case 0x8f4: /* PRCM_IRQENABLE_DSP */ ++ s->irqen[1] = value & 0x7; ++ omap_prcm_int_update(s, 1); ++ break; ++ ++ case 0x8f8: /* PRCM_IRQSTATUS_IVA */ ++ s->irqst[2] &= ~value; ++ omap_prcm_int_update(s, 2); ++ break; ++ case 0x8fc: /* PRCM_IRQENABLE_IVA */ ++ s->irqen[2] = value & 0x7; ++ omap_prcm_int_update(s, 2); ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return; ++ } ++} ++ ++static CPUReadMemoryFunc *omap_prcm_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap_prcm_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_prcm_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_prcm_write, ++}; ++ ++static void omap_prcm_reset(struct omap_prcm_s *s) ++{ ++ s->sysconfig = 0; ++ s->irqst[0] = 0; ++ s->irqst[1] = 0; ++ s->irqst[2] = 0; ++ s->irqen[0] = 0; ++ s->irqen[1] = 0; ++ s->irqen[2] = 0; ++ s->voltctrl = 0x1040; ++ s->ev = 0x14; ++ s->evtime[0] = 0; ++ s->evtime[1] = 0; ++ s->clkctrl[0] = 0; ++ s->clkctrl[1] = 0; ++ s->clkctrl[2] = 0; ++ s->clkctrl[3] = 0; ++ s->clken[1] = 7; ++ s->clken[3] = 7; ++ s->clken[4] = 0; ++ s->clken[5] = 0; ++ s->clken[6] = 0; ++ s->clken[7] = 0xc; ++ s->clken[8] = 0x3e; ++ s->clken[9] = 0x0d; ++ s->clken[10] = 0; ++ s->clken[11] = 0; ++ s->clkidle[0] = 0; ++ s->clkidle[2] = 7; ++ s->clkidle[3] = 0; ++ s->clkidle[4] = 0; ++ s->clkidle[5] = 0x0c; ++ s->clkidle[6] = 0; ++ s->clksel[0] = 0x01; ++ s->clksel[1] = 0x02100121; ++ s->clksel[2] = 0x00000000; ++ s->clksel[3] = 0x01; ++ s->clksel[4] = 0; ++ s->clksel[7] = 0x0121; ++ s->wkup[0] = 0x15; ++ s->wkup[1] = 0x13; ++ s->wkup[2] = 0x13; ++ s->wken[0] = 0x04667ff8; ++ s->wken[1] = 0x00000005; ++ s->wken[2] = 5; ++ s->wkst[0] = 0; ++ s->wkst[1] = 0; ++ s->wkst[2] = 0; ++ s->power[0] = 0x00c; ++ s->power[1] = 4; ++ s->power[2] = 0x0000c; ++ s->power[3] = 0x14; ++ s->rstctrl[0] = 1; ++ s->rst[3] = 1; ++} ++ ++static void omap_prcm_coldreset(struct omap_prcm_s *s) ++{ ++ s->setuptime[0] = 0; ++ s->setuptime[1] = 0; ++ memset(&s->scratch, 0, sizeof(s->scratch)); ++ s->rst[0] = 0x01; ++ s->rst[1] = 0x00; ++ s->rst[2] = 0x01; ++ s->clken[0] = 0; ++ s->clken[2] = 0; ++ s->clkidle[1] = 0; ++ s->clksel[5] = 0; ++ s->clksel[6] = 2; ++ s->clksrc[0] = 0x43; ++ s->clkout[0] = 0x0303; ++ s->clkemul[0] = 0; ++ s->clkpol[0] = 0x100; ++ s->rsttime_wkup = 0x1002; ++ ++ omap_prcm_reset(s); ++} ++ ++struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta, ++ qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int, ++ struct omap_mpu_state_s *mpu) ++{ ++ int iomemtype; ++ struct omap_prcm_s *s = (struct omap_prcm_s *) ++ qemu_mallocz(sizeof(struct omap_prcm_s)); ++ ++ s->irq[0] = mpu_int; ++ s->irq[1] = dsp_int; ++ s->irq[2] = iva_int; ++ s->mpu = mpu; ++ omap_prcm_coldreset(s); ++ ++ iomemtype = cpu_register_io_memory(0, omap_prcm_readfn, ++ omap_prcm_writefn, s); ++ s->base = omap_l4_attach(ta, 0, iomemtype); ++ omap_l4_attach(ta, 1, iomemtype); ++ ++ return s; ++} ++ ++/* System and Pinout control */ ++struct omap_sysctl_s { ++ target_phys_addr_t base; ++ struct omap_mpu_state_s *mpu; ++ ++ uint32_t sysconfig; ++ uint32_t devconfig; ++ uint32_t psaconfig; ++ uint32_t padconf[0x45]; ++ uint8_t obs; ++ uint32_t msuspendmux[5]; ++}; ++ ++static uint32_t omap_sysctl_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x000: /* CONTROL_REVISION */ ++ return 0x20; ++ ++ case 0x010: /* CONTROL_SYSCONFIG */ ++ return s->sysconfig; ++ ++ case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ ++ return s->padconf[(offset - 0x30) >> 2]; ++ ++ case 0x270: /* CONTROL_DEBOBS */ ++ return s->obs; ++ ++ case 0x274: /* CONTROL_DEVCONF */ ++ return s->devconfig; ++ ++ case 0x28c: /* CONTROL_EMU_SUPPORT */ ++ return 0; ++ ++ case 0x290: /* CONTROL_MSUSPENDMUX_0 */ ++ return s->msuspendmux[0]; ++ case 0x294: /* CONTROL_MSUSPENDMUX_1 */ ++ return s->msuspendmux[1]; ++ case 0x298: /* CONTROL_MSUSPENDMUX_2 */ ++ return s->msuspendmux[2]; ++ case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ ++ return s->msuspendmux[3]; ++ case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ ++ return s->msuspendmux[4]; ++ case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ ++ return 0; ++ ++ case 0x2b8: /* CONTROL_PSA_CTRL */ ++ return s->psaconfig; ++ case 0x2bc: /* CONTROL_PSA_CMD */ ++ case 0x2c0: /* CONTROL_PSA_VALUE */ ++ return 0; ++ ++ case 0x2b0: /* CONTROL_SEC_CTRL */ ++ return 0x800000f1; ++ case 0x2d0: /* CONTROL_SEC_EMU */ ++ return 0x80000015; ++ case 0x2d4: /* CONTROL_SEC_TAP */ ++ return 0x8000007f; ++ case 0x2b4: /* CONTROL_SEC_TEST */ ++ case 0x2f0: /* CONTROL_SEC_STATUS */ ++ case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ ++ /* Secure mode is not present on general-pusrpose device. Outside ++ * secure mode these values cannot be read or written. */ ++ return 0; ++ ++ case 0x2d8: /* CONTROL_OCM_RAM_PERM */ ++ return 0xff; ++ case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ ++ case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ ++ case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ ++ /* No secure mode so no Extended Secure RAM present. */ ++ return 0; ++ ++ case 0x2f8: /* CONTROL_STATUS */ ++ /* Device Type => General-purpose */ ++ return 0x0300; ++ case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ ++ ++ case 0x300: /* CONTROL_RPUB_KEY_H_0 */ ++ case 0x304: /* CONTROL_RPUB_KEY_H_1 */ ++ case 0x308: /* CONTROL_RPUB_KEY_H_2 */ ++ case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ ++ return 0xdecafbad; ++ ++ case 0x310: /* CONTROL_RAND_KEY_0 */ ++ case 0x314: /* CONTROL_RAND_KEY_1 */ ++ case 0x318: /* CONTROL_RAND_KEY_2 */ ++ case 0x31c: /* CONTROL_RAND_KEY_3 */ ++ case 0x320: /* CONTROL_CUST_KEY_0 */ ++ case 0x324: /* CONTROL_CUST_KEY_1 */ ++ case 0x330: /* CONTROL_TEST_KEY_0 */ ++ case 0x334: /* CONTROL_TEST_KEY_1 */ ++ case 0x338: /* CONTROL_TEST_KEY_2 */ ++ case 0x33c: /* CONTROL_TEST_KEY_3 */ ++ case 0x340: /* CONTROL_TEST_KEY_4 */ ++ case 0x344: /* CONTROL_TEST_KEY_5 */ ++ case 0x348: /* CONTROL_TEST_KEY_6 */ ++ case 0x34c: /* CONTROL_TEST_KEY_7 */ ++ case 0x350: /* CONTROL_TEST_KEY_8 */ ++ case 0x354: /* CONTROL_TEST_KEY_9 */ ++ /* Can only be accessed in secure mode and when C_FieldAccEnable ++ * bit is set in CONTROL_SEC_CTRL. ++ * TODO: otherwise an interconnect access error is generated. */ ++ return 0; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_sysctl_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x000: /* CONTROL_REVISION */ ++ case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */ ++ case 0x2c0: /* CONTROL_PSA_VALUE */ ++ case 0x2f8: /* CONTROL_STATUS */ ++ case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */ ++ case 0x300: /* CONTROL_RPUB_KEY_H_0 */ ++ case 0x304: /* CONTROL_RPUB_KEY_H_1 */ ++ case 0x308: /* CONTROL_RPUB_KEY_H_2 */ ++ case 0x30c: /* CONTROL_RPUB_KEY_H_3 */ ++ case 0x310: /* CONTROL_RAND_KEY_0 */ ++ case 0x314: /* CONTROL_RAND_KEY_1 */ ++ case 0x318: /* CONTROL_RAND_KEY_2 */ ++ case 0x31c: /* CONTROL_RAND_KEY_3 */ ++ case 0x320: /* CONTROL_CUST_KEY_0 */ ++ case 0x324: /* CONTROL_CUST_KEY_1 */ ++ case 0x330: /* CONTROL_TEST_KEY_0 */ ++ case 0x334: /* CONTROL_TEST_KEY_1 */ ++ case 0x338: /* CONTROL_TEST_KEY_2 */ ++ case 0x33c: /* CONTROL_TEST_KEY_3 */ ++ case 0x340: /* CONTROL_TEST_KEY_4 */ ++ case 0x344: /* CONTROL_TEST_KEY_5 */ ++ case 0x348: /* CONTROL_TEST_KEY_6 */ ++ case 0x34c: /* CONTROL_TEST_KEY_7 */ ++ case 0x350: /* CONTROL_TEST_KEY_8 */ ++ case 0x354: /* CONTROL_TEST_KEY_9 */ ++ OMAP_RO_REG(addr); ++ return; ++ ++ case 0x010: /* CONTROL_SYSCONFIG */ ++ s->sysconfig = value & 0x1e; ++ break; ++ ++ case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */ ++ /* XXX: should check constant bits */ ++ s->padconf[(offset - 0x30) >> 2] = value & 0x1f1f1f1f; ++ break; ++ ++ case 0x270: /* CONTROL_DEBOBS */ ++ s->obs = value & 0xff; ++ break; ++ ++ case 0x274: /* CONTROL_DEVCONF */ ++ s->devconfig = value & 0xffffc7ff; ++ break; ++ ++ case 0x28c: /* CONTROL_EMU_SUPPORT */ ++ break; ++ ++ case 0x290: /* CONTROL_MSUSPENDMUX_0 */ ++ s->msuspendmux[0] = value & 0x3fffffff; ++ break; ++ case 0x294: /* CONTROL_MSUSPENDMUX_1 */ ++ s->msuspendmux[1] = value & 0x3fffffff; ++ break; ++ case 0x298: /* CONTROL_MSUSPENDMUX_2 */ ++ s->msuspendmux[2] = value & 0x3fffffff; ++ break; ++ case 0x29c: /* CONTROL_MSUSPENDMUX_3 */ ++ s->msuspendmux[3] = value & 0x3fffffff; ++ break; ++ case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */ ++ s->msuspendmux[4] = value & 0x3fffffff; ++ break; ++ ++ case 0x2b8: /* CONTROL_PSA_CTRL */ ++ s->psaconfig = value & 0x1c; ++ s->psaconfig |= (value & 0x20) ? 2 : 1; ++ break; ++ case 0x2bc: /* CONTROL_PSA_CMD */ ++ break; ++ ++ case 0x2b0: /* CONTROL_SEC_CTRL */ ++ case 0x2b4: /* CONTROL_SEC_TEST */ ++ case 0x2d0: /* CONTROL_SEC_EMU */ ++ case 0x2d4: /* CONTROL_SEC_TAP */ ++ case 0x2d8: /* CONTROL_OCM_RAM_PERM */ ++ case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */ ++ case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */ ++ case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */ ++ case 0x2f0: /* CONTROL_SEC_STATUS */ ++ case 0x2f4: /* CONTROL_SEC_ERR_STATUS */ ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return; ++ } ++} ++ ++static CPUReadMemoryFunc *omap_sysctl_readfn[] = { ++ omap_badwidth_read32, /* TODO */ ++ omap_badwidth_read32, /* TODO */ ++ omap_sysctl_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_sysctl_writefn[] = { ++ omap_badwidth_write32, /* TODO */ ++ omap_badwidth_write32, /* TODO */ ++ omap_sysctl_write, ++}; ++ ++static void omap_sysctl_reset(struct omap_sysctl_s *s) ++{ ++ /* (power-on reset) */ ++ s->sysconfig = 0; ++ s->obs = 0; ++ s->devconfig = 0x0c000000; ++ s->msuspendmux[0] = 0x00000000; ++ s->msuspendmux[1] = 0x00000000; ++ s->msuspendmux[2] = 0x00000000; ++ s->msuspendmux[3] = 0x00000000; ++ s->msuspendmux[4] = 0x00000000; ++ s->psaconfig = 1; ++ ++ s->padconf[0x00] = 0x000f0f0f; ++ s->padconf[0x01] = 0x00000000; ++ s->padconf[0x02] = 0x00000000; ++ s->padconf[0x03] = 0x00000000; ++ s->padconf[0x04] = 0x00000000; ++ s->padconf[0x05] = 0x00000000; ++ s->padconf[0x06] = 0x00000000; ++ s->padconf[0x07] = 0x00000000; ++ s->padconf[0x08] = 0x08080800; ++ s->padconf[0x09] = 0x08080808; ++ s->padconf[0x0a] = 0x08080808; ++ s->padconf[0x0b] = 0x08080808; ++ s->padconf[0x0c] = 0x08080808; ++ s->padconf[0x0d] = 0x08080800; ++ s->padconf[0x0e] = 0x08080808; ++ s->padconf[0x0f] = 0x08080808; ++ s->padconf[0x10] = 0x18181808; /* | 0x07070700 if SBoot3 */ ++ s->padconf[0x11] = 0x18181818; /* | 0x07070707 if SBoot3 */ ++ s->padconf[0x12] = 0x18181818; /* | 0x07070707 if SBoot3 */ ++ s->padconf[0x13] = 0x18181818; /* | 0x07070707 if SBoot3 */ ++ s->padconf[0x14] = 0x18181818; /* | 0x00070707 if SBoot3 */ ++ s->padconf[0x15] = 0x18181818; ++ s->padconf[0x16] = 0x18181818; /* | 0x07000000 if SBoot3 */ ++ s->padconf[0x17] = 0x1f001f00; ++ s->padconf[0x18] = 0x1f1f1f1f; ++ s->padconf[0x19] = 0x00000000; ++ s->padconf[0x1a] = 0x1f180000; ++ s->padconf[0x1b] = 0x00001f1f; ++ s->padconf[0x1c] = 0x1f001f00; ++ s->padconf[0x1d] = 0x00000000; ++ s->padconf[0x1e] = 0x00000000; ++ s->padconf[0x1f] = 0x08000000; ++ s->padconf[0x20] = 0x08080808; ++ s->padconf[0x21] = 0x08080808; ++ s->padconf[0x22] = 0x0f080808; ++ s->padconf[0x23] = 0x0f0f0f0f; ++ s->padconf[0x24] = 0x000f0f0f; ++ s->padconf[0x25] = 0x1f1f1f0f; ++ s->padconf[0x26] = 0x080f0f1f; ++ s->padconf[0x27] = 0x070f1808; ++ s->padconf[0x28] = 0x0f070707; ++ s->padconf[0x29] = 0x000f0f1f; ++ s->padconf[0x2a] = 0x0f0f0f1f; ++ s->padconf[0x2b] = 0x08000000; ++ s->padconf[0x2c] = 0x0000001f; ++ s->padconf[0x2d] = 0x0f0f1f00; ++ s->padconf[0x2e] = 0x1f1f0f0f; ++ s->padconf[0x2f] = 0x0f1f1f1f; ++ s->padconf[0x30] = 0x0f0f0f0f; ++ s->padconf[0x31] = 0x0f1f0f1f; ++ s->padconf[0x32] = 0x0f0f0f0f; ++ s->padconf[0x33] = 0x0f1f0f1f; ++ s->padconf[0x34] = 0x1f1f0f0f; ++ s->padconf[0x35] = 0x0f0f1f1f; ++ s->padconf[0x36] = 0x0f0f1f0f; ++ s->padconf[0x37] = 0x0f0f0f0f; ++ s->padconf[0x38] = 0x1f18180f; ++ s->padconf[0x39] = 0x1f1f1f1f; ++ s->padconf[0x3a] = 0x00001f1f; ++ s->padconf[0x3b] = 0x00000000; ++ s->padconf[0x3c] = 0x00000000; ++ s->padconf[0x3d] = 0x0f0f0f0f; ++ s->padconf[0x3e] = 0x18000f0f; ++ s->padconf[0x3f] = 0x00070000; ++ s->padconf[0x40] = 0x00000707; ++ s->padconf[0x41] = 0x0f1f0700; ++ s->padconf[0x42] = 0x1f1f070f; ++ s->padconf[0x43] = 0x0008081f; ++ s->padconf[0x44] = 0x00000800; ++} ++ ++struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, ++ omap_clk iclk, struct omap_mpu_state_s *mpu) ++{ ++ int iomemtype; ++ struct omap_sysctl_s *s = (struct omap_sysctl_s *) ++ qemu_mallocz(sizeof(struct omap_sysctl_s)); ++ ++ s->mpu = mpu; ++ omap_sysctl_reset(s); ++ ++ iomemtype = cpu_register_io_memory(0, omap_sysctl_readfn, ++ omap_sysctl_writefn, s); ++ s->base = omap_l4_attach(ta, 0, iomemtype); ++ omap_l4_attach(ta, 0, iomemtype); ++ ++ return s; ++} ++ ++/* SDRAM Controller Subsystem */ ++struct omap_sdrc_s { ++ target_phys_addr_t base; ++ ++ uint8_t config; ++}; ++ ++static void omap_sdrc_reset(struct omap_sdrc_s *s) ++{ ++ s->config = 0x10; ++} ++ ++static uint32_t omap_sdrc_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x00: /* SDRC_REVISION */ ++ return 0x20; ++ ++ case 0x10: /* SDRC_SYSCONFIG */ ++ return s->config; ++ ++ case 0x14: /* SDRC_SYSSTATUS */ ++ return 1; /* RESETDONE */ ++ ++ case 0x40: /* SDRC_CS_CFG */ ++ case 0x44: /* SDRC_SHARING */ ++ case 0x48: /* SDRC_ERR_ADDR */ ++ case 0x4c: /* SDRC_ERR_TYPE */ ++ case 0x60: /* SDRC_DLLA_SCTRL */ ++ case 0x64: /* SDRC_DLLA_STATUS */ ++ case 0x68: /* SDRC_DLLB_CTRL */ ++ case 0x6c: /* SDRC_DLLB_STATUS */ ++ case 0x70: /* SDRC_POWER */ ++ case 0x80: /* SDRC_MCFG_0 */ ++ case 0x84: /* SDRC_MR_0 */ ++ case 0x88: /* SDRC_EMR1_0 */ ++ case 0x8c: /* SDRC_EMR2_0 */ ++ case 0x90: /* SDRC_EMR3_0 */ ++ case 0x94: /* SDRC_DCDL1_CTRL */ ++ case 0x98: /* SDRC_DCDL2_CTRL */ ++ case 0x9c: /* SDRC_ACTIM_CTRLA_0 */ ++ case 0xa0: /* SDRC_ACTIM_CTRLB_0 */ ++ case 0xa4: /* SDRC_RFR_CTRL_0 */ ++ case 0xa8: /* SDRC_MANUAL_0 */ ++ case 0xb0: /* SDRC_MCFG_1 */ ++ case 0xb4: /* SDRC_MR_1 */ ++ case 0xb8: /* SDRC_EMR1_1 */ ++ case 0xbc: /* SDRC_EMR2_1 */ ++ case 0xc0: /* SDRC_EMR3_1 */ ++ case 0xc4: /* SDRC_ACTIM_CTRLA_1 */ ++ case 0xc8: /* SDRC_ACTIM_CTRLB_1 */ ++ case 0xd4: /* SDRC_RFR_CTRL_1 */ ++ case 0xd8: /* SDRC_MANUAL_1 */ ++ return 0x00; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_sdrc_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; ++ int offset = addr - s->base; ++ ++ switch (offset) { ++ case 0x00: /* SDRC_REVISION */ ++ case 0x14: /* SDRC_SYSSTATUS */ ++ case 0x48: /* SDRC_ERR_ADDR */ ++ case 0x64: /* SDRC_DLLA_STATUS */ ++ case 0x6c: /* SDRC_DLLB_STATUS */ ++ OMAP_RO_REG(addr); ++ return; ++ ++ case 0x10: /* SDRC_SYSCONFIG */ ++ if ((value >> 3) != 0x2) ++ fprintf(stderr, "%s: bad SDRAM idle mode %i\n", ++ __FUNCTION__, value >> 3); ++ if (value & 2) ++ omap_sdrc_reset(s); ++ s->config = value & 0x18; ++ break; ++ ++ case 0x40: /* SDRC_CS_CFG */ ++ case 0x44: /* SDRC_SHARING */ ++ case 0x4c: /* SDRC_ERR_TYPE */ ++ case 0x60: /* SDRC_DLLA_SCTRL */ ++ case 0x68: /* SDRC_DLLB_CTRL */ ++ case 0x70: /* SDRC_POWER */ ++ case 0x80: /* SDRC_MCFG_0 */ ++ case 0x84: /* SDRC_MR_0 */ ++ case 0x88: /* SDRC_EMR1_0 */ ++ case 0x8c: /* SDRC_EMR2_0 */ ++ case 0x90: /* SDRC_EMR3_0 */ ++ case 0x94: /* SDRC_DCDL1_CTRL */ ++ case 0x98: /* SDRC_DCDL2_CTRL */ ++ case 0x9c: /* SDRC_ACTIM_CTRLA_0 */ ++ case 0xa0: /* SDRC_ACTIM_CTRLB_0 */ ++ case 0xa4: /* SDRC_RFR_CTRL_0 */ ++ case 0xa8: /* SDRC_MANUAL_0 */ ++ case 0xb0: /* SDRC_MCFG_1 */ ++ case 0xb4: /* SDRC_MR_1 */ ++ case 0xb8: /* SDRC_EMR1_1 */ ++ case 0xbc: /* SDRC_EMR2_1 */ ++ case 0xc0: /* SDRC_EMR3_1 */ ++ case 0xc4: /* SDRC_ACTIM_CTRLA_1 */ ++ case 0xc8: /* SDRC_ACTIM_CTRLB_1 */ ++ case 0xd4: /* SDRC_RFR_CTRL_1 */ ++ case 0xd8: /* SDRC_MANUAL_1 */ ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return; ++ } ++} ++ ++static CPUReadMemoryFunc *omap_sdrc_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap_sdrc_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_sdrc_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_sdrc_write, ++}; ++ ++struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base) ++{ ++ int iomemtype; ++ struct omap_sdrc_s *s = (struct omap_sdrc_s *) ++ qemu_mallocz(sizeof(struct omap_sdrc_s)); ++ ++ s->base = base; ++ omap_sdrc_reset(s); ++ ++ iomemtype = cpu_register_io_memory(0, omap_sdrc_readfn, ++ omap_sdrc_writefn, s); ++ cpu_register_physical_memory(s->base, 0x1000, iomemtype); ++ ++ return s; ++} ++ ++/* General-Purpose Memory Controller */ ++struct omap_gpmc_s { ++ target_phys_addr_t base; ++ qemu_irq irq; ++ ++ uint8_t sysconfig; ++ uint16_t irqst; ++ uint16_t irqen; ++ uint16_t timeout; ++ uint16_t config; ++ uint32_t prefconfig[2]; ++ int prefcontrol; ++ int preffifo; ++ int prefcount; ++ struct omap_gpmc_cs_file_s { ++ uint32_t config[7]; ++ target_phys_addr_t base; ++ size_t size; ++ int iomemtype; ++ void (*base_update)(void *opaque, target_phys_addr_t new); ++ void (*unmap)(void *opaque); ++ void *opaque; ++ } cs_file[8]; ++ int ecc_cs; ++ int ecc_ptr; ++ uint32_t ecc_cfg; ++ struct ecc_state_s ecc[9]; ++}; ++ ++static void omap_gpmc_int_update(struct omap_gpmc_s *s) ++{ ++ qemu_set_irq(s->irq, s->irqen & s->irqst); ++} ++ ++static void omap_gpmc_cs_map(struct omap_gpmc_cs_file_s *f, int base, int mask) ++{ ++ /* TODO: check for overlapping regions and report access errors */ ++ if ((mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf) || ++ (base < 0 || base >= 0x40) || ++ (base & 0x0f & ~mask)) { ++ fprintf(stderr, "%s: wrong cs address mapping/decoding!\n", ++ __FUNCTION__); ++ return; ++ } ++ ++ if (!f->opaque) ++ return; ++ ++ f->base = base << 24; ++ f->size = (0x0fffffff & ~(mask << 24)) + 1; ++ /* TODO: rather than setting the size of the mapping (which should be ++ * constant), the mask should cause wrapping of the address space, so ++ * that the same memory becomes accessible at every <i>size</i> bytes ++ * starting from <i>base</i>. */ ++ if (f->iomemtype) ++ cpu_register_physical_memory(f->base, f->size, f->iomemtype); ++ ++ if (f->base_update) ++ f->base_update(f->opaque, f->base); ++} ++ ++static void omap_gpmc_cs_unmap(struct omap_gpmc_cs_file_s *f) ++{ ++ if (f->size) { ++ if (f->unmap) ++ f->unmap(f->opaque); ++ if (f->iomemtype) ++ cpu_register_physical_memory(f->base, f->size, IO_MEM_UNASSIGNED); ++ f->base = 0; ++ f->size = 0; ++ } ++} ++ ++static void omap_gpmc_reset(struct omap_gpmc_s *s) ++{ ++ int i; ++ ++ s->sysconfig = 0; ++ s->irqst = 0; ++ s->irqen = 0; ++ omap_gpmc_int_update(s); ++ s->timeout = 0; ++ s->config = 0xa00; ++ s->prefconfig[0] = 0x00004000; ++ s->prefconfig[1] = 0x00000000; ++ s->prefcontrol = 0; ++ s->preffifo = 0; ++ s->prefcount = 0; ++ for (i = 0; i < 8; i ++) { ++ if (s->cs_file[i].config[6] & (1 << 6)) /* CSVALID */ ++ omap_gpmc_cs_unmap(s->cs_file + i); ++ s->cs_file[i].config[0] = i ? 1 << 12 : 0; ++ s->cs_file[i].config[1] = 0x101001; ++ s->cs_file[i].config[2] = 0x020201; ++ s->cs_file[i].config[3] = 0x10031003; ++ s->cs_file[i].config[4] = 0x10f1111; ++ s->cs_file[i].config[5] = 0; ++ s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6); ++ if (s->cs_file[i].config[6] & (1 << 6)) /* CSVALID */ ++ omap_gpmc_cs_map(&s->cs_file[i], ++ s->cs_file[i].config[6] & 0x1f, /* MASKADDR */ ++ (s->cs_file[i].config[6] >> 8 & 0xf)); /* BASEADDR */ ++ } ++ omap_gpmc_cs_map(s->cs_file, 0, 0xf); ++ s->ecc_cs = 0; ++ s->ecc_ptr = 0; ++ s->ecc_cfg = 0x3fcff000; ++ for (i = 0; i < 9; i ++) ++ ecc_reset(&s->ecc[i]); ++} ++ ++static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; ++ int offset = addr - s->base; ++ int cs; ++ struct omap_gpmc_cs_file_s *f; ++ ++ switch (offset) { ++ case 0x000: /* GPMC_REVISION */ ++ return 0x20; ++ ++ case 0x010: /* GPMC_SYSCONFIG */ ++ return s->sysconfig; ++ ++ case 0x014: /* GPMC_SYSSTATUS */ ++ return 1; /* RESETDONE */ ++ ++ case 0x018: /* GPMC_IRQSTATUS */ ++ return s->irqst; ++ ++ case 0x01c: /* GPMC_IRQENABLE */ ++ return s->irqen; ++ ++ case 0x040: /* GPMC_TIMEOUT_CONTROL */ ++ return s->timeout; ++ ++ case 0x044: /* GPMC_ERR_ADDRESS */ ++ case 0x048: /* GPMC_ERR_TYPE */ ++ return 0; ++ ++ case 0x050: /* GPMC_CONFIG */ ++ return s->config; ++ ++ case 0x054: /* GPMC_STATUS */ ++ return 0x001; ++ ++ case 0x060 ... 0x1d4: ++ cs = (offset - 0x060) / 0x30; ++ offset -= cs * 0x30; ++ f = s->cs_file + cs; ++ switch (offset - cs * 0x30) { ++ case 0x60: /* GPMC_CONFIG1 */ ++ return f->config[0]; ++ case 0x64: /* GPMC_CONFIG2 */ ++ return f->config[1]; ++ case 0x68: /* GPMC_CONFIG3 */ ++ return f->config[2]; ++ case 0x6c: /* GPMC_CONFIG4 */ ++ return f->config[3]; ++ case 0x70: /* GPMC_CONFIG5 */ ++ return f->config[4]; ++ case 0x74: /* GPMC_CONFIG6 */ ++ return f->config[5]; ++ case 0x78: /* GPMC_CONFIG7 */ ++ return f->config[6]; ++ case 0x84: /* GPMC_NAND_DATA */ ++ return 0; ++ } ++ break; ++ ++ case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ ++ return s->prefconfig[0]; ++ case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ ++ return s->prefconfig[1]; ++ case 0x1ec: /* GPMC_PREFETCH_CONTROL */ ++ return s->prefcontrol; ++ case 0x1f0: /* GPMC_PREFETCH_STATUS */ ++ return (s->preffifo << 24) | ++ ((s->preffifo > ++ ((s->prefconfig[0] >> 8) & 0x7f) ? 1 : 0) << 16) | ++ s->prefcount; ++ ++ case 0x1f4: /* GPMC_ECC_CONFIG */ ++ return s->ecc_cs; ++ case 0x1f8: /* GPMC_ECC_CONTROL */ ++ return s->ecc_ptr; ++ case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ ++ return s->ecc_cfg; ++ case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ ++ cs = (offset & 0x1f) >> 2; ++ /* TODO: check correctness */ ++ return ++ ((s->ecc[cs].cp & 0x07) << 0) | ++ ((s->ecc[cs].cp & 0x38) << 13) | ++ ((s->ecc[cs].lp[0] & 0x1ff) << 3) | ++ ((s->ecc[cs].lp[1] & 0x1ff) << 19); ++ ++ case 0x230: /* GPMC_TESTMODE_CTRL */ ++ return 0; ++ case 0x234: /* GPMC_PSA_LSB */ ++ case 0x238: /* GPMC_PSA_MSB */ ++ return 0x00000000; ++ } ++ ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_gpmc_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; ++ int offset = addr - s->base; ++ int cs; ++ struct omap_gpmc_cs_file_s *f; ++ ++ switch (offset) { ++ case 0x000: /* GPMC_REVISION */ ++ case 0x014: /* GPMC_SYSSTATUS */ ++ case 0x054: /* GPMC_STATUS */ ++ case 0x1f0: /* GPMC_PREFETCH_STATUS */ ++ case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ ++ case 0x234: /* GPMC_PSA_LSB */ ++ case 0x238: /* GPMC_PSA_MSB */ ++ OMAP_RO_REG(addr); ++ break; ++ ++ case 0x010: /* GPMC_SYSCONFIG */ ++ if ((value >> 3) == 0x3) ++ fprintf(stderr, "%s: bad SDRAM idle mode %i\n", ++ __FUNCTION__, value >> 3); ++ if (value & 2) ++ omap_gpmc_reset(s); ++ s->sysconfig = value & 0x19; ++ break; ++ ++ case 0x018: /* GPMC_IRQSTATUS */ ++ s->irqen = ~value; ++ omap_gpmc_int_update(s); ++ break; ++ ++ case 0x01c: /* GPMC_IRQENABLE */ ++ s->irqen = value & 0xf03; ++ omap_gpmc_int_update(s); ++ break; ++ ++ case 0x040: /* GPMC_TIMEOUT_CONTROL */ ++ s->timeout = value & 0x1ff1; ++ break; ++ ++ case 0x044: /* GPMC_ERR_ADDRESS */ ++ case 0x048: /* GPMC_ERR_TYPE */ ++ break; ++ ++ case 0x050: /* GPMC_CONFIG */ ++ s->config = value & 0xf13; ++ break; ++ ++ case 0x060 ... 0x1d4: ++ cs = (offset - 0x060) / 0x30; ++ offset -= cs * 0x30; ++ f = s->cs_file + cs; ++ switch (offset - cs * 0x30) { ++ case 0x60: /* GPMC_CONFIG1 */ ++ f->config[0] = value & 0xffef3e13; ++ break; ++ case 0x64: /* GPMC_CONFIG2 */ ++ f->config[1] = value & 0x001f1f8f; ++ break; ++ case 0x68: /* GPMC_CONFIG3 */ ++ f->config[2] = value & 0x001f1f8f; ++ break; ++ case 0x6c: /* GPMC_CONFIG4 */ ++ f->config[3] = value & 0x1f8f1f8f; ++ break; ++ case 0x70: /* GPMC_CONFIG5 */ ++ f->config[4] = value & 0x0f1f1f1f; ++ break; ++ case 0x74: /* GPMC_CONFIG6 */ ++ f->config[5] = value & 0x00000fcf; ++ break; ++ case 0x78: /* GPMC_CONFIG7 */ ++ if ((f->config[6] ^ value) & 0xf7f) { ++ if (f->config[6] & (1 << 6)) /* CSVALID */ ++ omap_gpmc_cs_unmap(f); ++ if (value & (1 << 6)) /* CSVALID */ ++ omap_gpmc_cs_map(f, value & 0x1f, /* MASKADDR */ ++ (value >> 8 & 0xf)); /* BASEADDR */ ++ } ++ f->config[6] = value & 0x00000f7f; ++ break; ++ case 0x7c: /* GPMC_NAND_COMMAND */ ++ case 0x80: /* GPMC_NAND_ADDRESS */ ++ case 0x84: /* GPMC_NAND_DATA */ ++ break; ++ ++ default: ++ goto bad_reg; ++ } ++ break; ++ ++ case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ ++ s->prefconfig[0] = value & 0x7f8f7fbf; ++ /* TODO: update interrupts, fifos, dmas */ ++ break; ++ ++ case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ ++ s->prefconfig[1] = value & 0x3fff; ++ break; ++ ++ case 0x1ec: /* GPMC_PREFETCH_CONTROL */ ++ s->prefcontrol = value & 1; ++ if (s->prefcontrol) { ++ if (s->prefconfig[0] & 1) ++ s->preffifo = 0x40; ++ else ++ s->preffifo = 0x00; ++ } ++ /* TODO: start */ ++ break; ++ ++ case 0x1f4: /* GPMC_ECC_CONFIG */ ++ s->ecc_cs = 0x8f; ++ break; ++ case 0x1f8: /* GPMC_ECC_CONTROL */ ++ if (value & (1 << 8)) ++ for (cs = 0; cs < 9; cs ++) ++ ecc_reset(&s->ecc[cs]); ++ s->ecc_ptr = value & 0xf; ++ if (s->ecc_ptr == 0 || s->ecc_ptr > 9) { ++ s->ecc_ptr = 0; ++ s->ecc_cs &= ~1; ++ } ++ break; ++ case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ ++ s->ecc_cfg = value & 0x3fcff1ff; ++ break; ++ case 0x230: /* GPMC_TESTMODE_CTRL */ ++ if (value & 7) ++ fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__); ++ break; ++ ++ default: ++ bad_reg: ++ OMAP_BAD_REG(addr); ++ return; ++ } ++} ++ ++static CPUReadMemoryFunc *omap_gpmc_readfn[] = { ++ omap_badwidth_read32, /* TODO */ ++ omap_badwidth_read32, /* TODO */ ++ omap_gpmc_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_gpmc_writefn[] = { ++ omap_badwidth_write32, /* TODO */ ++ omap_badwidth_write32, /* TODO */ ++ omap_gpmc_write, ++}; ++ ++struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq) ++{ ++ int iomemtype; ++ struct omap_gpmc_s *s = (struct omap_gpmc_s *) ++ qemu_mallocz(sizeof(struct omap_gpmc_s)); ++ ++ s->base = base; ++ omap_gpmc_reset(s); ++ ++ iomemtype = cpu_register_io_memory(0, omap_gpmc_readfn, ++ omap_gpmc_writefn, s); ++ cpu_register_physical_memory(s->base, 0x1000, iomemtype); ++ ++ return s; ++} ++ ++void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype, ++ void (*base_upd)(void *opaque, target_phys_addr_t new), ++ void (*unmap)(void *opaque), void *opaque) ++{ ++ struct omap_gpmc_cs_file_s *f; ++ ++ if (cs < 0 || cs >= 8) { ++ fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs); ++ exit(-1); ++ } ++ f = &s->cs_file[cs]; ++ ++ f->iomemtype = iomemtype; ++ f->base_update = base_upd; ++ f->unmap = unmap; ++ f->opaque = opaque; ++ ++ if (f->config[6] & (1 << 6)) /* CSVALID */ ++ omap_gpmc_cs_map(f, f->config[6] & 0x1f, /* MASKADDR */ ++ (f->config[6] >> 8 & 0xf)); /* BASEADDR */ ++} ++ ++/* General chip reset */ ++static void omap2_mpu_reset(void *opaque) ++{ ++ struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; ++ ++ omap_inth_reset(mpu->ih[0]); ++ omap_dma_reset(mpu->dma); ++ omap_prcm_reset(mpu->prcm); ++ omap_sysctl_reset(mpu->sysc); ++ omap_gp_timer_reset(mpu->gptimer[0]); ++ omap_gp_timer_reset(mpu->gptimer[1]); ++ omap_gp_timer_reset(mpu->gptimer[2]); ++ omap_gp_timer_reset(mpu->gptimer[3]); ++ omap_gp_timer_reset(mpu->gptimer[4]); ++ omap_gp_timer_reset(mpu->gptimer[5]); ++ omap_gp_timer_reset(mpu->gptimer[6]); ++ omap_gp_timer_reset(mpu->gptimer[7]); ++ omap_gp_timer_reset(mpu->gptimer[8]); ++ omap_gp_timer_reset(mpu->gptimer[9]); ++ omap_gp_timer_reset(mpu->gptimer[10]); ++ omap_gp_timer_reset(mpu->gptimer[11]); ++ omap_synctimer_reset(&mpu->synctimer); ++ omap_sdrc_reset(mpu->sdrc); ++ omap_gpmc_reset(mpu->gpmc); ++ omap_dss_reset(mpu->dss); ++#if 0 ++ omap_wd_timer_reset(mpu->wdt); ++ omap_ulpd_pm_reset(mpu); ++ omap_pin_cfg_reset(mpu); ++ omap_mpui_reset(mpu); ++ omap_tipb_bridge_reset(mpu->private_tipb); ++ omap_tipb_bridge_reset(mpu->public_tipb); ++ omap_dpll_reset(&mpu->dpll[0]); ++ omap_dpll_reset(&mpu->dpll[1]); ++ omap_dpll_reset(&mpu->dpll[2]); ++#endif ++ omap_uart_reset(mpu->uart[0]); ++ omap_uart_reset(mpu->uart[1]); ++ omap_uart_reset(mpu->uart[2]); ++ omap_mmc_reset(mpu->mmc); ++ omap_gpif_reset(mpu->gpif); ++ omap_mcspi_reset(mpu->mcspi[0]); ++ omap_mcspi_reset(mpu->mcspi[1]); ++#if 0 ++ omap_pwl_reset(mpu); ++ omap_pwt_reset(mpu); ++#endif ++ omap_i2c_reset(mpu->i2c[0]); ++ omap_i2c_reset(mpu->i2c[1]); ++#if 0 ++ omap_rtc_reset(mpu->rtc); ++ omap_mcbsp_reset(mpu->mcbsp1); ++ omap_mcbsp_reset(mpu->mcbsp2); ++ omap_mcbsp_reset(mpu->mcbsp3); ++ omap_lpg_reset(mpu->led[0]); ++ omap_lpg_reset(mpu->led[1]); ++ omap_clkm_reset(mpu); ++#endif ++ cpu_reset(mpu->env); ++} ++ ++static int omap2_validate_addr(struct omap_mpu_state_s *s, ++ target_phys_addr_t addr) ++{ ++ return 1; ++} ++ ++static const struct dma_irq_map omap2_dma_irq_map[] = { ++ { 0, OMAP_INT_24XX_SDMA_IRQ0 }, ++ { 0, OMAP_INT_24XX_SDMA_IRQ1 }, ++ { 0, OMAP_INT_24XX_SDMA_IRQ2 }, ++ { 0, OMAP_INT_24XX_SDMA_IRQ3 }, ++}; ++ ++struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size, ++ DisplayState *ds, const char *core) ++{ ++ struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) ++ qemu_mallocz(sizeof(struct omap_mpu_state_s)); ++ ram_addr_t sram_base, q3_base; ++ qemu_irq *cpu_irq; ++ qemu_irq dma_irqs[4]; ++ omap_clk gpio_clks[4]; ++ int sdindex; ++ int i; ++ ++ /* Core */ ++ s->mpu_model = omap2420; ++ s->env = cpu_init(core ?: "arm1136-r2"); ++ if (!s->env) { ++ fprintf(stderr, "Unable to find CPU definition\n"); ++ exit(1); ++ } ++ s->sdram_size = sdram_size; ++ s->sram_size = OMAP242X_SRAM_SIZE; ++ ++ s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; ++ ++ /* Clocks */ ++ omap_clk_init(s); ++ ++ /* Memory-mapped stuff */ ++ cpu_register_physical_memory(OMAP2_Q2_BASE, s->sdram_size, ++ (q3_base = qemu_ram_alloc(s->sdram_size)) | IO_MEM_RAM); ++ cpu_register_physical_memory(OMAP2_SRAM_BASE, s->sram_size, ++ (sram_base = qemu_ram_alloc(s->sram_size)) | IO_MEM_RAM); ++ ++ s->l4 = omap_l4_init(OMAP2_L4_BASE, 54); ++ ++ /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */ ++ cpu_irq = arm_pic_init_cpu(s->env); ++ s->ih[0] = omap2_inth_init(0x480fe000, 0x1000, 3, &s->irq[0], ++ cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ], ++ omap_findclk(s, "mpu_intc_fclk"), ++ omap_findclk(s, "mpu_intc_iclk")); ++ ++ s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3), ++ s->irq[0][OMAP_INT_24XX_PRCM_MPU_IRQ], NULL, NULL, s); ++ ++ s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1), ++ omap_findclk(s, "omapctrl_iclk"), s); ++ ++ for (i = 0; i < 4; i ++) ++ dma_irqs[i] = ++ s->irq[omap2_dma_irq_map[i].ih][omap2_dma_irq_map[i].intr]; ++ s->dma = omap_dma4_init(0x48056000, dma_irqs, s, 256, 32, ++ omap_findclk(s, "sdma_iclk"), ++ omap_findclk(s, "sdma_fclk")); ++ s->port->addr_valid = omap2_validate_addr; ++ ++ s->uart[0] = omap2_uart_init(omap_l4ta(s->l4, 19), ++ s->irq[0][OMAP_INT_24XX_UART1_IRQ], ++ omap_findclk(s, "uart1_fclk"), ++ omap_findclk(s, "uart1_iclk"), ++ s->drq[OMAP24XX_DMA_UART1_TX], ++ s->drq[OMAP24XX_DMA_UART1_RX], serial_hds[0]); ++ s->uart[1] = omap2_uart_init(omap_l4ta(s->l4, 20), ++ s->irq[0][OMAP_INT_24XX_UART2_IRQ], ++ omap_findclk(s, "uart2_fclk"), ++ omap_findclk(s, "uart2_iclk"), ++ s->drq[OMAP24XX_DMA_UART2_TX], ++ s->drq[OMAP24XX_DMA_UART2_RX], ++ serial_hds[0] ? serial_hds[1] : 0); ++ s->uart[2] = omap2_uart_init(omap_l4ta(s->l4, 21), ++ s->irq[0][OMAP_INT_24XX_UART3_IRQ], ++ omap_findclk(s, "uart3_fclk"), ++ omap_findclk(s, "uart3_iclk"), ++ s->drq[OMAP24XX_DMA_UART3_TX], ++ s->drq[OMAP24XX_DMA_UART3_RX], ++ serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0); ++ ++ s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7), ++ s->irq[0][OMAP_INT_24XX_GPTIMER1], ++ omap_findclk(s, "wu_gpt1_clk"), ++ omap_findclk(s, "wu_l4_iclk")); ++ s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8), ++ s->irq[0][OMAP_INT_24XX_GPTIMER2], ++ omap_findclk(s, "core_gpt2_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22), ++ s->irq[0][OMAP_INT_24XX_GPTIMER3], ++ omap_findclk(s, "core_gpt3_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23), ++ s->irq[0][OMAP_INT_24XX_GPTIMER4], ++ omap_findclk(s, "core_gpt4_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24), ++ s->irq[0][OMAP_INT_24XX_GPTIMER5], ++ omap_findclk(s, "core_gpt5_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25), ++ s->irq[0][OMAP_INT_24XX_GPTIMER6], ++ omap_findclk(s, "core_gpt6_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26), ++ s->irq[0][OMAP_INT_24XX_GPTIMER7], ++ omap_findclk(s, "core_gpt7_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27), ++ s->irq[0][OMAP_INT_24XX_GPTIMER8], ++ omap_findclk(s, "core_gpt8_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28), ++ s->irq[0][OMAP_INT_24XX_GPTIMER9], ++ omap_findclk(s, "core_gpt9_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29), ++ s->irq[0][OMAP_INT_24XX_GPTIMER10], ++ omap_findclk(s, "core_gpt10_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30), ++ s->irq[0][OMAP_INT_24XX_GPTIMER11], ++ omap_findclk(s, "core_gpt11_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31), ++ s->irq[0][OMAP_INT_24XX_GPTIMER12], ++ omap_findclk(s, "core_gpt12_clk"), ++ omap_findclk(s, "core_l4_iclk")); ++ ++ omap_tap_init(omap_l4ta(s->l4, 2), s); ++ ++ omap_synctimer_init(omap_l4tao(s->l4, 2), s, ++ omap_findclk(s, "clk32-kHz"), ++ omap_findclk(s, "core_l4_iclk")); ++ ++ s->i2c[0] = omap2_i2c_init(omap_l4tao(s->l4, 5), ++ s->irq[0][OMAP_INT_24XX_I2C1_IRQ], ++ &s->drq[OMAP24XX_DMA_I2C1_TX], ++ omap_findclk(s, "i2c1.fclk"), ++ omap_findclk(s, "i2c1.iclk")); ++ s->i2c[1] = omap2_i2c_init(omap_l4tao(s->l4, 6), ++ s->irq[0][OMAP_INT_24XX_I2C2_IRQ], ++ &s->drq[OMAP24XX_DMA_I2C2_TX], ++ omap_findclk(s, "i2c2.fclk"), ++ omap_findclk(s, "i2c2.iclk")); ++ ++ gpio_clks[0] = omap_findclk(s, "gpio1_dbclk"); ++ gpio_clks[1] = omap_findclk(s, "gpio2_dbclk"); ++ gpio_clks[2] = omap_findclk(s, "gpio3_dbclk"); ++ gpio_clks[3] = omap_findclk(s, "gpio4_dbclk"); ++ s->gpif = omap2_gpio_init(omap_l4ta(s->l4, 3), ++ &s->irq[0][OMAP_INT_24XX_GPIO_BANK1], ++ gpio_clks, omap_findclk(s, "gpio_iclk"), 4); ++ ++ s->sdrc = omap_sdrc_init(0x68009000); ++ s->gpmc = omap_gpmc_init(0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ]); ++ ++ sdindex = drive_get_index(IF_SD, 0, 0); ++ if (sdindex == -1) { ++ fprintf(stderr, "qemu: missing SecureDigital device\n"); ++ exit(1); ++ } ++ s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), drives_table[sdindex].bdrv, ++ s->irq[0][OMAP_INT_24XX_MMC_IRQ], ++ &s->drq[OMAP24XX_DMA_MMC1_TX], ++ omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk")); ++ ++ s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4, ++ s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ], ++ &s->drq[OMAP24XX_DMA_SPI1_TX0], ++ omap_findclk(s, "spi1_fclk"), ++ omap_findclk(s, "spi1_iclk")); ++ s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2, ++ s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ], ++ &s->drq[OMAP24XX_DMA_SPI2_TX0], ++ omap_findclk(s, "spi2_fclk"), ++ omap_findclk(s, "spi2_iclk")); ++ ++ s->dss = omap_dss_init(omap_l4ta(s->l4, 10), 0x68000800, ds, ++ /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */ ++ s->irq[0][OMAP_INT_24XX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS], ++ omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"), ++ omap_findclk(s, "dss_54m_clk"), ++ omap_findclk(s, "dss_l3_iclk"), ++ omap_findclk(s, "dss_l4_iclk")); ++ ++ /* Register mappings not currenlty implemented: ++ * SystemControlMod 48000000 - 48000fff ++ * SystemControlL4 48001000 - 48001fff ++ * 32kHz Timer Mod 48004000 - 48004fff ++ * 32kHz Timer L4 48005000 - 48005fff ++ * PRCM ModA 48008000 - 480087ff ++ * PRCM ModB 48008800 - 48008fff ++ * PRCM L4 48009000 - 48009fff ++ * TEST-BCM Mod 48012000 - 48012fff ++ * TEST-BCM L4 48013000 - 48013fff ++ * TEST-TAP Mod 48014000 - 48014fff ++ * TEST-TAP L4 48015000 - 48015fff ++ * GPIO1 Mod 48018000 - 48018fff ++ * GPIO Top 48019000 - 48019fff ++ * GPIO2 Mod 4801a000 - 4801afff ++ * GPIO L4 4801b000 - 4801bfff ++ * GPIO3 Mod 4801c000 - 4801cfff ++ * GPIO4 Mod 4801e000 - 4801efff ++ * WDTIMER1 Mod 48020000 - 48010fff ++ * WDTIMER Top 48021000 - 48011fff ++ * WDTIMER2 Mod 48022000 - 48012fff ++ * WDTIMER L4 48023000 - 48013fff ++ * WDTIMER3 Mod 48024000 - 48014fff ++ * WDTIMER3 L4 48025000 - 48015fff ++ * WDTIMER4 Mod 48026000 - 48016fff ++ * WDTIMER4 L4 48027000 - 48017fff ++ * GPTIMER1 Mod 48028000 - 48018fff ++ * GPTIMER1 L4 48029000 - 48019fff ++ * GPTIMER2 Mod 4802a000 - 4801afff ++ * GPTIMER2 L4 4802b000 - 4801bfff ++ * L4-Config AP 48040000 - 480407ff ++ * L4-Config IP 48040800 - 48040fff ++ * L4-Config LA 48041000 - 48041fff ++ * ARM11ETB Mod 48048000 - 48049fff ++ * ARM11ETB L4 4804a000 - 4804afff ++ * DISPLAY Top 48050000 - 480503ff ++ * DISPLAY DISPC 48050400 - 480507ff ++ * DISPLAY RFBI 48050800 - 48050bff ++ * DISPLAY VENC 48050c00 - 48050fff ++ * DISPLAY L4 48051000 - 48051fff ++ * CAMERA Top 48052000 - 480523ff ++ * CAMERA core 48052400 - 480527ff ++ * CAMERA DMA 48052800 - 48052bff ++ * CAMERA MMU 48052c00 - 48052fff ++ * CAMERA L4 48053000 - 48053fff ++ * SDMA Mod 48056000 - 48056fff ++ * SDMA L4 48057000 - 48057fff ++ * SSI Top 48058000 - 48058fff ++ * SSI GDD 48059000 - 48059fff ++ * SSI Port1 4805a000 - 4805afff ++ * SSI Port2 4805b000 - 4805bfff ++ * SSI L4 4805c000 - 4805cfff ++ * USB Mod 4805e000 - 480fefff ++ * USB L4 4805f000 - 480fffff ++ * WIN_TRACER1 Mod 48060000 - 48060fff ++ * WIN_TRACER1 L4 48061000 - 48061fff ++ * WIN_TRACER2 Mod 48062000 - 48062fff ++ * WIN_TRACER2 L4 48063000 - 48063fff ++ * WIN_TRACER3 Mod 48064000 - 48064fff ++ * WIN_TRACER3 L4 48065000 - 48065fff ++ * WIN_TRACER4 Top 48066000 - 480660ff ++ * WIN_TRACER4 ETT 48066100 - 480661ff ++ * WIN_TRACER4 WT 48066200 - 480662ff ++ * WIN_TRACER4 L4 48067000 - 48067fff ++ * XTI Mod 48068000 - 48068fff ++ * XTI L4 48069000 - 48069fff ++ * UART1 Mod 4806a000 - 4806afff ++ * UART1 L4 4806b000 - 4806bfff ++ * UART2 Mod 4806c000 - 4806cfff ++ * UART2 L4 4806d000 - 4806dfff ++ * UART3 Mod 4806e000 - 4806efff ++ * UART3 L4 4806f000 - 4806ffff ++ * I2C1 Mod 48070000 - 48070fff ++ * I2C1 L4 48071000 - 48071fff ++ * I2C2 Mod 48072000 - 48072fff ++ * I2C2 L4 48073000 - 48073fff ++ * McBSP1 Mod 48074000 - 48074fff ++ * McBSP1 L4 48075000 - 48075fff ++ * McBSP2 Mod 48076000 - 48076fff ++ * McBSP2 L4 48077000 - 48077fff ++ * GPTIMER3 Mod 48078000 - 48078fff ++ * GPTIMER3 L4 48079000 - 48079fff ++ * GPTIMER4 Mod 4807a000 - 4807afff ++ * GPTIMER4 L4 4807b000 - 4807bfff ++ * GPTIMER5 Mod 4807c000 - 4807cfff ++ * GPTIMER5 L4 4807d000 - 4807dfff ++ * GPTIMER6 Mod 4807e000 - 4807efff ++ * GPTIMER6 L4 4807f000 - 4807ffff ++ * GPTIMER7 Mod 48080000 - 48080fff ++ * GPTIMER7 L4 48081000 - 48081fff ++ * GPTIMER8 Mod 48082000 - 48082fff ++ * GPTIMER8 L4 48083000 - 48083fff ++ * GPTIMER9 Mod 48084000 - 48084fff ++ * GPTIMER9 L4 48085000 - 48085fff ++ * GPTIMER10 Mod 48086000 - 48086fff ++ * GPTIMER10 L4 48087000 - 48087fff ++ * GPTIMER11 Mod 48088000 - 48088fff ++ * GPTIMER11 L4 48089000 - 48089fff ++ * GPTIMER12 Mod 4808a000 - 4808afff ++ * GPTIMER12 L4 4808b000 - 4808bfff ++ * EAC Mod 48090000 - 48090fff ++ * EAC L4 48091000 - 48091fff ++ * FAC Mod 48092000 - 48092fff ++ * FAC L4 48093000 - 48093fff ++ * MAILBOX Mod 48094000 - 48094fff ++ * MAILBOX L4 48095000 - 48095fff ++ * SPI1 Mod 48098000 - 48098fff ++ * SPI1 L4 48099000 - 48099fff ++ * SPI2 Mod 4809a000 - 4809afff ++ * SPI2 L4 4809b000 - 4809bfff ++ * MMC/SDIO Mod 4809c000 - 4809cfff ++ * MMC/SDIO L4 4809d000 - 4809dfff ++ * MS_PRO Mod 4809e000 - 4809efff ++ * MS_PRO L4 4809f000 - 4809ffff ++ * RNG Mod 480a0000 - 480a0fff ++ * RNG L4 480a1000 - 480a1fff ++ * DES3DES Mod 480a2000 - 480a2fff ++ * DES3DES L4 480a3000 - 480a3fff ++ * SHA1MD5 Mod 480a4000 - 480a4fff ++ * SHA1MD5 L4 480a5000 - 480a5fff ++ * AES Mod 480a6000 - 480a6fff ++ * AES L4 480a7000 - 480a7fff ++ * PKA Mod 480a8000 - 480a9fff ++ * PKA L4 480aa000 - 480aafff ++ * MG Mod 480b0000 - 480b0fff ++ * MG L4 480b1000 - 480b1fff ++ * HDQ/1-wire Mod 480b2000 - 480b2fff ++ * HDQ/1-wire L4 480b3000 - 480b3fff ++ * MPU interrupt 480fe000 - 480fefff ++ * IVA RAM 5c000000 - 5c01ffff ++ * IVA ROM 5c020000 - 5c027fff ++ * IMG_BUF_A 5c040000 - 5c040fff ++ * IMG_BUF_B 5c042000 - 5c042fff ++ * VLCDS 5c048000 - 5c0487ff ++ * IMX_COEF 5c049000 - 5c04afff ++ * IMX_CMD 5c051000 - 5c051fff ++ * VLCDQ 5c053000 - 5c0533ff ++ * VLCDH 5c054000 - 5c054fff ++ * SEQ_CMD 5c055000 - 5c055fff ++ * IMX_REG 5c056000 - 5c0560ff ++ * VLCD_REG 5c056100 - 5c0561ff ++ * SEQ_REG 5c056200 - 5c0562ff ++ * IMG_BUF_REG 5c056300 - 5c0563ff ++ * SEQIRQ_REG 5c056400 - 5c0564ff ++ * OCP_REG 5c060000 - 5c060fff ++ * SYSC_REG 5c070000 - 5c070fff ++ * MMU_REG 5d000000 - 5d000fff ++ * sDMA R 68000400 - 680005ff ++ * sDMA W 68000600 - 680007ff ++ * Display Control 68000800 - 680009ff ++ * DSP subsystem 68000a00 - 68000bff ++ * MPU subsystem 68000c00 - 68000dff ++ * IVA subsystem 68001000 - 680011ff ++ * USB 68001200 - 680013ff ++ * Camera 68001400 - 680015ff ++ * VLYNQ (firewall) 68001800 - 68001bff ++ * VLYNQ 68001e00 - 68001fff ++ * SSI 68002000 - 680021ff ++ * L4 68002400 - 680025ff ++ * DSP (firewall) 68002800 - 68002bff ++ * DSP subsystem 68002e00 - 68002fff ++ * IVA (firewall) 68003000 - 680033ff ++ * IVA 68003600 - 680037ff ++ * GFX 68003a00 - 68003bff ++ * CMDWR emulation 68003c00 - 68003dff ++ * SMS 68004000 - 680041ff ++ * OCM 68004200 - 680043ff ++ * GPMC 68004400 - 680045ff ++ * RAM (firewall) 68005000 - 680053ff ++ * RAM (err login) 68005400 - 680057ff ++ * ROM (firewall) 68005800 - 68005bff ++ * ROM (err login) 68005c00 - 68005fff ++ * GPMC (firewall) 68006000 - 680063ff ++ * GPMC (err login) 68006400 - 680067ff ++ * SMS (err login) 68006c00 - 68006fff ++ * SMS registers 68008000 - 68008fff ++ * SDRC registers 68009000 - 68009fff ++ * GPMC registers 6800a000 6800afff ++ */ ++ ++ qemu_register_reset(omap2_mpu_reset, s); ++ ++ return s; ++} +diff --git a/hw/omap_clk.c b/hw/omap_clk.c +index 37daec2..da03e15 100644 +--- a/hw/omap_clk.c ++++ b/hw/omap_clk.c +@@ -34,6 +34,9 @@ struct clk { + #define CLOCK_IN_OMAP730 (1 << 11) + #define CLOCK_IN_OMAP1510 (1 << 12) + #define CLOCK_IN_OMAP16XX (1 << 13) ++#define CLOCK_IN_OMAP242X (1 << 14) ++#define CLOCK_IN_OMAP243X (1 << 15) ++#define CLOCK_IN_OMAP343X (1 << 16) + uint32_t flags; + int id; + +@@ -55,7 +58,8 @@ static struct clk xtal_osc12m = { + static struct clk xtal_osc32k = { + .name = "xtal_osc_32k", + .rate = 32768, +- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, ++ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ++ CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, + }; + + static struct clk ck_ref = { +@@ -502,11 +506,441 @@ static struct clk i2c_ick = { + static struct clk clk32k = { + .name = "clk32-kHz", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | +- ALWAYS_ENABLED, +- .parent = &xtal_osc32k, ++ CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, ++ .parent = &xtal_osc32k, ++}; ++ ++static struct clk apll_96m = { ++ .name = "apll_96m", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, ++ .rate = 96000000, ++ /*.parent = sys.xtalin */ ++}; ++ ++static struct clk apll_54m = { ++ .name = "apll_54m", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, ++ .rate = 54000000, ++ /*.parent = sys.xtalin */ ++}; ++ ++static struct clk sys_clk = { ++ .name = "sys_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, ++ .rate = 32768, ++ /*.parent = sys.xtalin */ ++}; ++ ++static struct clk sleep_clk = { ++ .name = "sleep_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, ++ .rate = 32768, ++ /*.parent = sys.xtalin */ ++}; ++ ++static struct clk dpll_ck = { ++ .name = "dpll", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, ++ /*.parent = sys.xtalin */ ++}; ++ ++static struct clk dpll_x2_ck = { ++ .name = "dpll_x2", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, ++ /*.parent = sys.xtalin */ ++}; ++ ++static struct clk wdt1_sys_clk = { ++ .name = "wdt1_sys_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED, ++ .rate = 32768, ++ /*.parent = sys.xtalin */ ++}; ++ ++static struct clk func_96m_clk = { ++ .name = "func_96m_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .divisor = 1, ++ .parent = &apll_96m, ++}; ++ ++static struct clk func_48m_clk = { ++ .name = "func_48m_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .divisor = 2, ++ .parent = &apll_96m, ++}; ++ ++static struct clk func_12m_clk = { ++ .name = "func_12m_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .divisor = 8, ++ .parent = &apll_96m, ++}; ++ ++static struct clk func_54m_clk = { ++ .name = "func_54m_clk", ++ .flags = CLOCK_IN_OMAP242X, ++ .divisor = 1, ++ .parent = &apll_54m, ++}; ++ ++static struct clk sys_clkout = { ++ .name = "clkout", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk sys_clkout2 = { ++ .name = "clkout2", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_clk = { ++ .name = "core_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &dpll_ck, ++}; ++ ++static struct clk l3_clk = { ++ .name = "l3_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_clk, ++}; ++ ++static struct clk core_l4_iclk = { ++ .name = "core_l4_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &l3_clk, ++}; ++ ++static struct clk wu_l4_iclk = { ++ .name = "wu_l4_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &l3_clk, ++}; ++ ++static struct clk core_l3_iclk = { ++ .name = "core_l3_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_clk, ++}; ++ ++static struct clk core_l4_usb_clk = { ++ .name = "core_l4_usb_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &l3_clk, ++}; ++ ++static struct clk wu_gpt1_clk = { ++ .name = "wu_gpt1_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk wu_32k_clk = { ++ .name = "wu_32k_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk uart1_fclk = { ++ .name = "uart1_fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &func_48m_clk, ++}; ++ ++static struct clk uart1_iclk = { ++ .name = "uart1_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l4_iclk, ++}; ++ ++static struct clk uart2_fclk = { ++ .name = "uart2_fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &func_48m_clk, ++}; ++ ++static struct clk uart2_iclk = { ++ .name = "uart2_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l4_iclk, ++}; ++ ++static struct clk uart3_fclk = { ++ .name = "uart3_fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &func_48m_clk, ++}; ++ ++static struct clk uart3_iclk = { ++ .name = "uart3_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l4_iclk, ++}; ++ ++static struct clk mpu_fclk = { ++ .name = "mpu_fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_clk, ++}; ++ ++static struct clk mpu_iclk = { ++ .name = "mpu_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_clk, ++}; ++ ++static struct clk int_m_fclk = { ++ .name = "int_m_fclk", ++ .alias = "mpu_intc_fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_clk, ++}; ++ ++static struct clk int_m_iclk = { ++ .name = "int_m_iclk", ++ .alias = "mpu_intc_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_clk, ++}; ++ ++static struct clk core_gpt2_clk = { ++ .name = "core_gpt2_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt3_clk = { ++ .name = "core_gpt3_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt4_clk = { ++ .name = "core_gpt4_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt5_clk = { ++ .name = "core_gpt5_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt6_clk = { ++ .name = "core_gpt6_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt7_clk = { ++ .name = "core_gpt7_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt8_clk = { ++ .name = "core_gpt8_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt9_clk = { ++ .name = "core_gpt9_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt10_clk = { ++ .name = "core_gpt10_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt11_clk = { ++ .name = "core_gpt11_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk core_gpt12_clk = { ++ .name = "core_gpt12_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++}; ++ ++static struct clk mcbsp1_clk = { ++ .name = "mcbsp1_cg", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .divisor = 2, ++ .parent = &func_96m_clk, ++}; ++ ++static struct clk mcbsp2_clk = { ++ .name = "mcbsp2_cg", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .divisor = 2, ++ .parent = &func_96m_clk, ++}; ++ ++static struct clk emul_clk = { ++ .name = "emul_ck", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &func_54m_clk, ++}; ++ ++static struct clk sdma_fclk = { ++ .name = "sdma_fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &l3_clk, ++}; ++ ++static struct clk sdma_iclk = { ++ .name = "sdma_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l3_iclk, /* core_l4_iclk for the configuration port */ ++}; ++ ++static struct clk i2c1_fclk = { ++ .name = "i2c1.fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &func_12m_clk, ++ .divisor = 1, ++}; ++ ++static struct clk i2c1_iclk = { ++ .name = "i2c1.iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l4_iclk, ++}; ++ ++static struct clk i2c2_fclk = { ++ .name = "i2c2.fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &func_12m_clk, ++ .divisor = 1, ++}; ++ ++static struct clk i2c2_iclk = { ++ .name = "i2c2.iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l4_iclk, ++}; ++ ++static struct clk gpio_dbclk[4] = { ++ { ++ .name = "gpio1_dbclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &wu_32k_clk, ++ }, { ++ .name = "gpio2_dbclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &wu_32k_clk, ++ }, { ++ .name = "gpio3_dbclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &wu_32k_clk, ++ }, { ++ .name = "gpio4_dbclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &wu_32k_clk, ++ }, ++}; ++ ++static struct clk gpio_iclk = { ++ .name = "gpio_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &wu_l4_iclk, ++}; ++ ++static struct clk mmc_fck = { ++ .name = "mmc_fclk", ++ .flags = CLOCK_IN_OMAP242X, ++ .parent = &func_96m_clk, ++}; ++ ++static struct clk mmc_ick = { ++ .name = "mmc_iclk", ++ .flags = CLOCK_IN_OMAP242X, ++ .parent = &core_l4_iclk, ++}; ++ ++static struct clk spi_fclk[3] = { ++ { ++ .name = "spi1_fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &func_48m_clk, ++ }, { ++ .name = "spi2_fclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &func_48m_clk, ++ }, { ++ .name = "spi3_fclk", ++ .flags = CLOCK_IN_OMAP243X, ++ .parent = &func_48m_clk, ++ }, ++}; ++ ++static struct clk dss_clk[2] = { ++ { ++ .name = "dss_clk1", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_clk, ++ }, { ++ .name = "dss_clk2", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &sys_clk, ++ }, ++}; ++ ++static struct clk dss_54m_clk = { ++ .name = "dss_54m_clk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &func_54m_clk, ++}; ++ ++static struct clk dss_l3_iclk = { ++ .name = "dss_l3_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l3_iclk, ++}; ++ ++static struct clk dss_l4_iclk = { ++ .name = "dss_l4_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l4_iclk, ++}; ++ ++static struct clk spi_iclk[3] = { ++ { ++ .name = "spi1_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l4_iclk, ++ }, { ++ .name = "spi2_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ .parent = &core_l4_iclk, ++ }, { ++ .name = "spi3_iclk", ++ .flags = CLOCK_IN_OMAP243X, ++ .parent = &core_l4_iclk, ++ }, ++}; ++ ++static struct clk omapctrl_clk = { ++ .name = "omapctrl_iclk", ++ .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, ++ /* XXX Should be in WKUP domain */ ++ .parent = &core_l4_iclk, + }; + + static struct clk *onchip_clks[] = { ++ /* OMAP 1 */ ++ + /* non-ULPD clocks */ + &xtal_osc12m, + &xtal_osc32k, +@@ -572,6 +1006,80 @@ static struct clk *onchip_clks[] = { + /* Virtual clocks */ + &i2c_fck, + &i2c_ick, ++ ++ /* OMAP 2 */ ++ ++ &apll_96m, ++ &apll_54m, ++ &sys_clk, ++ &sleep_clk, ++ &dpll_ck, ++ &dpll_x2_ck, ++ &wdt1_sys_clk, ++ &func_96m_clk, ++ &func_48m_clk, ++ &func_12m_clk, ++ &func_54m_clk, ++ &sys_clkout, ++ &sys_clkout2, ++ &core_clk, ++ &l3_clk, ++ &core_l4_iclk, ++ &wu_l4_iclk, ++ &core_l3_iclk, ++ &core_l4_usb_clk, ++ &wu_gpt1_clk, ++ &wu_32k_clk, ++ &uart1_fclk, ++ &uart1_iclk, ++ &uart2_fclk, ++ &uart2_iclk, ++ &uart3_fclk, ++ &uart3_iclk, ++ &mpu_fclk, ++ &mpu_iclk, ++ &int_m_fclk, ++ &int_m_iclk, ++ &core_gpt2_clk, ++ &core_gpt3_clk, ++ &core_gpt4_clk, ++ &core_gpt5_clk, ++ &core_gpt6_clk, ++ &core_gpt7_clk, ++ &core_gpt8_clk, ++ &core_gpt9_clk, ++ &core_gpt10_clk, ++ &core_gpt11_clk, ++ &core_gpt12_clk, ++ &mcbsp1_clk, ++ &mcbsp2_clk, ++ &emul_clk, ++ &sdma_fclk, ++ &sdma_iclk, ++ &i2c1_fclk, ++ &i2c1_iclk, ++ &i2c2_fclk, ++ &i2c2_iclk, ++ &gpio_dbclk[0], ++ &gpio_dbclk[1], ++ &gpio_dbclk[2], ++ &gpio_dbclk[3], ++ &gpio_iclk, ++ &mmc_fck, ++ &mmc_ick, ++ &spi_fclk[0], ++ &spi_iclk[0], ++ &spi_fclk[1], ++ &spi_iclk[1], ++ &spi_fclk[2], ++ &spi_iclk[2], ++ &dss_clk[0], ++ &dss_clk[1], ++ &dss_54m_clk, ++ &dss_l3_iclk, ++ &dss_l4_iclk, ++ &omapctrl_clk, ++ + 0 + }; + +@@ -727,6 +1235,12 @@ void omap_clk_init(struct omap_mpu_state_s *mpu) + flag = CLOCK_IN_OMAP310; + else if (cpu_is_omap1510(mpu)) + flag = CLOCK_IN_OMAP1510; ++ else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu)) ++ flag = CLOCK_IN_OMAP242X; ++ else if (cpu_is_omap2430(mpu)) ++ flag = CLOCK_IN_OMAP243X; ++ else if (cpu_is_omap3430(mpu)) ++ flag = CLOCK_IN_OMAP243X; + else + return; + +diff --git a/hw/omap_dma.c b/hw/omap_dma.c +index 1835826..6c0bd82 100644 +--- a/hw/omap_dma.c ++++ b/hw/omap_dma.c +@@ -28,12 +28,15 @@ struct omap_dma_channel_s { + /* transfer data */ + int burst[2]; + int pack[2]; ++ int endian[2]; ++ int endian_lock[2]; ++ int translate[2]; + enum omap_dma_port port[2]; + target_phys_addr_t addr[2]; + omap_dma_addressing_t mode[2]; +- uint16_t elements; ++ uint32_t elements; + uint16_t frames; +- int16_t frame_index[2]; ++ int32_t frame_index[2]; + int16_t element_index[2]; + int data_type; + +@@ -41,6 +44,7 @@ struct omap_dma_channel_s { + int transparent_copy; + int constant_fill; + uint32_t color; ++ int prefetch; + + /* auto init and linked channel data */ + int end_prog; +@@ -52,11 +56,13 @@ struct omap_dma_channel_s { + /* interruption data */ + int interrupts; + int status; ++ int cstatus; + + /* state data */ + int active; + int enable; + int sync; ++ int src_sync; + int pending_request; + int waiting_end_prog; + uint16_t cpc; +@@ -75,16 +81,21 @@ struct omap_dma_channel_s { + target_phys_addr_t src, dest; + int frame; + int element; ++ int pck_element; + int frame_delta[2]; + int elem_delta[2]; + int frames; + int elements; ++ int pck_elements; + } active_set; + + /* unused parameters */ ++ int write_mode; + int priority; + int interleave_disabled; + int type; ++ int suspend; ++ int buf_disable; + }; + + struct omap_dma_s { +@@ -93,15 +104,21 @@ struct omap_dma_s { + target_phys_addr_t base; + omap_clk clk; + int64_t delay; +- uint32_t drq; ++ uint64_t drq; ++ qemu_irq irq[4]; ++ void (*intr_update)(struct omap_dma_s *s); + enum omap_dma_model model; + int omap_3_1_mapping_disabled; + +- uint16_t gcr; ++ uint32_t gcr; ++ uint32_t ocp; ++ uint32_t caps[5]; ++ uint32_t irqen[4]; ++ uint32_t irqstat[4]; + int run_count; + + int chans; +- struct omap_dma_channel_s ch[16]; ++ struct omap_dma_channel_s ch[32]; + struct omap_dma_lcd_channel_s lcd_ch; + }; + +@@ -113,23 +130,13 @@ struct omap_dma_s { + #define LAST_FRAME_INTR (1 << 4) + #define END_BLOCK_INTR (1 << 5) + #define SYNC (1 << 6) ++#define END_PKT_INTR (1 << 7) ++#define TRANS_ERR_INTR (1 << 8) ++#define MISALIGN_INTR (1 << 11) + +-static void omap_dma_interrupts_update(struct omap_dma_s *s) ++static inline void omap_dma_interrupts_update(struct omap_dma_s *s) + { +- struct omap_dma_channel_s *ch = s->ch; +- int i; +- +- if (s->omap_3_1_mapping_disabled) { +- for (i = 0; i < s->chans; i ++, ch ++) +- if (ch->status) +- qemu_irq_raise(ch->irq); +- } else { +- /* First three interrupts are shared between two channels each. */ +- for (i = 0; i < 6; i ++, ch ++) { +- if (ch->status || (ch->sibling && ch->sibling->status)) +- qemu_irq_raise(ch->irq); +- } +- } ++ return s->intr_update(s); + } + + static void omap_dma_channel_load(struct omap_dma_s *s, +@@ -148,8 +155,10 @@ static void omap_dma_channel_load(struct omap_dma_s *s, + a->dest = ch->addr[1]; + a->frames = ch->frames; + a->elements = ch->elements; ++ a->pck_elements = ch->frame_index[!ch->src_sync]; + a->frame = 0; + a->element = 0; ++ a->pck_element = 0; + + if (unlikely(!ch->elements || !ch->frames)) { + printf("%s: bad DMA request\n", __FUNCTION__); +@@ -202,16 +211,15 @@ static void omap_dma_deactivate_channel(struct omap_dma_s *s, + /* Update cpc */ + ch->cpc = ch->active_set.dest & 0xffff; + +- if (ch->pending_request && !ch->waiting_end_prog) { ++ if (ch->pending_request && !ch->waiting_end_prog && ch->enable) { + /* Don't deactivate the channel */ + ch->pending_request = 0; +- if (ch->enable) +- return; ++ return; + } + + /* Don't deactive the channel if it is synchronized and the DMA request is + active */ +- if (ch->sync && (s->drq & (1 << ch->sync)) && ch->enable) ++ if (ch->sync && ch->enable && (s->drq & (1 << ch->sync))) + return; + + if (ch->active) { +@@ -231,6 +239,9 @@ static void omap_dma_enable_channel(struct omap_dma_s *s, + ch->enable = 1; + ch->waiting_end_prog = 0; + omap_dma_channel_load(s, ch); ++ /* TODO: theoretically if ch->sync && ch->prefetch && ++ * !s->drq[ch->sync], we should also activate and fetch from source ++ * and then stall until signalled. */ + if ((!ch->sync) || (s->drq & (1 << ch->sync))) + omap_dma_activate_channel(s, ch); + } +@@ -259,16 +270,47 @@ static void omap_dma_channel_end_prog(struct omap_dma_s *s, + } + } + ++static void omap_dma_interrupts_3_1_update(struct omap_dma_s *s) ++{ ++ struct omap_dma_channel_s *ch = s->ch; ++ ++ /* First three interrupts are shared between two channels each. */ ++ if (ch[0].status | ch[6].status) ++ qemu_irq_raise(ch[0].irq); ++ if (ch[1].status | ch[7].status) ++ qemu_irq_raise(ch[1].irq); ++ if (ch[2].status | ch[8].status) ++ qemu_irq_raise(ch[2].irq); ++ if (ch[3].status) ++ qemu_irq_raise(ch[3].irq); ++ if (ch[4].status) ++ qemu_irq_raise(ch[4].irq); ++ if (ch[5].status) ++ qemu_irq_raise(ch[5].irq); ++} ++ ++static void omap_dma_interrupts_3_2_update(struct omap_dma_s *s) ++{ ++ struct omap_dma_channel_s *ch = s->ch; ++ int i; ++ ++ for (i = s->chans; i; ch ++, i --) ++ if (ch->status) ++ qemu_irq_raise(ch->irq); ++} ++ + static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s) + { + s->omap_3_1_mapping_disabled = 0; + s->chans = 9; ++ s->intr_update = omap_dma_interrupts_3_1_update; + } + + static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s) + { + s->omap_3_1_mapping_disabled = 1; + s->chans = 16; ++ s->intr_update = omap_dma_interrupts_3_2_update; + } + + static void omap_dma_process_request(struct omap_dma_s *s, int request) +@@ -358,6 +400,22 @@ static void omap_dma_channel_run(struct omap_dma_s *s) + if (ch->interrupts & HALF_FRAME_INTR) + ch->status |= HALF_FRAME_INTR; + ++ if (ch->fs && ch->bs) { ++ a->pck_element ++; ++ /* Check if a full packet has beed transferred. */ ++ if (a->pck_element == a->pck_elements) { ++ a->pck_element = 0; ++ ++ /* Set the END_PKT interrupt */ ++ if ((ch->interrupts & END_PKT_INTR) && !ch->src_sync) ++ ch->status |= END_PKT_INTR; ++ ++ /* If the channel is packet-synchronized, deactivate it */ ++ if (ch->sync) ++ omap_dma_deactivate_channel(s, ch); ++ } ++ } ++ + if (a->element == a->elements) { + /* End of Frame */ + a->element = 0; +@@ -366,7 +424,7 @@ static void omap_dma_channel_run(struct omap_dma_s *s) + a->frame ++; + + /* If the channel is frame synchronized, deactivate it */ +- if (ch->sync && ch->fs) ++ if (ch->sync && ch->fs && !ch->bs) + omap_dma_deactivate_channel(s, ch); + + /* If the channel is async, update cpc */ +@@ -414,50 +472,62 @@ void omap_dma_reset(struct omap_dma_s *s) + int i; + + qemu_del_timer(s->tm); +- s->gcr = 0x0004; ++ if (s->model < omap_dma_4) ++ s->gcr = 0x0004; ++ else ++ s->gcr = 0x00010010; ++ s->ocp = 0x00000000; ++ memset(&s->irqstat, 0, sizeof(s->irqstat)); ++ memset(&s->irqen, 0, sizeof(s->irqen)); + s->drq = 0x00000000; + s->run_count = 0; + s->lcd_ch.src = emiff; + s->lcd_ch.condition = 0; + s->lcd_ch.interrupts = 0; + s->lcd_ch.dual = 0; +- omap_dma_enable_3_1_mapping(s); ++ if (s->model < omap_dma_4) ++ omap_dma_enable_3_1_mapping(s); + for (i = 0; i < s->chans; i ++) { ++ s->ch[i].suspend = 0; ++ s->ch[i].prefetch = 0; ++ s->ch[i].buf_disable = 0; ++ s->ch[i].src_sync = 0; + memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst)); + memset(&s->ch[i].port, 0, sizeof(s->ch[i].port)); + memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode)); +- memset(&s->ch[i].elements, 0, sizeof(s->ch[i].elements)); +- memset(&s->ch[i].frames, 0, sizeof(s->ch[i].frames)); + memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index)); + memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index)); +- memset(&s->ch[i].data_type, 0, sizeof(s->ch[i].data_type)); +- memset(&s->ch[i].transparent_copy, 0, +- sizeof(s->ch[i].transparent_copy)); +- memset(&s->ch[i].constant_fill, 0, sizeof(s->ch[i].constant_fill)); +- memset(&s->ch[i].color, 0, sizeof(s->ch[i].color)); +- memset(&s->ch[i].end_prog, 0, sizeof(s->ch[i].end_prog)); +- memset(&s->ch[i].repeat, 0, sizeof(s->ch[i].repeat)); +- memset(&s->ch[i].auto_init, 0, sizeof(s->ch[i].auto_init)); +- memset(&s->ch[i].link_enabled, 0, sizeof(s->ch[i].link_enabled)); +- memset(&s->ch[i].link_next_ch, 0, sizeof(s->ch[i].link_next_ch)); +- s->ch[i].interrupts = 0x0003; +- memset(&s->ch[i].status, 0, sizeof(s->ch[i].status)); +- memset(&s->ch[i].active, 0, sizeof(s->ch[i].active)); +- memset(&s->ch[i].enable, 0, sizeof(s->ch[i].enable)); +- memset(&s->ch[i].sync, 0, sizeof(s->ch[i].sync)); +- memset(&s->ch[i].pending_request, 0, sizeof(s->ch[i].pending_request)); +- memset(&s->ch[i].waiting_end_prog, 0, +- sizeof(s->ch[i].waiting_end_prog)); +- memset(&s->ch[i].cpc, 0, sizeof(s->ch[i].cpc)); +- memset(&s->ch[i].fs, 0, sizeof(s->ch[i].fs)); +- memset(&s->ch[i].bs, 0, sizeof(s->ch[i].bs)); +- memset(&s->ch[i].omap_3_1_compatible_disable, 0, +- sizeof(s->ch[i].omap_3_1_compatible_disable)); ++ memset(&s->ch[i].endian, 0, sizeof(s->ch[i].endian)); ++ memset(&s->ch[i].endian_lock, 0, sizeof(s->ch[i].endian_lock)); ++ memset(&s->ch[i].translate, 0, sizeof(s->ch[i].translate)); ++ s->ch[i].write_mode = 0; ++ s->ch[i].data_type = 0; ++ s->ch[i].transparent_copy = 0; ++ s->ch[i].constant_fill = 0; ++ s->ch[i].color = 0x00000000; ++ s->ch[i].end_prog = 0; ++ s->ch[i].repeat = 0; ++ s->ch[i].auto_init = 0; ++ s->ch[i].link_enabled = 0; ++ if (s->model < omap_dma_4) ++ s->ch[i].interrupts = 0x0003; ++ else ++ s->ch[i].interrupts = 0x0000; ++ s->ch[i].status = 0; ++ s->ch[i].cstatus = 0; ++ s->ch[i].active = 0; ++ s->ch[i].enable = 0; ++ s->ch[i].sync = 0; ++ s->ch[i].pending_request = 0; ++ s->ch[i].waiting_end_prog = 0; ++ s->ch[i].cpc = 0x0000; ++ s->ch[i].fs = 0; ++ s->ch[i].bs = 0; ++ s->ch[i].omap_3_1_compatible_disable = 0; + memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set)); +- memset(&s->ch[i].priority, 0, sizeof(s->ch[i].priority)); +- memset(&s->ch[i].interleave_disabled, 0, +- sizeof(s->ch[i].interleave_disabled)); +- memset(&s->ch[i].type, 0, sizeof(s->ch[i].type)); ++ s->ch[i].priority = 0; ++ s->ch[i].interleave_disabled = 0; ++ s->ch[i].type = 0; + } + } + +@@ -476,7 +546,7 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, + break; + + case 0x02: /* SYS_DMA_CCR_CH0 */ +- if (s->model == omap_dma_3_1) ++ if (s->model <= omap_dma_3_1) + *value = 0 << 10; /* FIFO_FLUSH reads as 0 */ + else + *value = ch->omap_3_1_compatible_disable << 10; +@@ -596,11 +666,11 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, + ch->burst[0] = (value & 0x0180) >> 7; + ch->pack[0] = (value & 0x0040) >> 6; + ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2); +- ch->data_type = (1 << (value & 3)); +- if (ch->port[0] >= omap_dma_port_last) ++ ch->data_type = 1 << (value & 3); ++ if (ch->port[0] >= __omap_dma_port_last) + printf("%s: invalid DMA port %i\n", __FUNCTION__, + ch->port[0]); +- if (ch->port[1] >= omap_dma_port_last) ++ if (ch->port[1] >= __omap_dma_port_last) + printf("%s: invalid DMA port %i\n", __FUNCTION__, + ch->port[1]); + if ((value & 3) == 3) +@@ -611,7 +681,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, + ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); + ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); + ch->end_prog = (value & 0x0800) >> 11; +- if (s->model > omap_dma_3_1) ++ if (s->model >= omap_dma_3_2) + ch->omap_3_1_compatible_disable = (value >> 10) & 0x1; + ch->repeat = (value & 0x0200) >> 9; + ch->auto_init = (value & 0x0100) >> 8; +@@ -630,7 +700,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, + break; + + case 0x04: /* SYS_DMA_CICR_CH0 */ +- ch->interrupts = value; ++ ch->interrupts = value & 0x3f; + break; + + case 0x06: /* SYS_DMA_CSR_CH0 */ +@@ -696,7 +766,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, + break; + + case 0x24: /* DMA_CCR2 */ +- ch->bs = (value >> 2) & 0x1; ++ ch->bs = (value >> 2) & 0x1; + ch->transparent_copy = (value >> 1) & 0x1; + ch->constant_fill = value & 0x1; + break; +@@ -1126,48 +1196,29 @@ static int omap_dma_sys_read(struct omap_dma_s *s, int offset, + break; + + case 0x44e: /* DMA_CAPS_0_U */ +- *ret = (1 << 3) | /* Constant Fill Capacity */ +- (1 << 2); /* Transparent BLT Capacity */ ++ *ret = (s->caps[0] >> 16) & 0xffff; + break; +- + case 0x450: /* DMA_CAPS_0_L */ +- case 0x452: /* DMA_CAPS_1_U */ +- *ret = 0; ++ *ret = (s->caps[0] >> 0) & 0xffff; + break; + ++ case 0x452: /* DMA_CAPS_1_U */ ++ *ret = (s->caps[1] >> 16) & 0xffff; ++ break; + case 0x454: /* DMA_CAPS_1_L */ +- *ret = (1 << 1); /* 1-bit palletized capability */ ++ *ret = (s->caps[1] >> 0) & 0xffff; + break; + + case 0x456: /* DMA_CAPS_2 */ +- *ret = (1 << 8) | /* SSDIC */ +- (1 << 7) | /* DDIAC */ +- (1 << 6) | /* DSIAC */ +- (1 << 5) | /* DPIAC */ +- (1 << 4) | /* DCAC */ +- (1 << 3) | /* SDIAC */ +- (1 << 2) | /* SSIAC */ +- (1 << 1) | /* SPIAC */ +- 1; /* SCAC */ ++ *ret = s->caps[2]; + break; + + case 0x458: /* DMA_CAPS_3 */ +- *ret = (1 << 5) | /* CCC */ +- (1 << 4) | /* IC */ +- (1 << 3) | /* ARC */ +- (1 << 2) | /* AEC */ +- (1 << 1) | /* FSC */ +- 1; /* ESC */ ++ *ret = s->caps[3]; + break; + + case 0x45a: /* DMA_CAPS_4 */ +- *ret = (1 << 6) | /* SSC */ +- (1 << 5) | /* BIC */ +- (1 << 4) | /* LFIC */ +- (1 << 3) | /* FIC */ +- (1 << 2) | /* HFIC */ +- (1 << 1) | /* EDIC */ +- 1; /* TOIC */ ++ *ret = s->caps[4]; + break; + + case 0x460: /* DMA_PCh2_SR */ +@@ -1193,7 +1244,7 @@ static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) + + switch (offset) { + case 0x300 ... 0x3fe: +- if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { ++ if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { + if (omap_dma_3_1_lcd_read(&s->lcd_ch, offset, &ret)) + break; + return ret; +@@ -1207,7 +1258,7 @@ static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) + return ret; + + case 0x404 ... 0x4fe: +- if (s->model == omap_dma_3_1) ++ if (s->model <= omap_dma_3_1) + break; + /* Fall through. */ + case 0x400: +@@ -1236,7 +1287,7 @@ static void omap_dma_write(void *opaque, target_phys_addr_t addr, + + switch (offset) { + case 0x300 ... 0x3fe: +- if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { ++ if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { + if (omap_dma_3_1_lcd_write(&s->lcd_ch, offset, value)) + break; + return; +@@ -1250,7 +1301,7 @@ static void omap_dma_write(void *opaque, target_phys_addr_t addr, + return; + + case 0x404 ... 0x4fe: +- if (s->model == omap_dma_3_1) ++ if (s->model <= omap_dma_3_1) + break; + case 0x400: + /* Fall through. */ +@@ -1285,7 +1336,7 @@ static CPUWriteMemoryFunc *omap_dma_writefn[] = { + static void omap_dma_request(void *opaque, int drq, int req) + { + struct omap_dma_s *s = (struct omap_dma_s *) opaque; +- /* The request pins are level triggered. */ ++ /* The request pins are level triggered in QEMU. */ + if (req) { + if (~s->drq & (1 << drq)) { + s->drq |= 1 << drq; +@@ -1310,6 +1361,52 @@ static void omap_dma_clk_update(void *opaque, int line, int on) + } + } + ++static void omap_dma_setcaps(struct omap_dma_s *s) ++{ ++ switch (s->model) { ++ default: ++ case omap_dma_3_1: ++ break; ++ case omap_dma_3_2: ++ case omap_dma_4: ++ /* XXX Only available for sDMA */ ++ s->caps[0] = ++ (1 << 19) | /* Constant Fill Capability */ ++ (1 << 18); /* Transparent BLT Capability */ ++ s->caps[1] = ++ (1 << 1); /* 1-bit palettized capability (DMA 3.2 only) */ ++ s->caps[2] = ++ (1 << 8) | /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */ ++ (1 << 7) | /* DST_DOUBLE_INDEX_ADRS_CPBLTY */ ++ (1 << 6) | /* DST_SINGLE_INDEX_ADRS_CPBLTY */ ++ (1 << 5) | /* DST_POST_INCRMNT_ADRS_CPBLTY */ ++ (1 << 4) | /* DST_CONST_ADRS_CPBLTY */ ++ (1 << 3) | /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */ ++ (1 << 2) | /* SRC_SINGLE_INDEX_ADRS_CPBLTY */ ++ (1 << 1) | /* SRC_POST_INCRMNT_ADRS_CPBLTY */ ++ (1 << 0); /* SRC_CONST_ADRS_CPBLTY */ ++ s->caps[3] = ++ (1 << 6) | /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */ ++ (1 << 7) | /* PKT_SYNCHR_CPBLTY (DMA 4 only) */ ++ (1 << 5) | /* CHANNEL_CHAINING_CPBLTY */ ++ (1 << 4) | /* LCh_INTERLEAVE_CPBLTY */ ++ (1 << 3) | /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */ ++ (1 << 2) | /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */ ++ (1 << 1) | /* FRAME_SYNCHR_CPBLTY */ ++ (1 << 0); /* ELMNT_SYNCHR_CPBLTY */ ++ s->caps[4] = ++ (1 << 7) | /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */ ++ (1 << 6) | /* SYNC_STATUS_CPBLTY */ ++ (1 << 5) | /* BLOCK_INTERRUPT_CPBLTY */ ++ (1 << 4) | /* LAST_FRAME_INTERRUPT_CPBLTY */ ++ (1 << 3) | /* FRAME_INTERRUPT_CPBLTY */ ++ (1 << 2) | /* HALF_FRAME_INTERRUPT_CPBLTY */ ++ (1 << 1) | /* EVENT_DROP_INTERRUPT_CPBLTY */ ++ (1 << 0); /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */ ++ break; ++ } ++} ++ + struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, + qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, + enum omap_dma_model model) +@@ -1318,7 +1415,7 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, + struct omap_dma_s *s = (struct omap_dma_s *) + qemu_mallocz(sizeof(struct omap_dma_s)); + +- if (model == omap_dma_3_1) { ++ if (model <= omap_dma_3_1) { + num_irqs = 6; + memsize = 0x800; + } else { +@@ -1331,6 +1428,7 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, + s->clk = clk; + s->lcd_ch.irq = lcd_irq; + s->lcd_ch.mpu = mpu; ++ omap_dma_setcaps(s); + while (num_irqs --) + s->ch[num_irqs].irq = irqs[num_irqs]; + for (i = 0; i < 3; i ++) { +@@ -1350,6 +1448,393 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, + return s; + } + ++static void omap_dma_interrupts_4_update(struct omap_dma_s *s) ++{ ++ struct omap_dma_channel_s *ch = s->ch; ++ uint32_t bmp, bit; ++ ++ for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1) ++ if (ch->status) { ++ bmp |= bit; ++ ch->cstatus |= ch->status; ++ ch->status = 0; ++ } ++ if ((s->irqstat[0] |= s->irqen[0] & bmp)) ++ qemu_irq_raise(s->irq[0]); ++ if ((s->irqstat[1] |= s->irqen[1] & bmp)) ++ qemu_irq_raise(s->irq[1]); ++ if ((s->irqstat[2] |= s->irqen[2] & bmp)) ++ qemu_irq_raise(s->irq[2]); ++ if ((s->irqstat[3] |= s->irqen[3] & bmp)) ++ qemu_irq_raise(s->irq[3]); ++} ++ ++static uint32_t omap_dma4_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_dma_s *s = (struct omap_dma_s *) opaque; ++ int irqn = 0, chnum, offset = addr - s->base; ++ struct omap_dma_channel_s *ch; ++ ++ switch (offset) { ++ case 0x00: /* DMA4_REVISION */ ++ return 0x40; ++ ++ case 0x14: /* DMA4_IRQSTATUS_L3 */ ++ irqn ++; ++ case 0x10: /* DMA4_IRQSTATUS_L2 */ ++ irqn ++; ++ case 0x0c: /* DMA4_IRQSTATUS_L1 */ ++ irqn ++; ++ case 0x08: /* DMA4_IRQSTATUS_L0 */ ++ return s->irqstat[irqn]; ++ ++ case 0x24: /* DMA4_IRQENABLE_L3 */ ++ irqn ++; ++ case 0x20: /* DMA4_IRQENABLE_L2 */ ++ irqn ++; ++ case 0x1c: /* DMA4_IRQENABLE_L1 */ ++ irqn ++; ++ case 0x18: /* DMA4_IRQENABLE_L0 */ ++ return s->irqen[irqn]; ++ ++ case 0x28: /* DMA4_SYSSTATUS */ ++ return 1; /* RESETDONE */ ++ ++ case 0x2c: /* DMA4_OCP_SYSCONFIG */ ++ return s->ocp; ++ ++ case 0x64: /* DMA4_CAPS_0 */ ++ return s->caps[0]; ++ case 0x6c: /* DMA4_CAPS_2 */ ++ return s->caps[2]; ++ case 0x70: /* DMA4_CAPS_3 */ ++ return s->caps[3]; ++ case 0x74: /* DMA4_CAPS_4 */ ++ return s->caps[4]; ++ ++ case 0x78: /* DMA4_GCR */ ++ return s->gcr; ++ ++ case 0x80 ... 0xfff: ++ offset -= 0x80; ++ chnum = offset / 0x60; ++ ch = s->ch + chnum; ++ offset -= chnum * 0x60; ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return 0; ++ } ++ ++ /* Per-channel registers */ ++ switch (offset) { ++ case 0x00: /* DMA4_CCR */ ++ return (ch->buf_disable << 25) | ++ (ch->src_sync << 24) | ++ (ch->prefetch << 23) | ++ ((ch->sync & 0x60) << 14) | ++ (ch->bs << 18) | ++ (ch->transparent_copy << 17) | ++ (ch->constant_fill << 16) | ++ (ch->mode[1] << 14) | ++ (ch->mode[0] << 12) | ++ (0 << 10) | (0 << 9) | ++ (ch->suspend << 8) | ++ (ch->enable << 7) | ++ (ch->priority << 6) | ++ (ch->fs << 5) | (ch->sync & 0x1f); ++ ++ case 0x04: /* DMA4_CLNK_CTRL */ ++ return (ch->link_enabled << 15) | ch->link_next_ch; ++ ++ case 0x08: /* DMA4_CICR */ ++ return ch->interrupts; ++ ++ case 0x0c: /* DMA4_CSR */ ++ return ch->cstatus; ++ ++ case 0x10: /* DMA4_CSDP */ ++ return (ch->endian[0] << 21) | ++ (ch->endian_lock[0] << 20) | ++ (ch->endian[1] << 19) | ++ (ch->endian_lock[1] << 18) | ++ (ch->write_mode << 16) | ++ (ch->burst[1] << 14) | ++ (ch->pack[1] << 13) | ++ (ch->translate[1] << 9) | ++ (ch->burst[0] << 7) | ++ (ch->pack[0] << 6) | ++ (ch->translate[0] << 2) | ++ (ch->data_type >> 1); ++ ++ case 0x14: /* DMA4_CEN */ ++ return ch->elements; ++ ++ case 0x18: /* DMA4_CFN */ ++ return ch->frames; ++ ++ case 0x1c: /* DMA4_CSSA */ ++ return ch->addr[0]; ++ ++ case 0x20: /* DMA4_CDSA */ ++ return ch->addr[1]; ++ ++ case 0x24: /* DMA4_CSEI */ ++ return ch->element_index[0]; ++ ++ case 0x28: /* DMA4_CSFI */ ++ return ch->frame_index[0]; ++ ++ case 0x2c: /* DMA4_CDEI */ ++ return ch->element_index[1]; ++ ++ case 0x30: /* DMA4_CDFI */ ++ return ch->frame_index[1]; ++ ++ case 0x34: /* DMA4_CSAC */ ++ return ch->active_set.src & 0xffff; ++ ++ case 0x38: /* DMA4_CDAC */ ++ return ch->active_set.dest & 0xffff; ++ ++ case 0x3c: /* DMA4_CCEN */ ++ return ch->active_set.element; ++ ++ case 0x40: /* DMA4_CCFN */ ++ return ch->active_set.frame; ++ ++ case 0x44: /* DMA4_COLOR */ ++ /* XXX only in sDMA */ ++ return ch->color; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return 0; ++ } ++} ++ ++static void omap_dma4_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_dma_s *s = (struct omap_dma_s *) opaque; ++ int chnum, irqn = 0, offset = addr - s->base; ++ struct omap_dma_channel_s *ch; ++ ++ switch (offset) { ++ case 0x14: /* DMA4_IRQSTATUS_L3 */ ++ irqn ++; ++ case 0x10: /* DMA4_IRQSTATUS_L2 */ ++ irqn ++; ++ case 0x0c: /* DMA4_IRQSTATUS_L1 */ ++ irqn ++; ++ case 0x08: /* DMA4_IRQSTATUS_L0 */ ++ s->irqstat[irqn] &= ~value; ++ if (!s->irqstat[irqn]) ++ qemu_irq_lower(s->irq[irqn]); ++ return; ++ ++ case 0x24: /* DMA4_IRQENABLE_L3 */ ++ irqn ++; ++ case 0x20: /* DMA4_IRQENABLE_L2 */ ++ irqn ++; ++ case 0x1c: /* DMA4_IRQENABLE_L1 */ ++ irqn ++; ++ case 0x18: /* DMA4_IRQENABLE_L0 */ ++ s->irqen[irqn] = value; ++ return; ++ ++ case 0x2c: /* DMA4_OCP_SYSCONFIG */ ++ if (value & 2) /* SOFTRESET */ ++ omap_dma_reset(s); ++ s->ocp = value & 0x3321; ++ if (((s->ocp >> 12) & 3) == 3) /* MIDLEMODE */ ++ fprintf(stderr, "%s: invalid DMA power mode\n", __FUNCTION__); ++ return; ++ ++ case 0x78: /* DMA4_GCR */ ++ s->gcr = value & 0x00ff00ff; ++ if ((value & 0xff) == 0x00) /* MAX_CHANNEL_FIFO_DEPTH */ ++ fprintf(stderr, "%s: wrong FIFO depth in GCR\n", __FUNCTION__); ++ return; ++ ++ case 0x80 ... 0xfff: ++ offset -= 0x80; ++ chnum = offset / 0x60; ++ ch = s->ch + chnum; ++ offset -= chnum * 0x60; ++ break; ++ ++ case 0x00: /* DMA4_REVISION */ ++ case 0x28: /* DMA4_SYSSTATUS */ ++ case 0x64: /* DMA4_CAPS_0 */ ++ case 0x6c: /* DMA4_CAPS_2 */ ++ case 0x70: /* DMA4_CAPS_3 */ ++ case 0x74: /* DMA4_CAPS_4 */ ++ OMAP_RO_REG(addr); ++ return; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ return; ++ } ++ ++ /* Per-channel registers */ ++ switch (offset) { ++ case 0x00: /* DMA4_CCR */ ++ ch->buf_disable = (value >> 25) & 1; ++ ch->src_sync = (value >> 24) & 1; /* XXX For CamDMA must be 1 */ ++ if (ch->buf_disable && !ch->src_sync) ++ fprintf(stderr, "%s: Buffering disable is not allowed in " ++ "destination synchronised mode\n", __FUNCTION__); ++ ch->prefetch = (value >> 23) & 1; ++ ch->bs = (value >> 18) & 1; ++ ch->transparent_copy = (value >> 17) & 1; ++ ch->constant_fill = (value >> 16) & 1; ++ ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); ++ ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); ++ ch->suspend = (value & 0x0100) >> 8; ++ ch->priority = (value & 0x0040) >> 6; ++ ch->fs = (value & 0x0020) >> 5; ++ if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1]) ++ fprintf(stderr, "%s: For a packet transfer at least one port " ++ "must be constant-addressed\n", __FUNCTION__); ++ ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060); ++ /* XXX must be 0x01 for CamDMA */ ++ ++ if (value & 0x0080) ++ omap_dma_enable_channel(s, ch); ++ else ++ omap_dma_disable_channel(s, ch); ++ ++ break; ++ ++ case 0x04: /* DMA4_CLNK_CTRL */ ++ ch->link_enabled = (value >> 15) & 0x1; ++ ch->link_next_ch = value & 0x1f; ++ break; ++ ++ case 0x08: /* DMA4_CICR */ ++ ch->interrupts = value & 0x09be; ++ break; ++ ++ case 0x0c: /* DMA4_CSR */ ++ ch->cstatus &= ~value; ++ break; ++ ++ case 0x10: /* DMA4_CSDP */ ++ ch->endian[0] =(value >> 21) & 1; ++ ch->endian_lock[0] =(value >> 20) & 1; ++ ch->endian[1] =(value >> 19) & 1; ++ ch->endian_lock[1] =(value >> 18) & 1; ++ if (ch->endian[0] != ch->endian[1]) ++ fprintf(stderr, "%s: DMA endianned conversion enable attempt\n", ++ __FUNCTION__); ++ ch->write_mode = (value >> 16) & 3; ++ ch->burst[1] = (value & 0xc000) >> 14; ++ ch->pack[1] = (value & 0x2000) >> 13; ++ ch->translate[1] = (value & 0x1e00) >> 9; ++ ch->burst[0] = (value & 0x0180) >> 7; ++ ch->pack[0] = (value & 0x0040) >> 6; ++ ch->translate[0] = (value & 0x003c) >> 2; ++ if (ch->translate[0] | ch->translate[1]) ++ fprintf(stderr, "%s: bad MReqAddressTranslate sideband signal\n", ++ __FUNCTION__); ++ ch->data_type = 1 << (value & 3); ++ if ((value & 3) == 3) ++ printf("%s: bad data_type for DMA channel\n", __FUNCTION__); ++ break; ++ ++ case 0x14: /* DMA4_CEN */ ++ ch->elements = value & 0xffffff; ++ break; ++ ++ case 0x18: /* DMA4_CFN */ ++ ch->frames = value & 0xffff; ++ break; ++ ++ case 0x1c: /* DMA4_CSSA */ ++ ch->addr[0] = (target_phys_addr_t) (uint32_t) value; ++ break; ++ ++ case 0x20: /* DMA4_CDSA */ ++ ch->addr[1] = (target_phys_addr_t) (uint32_t) value; ++ break; ++ ++ case 0x24: /* DMA4_CSEI */ ++ ch->element_index[0] = (int16_t) value; ++ break; ++ ++ case 0x28: /* DMA4_CSFI */ ++ ch->frame_index[0] = (int32_t) value; ++ break; ++ ++ case 0x2c: /* DMA4_CDEI */ ++ ch->element_index[1] = (int16_t) value; ++ break; ++ ++ case 0x30: /* DMA4_CDFI */ ++ ch->frame_index[1] = (int32_t) value; ++ break; ++ ++ case 0x44: /* DMA4_COLOR */ ++ /* XXX only in sDMA */ ++ ch->color = value; ++ break; ++ ++ case 0x34: /* DMA4_CSAC */ ++ case 0x38: /* DMA4_CDAC */ ++ case 0x3c: /* DMA4_CCEN */ ++ case 0x40: /* DMA4_CCFN */ ++ OMAP_RO_REG(addr); ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ } ++} ++ ++static CPUReadMemoryFunc *omap_dma4_readfn[] = { ++ omap_badwidth_read16, ++ omap_dma4_read, ++ omap_dma4_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_dma4_writefn[] = { ++ omap_badwidth_write16, ++ omap_dma4_write, ++ omap_dma4_write, ++}; ++ ++struct omap_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs, ++ struct omap_mpu_state_s *mpu, int fifo, ++ int chans, omap_clk iclk, omap_clk fclk) ++{ ++ int iomemtype; ++ struct omap_dma_s *s = (struct omap_dma_s *) ++ qemu_mallocz(sizeof(struct omap_dma_s)); ++ ++ s->base = base; ++ s->model = omap_dma_4; ++ s->chans = chans; ++ s->mpu = mpu; ++ s->clk = fclk; ++ memcpy(&s->irq, irqs, sizeof(s->irq)); ++ s->intr_update = omap_dma_interrupts_4_update; ++ omap_dma_setcaps(s); ++ s->tm = qemu_new_timer(vm_clock, (QEMUTimerCB *) omap_dma_channel_run, s); ++ omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); ++ mpu->drq = qemu_allocate_irqs(omap_dma_request, s, 64); ++ omap_dma_reset(s); ++ omap_dma_clk_update(s, 0, 1); ++ ++ iomemtype = cpu_register_io_memory(0, omap_dma4_readfn, ++ omap_dma4_writefn, s); ++ cpu_register_physical_memory(s->base, 0x1000, iomemtype); ++ ++ return s; ++} ++ + struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct omap_dma_s *s) + { + return &s->lcd_ch; +diff --git a/hw/omap_dss.c b/hw/omap_dss.c +new file mode 100644 +index 0000000..1c16802 +--- /dev/null ++++ b/hw/omap_dss.c +@@ -0,0 +1,1088 @@ ++/* ++ * OMAP2 Display Subsystem. ++ * ++ * Copyright (C) 2008 Nokia Corporation ++ * Written by Andrzej Zaborowski <andrew@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * 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 "console.h" ++#include "omap.h" ++ ++struct omap_dss_s { ++ target_phys_addr_t diss_base; ++ target_phys_addr_t disc_base; ++ target_phys_addr_t rfbi_base; ++ target_phys_addr_t venc_base; ++ target_phys_addr_t im3_base; ++ qemu_irq irq; ++ qemu_irq drq; ++ DisplayState *state; ++ ++ int autoidle; ++ int control; ++ int enable; ++ ++ struct omap_dss_panel_s { ++ int enable; ++ int nx; ++ int ny; ++ ++ int x; ++ int y; ++ } dig, lcd; ++ ++ struct { ++ uint32_t idlemode; ++ uint32_t irqst; ++ uint32_t irqen; ++ uint32_t control; ++ uint32_t config; ++ uint32_t capable; ++ uint32_t timing[3]; ++ int line; ++ uint32_t bg[2]; ++ uint32_t trans[2]; ++ ++ struct omap_dss_plane_s { ++ int enable; ++ int bpp; ++ int posx; ++ int posy; ++ int nx; ++ int ny; ++ ++ target_phys_addr_t addr[3]; ++ ++ uint32_t attr; ++ uint32_t tresh; ++ int rowinc; ++ int colinc; ++ int wininc; ++ } l[3]; ++ ++ int invalidate; ++ uint16_t palette[256]; ++ } dispc; ++ ++ struct { ++ int idlemode; ++ uint32_t control; ++ int enable; ++ int pixels; ++ int busy; ++ int skiplines; ++ uint16_t rxbuf; ++ uint32_t config[2]; ++ uint32_t time[4]; ++ uint32_t data[6]; ++ uint16_t vsync; ++ uint16_t hsync; ++ struct rfbi_chip_s *chip[2]; ++ } rfbi; ++}; ++ ++static void omap_dispc_interrupt_update(struct omap_dss_s *s) ++{ ++ qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen); ++} ++ ++static void omap_rfbi_reset(struct omap_dss_s *s) ++{ ++ s->rfbi.idlemode = 0; ++ s->rfbi.control = 2; ++ s->rfbi.enable = 0; ++ s->rfbi.pixels = 0; ++ s->rfbi.skiplines = 0; ++ s->rfbi.busy = 0; ++ s->rfbi.config[0] = 0x00310000; ++ s->rfbi.config[1] = 0x00310000; ++ s->rfbi.time[0] = 0; ++ s->rfbi.time[1] = 0; ++ s->rfbi.time[2] = 0; ++ s->rfbi.time[3] = 0; ++ s->rfbi.data[0] = 0; ++ s->rfbi.data[1] = 0; ++ s->rfbi.data[2] = 0; ++ s->rfbi.data[3] = 0; ++ s->rfbi.data[4] = 0; ++ s->rfbi.data[5] = 0; ++ s->rfbi.vsync = 0; ++ s->rfbi.hsync = 0; ++} ++ ++void omap_dss_reset(struct omap_dss_s *s) ++{ ++ s->autoidle = 0; ++ s->control = 0; ++ s->enable = 0; ++ ++ s->dig.enable = 0; ++ s->dig.nx = 1; ++ s->dig.ny = 1; ++ ++ s->lcd.enable = 0; ++ s->lcd.nx = 1; ++ s->lcd.ny = 1; ++ ++ s->dispc.idlemode = 0; ++ s->dispc.irqst = 0; ++ s->dispc.irqen = 0; ++ s->dispc.control = 0; ++ s->dispc.config = 0; ++ s->dispc.capable = 0x161; ++ s->dispc.timing[0] = 0; ++ s->dispc.timing[1] = 0; ++ s->dispc.timing[2] = 0; ++ s->dispc.line = 0; ++ s->dispc.bg[0] = 0; ++ s->dispc.bg[1] = 0; ++ s->dispc.trans[0] = 0; ++ s->dispc.trans[1] = 0; ++ ++ s->dispc.l[0].enable = 0; ++ s->dispc.l[0].bpp = 0; ++ s->dispc.l[0].addr[0] = 0; ++ s->dispc.l[0].addr[1] = 0; ++ s->dispc.l[0].addr[2] = 0; ++ s->dispc.l[0].posx = 0; ++ s->dispc.l[0].posy = 0; ++ s->dispc.l[0].nx = 1; ++ s->dispc.l[0].ny = 1; ++ s->dispc.l[0].attr = 0; ++ s->dispc.l[0].tresh = 0; ++ s->dispc.l[0].rowinc = 1; ++ s->dispc.l[0].colinc = 1; ++ s->dispc.l[0].wininc = 0; ++ ++ omap_rfbi_reset(s); ++ omap_dispc_interrupt_update(s); ++} ++ ++static uint32_t omap_diss_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->diss_base; ++ ++ switch (offset) { ++ case 0x00: /* DSS_REVISIONNUMBER */ ++ return 0x20; ++ ++ case 0x10: /* DSS_SYSCONFIG */ ++ return s->autoidle; ++ ++ case 0x14: /* DSS_SYSSTATUS */ ++ return 1; /* RESETDONE */ ++ ++ case 0x40: /* DSS_CONTROL */ ++ return s->control; ++ ++ case 0x50: /* DSS_PSA_LCD_REG_1 */ ++ case 0x54: /* DSS_PSA_LCD_REG_2 */ ++ case 0x58: /* DSS_PSA_VIDEO_REG */ ++ /* TODO: fake some values when appropriate s->control bits are set */ ++ return 0; ++ ++ case 0x5c: /* DSS_STATUS */ ++ return 1 + (s->control & 1); ++ ++ default: ++ break; ++ } ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_diss_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->diss_base; ++ ++ switch (offset) { ++ case 0x00: /* DSS_REVISIONNUMBER */ ++ case 0x14: /* DSS_SYSSTATUS */ ++ case 0x50: /* DSS_PSA_LCD_REG_1 */ ++ case 0x54: /* DSS_PSA_LCD_REG_2 */ ++ case 0x58: /* DSS_PSA_VIDEO_REG */ ++ case 0x5c: /* DSS_STATUS */ ++ OMAP_RO_REG(addr); ++ break; ++ ++ case 0x10: /* DSS_SYSCONFIG */ ++ if (value & 2) /* SOFTRESET */ ++ omap_dss_reset(s); ++ s->autoidle = value & 1; ++ break; ++ ++ case 0x40: /* DSS_CONTROL */ ++ s->control = value & 0x3dd; ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ } ++} ++ ++static CPUReadMemoryFunc *omap_diss1_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap_diss_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_diss1_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_diss_write, ++}; ++ ++static uint32_t omap_disc_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->disc_base; ++ ++ switch (offset) { ++ case 0x000: /* DISPC_REVISION */ ++ return 0x20; ++ ++ case 0x010: /* DISPC_SYSCONFIG */ ++ return s->dispc.idlemode; ++ ++ case 0x014: /* DISPC_SYSSTATUS */ ++ return 1; /* RESETDONE */ ++ ++ case 0x018: /* DISPC_IRQSTATUS */ ++ return s->dispc.irqst; ++ ++ case 0x01c: /* DISPC_IRQENABLE */ ++ return s->dispc.irqen; ++ ++ case 0x040: /* DISPC_CONTROL */ ++ return s->dispc.control; ++ ++ case 0x044: /* DISPC_CONFIG */ ++ return s->dispc.config; ++ ++ case 0x048: /* DISPC_CAPABLE */ ++ return s->dispc.capable; ++ ++ case 0x04c: /* DISPC_DEFAULT_COLOR0 */ ++ return s->dispc.bg[0]; ++ case 0x050: /* DISPC_DEFAULT_COLOR1 */ ++ return s->dispc.bg[1]; ++ case 0x054: /* DISPC_TRANS_COLOR0 */ ++ return s->dispc.trans[0]; ++ case 0x058: /* DISPC_TRANS_COLOR1 */ ++ return s->dispc.trans[1]; ++ ++ case 0x05c: /* DISPC_LINE_STATUS */ ++ return 0x7ff; ++ case 0x060: /* DISPC_LINE_NUMBER */ ++ return s->dispc.line; ++ ++ case 0x064: /* DISPC_TIMING_H */ ++ return s->dispc.timing[0]; ++ case 0x068: /* DISPC_TIMING_V */ ++ return s->dispc.timing[1]; ++ case 0x06c: /* DISPC_POL_FREQ */ ++ return s->dispc.timing[2]; ++ case 0x070: /* DISPC_DIVISOR */ ++ return s->dispc.timing[3]; ++ ++ case 0x078: /* DISPC_SIZE_DIG */ ++ return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1); ++ case 0x07c: /* DISPC_SIZE_LCD */ ++ return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1); ++ ++ case 0x080: /* DISPC_GFX_BA0 */ ++ return s->dispc.l[0].addr[0]; ++ case 0x084: /* DISPC_GFX_BA1 */ ++ return s->dispc.l[0].addr[1]; ++ case 0x088: /* DISPC_GFX_POSITION */ ++ return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx; ++ case 0x08c: /* DISPC_GFX_SIZE */ ++ return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1); ++ case 0x0a0: /* DISPC_GFX_ATTRIBUTES */ ++ return s->dispc.l[0].attr; ++ case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */ ++ return s->dispc.l[0].tresh; ++ case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */ ++ return 256; ++ case 0x0ac: /* DISPC_GFX_ROW_INC */ ++ return s->dispc.l[0].rowinc; ++ case 0x0b0: /* DISPC_GFX_PIXEL_INC */ ++ return s->dispc.l[0].colinc; ++ case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */ ++ return s->dispc.l[0].wininc; ++ case 0x0b8: /* DISPC_GFX_TABLE_BA */ ++ return s->dispc.l[0].addr[2]; ++ ++ case 0x0bc: /* DISPC_VID1_BA0 */ ++ case 0x0c0: /* DISPC_VID1_BA1 */ ++ case 0x0c4: /* DISPC_VID1_POSITION */ ++ case 0x0c8: /* DISPC_VID1_SIZE */ ++ case 0x0cc: /* DISPC_VID1_ATTRIBUTES */ ++ case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */ ++ case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */ ++ case 0x0d8: /* DISPC_VID1_ROW_INC */ ++ case 0x0dc: /* DISPC_VID1_PIXEL_INC */ ++ case 0x0e0: /* DISPC_VID1_FIR */ ++ case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */ ++ case 0x0e8: /* DISPC_VID1_ACCU0 */ ++ case 0x0ec: /* DISPC_VID1_ACCU1 */ ++ case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */ ++ case 0x14c: /* DISPC_VID2_BA0 */ ++ case 0x150: /* DISPC_VID2_BA1 */ ++ case 0x154: /* DISPC_VID2_POSITION */ ++ case 0x158: /* DISPC_VID2_SIZE */ ++ case 0x15c: /* DISPC_VID2_ATTRIBUTES */ ++ case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */ ++ case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */ ++ case 0x168: /* DISPC_VID2_ROW_INC */ ++ case 0x16c: /* DISPC_VID2_PIXEL_INC */ ++ case 0x170: /* DISPC_VID2_FIR */ ++ case 0x174: /* DISPC_VID2_PICTURE_SIZE */ ++ case 0x178: /* DISPC_VID2_ACCU0 */ ++ case 0x17c: /* DISPC_VID2_ACCU1 */ ++ case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */ ++ case 0x1d4: /* DISPC_DATA_CYCLE1 */ ++ case 0x1d8: /* DISPC_DATA_CYCLE2 */ ++ case 0x1dc: /* DISPC_DATA_CYCLE3 */ ++ return 0; ++ ++ default: ++ break; ++ } ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_disc_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->disc_base; ++ ++ switch (offset) { ++ case 0x010: /* DISPC_SYSCONFIG */ ++ if (value & 2) /* SOFTRESET */ ++ omap_dss_reset(s); ++ s->dispc.idlemode = value & 0x301b; ++ break; ++ ++ case 0x018: /* DISPC_IRQSTATUS */ ++ s->dispc.irqst &= ~value; ++ omap_dispc_interrupt_update(s); ++ break; ++ ++ case 0x01c: /* DISPC_IRQENABLE */ ++ s->dispc.irqen = value & 0xffff; ++ omap_dispc_interrupt_update(s); ++ break; ++ ++ case 0x040: /* DISPC_CONTROL */ ++ s->dispc.control = value & 0x07ff9fff; ++ s->dig.enable = (value >> 1) & 1; ++ s->lcd.enable = (value >> 0) & 1; ++ if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */ ++ if (~((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) ++ fprintf(stderr, "%s: Overlay Optimization when no overlay " ++ "region effectively exists leads to " ++ "unpredictable behaviour!\n", __FUNCTION__); ++ if (value & (1 << 6)) { /* GODIGITAL */ ++ //// Shadows: ++ //// s->dispc.config ++ //// s->dispc.capable ++ //// s->dispc.bg[0] ++ //// s->dispc.bg[1] ++ //// s->dispc.trans[0] ++ //// s->dispc.trans[1] ++ //// s->dispc.line ++ //// s->dispc.timing[0] ++ //// s->dispc.timing[1] ++ //// s->dispc.timing[2] ++ //// s->dispc.timing[3] ++ //// s->lcd.nx ++ //// s->lcd.ny ++ //// s->dig.nx ++ //// s->dig.ny ++ //// s->dispc.l[0].addr[0] ++ //// s->dispc.l[0].addr[1] ++ //// s->dispc.l[0].addr[2] ++ //// s->dispc.l[0].posx ++ //// s->dispc.l[0].posy ++ //// s->dispc.l[0].nx ++ //// s->dispc.l[0].ny ++ //// s->dispc.l[0].tresh ++ //// s->dispc.l[0].rowinc ++ //// s->dispc.l[0].colinc ++ //// s->dispc.l[0].wininc ++ } ++ if (value & (1 << 5)) { /* GOLCD */ ++ } ++ s->dispc.invalidate = 1; ++ break; ++ ++ case 0x044: /* DISPC_CONFIG */ ++ s->dispc.config = value & 0x3fff; ++ //// bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded ++ //// bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded ++ s->dispc.invalidate = 1; ++ break; ++ ++ case 0x048: /* DISPC_CAPABLE */ ++ s->dispc.capable = value & 0x3ff; ++ break; ++ ++ case 0x04c: /* DISPC_DEFAULT_COLOR0 */ ++ s->dispc.bg[0] = value & 0xffffff; ++ s->dispc.invalidate = 1; ++ break; ++ case 0x050: /* DISPC_DEFAULT_COLOR1 */ ++ s->dispc.bg[1] = value & 0xffffff; ++ s->dispc.invalidate = 1; ++ break; ++ case 0x054: /* DISPC_TRANS_COLOR0 */ ++ s->dispc.trans[0] = value & 0xffffff; ++ s->dispc.invalidate = 1; ++ break; ++ case 0x058: /* DISPC_TRANS_COLOR1 */ ++ s->dispc.trans[1] = value & 0xffffff; ++ s->dispc.invalidate = 1; ++ break; ++ ++ case 0x060: /* DISPC_LINE_NUMBER */ ++ s->dispc.line = value & 0x7ff; ++ break; ++ ++ case 0x064: /* DISPC_TIMING_H */ ++ s->dispc.timing[0] = value & 0x0ff0ff3f; ++ break; ++ case 0x068: /* DISPC_TIMING_V */ ++ s->dispc.timing[1] = value & 0x0ff0ff3f; ++ break; ++ case 0x06c: /* DISPC_POL_FREQ */ ++ s->dispc.timing[2] = value & 0x0003ffff; ++ break; ++ case 0x070: /* DISPC_DIVISOR */ ++ s->dispc.timing[3] = value & 0x00ff00ff; ++ break; ++ ++ case 0x078: /* DISPC_SIZE_DIG */ ++ s->dig.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */ ++ s->dig.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */ ++ s->dispc.invalidate = 1; ++ break; ++ case 0x07c: /* DISPC_SIZE_LCD */ ++ s->lcd.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */ ++ s->lcd.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */ ++ s->dispc.invalidate = 1; ++ break; ++ case 0x080: /* DISPC_GFX_BA0 */ ++ s->dispc.l[0].addr[0] = (target_phys_addr_t) value; ++ s->dispc.invalidate = 1; ++ break; ++ case 0x084: /* DISPC_GFX_BA1 */ ++ s->dispc.l[0].addr[1] = (target_phys_addr_t) value; ++ s->dispc.invalidate = 1; ++ break; ++ case 0x088: /* DISPC_GFX_POSITION */ ++ s->dispc.l[0].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */ ++ s->dispc.l[0].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */ ++ s->dispc.invalidate = 1; ++ break; ++ case 0x08c: /* DISPC_GFX_SIZE */ ++ s->dispc.l[0].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */ ++ s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */ ++ s->dispc.invalidate = 1; ++ break; ++ case 0x0a0: /* DISPC_GFX_ATTRIBUTES */ ++ s->dispc.l[0].attr = value & 0x7ff; ++ if (value & (3 << 9)) ++ fprintf(stderr, "%s: Big-endian pixel format not supported\n", ++ __FUNCTION__); ++ s->dispc.l[0].enable = value & 1; ++ s->dispc.l[0].bpp = (value >> 1) & 0xf; ++ s->dispc.invalidate = 1; ++ break; ++ case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */ ++ s->dispc.l[0].tresh = value & 0x01ff01ff; ++ break; ++ case 0x0ac: /* DISPC_GFX_ROW_INC */ ++ s->dispc.l[0].rowinc = value; ++ s->dispc.invalidate = 1; ++ break; ++ case 0x0b0: /* DISPC_GFX_PIXEL_INC */ ++ s->dispc.l[0].colinc = value; ++ s->dispc.invalidate = 1; ++ break; ++ case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */ ++ s->dispc.l[0].wininc = value; ++ break; ++ case 0x0b8: /* DISPC_GFX_TABLE_BA */ ++ s->dispc.l[0].addr[2] = (target_phys_addr_t) value; ++ s->dispc.invalidate = 1; ++ break; ++ ++ case 0x0bc: /* DISPC_VID1_BA0 */ ++ case 0x0c0: /* DISPC_VID1_BA1 */ ++ case 0x0c4: /* DISPC_VID1_POSITION */ ++ case 0x0c8: /* DISPC_VID1_SIZE */ ++ case 0x0cc: /* DISPC_VID1_ATTRIBUTES */ ++ case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */ ++ case 0x0d8: /* DISPC_VID1_ROW_INC */ ++ case 0x0dc: /* DISPC_VID1_PIXEL_INC */ ++ case 0x0e0: /* DISPC_VID1_FIR */ ++ case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */ ++ case 0x0e8: /* DISPC_VID1_ACCU0 */ ++ case 0x0ec: /* DISPC_VID1_ACCU1 */ ++ case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */ ++ case 0x14c: /* DISPC_VID2_BA0 */ ++ case 0x150: /* DISPC_VID2_BA1 */ ++ case 0x154: /* DISPC_VID2_POSITION */ ++ case 0x158: /* DISPC_VID2_SIZE */ ++ case 0x15c: /* DISPC_VID2_ATTRIBUTES */ ++ case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */ ++ case 0x168: /* DISPC_VID2_ROW_INC */ ++ case 0x16c: /* DISPC_VID2_PIXEL_INC */ ++ case 0x170: /* DISPC_VID2_FIR */ ++ case 0x174: /* DISPC_VID2_PICTURE_SIZE */ ++ case 0x178: /* DISPC_VID2_ACCU0 */ ++ case 0x17c: /* DISPC_VID2_ACCU1 */ ++ case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */ ++ case 0x1d4: /* DISPC_DATA_CYCLE1 */ ++ case 0x1d8: /* DISPC_DATA_CYCLE2 */ ++ case 0x1dc: /* DISPC_DATA_CYCLE3 */ ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ } ++} ++ ++static CPUReadMemoryFunc *omap_disc1_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap_disc_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_disc1_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_disc_write, ++}; ++ ++static void *omap_rfbi_get_buffer(struct omap_dss_s *s) ++{ ++ target_phys_addr_t fb; ++ uint32_t pd; ++ ++ /* TODO */ ++ fb = s->dispc.l[0].addr[0]; ++ ++ pd = cpu_get_physical_page_desc(fb); ++ if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) ++ /* TODO */ ++ cpu_abort(cpu_single_env, "%s: framebuffer outside RAM!\n", ++ __FUNCTION__); ++ else ++ return phys_ram_base + ++ (pd & TARGET_PAGE_MASK) + ++ (fb & ~TARGET_PAGE_MASK); ++} ++ ++static void omap_rfbi_transfer_stop(struct omap_dss_s *s) ++{ ++ if (!s->rfbi.busy) ++ return; ++ ++ /* TODO: in non-Bypass mode we probably need to just deassert the DRQ. */ ++ ++ s->rfbi.busy = 0; ++} ++ ++static void omap_rfbi_transfer_start(struct omap_dss_s *s) ++{ ++ void *data; ++ size_t len; ++ int pitch; ++ ++ if (!s->rfbi.enable || s->rfbi.busy) ++ return; ++ ++ if (s->rfbi.control & (1 << 1)) { /* BYPASS */ ++ /* TODO: in non-Bypass mode we probably need to just assert the ++ * DRQ and wait for DMA to write the pixels. */ ++ fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__); ++ return; ++ } ++ ++ if (!(s->dispc.control & (1 << 11))) /* RFBIMODE */ ++ return; ++ /* TODO: check that LCD output is enabled in DISPC. */ ++ ++ s->rfbi.busy = 1; ++ ++ data = omap_rfbi_get_buffer(s); ++ ++ /* TODO bpp */ ++ len = s->rfbi.pixels * 2; ++ s->rfbi.pixels = 0; ++ ++ /* TODO: negative values */ ++ pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2; ++ ++ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) ++ s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch); ++ if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) ++ s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch); ++ ++ omap_rfbi_transfer_stop(s); ++ ++ /* TODO */ ++ s->dispc.irqst |= 1; /* FRAMEDONE */ ++ omap_dispc_interrupt_update(s); ++} ++ ++static uint32_t omap_rfbi_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->rfbi_base; ++ ++ switch (offset) { ++ case 0x00: /* RFBI_REVISION */ ++ return 0x10; ++ ++ case 0x10: /* RFBI_SYSCONFIG */ ++ return s->rfbi.idlemode; ++ ++ case 0x14: /* RFBI_SYSSTATUS */ ++ return 1 | (s->rfbi.busy << 8); /* RESETDONE */ ++ ++ case 0x40: /* RFBI_CONTROL */ ++ return s->rfbi.control; ++ ++ case 0x44: /* RFBI_PIXELCNT */ ++ return s->rfbi.pixels; ++ ++ case 0x48: /* RFBI_LINE_NUMBER */ ++ return s->rfbi.skiplines; ++ ++ case 0x58: /* RFBI_READ */ ++ case 0x5c: /* RFBI_STATUS */ ++ return s->rfbi.rxbuf; ++ ++ case 0x60: /* RFBI_CONFIG0 */ ++ return s->rfbi.config[0]; ++ case 0x64: /* RFBI_ONOFF_TIME0 */ ++ return s->rfbi.time[0]; ++ case 0x68: /* RFBI_CYCLE_TIME0 */ ++ return s->rfbi.time[1]; ++ case 0x6c: /* RFBI_DATA_CYCLE1_0 */ ++ return s->rfbi.data[0]; ++ case 0x70: /* RFBI_DATA_CYCLE2_0 */ ++ return s->rfbi.data[1]; ++ case 0x74: /* RFBI_DATA_CYCLE3_0 */ ++ return s->rfbi.data[2]; ++ ++ case 0x78: /* RFBI_CONFIG1 */ ++ return s->rfbi.config[1]; ++ case 0x7c: /* RFBI_ONOFF_TIME1 */ ++ return s->rfbi.time[2]; ++ case 0x80: /* RFBI_CYCLE_TIME1 */ ++ return s->rfbi.time[3]; ++ case 0x84: /* RFBI_DATA_CYCLE1_1 */ ++ return s->rfbi.data[3]; ++ case 0x88: /* RFBI_DATA_CYCLE2_1 */ ++ return s->rfbi.data[4]; ++ case 0x8c: /* RFBI_DATA_CYCLE3_1 */ ++ return s->rfbi.data[5]; ++ ++ case 0x90: /* RFBI_VSYNC_WIDTH */ ++ return s->rfbi.vsync; ++ case 0x94: /* RFBI_HSYNC_WIDTH */ ++ return s->rfbi.hsync; ++ } ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_rfbi_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->rfbi_base; ++ ++ switch (offset) { ++ case 0x10: /* RFBI_SYSCONFIG */ ++ if (value & 2) /* SOFTRESET */ ++ omap_rfbi_reset(s); ++ s->rfbi.idlemode = value & 0x19; ++ break; ++ ++ case 0x40: /* RFBI_CONTROL */ ++ s->rfbi.control = value & 0xf; ++ s->rfbi.enable = value & 1; ++ if (value & (1 << 4) && /* ITE */ ++ !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc)) ++ omap_rfbi_transfer_start(s); ++ break; ++ ++ case 0x44: /* RFBI_PIXELCNT */ ++ s->rfbi.pixels = value; ++ break; ++ ++ case 0x48: /* RFBI_LINE_NUMBER */ ++ s->rfbi.skiplines = value & 0x7ff; ++ break; ++ ++ case 0x4c: /* RFBI_CMD */ ++ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) ++ s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff); ++ if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) ++ s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff); ++ break; ++ case 0x50: /* RFBI_PARAM */ ++ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) ++ s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff); ++ if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) ++ s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff); ++ break; ++ case 0x54: /* RFBI_DATA */ ++ /* TODO: take into account the format set up in s->rfbi.config[?] and ++ * s->rfbi.data[?], but special-case the most usual scenario so that ++ * speed doesn't suffer. */ ++ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) { ++ s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff); ++ s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16); ++ } ++ if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) { ++ s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff); ++ s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16); ++ } ++ if (!-- s->rfbi.pixels) ++ omap_rfbi_transfer_stop(s); ++ break; ++ case 0x58: /* RFBI_READ */ ++ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) ++ s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1); ++ else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) ++ s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1); ++ if (!-- s->rfbi.pixels) ++ omap_rfbi_transfer_stop(s); ++ break; ++ ++ case 0x5c: /* RFBI_STATUS */ ++ if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) ++ s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0); ++ else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) ++ s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0); ++ if (!-- s->rfbi.pixels) ++ omap_rfbi_transfer_stop(s); ++ break; ++ ++ case 0x60: /* RFBI_CONFIG0 */ ++ s->rfbi.config[0] = value & 0x003f1fff; ++ break; ++ ++ case 0x64: /* RFBI_ONOFF_TIME0 */ ++ s->rfbi.time[0] = value & 0x3fffffff; ++ break; ++ case 0x68: /* RFBI_CYCLE_TIME0 */ ++ s->rfbi.time[1] = value & 0x0fffffff; ++ break; ++ case 0x6c: /* RFBI_DATA_CYCLE1_0 */ ++ s->rfbi.data[0] = value & 0x0f1f0f1f; ++ break; ++ case 0x70: /* RFBI_DATA_CYCLE2_0 */ ++ s->rfbi.data[1] = value & 0x0f1f0f1f; ++ break; ++ case 0x74: /* RFBI_DATA_CYCLE3_0 */ ++ s->rfbi.data[2] = value & 0x0f1f0f1f; ++ break; ++ case 0x78: /* RFBI_CONFIG1 */ ++ s->rfbi.config[1] = value & 0x003f1fff; ++ break; ++ ++ case 0x7c: /* RFBI_ONOFF_TIME1 */ ++ s->rfbi.time[2] = value & 0x3fffffff; ++ break; ++ case 0x80: /* RFBI_CYCLE_TIME1 */ ++ s->rfbi.time[3] = value & 0x0fffffff; ++ break; ++ case 0x84: /* RFBI_DATA_CYCLE1_1 */ ++ s->rfbi.data[3] = value & 0x0f1f0f1f; ++ break; ++ case 0x88: /* RFBI_DATA_CYCLE2_1 */ ++ s->rfbi.data[4] = value & 0x0f1f0f1f; ++ break; ++ case 0x8c: /* RFBI_DATA_CYCLE3_1 */ ++ s->rfbi.data[5] = value & 0x0f1f0f1f; ++ break; ++ ++ case 0x90: /* RFBI_VSYNC_WIDTH */ ++ s->rfbi.vsync = value & 0xffff; ++ break; ++ case 0x94: /* RFBI_HSYNC_WIDTH */ ++ s->rfbi.hsync = value & 0xffff; ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ } ++} ++ ++static CPUReadMemoryFunc *omap_rfbi1_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap_rfbi_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_rfbi1_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_rfbi_write, ++}; ++ ++static uint32_t omap_venc_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->venc_base; ++ ++ switch (offset) { ++ case 0x00: /* REV_ID */ ++ case 0x04: /* STATUS */ ++ case 0x08: /* F_CONTROL */ ++ case 0x10: /* VIDOUT_CTRL */ ++ case 0x14: /* SYNC_CTRL */ ++ case 0x1c: /* LLEN */ ++ case 0x20: /* FLENS */ ++ case 0x24: /* HFLTR_CTRL */ ++ case 0x28: /* CC_CARR_WSS_CARR */ ++ case 0x2c: /* C_PHASE */ ++ case 0x30: /* GAIN_U */ ++ case 0x34: /* GAIN_V */ ++ case 0x38: /* GAIN_Y */ ++ case 0x3c: /* BLACK_LEVEL */ ++ case 0x40: /* BLANK_LEVEL */ ++ case 0x44: /* X_COLOR */ ++ case 0x48: /* M_CONTROL */ ++ case 0x4c: /* BSTAMP_WSS_DATA */ ++ case 0x50: /* S_CARR */ ++ case 0x54: /* LINE21 */ ++ case 0x58: /* LN_SEL */ ++ case 0x5c: /* L21__WC_CTL */ ++ case 0x60: /* HTRIGGER_VTRIGGER */ ++ case 0x64: /* SAVID__EAVID */ ++ case 0x68: /* FLEN__FAL */ ++ case 0x6c: /* LAL__PHASE_RESET */ ++ case 0x70: /* HS_INT_START_STOP_X */ ++ case 0x74: /* HS_EXT_START_STOP_X */ ++ case 0x78: /* VS_INT_START_X */ ++ case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */ ++ case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */ ++ case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */ ++ case 0x88: /* VS_EXT_STOP_Y */ ++ case 0x90: /* AVID_START_STOP_X */ ++ case 0x94: /* AVID_START_STOP_Y */ ++ case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */ ++ case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */ ++ case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */ ++ case 0xb0: /* TVDETGP_INT_START_STOP_X */ ++ case 0xb4: /* TVDETGP_INT_START_STOP_Y */ ++ case 0xb8: /* GEN_CTRL */ ++ case 0xc4: /* DAC_TST__DAC_A */ ++ case 0xc8: /* DAC_B__DAC_C */ ++ return 0; ++ ++ default: ++ break; ++ } ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_venc_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->venc_base; ++ ++ switch (offset) { ++ case 0x08: /* F_CONTROL */ ++ case 0x10: /* VIDOUT_CTRL */ ++ case 0x14: /* SYNC_CTRL */ ++ case 0x1c: /* LLEN */ ++ case 0x20: /* FLENS */ ++ case 0x24: /* HFLTR_CTRL */ ++ case 0x28: /* CC_CARR_WSS_CARR */ ++ case 0x2c: /* C_PHASE */ ++ case 0x30: /* GAIN_U */ ++ case 0x34: /* GAIN_V */ ++ case 0x38: /* GAIN_Y */ ++ case 0x3c: /* BLACK_LEVEL */ ++ case 0x40: /* BLANK_LEVEL */ ++ case 0x44: /* X_COLOR */ ++ case 0x48: /* M_CONTROL */ ++ case 0x4c: /* BSTAMP_WSS_DATA */ ++ case 0x50: /* S_CARR */ ++ case 0x54: /* LINE21 */ ++ case 0x58: /* LN_SEL */ ++ case 0x5c: /* L21__WC_CTL */ ++ case 0x60: /* HTRIGGER_VTRIGGER */ ++ case 0x64: /* SAVID__EAVID */ ++ case 0x68: /* FLEN__FAL */ ++ case 0x6c: /* LAL__PHASE_RESET */ ++ case 0x70: /* HS_INT_START_STOP_X */ ++ case 0x74: /* HS_EXT_START_STOP_X */ ++ case 0x78: /* VS_INT_START_X */ ++ case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */ ++ case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */ ++ case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */ ++ case 0x88: /* VS_EXT_STOP_Y */ ++ case 0x90: /* AVID_START_STOP_X */ ++ case 0x94: /* AVID_START_STOP_Y */ ++ case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */ ++ case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */ ++ case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */ ++ case 0xb0: /* TVDETGP_INT_START_STOP_X */ ++ case 0xb4: /* TVDETGP_INT_START_STOP_Y */ ++ case 0xb8: /* GEN_CTRL */ ++ case 0xc4: /* DAC_TST__DAC_A */ ++ case 0xc8: /* DAC_B__DAC_C */ ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ } ++} ++ ++static CPUReadMemoryFunc *omap_venc1_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap_venc_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_venc1_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_venc_write, ++}; ++ ++static uint32_t omap_im3_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->im3_base; ++ ++ switch (offset) { ++ case 0x0a8: /* SBIMERRLOGA */ ++ case 0x0b0: /* SBIMERRLOG */ ++ case 0x190: /* SBIMSTATE */ ++ case 0x198: /* SBTMSTATE_L */ ++ case 0x19c: /* SBTMSTATE_H */ ++ case 0x1a8: /* SBIMCONFIG_L */ ++ case 0x1ac: /* SBIMCONFIG_H */ ++ case 0x1f8: /* SBID_L */ ++ case 0x1fc: /* SBID_H */ ++ return 0; ++ ++ default: ++ break; ++ } ++ OMAP_BAD_REG(addr); ++ return 0; ++} ++ ++static void omap_im3_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct omap_dss_s *s = (struct omap_dss_s *) opaque; ++ int offset = addr - s->im3_base; ++ ++ switch (offset) { ++ case 0x0b0: /* SBIMERRLOG */ ++ case 0x190: /* SBIMSTATE */ ++ case 0x198: /* SBTMSTATE_L */ ++ case 0x19c: /* SBTMSTATE_H */ ++ case 0x1a8: /* SBIMCONFIG_L */ ++ case 0x1ac: /* SBIMCONFIG_H */ ++ break; ++ ++ default: ++ OMAP_BAD_REG(addr); ++ } ++} ++ ++static CPUReadMemoryFunc *omap_im3_readfn[] = { ++ omap_badwidth_read32, ++ omap_badwidth_read32, ++ omap_im3_read, ++}; ++ ++static CPUWriteMemoryFunc *omap_im3_writefn[] = { ++ omap_badwidth_write32, ++ omap_badwidth_write32, ++ omap_im3_write, ++}; ++ ++struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta, ++ target_phys_addr_t l3_base, DisplayState *ds, ++ qemu_irq irq, qemu_irq drq, ++ omap_clk fck1, omap_clk fck2, omap_clk ck54m, ++ omap_clk ick1, omap_clk ick2) ++{ ++ int iomemtype[5]; ++ struct omap_dss_s *s = (struct omap_dss_s *) ++ qemu_mallocz(sizeof(struct omap_dss_s)); ++ ++ s->irq = irq; ++ s->drq = drq; ++ s->state = ds; ++ omap_dss_reset(s); ++ ++ iomemtype[0] = cpu_register_io_memory(0, omap_diss1_readfn, ++ omap_diss1_writefn, s); ++ iomemtype[1] = cpu_register_io_memory(0, omap_disc1_readfn, ++ omap_disc1_writefn, s); ++ iomemtype[2] = cpu_register_io_memory(0, omap_rfbi1_readfn, ++ omap_rfbi1_writefn, s); ++ iomemtype[3] = cpu_register_io_memory(0, omap_venc1_readfn, ++ omap_venc1_writefn, s); ++ iomemtype[4] = cpu_register_io_memory(0, omap_im3_readfn, ++ omap_im3_writefn, s); ++ s->diss_base = omap_l4_attach(ta, 0, iomemtype[0]); ++ s->disc_base = omap_l4_attach(ta, 1, iomemtype[1]); ++ s->rfbi_base = omap_l4_attach(ta, 2, iomemtype[2]); ++ s->venc_base = omap_l4_attach(ta, 3, iomemtype[3]); ++ s->im3_base = l3_base; ++ cpu_register_physical_memory(s->im3_base, 0x1000, iomemtype[4]); ++ ++#if 0 ++ if (ds) ++ graphic_console_init(ds, omap_update_display, ++ omap_invalidate_display, omap_screen_dump, s); ++#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); ++ s->rfbi.chip[cs] = chip; ++} +diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c +index de63309..9915676 100644 +--- a/hw/omap_i2c.c ++++ b/hw/omap_i2c.c +@@ -150,6 +150,8 @@ static void omap_i2c_fifo_run(struct omap_i2c_s *s) + } + if (ack && s->count_cur) + s->stat |= 1 << 4; /* XRDY */ ++ else ++ s->stat &= ~(1 << 4); /* XRDY */ + if (!s->count_cur) { + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ +@@ -161,6 +163,8 @@ static void omap_i2c_fifo_run(struct omap_i2c_s *s) + } + if (s->rxlen) + s->stat |= 1 << 3; /* RRDY */ ++ else ++ s->stat &= ~(1 << 3); /* RRDY */ + } + if (!s->count_cur) { + if ((s->control >> 1) & 1) { /* STP */ +@@ -321,7 +325,8 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr, + return; + } + +- s->stat &= ~(value & 0x3f); ++ /* RRDY and XRDY are reset by hardware. (in all versions???) */ ++ s->stat &= ~(value & 0x27); + omap_i2c_interrupts_update(s); + break; + +@@ -376,11 +381,13 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr, + break; + } + if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */ +- printf("%s: I^2C slave mode not supported\n", __FUNCTION__); ++ fprintf(stderr, "%s: I^2C slave mode not supported\n", ++ __FUNCTION__); + break; + } + if ((value & (1 << 15)) && value & (1 << 8)) { /* XA */ +- printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__); ++ fprintf(stderr, "%s: 10-bit addressing mode not supported\n", ++ __FUNCTION__); + break; + } + if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */ +@@ -427,7 +434,7 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr, + omap_i2c_interrupts_update(s); + } + if (value & (1 << 15)) /* ST_EN */ +- printf("%s: System Test not supported\n", __FUNCTION__); ++ fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__); + break; + + default: +diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c +index 6fbbb84..e46289a 100644 +--- a/hw/omap_mmc.c ++++ b/hw/omap_mmc.c +@@ -26,19 +26,24 @@ struct omap_mmc_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq *dma; ++ qemu_irq coverswitch; + omap_clk clk; + SDState *card; + uint16_t last_cmd; + uint16_t sdio; + uint16_t rsp[8]; + uint32_t arg; ++ int lines; + int dw; + int mode; + int enable; ++ int be; ++ int rev; + uint16_t status; + uint16_t mask; + uint8_t cto; + uint16_t dto; ++ int clkdiv; + uint16_t fifo[32]; + int fifo_start; + int fifo_len; +@@ -53,6 +58,11 @@ struct omap_mmc_s { + + int ddir; + int transfer; ++ ++ int cdet_wakeup; ++ int cdet_enable; ++ int cdet_state; ++ qemu_irq cdet; + }; + + static void omap_mmc_interrupts_update(struct omap_mmc_s *s) +@@ -107,6 +117,11 @@ static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir, + struct sd_request_s request; + uint8_t response[16]; + ++ if (init && cmd == 0) { ++ host->status |= 0x0001; ++ return; ++ } ++ + if (resptype == sd_r1 && busy) + resptype = sd_r1b; + +@@ -265,6 +280,34 @@ static void omap_mmc_update(void *opaque) + omap_mmc_interrupts_update(s); + } + ++void omap_mmc_reset(struct omap_mmc_s *host) ++{ ++ host->last_cmd = 0; ++ memset(host->rsp, 0, sizeof(host->rsp)); ++ host->arg = 0; ++ host->dw = 0; ++ host->mode = 0; ++ host->enable = 0; ++ host->status = 0; ++ host->mask = 0; ++ host->cto = 0; ++ host->dto = 0; ++ host->fifo_len = 0; ++ host->blen = 0; ++ host->blen_counter = 0; ++ host->nblk = 0; ++ host->nblk_counter = 0; ++ host->tx_dma = 0; ++ host->rx_dma = 0; ++ host->ae_level = 0x00; ++ host->af_level = 0x1f; ++ host->transfer = 0; ++ host->cdet_wakeup = 0; ++ host->cdet_enable = 0; ++ qemu_set_irq(host->coverswitch, host->cdet_state); ++ host->clkdiv = 0; ++} ++ + static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset) + { + uint16_t i; +@@ -282,7 +325,8 @@ static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset) + return s->arg >> 16; + + case 0x0c: /* MMC_CON */ +- return (s->dw << 15) | (s->mode << 12) | (s->enable << 11); ++ return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) | ++ (s->be << 10) | s->clkdiv; + + case 0x10: /* MMC_STAT */ + return s->status; +@@ -324,12 +368,12 @@ static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset) + case 0x30: /* MMC_SPI */ + return 0x0000; + case 0x34: /* MMC_SDIO */ +- return s->sdio; ++ return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio; + case 0x38: /* MMC_SYST */ + return 0x0000; + + case 0x3c: /* MMC_REV */ +- return 0x0001; ++ return s->rev; + + case 0x40: /* MMC_RSP0 */ + case 0x44: /* MMC_RSP1 */ +@@ -340,6 +384,13 @@ static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset) + case 0x58: /* MMC_RSP6 */ + case 0x5c: /* MMC_RSP7 */ + return s->rsp[(offset - 0x40) >> 2]; ++ ++ /* OMAP2-specific */ ++ case 0x60: /* MMC_IOSR */ ++ case 0x64: /* MMC_SYSC */ ++ return 0; ++ case 0x68: /* MMC_SYSS */ ++ return 1; /* RSTD */ + } + + OMAP_BAD_REG(offset); +@@ -383,10 +434,16 @@ static void omap_mmc_write(void *opaque, target_phys_addr_t offset, + s->dw = (value >> 15) & 1; + s->mode = (value >> 12) & 3; + s->enable = (value >> 11) & 1; ++ s->be = (value >> 10) & 1; ++ s->clkdiv = (value >> 0) & (s->rev >= 2 ? 0x3ff : 0xff); + if (s->mode != 0) + printf("SD mode %i unimplemented!\n", s->mode); +- if (s->dw != 0) ++ if (s->be != 0) ++ printf("SD FIFO byte sex unimplemented!\n"); ++ if (s->dw != 0 && s->lines < 4) + printf("4-bit SD bus enabled\n"); ++ if (!s->enable) ++ omap_mmc_reset(s); + break; + + case 0x10: /* MMC_STAT */ +@@ -395,13 +452,13 @@ static void omap_mmc_write(void *opaque, target_phys_addr_t offset, + break; + + case 0x14: /* MMC_IE */ +- s->mask = value; ++ s->mask = value & 0x7fff; + omap_mmc_interrupts_update(s); + break; + + case 0x18: /* MMC_CTO */ + s->cto = value & 0xff; +- if (s->cto > 0xfd) ++ if (s->cto > 0xfd && s->rev <= 1) + printf("MMC: CTO of 0xff and 0xfe cannot be used!\n"); + break; + +@@ -446,10 +503,12 @@ static void omap_mmc_write(void *opaque, target_phys_addr_t offset, + break; + + /* SPI, SDIO and TEST modes unimplemented */ +- case 0x30: /* MMC_SPI */ ++ case 0x30: /* MMC_SPI (OMAP1 only) */ + break; + case 0x34: /* MMC_SDIO */ +- s->sdio = value & 0x2020; ++ s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020); ++ s->cdet_wakeup = (value >> 9) & 1; ++ s->cdet_enable = (value >> 2) & 1; + break; + case 0x38: /* MMC_SYST */ + break; +@@ -466,6 +525,19 @@ static void omap_mmc_write(void *opaque, target_phys_addr_t offset, + OMAP_RO_REG(offset); + break; + ++ /* OMAP2-specific */ ++ case 0x60: /* MMC_IOSR */ ++ if (value & 0xf) ++ printf("MMC: SDIO bits used!\n"); ++ break; ++ case 0x64: /* MMC_SYSC */ ++ if (value & (1 << 2)) /* SRTS */ ++ omap_mmc_reset(s); ++ break; ++ case 0x68: /* MMC_SYSS */ ++ OMAP_RO_REG(offset); ++ break; ++ + default: + OMAP_BAD_REG(offset); + } +@@ -483,28 +555,21 @@ static CPUWriteMemoryFunc *omap_mmc_writefn[] = { + omap_badwidth_write16, + }; + +-void omap_mmc_reset(struct omap_mmc_s *host) ++static void omap_mmc_cover_cb(void *opaque, int line, int level) + { +- host->last_cmd = 0; +- memset(host->rsp, 0, sizeof(host->rsp)); +- host->arg = 0; +- host->dw = 0; +- host->mode = 0; +- host->enable = 0; +- host->status = 0; +- host->mask = 0; +- host->cto = 0; +- host->dto = 0; +- host->fifo_len = 0; +- host->blen = 0; +- host->blen_counter = 0; +- host->nblk = 0; +- host->nblk_counter = 0; +- host->tx_dma = 0; +- host->rx_dma = 0; +- host->ae_level = 0x00; +- host->af_level = 0x1f; +- host->transfer = 0; ++ struct omap_mmc_s *host = (struct omap_mmc_s *) opaque; ++ ++ if (!host->cdet_state && level) { ++ host->status |= 0x0002; ++ omap_mmc_interrupts_update(host); ++ if (host->cdet_wakeup) ++ /* TODO: Assert wake-up */; ++ } ++ ++ if (host->cdet_state != level) { ++ qemu_set_irq(host->coverswitch, level); ++ host->cdet_state = level; ++ } + } + + struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, +@@ -519,6 +584,10 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, + s->base = base; + s->dma = dma; + s->clk = clk; ++ s->lines = 1; /* TODO: needs to be settable per-board */ ++ s->rev = 1; ++ ++ omap_mmc_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_mmc_readfn, + omap_mmc_writefn, s); +@@ -530,7 +599,46 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, + return s; + } + ++struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, ++ BlockDriverState *bd, qemu_irq irq, qemu_irq dma[], ++ omap_clk fclk, omap_clk iclk) ++{ ++ int iomemtype; ++ struct omap_mmc_s *s = (struct omap_mmc_s *) ++ qemu_mallocz(sizeof(struct omap_mmc_s)); ++ ++ s->irq = irq; ++ s->dma = dma; ++ s->clk = fclk; ++ s->lines = 4; ++ s->rev = 2; ++ ++ omap_mmc_reset(s); ++ ++ iomemtype = cpu_register_io_memory(0, omap_mmc_readfn, ++ omap_mmc_writefn, s); ++ s->base = omap_l4_attach(ta, 0, iomemtype); ++ ++ /* Instantiate the storage */ ++ s->card = sd_init(bd, 0); ++ ++ s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0]; ++ sd_set_cb(s->card, 0, s->cdet); ++ ++ return s; ++} ++ + void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover) + { +- sd_set_cb(s->card, ro, cover); ++ if (s->cdet) { ++ sd_set_cb(s->card, ro, s->cdet); ++ s->coverswitch = cover; ++ qemu_set_irq(cover, s->cdet_state); ++ } else ++ sd_set_cb(s->card, ro, cover); ++} ++ ++void omap_mmc_enable(struct omap_mmc_s *s, int enable) ++{ ++ sd_enable(s->card, enable); + } +diff --git a/hw/onenand.c b/hw/onenand.c +new file mode 100644 +index 0000000..549d392 +--- /dev/null ++++ b/hw/onenand.c +@@ -0,0 +1,642 @@ ++/* ++ * OneNAND flash memories emulation. ++ * ++ * Copyright (C) 2008 Nokia Corporation ++ * Written by Andrzej Zaborowski <andrew@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * 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 "flash.h" ++#include "irq.h" ++#include "sysemu.h" ++#include "block.h" ++ ++/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */ ++#define PAGE_SHIFT 11 ++ ++/* Fixed */ ++#define BLOCK_SHIFT (PAGE_SHIFT + 6) ++ ++struct onenand_s { ++ uint32_t id; ++ int shift; ++ target_phys_addr_t base; ++ qemu_irq intr; ++ qemu_irq rdy; ++ BlockDriverState *bdrv; ++ BlockDriverState *bdrv_cur; ++ uint8_t *image; ++ uint8_t *otp; ++ uint8_t *current; ++ ram_addr_t ram; ++ uint8_t *boot[2]; ++ uint8_t *data[2][2]; ++ int iomemtype; ++ int cycle; ++ int otpmode; ++ ++ uint16_t addr[8]; ++ uint16_t unladdr[8]; ++ int bufaddr; ++ int count; ++ uint16_t command; ++ uint16_t config[2]; ++ uint16_t status; ++ uint16_t intstatus; ++ uint16_t wpstatus; ++ ++ struct ecc_state_s ecc; ++ ++ int density_mask; ++ int secs; ++ int secs_cur; ++ int blocks; ++ uint8_t *blockwp; ++}; ++ ++enum { ++ ONEN_BUF_BLOCK = 0, ++ ONEN_BUF_BLOCK2 = 1, ++ ONEN_BUF_DEST_BLOCK = 2, ++ ONEN_BUF_DEST_PAGE = 3, ++ ONEN_BUF_PAGE = 7, ++}; ++ ++enum { ++ ONEN_ERR_CMD = 1 << 10, ++ ONEN_ERR_ERASE = 1 << 11, ++ ONEN_ERR_PROG = 1 << 12, ++ ONEN_ERR_LOAD = 1 << 13, ++}; ++ ++enum { ++ ONEN_INT_RESET = 1 << 4, ++ ONEN_INT_ERASE = 1 << 5, ++ ONEN_INT_PROG = 1 << 6, ++ ONEN_INT_LOAD = 1 << 7, ++ ONEN_INT = 1 << 15, ++}; ++ ++enum { ++ ONEN_LOCK_LOCKTIGHTEN = 1 << 0, ++ ONEN_LOCK_LOCKED = 1 << 1, ++ ONEN_LOCK_UNLOCKED = 1 << 2, ++}; ++ ++void onenand_base_update(void *opaque, target_phys_addr_t new) ++{ ++ struct onenand_s *s = (struct onenand_s *) opaque; ++ ++ s->base = new; ++ ++ /* XXX: We should use IO_MEM_ROMD but we broke it earlier... ++ * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to ++ * write boot commands. Also take note of the BWPS bit. */ ++ cpu_register_physical_memory(s->base + (0x0000 << s->shift), ++ 0x0200 << s->shift, s->iomemtype); ++ cpu_register_physical_memory(s->base + (0x0200 << s->shift), ++ 0xbe00 << s->shift, ++ (s->ram +(0x0200 << s->shift)) | IO_MEM_RAM); ++ if (s->iomemtype) ++ cpu_register_physical_memory(s->base + (0xc000 << s->shift), ++ 0x4000 << s->shift, s->iomemtype); ++} ++ ++void onenand_base_unmap(void *opaque) ++{ ++ struct onenand_s *s = (struct onenand_s *) opaque; ++ ++ cpu_register_physical_memory(s->base, ++ 0x10000 << s->shift, IO_MEM_UNASSIGNED); ++} ++ ++static void onenand_intr_update(struct onenand_s *s) ++{ ++ qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1); ++} ++ ++/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */ ++static void onenand_reset(struct onenand_s *s, int cold) ++{ ++ memset(&s->addr, 0, sizeof(s->addr)); ++ s->command = 0; ++ s->count = 1; ++ s->bufaddr = 0; ++ s->config[0] = 0x40c0; ++ s->config[1] = 0x0000; ++ onenand_intr_update(s); ++ qemu_irq_raise(s->rdy); ++ s->status = 0x0000; ++ s->intstatus = cold ? 0x8080 : 0x8010; ++ s->unladdr[0] = 0; ++ s->unladdr[1] = 0; ++ s->wpstatus = 0x0002; ++ s->cycle = 0; ++ s->otpmode = 0; ++ s->bdrv_cur = s->bdrv; ++ s->current = s->image; ++ s->secs_cur = s->secs; ++ ++ if (cold) { ++ /* Lock the whole flash */ ++ memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks); ++ ++ if (s->bdrv && bdrv_read(s->bdrv, 0, s->boot[0], 8) < 0) ++ cpu_abort(cpu_single_env, "%s: Loading the BootRAM failed.\n", ++ __FUNCTION__); ++ } ++} ++ ++static inline int onenand_load_main(struct onenand_s *s, int sec, int secn, ++ void *dest) ++{ ++ if (s->bdrv_cur) ++ return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0; ++ else if (sec + secn > s->secs_cur) ++ return 1; ++ ++ memcpy(dest, s->current + (sec << 9), secn << 9); ++ ++ return 0; ++} ++ ++static inline int onenand_prog_main(struct onenand_s *s, int sec, int secn, ++ void *src) ++{ ++ if (s->bdrv_cur) ++ return bdrv_write(s->bdrv_cur, sec, src, secn) < 0; ++ else if (sec + secn > s->secs_cur) ++ return 1; ++ ++ memcpy(s->current + (sec << 9), src, secn << 9); ++ ++ return 0; ++} ++ ++static inline int onenand_load_spare(struct onenand_s *s, int sec, int secn, ++ void *dest) ++{ ++ uint8_t buf[512]; ++ ++ if (s->bdrv_cur) { ++ if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0) ++ return 1; ++ memcpy(dest, buf + ((sec & 31) << 4), secn << 4); ++ } else if (sec + secn > s->secs_cur) ++ return 1; ++ else ++ memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4); ++ ++ return 0; ++} ++ ++static inline int onenand_prog_spare(struct onenand_s *s, int sec, int secn, ++ void *src) ++{ ++ uint8_t buf[512]; ++ ++ if (s->bdrv_cur) { ++ if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0) ++ return 1; ++ memcpy(buf + ((sec & 31) << 4), src, secn << 4); ++ return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0; ++ } else if (sec + secn > s->secs_cur) ++ return 1; ++ ++ memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4); ++ ++ return 0; ++} ++ ++static inline int onenand_erase(struct onenand_s *s, int sec, int num) ++{ ++ /* TODO: optimise */ ++ uint8_t buf[512]; ++ ++ memset(buf, 0xff, sizeof(buf)); ++ for (; num > 0; num --, sec ++) { ++ if (onenand_prog_main(s, sec, 1, buf)) ++ return 1; ++ if (onenand_prog_spare(s, sec, 1, buf)) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void onenand_command(struct onenand_s *s, int cmd) ++{ ++ int b; ++ int sec; ++ void *buf; ++#define SETADDR(block, page) \ ++ sec = (s->addr[page] & 3) + \ ++ ((((s->addr[page] >> 2) & 0x3f) + \ ++ (((s->addr[block] & 0xfff) | \ ++ (s->addr[block] >> 15 ? \ ++ s->density_mask : 0)) << 6)) << (PAGE_SHIFT - 9)); ++#define SETBUF_M() \ ++ buf = (s->bufaddr & 8) ? \ ++ s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0]; \ ++ buf += (s->bufaddr & 3) << 9; ++#define SETBUF_S() \ ++ buf = (s->bufaddr & 8) ? \ ++ s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1]; \ ++ buf += (s->bufaddr & 3) << 4; ++ ++ switch (cmd) { ++ case 0x00: /* Load single/multiple sector data unit into buffer */ ++ SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) ++ ++ SETBUF_M() ++ if (onenand_load_main(s, sec, s->count, buf)) ++ s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD; ++ ++#if 0 ++ SETBUF_S() ++ if (onenand_load_spare(s, sec, s->count, buf)) ++ s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD; ++#endif ++ ++ /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages) ++ * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages) ++ * then we need two split the read/write into two chunks. ++ */ ++ s->intstatus |= ONEN_INT | ONEN_INT_LOAD; ++ break; ++ case 0x13: /* Load single/multiple spare sector into buffer */ ++ SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) ++ ++ SETBUF_S() ++ if (onenand_load_spare(s, sec, s->count, buf)) ++ s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD; ++ ++ /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages) ++ * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages) ++ * then we need two split the read/write into two chunks. ++ */ ++ s->intstatus |= ONEN_INT | ONEN_INT_LOAD; ++ break; ++ case 0x80: /* Program single/multiple sector data unit from buffer */ ++ SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) ++ ++ SETBUF_M() ++ if (onenand_prog_main(s, sec, s->count, buf)) ++ s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; ++ ++#if 0 ++ SETBUF_S() ++ if (onenand_prog_spare(s, sec, s->count, buf)) ++ s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; ++#endif ++ ++ /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages) ++ * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages) ++ * then we need two split the read/write into two chunks. ++ */ ++ s->intstatus |= ONEN_INT | ONEN_INT_PROG; ++ break; ++ case 0x1a: /* Program single/multiple spare area sector from buffer */ ++ SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) ++ ++ SETBUF_S() ++ if (onenand_prog_spare(s, sec, s->count, buf)) ++ s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; ++ ++ /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages) ++ * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages) ++ * then we need two split the read/write into two chunks. ++ */ ++ s->intstatus |= ONEN_INT | ONEN_INT_PROG; ++ break; ++ case 0x1b: /* Copy-back program */ ++ SETBUF_S() ++ ++ SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) ++ if (onenand_load_main(s, sec, s->count, buf)) ++ s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; ++ ++ SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE) ++ if (onenand_prog_main(s, sec, s->count, buf)) ++ s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; ++ ++ /* TODO: spare areas */ ++ ++ s->intstatus |= ONEN_INT | ONEN_INT_PROG; ++ break; ++ ++ case 0x23: /* Unlock NAND array block(s) */ ++ s->intstatus |= ONEN_INT; ++ ++ /* XXX the previous (?) area should be locked automatically */ ++ for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) { ++ if (b >= s->blocks) { ++ s->status |= ONEN_ERR_CMD; ++ break; ++ } ++ if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN) ++ break; ++ ++ s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED; ++ } ++ break; ++ case 0x2a: /* Lock NAND array block(s) */ ++ s->intstatus |= ONEN_INT; ++ ++ for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) { ++ if (b >= s->blocks) { ++ s->status |= ONEN_ERR_CMD; ++ break; ++ } ++ if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN) ++ break; ++ ++ s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED; ++ } ++ break; ++ case 0x2c: /* Lock-tight NAND array block(s) */ ++ s->intstatus |= ONEN_INT; ++ ++ for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) { ++ if (b >= s->blocks) { ++ s->status |= ONEN_ERR_CMD; ++ break; ++ } ++ if (s->blockwp[b] == ONEN_LOCK_UNLOCKED) ++ continue; ++ ++ s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN; ++ } ++ break; ++ ++ case 0x71: /* Erase-Verify-Read */ ++ s->intstatus |= ONEN_INT; ++ break; ++ case 0x95: /* Multi-block erase */ ++ qemu_irq_pulse(s->intr); ++ /* Fall through. */ ++ case 0x94: /* Block erase */ ++ sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) | ++ (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0)) ++ << (BLOCK_SHIFT - 9); ++ if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9))) ++ s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE; ++ ++ s->intstatus |= ONEN_INT | ONEN_INT_ERASE; ++ break; ++ case 0xb0: /* Erase suspend */ ++ break; ++ case 0x30: /* Erase resume */ ++ s->intstatus |= ONEN_INT | ONEN_INT_ERASE; ++ break; ++ ++ case 0xf0: /* Reset NAND Flash core */ ++ onenand_reset(s, 0); ++ break; ++ case 0xf3: /* Reset OneNAND */ ++ onenand_reset(s, 0); ++ break; ++ ++ case 0x65: /* OTP Access */ ++ s->intstatus |= ONEN_INT; ++ s->bdrv_cur = 0; ++ s->current = s->otp; ++ s->secs_cur = 1 << (BLOCK_SHIFT - 9); ++ s->addr[ONEN_BUF_BLOCK] = 0; ++ s->otpmode = 1; ++ break; ++ ++ default: ++ s->status |= ONEN_ERR_CMD; ++ s->intstatus |= ONEN_INT; ++ fprintf(stderr, "%s: unknown OneNAND command %x\n", ++ __FUNCTION__, cmd); ++ } ++ ++ onenand_intr_update(s); ++} ++ ++static uint32_t onenand_read(void *opaque, target_phys_addr_t addr) ++{ ++ struct onenand_s *s = (struct onenand_s *) opaque; ++ int offset = (addr - s->base) >> s->shift; ++ ++ switch (offset) { ++ case 0x0000 ... 0xc000: ++ return lduw_le_p(s->boot[0] + (addr - s->base)); ++ ++ case 0xf000: /* Manufacturer ID */ ++ return (s->id >> 16) & 0xff; ++ case 0xf001: /* Device ID */ ++ return (s->id >> 8) & 0xff; ++ /* TODO: get the following values from a real chip! */ ++ case 0xf002: /* Version ID */ ++ return (s->id >> 0) & 0xff; ++ case 0xf003: /* Data Buffer size */ ++ return 1 << PAGE_SHIFT; ++ case 0xf004: /* Boot Buffer size */ ++ return 0x200; ++ case 0xf005: /* Amount of buffers */ ++ return 1 | (2 << 8); ++ case 0xf006: /* Technology */ ++ return 0; ++ ++ case 0xf100 ... 0xf107: /* Start addresses */ ++ return s->addr[offset - 0xf100]; ++ ++ case 0xf200: /* Start buffer */ ++ return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10))); ++ ++ case 0xf220: /* Command */ ++ return s->command; ++ case 0xf221: /* System Configuration 1 */ ++ return s->config[0] & 0xffe0; ++ case 0xf222: /* System Configuration 2 */ ++ return s->config[1]; ++ ++ case 0xf240: /* Controller Status */ ++ return s->status; ++ case 0xf241: /* Interrupt */ ++ return s->intstatus; ++ case 0xf24c: /* Unlock Start Block Address */ ++ return s->unladdr[0]; ++ case 0xf24d: /* Unlock End Block Address */ ++ return s->unladdr[1]; ++ case 0xf24e: /* Write Protection Status */ ++ return s->wpstatus; ++ ++ case 0xff00: /* ECC Status */ ++ return 0x00; ++ case 0xff01: /* ECC Result of main area data */ ++ case 0xff02: /* ECC Result of spare area data */ ++ case 0xff03: /* ECC Result of main area data */ ++ case 0xff04: /* ECC Result of spare area data */ ++ cpu_abort(cpu_single_env, "%s: imeplement ECC\n", __FUNCTION__); ++ return 0x0000; ++ } ++ ++ fprintf(stderr, "%s: unknown OneNAND register %x\n", ++ __FUNCTION__, offset); ++ return 0; ++} ++ ++static void onenand_write(void *opaque, target_phys_addr_t addr, ++ uint32_t value) ++{ ++ struct onenand_s *s = (struct onenand_s *) opaque; ++ int offset = (addr - s->base) >> s->shift; ++ int sec; ++ ++ switch (offset) { ++ case 0x0000 ... 0x01ff: ++ case 0x8000 ... 0x800f: ++ if (s->cycle) { ++ s->cycle = 0; ++ ++ if (value == 0x0000) { ++ SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) ++ onenand_load_main(s, sec, ++ 1 << (PAGE_SHIFT - 9), s->data[0][0]); ++ s->addr[ONEN_BUF_PAGE] += 4; ++ s->addr[ONEN_BUF_PAGE] &= 0xff; ++ } ++ break; ++ } ++ ++ switch (value) { ++ case 0x00f0: /* Reset OneNAND */ ++ onenand_reset(s, 0); ++ break; ++ ++ case 0x00e0: /* Load Data into Buffer */ ++ s->cycle = 1; ++ break; ++ ++ case 0x0090: /* Read Identification Data */ ++ memset(s->boot[0], 0, 3 << s->shift); ++ s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff; ++ s->boot[0][1 << s->shift] = (s->id >> 8) & 0xff; ++ s->boot[0][2 << s->shift] = s->wpstatus & 0xff; ++ break; ++ ++ default: ++ fprintf(stderr, "%s: unknown OneNAND boot command %x\n", ++ __FUNCTION__, value); ++ } ++ break; ++ ++ case 0xf100 ... 0xf107: /* Start addresses */ ++ s->addr[offset - 0xf100] = value; ++ break; ++ ++ case 0xf200: /* Start buffer */ ++ s->bufaddr = (value >> 8) & 0xf; ++ if (PAGE_SHIFT == 11) ++ s->count = (value & 3) ?: 4; ++ else if (PAGE_SHIFT == 10) ++ s->count = (value & 1) ?: 2; ++ break; ++ ++ case 0xf220: /* Command */ ++ if (s->intstatus & (1 << 15)) ++ break; ++ s->command = value; ++ onenand_command(s, s->command); ++ break; ++ case 0xf221: /* System Configuration 1 */ ++ s->config[0] = value; ++ onenand_intr_update(s); ++ qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1); ++ break; ++ case 0xf222: /* System Configuration 2 */ ++ s->config[1] = value; ++ break; ++ ++ case 0xf241: /* Interrupt */ ++ s->intstatus &= value; ++ if ((1 << 15) & ~s->intstatus) ++ s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE | ++ ONEN_ERR_PROG | ONEN_ERR_LOAD); ++ onenand_intr_update(s); ++ break; ++ case 0xf24c: /* Unlock Start Block Address */ ++ s->unladdr[0] = value & (s->blocks - 1); ++ /* For some reason we have to set the end address to by default ++ * be same as start because the software forgets to write anything ++ * in there. */ ++ s->unladdr[1] = value & (s->blocks - 1); ++ break; ++ case 0xf24d: /* Unlock End Block Address */ ++ s->unladdr[1] = value & (s->blocks - 1); ++ break; ++ ++ default: ++ fprintf(stderr, "%s: unknown OneNAND register %x\n", ++ __FUNCTION__, offset); ++ } ++} ++ ++static CPUReadMemoryFunc *onenand_readfn[] = { ++ onenand_read, /* TODO */ ++ onenand_read, ++ onenand_read, ++}; ++ ++static CPUWriteMemoryFunc *onenand_writefn[] = { ++ onenand_write, /* TODO */ ++ onenand_write, ++ onenand_write, ++}; ++ ++void *onenand_init(uint32_t id, int regshift, qemu_irq irq) ++{ ++ struct onenand_s *s = (struct onenand_s *) qemu_mallocz(sizeof(*s)); ++ int bdrv_index = drive_get_index(IF_MTD, 0, 0); ++ uint32_t size = 1 << (24 + ((id >> 12) & 7)); ++ void *ram; ++ ++ s->shift = regshift; ++ s->intr = irq; ++ s->rdy = 0; ++ s->id = id; ++ s->blocks = size >> BLOCK_SHIFT; ++ s->secs = size >> 9; ++ s->blockwp = qemu_malloc(s->blocks); ++ s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0; ++ s->iomemtype = cpu_register_io_memory(0, onenand_readfn, ++ onenand_writefn, s); ++ if (bdrv_index == -1) ++ s->image = memset(qemu_malloc(size + (size >> 5)), ++ 0xff, size + (size >> 5)); ++ else ++ s->bdrv = drives_table[bdrv_index].bdrv; ++ s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT), ++ 0xff, (64 + 2) << PAGE_SHIFT); ++ s->ram = qemu_ram_alloc(0xc000 << s->shift); ++ ram = phys_ram_base + s->ram; ++ s->boot[0] = ram + (0x0000 << s->shift); ++ s->boot[1] = ram + (0x8000 << s->shift); ++ s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift); ++ s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift); ++ s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift); ++ s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift); ++ ++ onenand_reset(s, 1); ++ ++ return s; ++} +diff --git a/hw/palm.c b/hw/palm.c +index 9400ea7..8b767e2 100644 +--- a/hw/palm.c ++++ b/hw/palm.c +@@ -25,6 +25,7 @@ + #include "omap.h" + #include "boards.h" + #include "arm-misc.h" ++#include "devices.h" + + static uint32_t static_readb(void *opaque, target_phys_addr_t offset) + { +@@ -32,12 +33,14 @@ static uint32_t static_readb(void *opaque, target_phys_addr_t offset) + return *val >> ((offset & 3) << 3); + } + +-static uint32_t static_readh(void *opaque, target_phys_addr_t offset) { ++static uint32_t static_readh(void *opaque, target_phys_addr_t offset) ++{ + uint32_t *val = (uint32_t *) opaque; + return *val >> ((offset & 1) << 3); + } + +-static uint32_t static_readw(void *opaque, target_phys_addr_t offset) { ++static uint32_t static_readw(void *opaque, target_phys_addr_t offset) ++{ + uint32_t *val = (uint32_t *) opaque; + return *val >> ((offset & 0) << 3); + } +@@ -183,6 +186,12 @@ static void palmte_gpio_setup(struct omap_mpu_state_s *cpu) + qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]); + } + ++static struct arm_boot_info palmte_binfo = { ++ .loader_start = OMAP_EMIFF_BASE, ++ .ram_size = 0x02000000, ++ .board_id = 0x331, ++}; ++ + static void palmte_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, +@@ -190,7 +199,7 @@ static void palmte_init(int ram_size, int vga_ram_size, + { + struct omap_mpu_state_s *cpu; + int flash_size = 0x00800000; +- int sdram_size = 0x02000000; ++ int sdram_size = palmte_binfo.ram_size; + int io; + static uint32_t cs0val = 0xffffffff; + static uint32_t cs1val = 0x0000e1a0; +@@ -250,10 +259,12 @@ static void palmte_init(int ram_size, int vga_ram_size, + /* Load the kernel. */ + if (kernel_filename) { + /* Start at bootloader. */ +- cpu->env->regs[15] = OMAP_EMIFF_BASE; ++ cpu->env->regs[15] = palmte_binfo.loader_start; + +- arm_load_kernel(cpu->env, sdram_size, kernel_filename, kernel_cmdline, +- initrd_filename, 0x331, OMAP_EMIFF_BASE); ++ palmte_binfo.kernel_filename = kernel_filename; ++ palmte_binfo.kernel_cmdline = kernel_cmdline; ++ palmte_binfo.initrd_filename = initrd_filename; ++ arm_load_kernel(cpu->env, &palmte_binfo); + } + + dpy_resize(ds, 320, 320); +diff --git a/hw/realview.c b/hw/realview.c +index 29579d8..acf3b9e 100644 +--- a/hw/realview.c ++++ b/hw/realview.c +@@ -18,6 +18,11 @@ + + /* Board init. */ + ++static struct arm_boot_info realview_binfo = { ++ .loader_start = 0x0, ++ .board_id = 0x33b, ++}; ++ + static void realview_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, +@@ -177,8 +182,12 @@ static void realview_init(int ram_size, int vga_ram_size, + /* 0x68000000 PCI mem 1. */ + /* 0x6c000000 PCI mem 2. */ + +- arm_load_kernel(first_cpu, ram_size, kernel_filename, kernel_cmdline, +- initrd_filename, 0x33b, 0x0); ++ realview_binfo.ram_size = ram_size; ++ realview_binfo.kernel_filename = kernel_filename; ++ realview_binfo.kernel_cmdline = kernel_cmdline; ++ realview_binfo.initrd_filename = initrd_filename; ++ realview_binfo.nb_cpus = ncpu; ++ arm_load_kernel(first_cpu, &realview_binfo); + + /* ??? Hack to map an additional page of ram for the secondary CPU + startup code. I guess this works on real hardware because the +diff --git a/hw/sd.c b/hw/sd.c +index 1f71d85..de7dd89 100644 +--- a/hw/sd.c ++++ b/hw/sd.c +@@ -37,7 +37,7 @@ + + #ifdef DEBUG_SD + #define DPRINTF(fmt, args...) \ +-do { printf("SD: " fmt , ##args); } while (0) ++do { fprintf(stderr, "SD: " fmt , ##args); } while (0) + #else + #define DPRINTF(fmt, args...) do {} while(0) + #endif +@@ -99,6 +99,8 @@ struct SDState { + qemu_irq inserted_cb; + BlockDriverState *bdrv; + uint8_t *buf; ++ ++ int enable; + }; + + static void sd_set_status(SDState *sd) +@@ -530,7 +532,7 @@ static void sd_lock_command(SDState *sd) + sd->card_status &= ~CARD_IS_LOCKED; + sd->pwd_len = 0; + /* Erasing the entire card here! */ +- printf("SD: Card force-erased by CMD42\n"); ++ fprintf(stderr, "SD: Card force-erased by CMD42\n"); + return; + } + +@@ -1076,7 +1078,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, + return sd_r1; + + case 56: /* CMD56: GEN_CMD */ +- printf("SD: GEN_CMD 0x%08x\n", req.arg); ++ fprintf(stderr, "SD: GEN_CMD 0x%08x\n", req.arg); + + switch (sd->state) { + case sd_transfer_state: +@@ -1096,18 +1098,18 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, + bad_cmd: + sd->card_status |= ILLEGAL_COMMAND; + +- printf("SD: Unknown CMD%i\n", req.cmd); ++ fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd); + return sd_r0; + + unimplemented_cmd: + /* Commands that are recognised but not yet implemented in SPI mode. */ + sd->card_status |= ILLEGAL_COMMAND; +- printf ("SD: CMD%i not implemented in SPI mode\n", req.cmd); ++ fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd); + return sd_r0; + } + + sd->card_status |= ILLEGAL_COMMAND; +- printf("SD: CMD%i in a wrong state\n", req.cmd); ++ fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd); + return sd_r0; + } + +@@ -1217,7 +1219,7 @@ static sd_rsp_type_t sd_app_command(SDState *sd, + return sd_normal_command(sd, req); + } + +- printf("SD: ACMD%i in a wrong state\n", req.cmd); ++ fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd); + return sd_r0; + } + +@@ -1227,7 +1229,7 @@ int sd_do_command(SDState *sd, struct sd_request_s *req, + sd_rsp_type_t rtype; + int rsplen; + +- if (!bdrv_is_inserted(sd->bdrv)) { ++ if (!bdrv_is_inserted(sd->bdrv) || !sd->enable) { + return 0; + } + +@@ -1247,7 +1249,7 @@ int sd_do_command(SDState *sd, struct sd_request_s *req, + sd_cmd_class[req->cmd] == 7 || + req->cmd == 16 || req->cmd == 55))) { + sd->card_status |= ILLEGAL_COMMAND; +- printf("SD: Card is locked\n"); ++ fprintf(stderr, "SD: Card is locked\n"); + return 0; + } + +@@ -1321,7 +1323,7 @@ static void sd_blk_read(SDState *sd, uint32_t addr, uint32_t len) + uint32_t end = addr + len; + + if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) { +- printf("sd_blk_read: read error on host side\n"); ++ fprintf(stderr, "sd_blk_read: read error on host side\n"); + return; + } + +@@ -1329,7 +1331,7 @@ static void sd_blk_read(SDState *sd, uint32_t addr, uint32_t len) + memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511)); + + if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) { +- printf("sd_blk_read: read error on host side\n"); ++ fprintf(stderr, "sd_blk_read: read error on host side\n"); + return; + } + memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511); +@@ -1343,28 +1345,28 @@ static void sd_blk_write(SDState *sd, uint32_t addr, uint32_t len) + + if ((addr & 511) || len < 512) + if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) { +- printf("sd_blk_write: read error on host side\n"); ++ fprintf(stderr, "sd_blk_write: read error on host side\n"); + return; + } + + if (end > (addr & ~511) + 512) { + memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511)); + if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1) { +- printf("sd_blk_write: write error on host side\n"); ++ fprintf(stderr, "sd_blk_write: write error on host side\n"); + return; + } + + if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) { +- printf("sd_blk_write: read error on host side\n"); ++ fprintf(stderr, "sd_blk_write: read error on host side\n"); + return; + } + memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511); + if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) == -1) +- printf("sd_blk_write: write error on host side\n"); ++ fprintf(stderr, "sd_blk_write: write error on host side\n"); + } else { + memcpy(sd->buf + (addr & 511), sd->data, len); + if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1) +- printf("sd_blk_write: write error on host side\n"); ++ fprintf(stderr, "sd_blk_write: write error on host side\n"); + } + } + +@@ -1377,11 +1379,11 @@ void sd_write_data(SDState *sd, uint8_t value) + { + int i; + +- if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv)) ++ if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable) + return; + + if (sd->state != sd_receivingdata_state) { +- printf("sd_write_data: not in Receiving-Data state\n"); ++ fprintf(stderr, "sd_write_data: not in Receiving-Data state\n"); + return; + } + +@@ -1489,7 +1491,7 @@ void sd_write_data(SDState *sd, uint8_t value) + break; + + default: +- printf("sd_write_data: unknown command\n"); ++ fprintf(stderr, "sd_write_data: unknown command\n"); + break; + } + } +@@ -1499,11 +1501,11 @@ uint8_t sd_read_data(SDState *sd) + /* TODO: Append CRCs */ + uint8_t ret; + +- if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv)) ++ if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable) + return 0x00; + + if (sd->state != sd_sendingdata_state) { +- printf("sd_read_data: not in Sending-Data state\n"); ++ fprintf(stderr, "sd_read_data: not in Sending-Data state\n"); + return 0x00; + } + +@@ -1603,7 +1605,7 @@ uint8_t sd_read_data(SDState *sd) + break; + + default: +- printf("sd_read_data: unknown command\n"); ++ fprintf(stderr, "sd_read_data: unknown command\n"); + return 0x00; + } + +@@ -1614,3 +1616,8 @@ int sd_data_ready(SDState *sd) + { + return sd->state == sd_sendingdata_state; + } ++ ++void sd_enable(SDState *sd, int enable) ++{ ++ sd->enable = enable; ++} +diff --git a/hw/sd.h b/hw/sd.h +index 85f110f..cb7bc9c 100644 +--- a/hw/sd.h ++++ b/hw/sd.h +@@ -74,6 +74,7 @@ void sd_write_data(SDState *sd, uint8_t value); + uint8_t sd_read_data(SDState *sd); + void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert); + int sd_data_ready(SDState *sd); ++void sd_enable(SDState *sd, int enable); + + /* ssi-sd.c */ + int ssi_sd_xfer(void *opaque, int val); +diff --git a/hw/spitz.c b/hw/spitz.c +index 159c633..b059f9a 100644 +--- a/hw/spitz.c ++++ b/hw/spitz.c +@@ -1180,12 +1180,17 @@ static void sl_bootparam_write(uint32_t ptr) + /* Board init. */ + enum spitz_model_e { spitz, akita, borzoi, terrier }; + ++static struct arm_boot_info spitz_binfo = { ++ .loader_start = PXA2XX_SDRAM_BASE, ++ .ram_size = 0x04000000, ++}; ++ + static void spitz_common_init(int ram_size, int vga_ram_size, + DisplayState *ds, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + const char *cpu_model, enum spitz_model_e model, int arm_id) + { +- uint32_t spitz_ram = 0x04000000; ++ uint32_t spitz_ram = spitz_binfo.ram_size; + uint32_t spitz_rom = 0x00800000; + struct pxa2xx_state_s *cpu; + struct scoop_info_s *scp; +@@ -1230,10 +1235,13 @@ static void spitz_common_init(int ram_size, int vga_ram_size, + spitz_microdrive_attach(cpu); + + /* Setup initial (reset) machine state */ +- cpu->env->regs[15] = PXA2XX_SDRAM_BASE; ++ cpu->env->regs[15] = spitz_binfo.loader_start; + +- arm_load_kernel(cpu->env, spitz_ram, kernel_filename, kernel_cmdline, +- initrd_filename, arm_id, PXA2XX_SDRAM_BASE); ++ spitz_binfo.kernel_filename = kernel_filename; ++ spitz_binfo.kernel_cmdline = kernel_cmdline; ++ spitz_binfo.initrd_filename = initrd_filename; ++ spitz_binfo.board_id = arm_id; ++ arm_load_kernel(cpu->env, &spitz_binfo); + sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_SDRAM_BASE); + } + +diff --git a/hw/tmp105.c b/hw/tmp105.c +new file mode 100644 +index 0000000..d9a3900 +--- /dev/null ++++ b/hw/tmp105.c +@@ -0,0 +1,249 @@ ++/* ++ * Texas Instruments TMP105 temperature sensor. ++ * ++ * Copyright (C) 2008 Nokia Corporation ++ * Written by Andrzej Zaborowski <andrew@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * 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 "i2c.h" ++ ++struct tmp105_s { ++ i2c_slave i2c; ++ int len; ++ uint8_t buf[2]; ++ qemu_irq pin; ++ ++ uint8_t pointer; ++ uint8_t config; ++ int16_t temperature; ++ int16_t limit[2]; ++ int faults; ++ int alarm; ++}; ++ ++static void tmp105_interrupt_update(struct tmp105_s *s) ++{ ++ qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */ ++} ++ ++static void tmp105_alarm_update(struct tmp105_s *s) ++{ ++ if ((s->config >> 0) & 1) { /* SD */ ++ if ((s->config >> 7) & 1) /* OS */ ++ s->config &= ~(1 << 7); /* OS */ ++ else ++ return; ++ } ++ ++ if ((s->config >> 1) & 1) { /* TM */ ++ if (s->temperature >= s->limit[1]) ++ s->alarm = 1; ++ else if (s->temperature < s->limit[0]) ++ s->alarm = 1; ++ } else { ++ if (s->temperature >= s->limit[1]) ++ s->alarm = 1; ++ else if (s->temperature < s->limit[0]) ++ s->alarm = 0; ++ } ++ ++ tmp105_interrupt_update(s); ++} ++ ++/* Units are 0.001 centigrades relative to 0 C. */ ++void tmp105_set(i2c_slave *i2c, int temp) ++{ ++ struct tmp105_s *s = (struct tmp105_s *) i2c; ++ ++ if (temp >= 128000 || temp < -128000) { ++ fprintf(stderr, "%s: values is out of range (%i.%03i C)\n", ++ __FUNCTION__, temp / 1000, temp % 1000); ++ exit(-1); ++ } ++ ++ s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4; ++ ++ tmp105_alarm_update(s); ++} ++ ++static const int tmp105_faultq[4] = { 1, 2, 4, 6 }; ++ ++static void tmp105_read(struct tmp105_s *s) ++{ ++ s->len = 0; ++ ++ if ((s->config >> 1) & 1) { /* TM */ ++ s->alarm = 0; ++ tmp105_interrupt_update(s); ++ } ++ ++ switch (s->pointer & 3) { ++ case 0: /* Temperature */ ++ s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8); ++ s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) & ++ (0xf0 << ((~s->config >> 5) & 3)); /* R */ ++ break; ++ ++ case 1: /* Configuration */ ++ s->buf[s->len ++] = s->config; ++ break; ++ ++ case 2: /* T_LOW */ ++ s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8; ++ s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0; ++ break; ++ ++ case 3: /* T_HIGH */ ++ s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8; ++ s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0; ++ break; ++ } ++} ++ ++static void tmp105_write(struct tmp105_s *s) ++{ ++ switch (s->pointer & 3) { ++ case 0: /* Temperature */ ++ break; ++ ++ case 1: /* Configuration */ ++ if (s->buf[0] & ~s->config & (1 << 0)) /* SD */ ++ printf("%s: TMP105 shutdown\n", __FUNCTION__); ++ s->config = s->buf[0]; ++ s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */ ++ tmp105_alarm_update(s); ++ break; ++ ++ case 2: /* T_LOW */ ++ case 3: /* T_HIGH */ ++ if (s->len >= 3) ++ s->limit[s->pointer & 1] = (int16_t) ++ ((((uint16_t) s->buf[0]) << 8) | s->buf[1]); ++ tmp105_alarm_update(s); ++ break; ++ } ++} ++ ++static int tmp105_rx(i2c_slave *i2c) ++{ ++ struct tmp105_s *s = (struct tmp105_s *) i2c; ++ ++ if (s->len < 2) ++ return s->buf[s->len ++]; ++ else ++ return 0xff; ++} ++ ++static int tmp105_tx(i2c_slave *i2c, uint8_t data) ++{ ++ struct tmp105_s *s = (struct tmp105_s *) i2c; ++ ++ if (!s->len ++) ++ s->pointer = data; ++ else { ++ if (s->len <= 2) ++ s->buf[s->len - 1] = data; ++ tmp105_write(s); ++ } ++ ++ return 0; ++} ++ ++static void tmp105_event(i2c_slave *i2c, enum i2c_event event) ++{ ++ struct tmp105_s *s = (struct tmp105_s *) i2c; ++ ++ if (event == I2C_START_RECV) ++ tmp105_read(s); ++ ++ s->len = 0; ++} ++ ++static void tmp105_save(QEMUFile *f, void *opaque) ++{ ++ struct tmp105_s *s = (struct tmp105_s *) opaque; ++ ++ qemu_put_byte(f, s->len); ++ qemu_put_8s(f, &s->buf[0]); ++ qemu_put_8s(f, &s->buf[1]); ++ ++ qemu_put_8s(f, &s->pointer); ++ qemu_put_8s(f, &s->config); ++ qemu_put_be16s(f, &s->temperature); ++ qemu_put_be16s(f, &s->limit[0]); ++ qemu_put_be16s(f, &s->limit[1]); ++ qemu_put_byte(f, s->alarm); ++ s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */ ++ ++ i2c_slave_save(f, &s->i2c); ++} ++ ++static int tmp105_load(QEMUFile *f, void *opaque, int version_id) ++{ ++ struct tmp105_s *s = (struct tmp105_s *) opaque; ++ ++ s->len = qemu_get_byte(f); ++ qemu_get_8s(f, &s->buf[0]); ++ qemu_get_8s(f, &s->buf[1]); ++ ++ qemu_get_8s(f, &s->pointer); ++ qemu_get_8s(f, &s->config); ++ qemu_get_be16s(f, &s->temperature); ++ qemu_get_be16s(f, &s->limit[0]); ++ qemu_get_be16s(f, &s->limit[1]); ++ s->alarm = qemu_get_byte(f); ++ ++ tmp105_interrupt_update(s); ++ ++ i2c_slave_load(f, &s->i2c); ++ return 0; ++} ++ ++void tmp105_reset(i2c_slave *i2c) ++{ ++ struct tmp105_s *s = (struct tmp105_s *) i2c; ++ ++ s->temperature = 0; ++ s->pointer = 0; ++ s->config = 0; ++ s->faults = tmp105_faultq[(s->config >> 3) & 3]; ++ s->alarm = 0; ++ ++ tmp105_interrupt_update(s); ++} ++ ++static int tmp105_iid = 0; ++ ++struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm) ++{ ++ struct tmp105_s *s = (struct tmp105_s *) ++ i2c_slave_init(bus, 0, sizeof(struct tmp105_s)); ++ ++ s->i2c.event = tmp105_event; ++ s->i2c.recv = tmp105_rx; ++ s->i2c.send = tmp105_tx; ++ s->pin = alarm; ++ ++ tmp105_reset(&s->i2c); ++ ++ register_savevm("TMP105", tmp105_iid ++, 0, ++ tmp105_save, tmp105_load, s); ++ ++ return &s->i2c; ++} +diff --git a/hw/tsc210x.c b/hw/tsc210x.c +index 96956a4..1654b8b 100644 +--- a/hw/tsc210x.c ++++ b/hw/tsc210x.c +@@ -2,6 +2,7 @@ + * TI TSC2102 (touchscreen/sensors/audio controller) emulator. + * + * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> ++ * Copyright (C) 2008 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 +@@ -35,12 +36,15 @@ + + struct tsc210x_state_s { + qemu_irq pint; ++ qemu_irq kbint; ++ qemu_irq davint; + QEMUTimer *timer; + QEMUSoundCard card; + struct uwire_slave_s chip; + struct i2s_codec_s codec; + uint8_t in_fifo[16384]; + uint8_t out_fifo[16384]; ++ uint16_t model; + + int x, y; + int pressure; +@@ -64,7 +68,7 @@ struct tsc210x_state_s { + uint16_t audio_ctrl1; + uint16_t audio_ctrl2; + uint16_t audio_ctrl3; +- uint16_t pll[2]; ++ uint16_t pll[3]; + uint16_t volume; + int64_t volume_change; + int softstep; +@@ -78,6 +82,17 @@ struct tsc210x_state_s { + int i2s_rx_rate; + int i2s_tx_rate; + AudioState *audio; ++ ++ int tr[8]; ++ ++ struct { ++ uint16_t down; ++ uint16_t mask; ++ int scan; ++ int debounce; ++ int mode; ++ int intr; ++ } kb; + }; + + static const int resolution[4] = { 12, 8, 10, 12 }; +@@ -118,17 +133,10 @@ static const uint16_t mode_regs[16] = { + 0x0000, /* Y+, X- drivers */ + }; + +-/* +- * Convert screen coordinates to arbitrary values that the +- * touchscreen in my Palm Tungsten E device returns. +- * This shouldn't really matter (because the guest system +- * should calibrate the touchscreen anyway), but let's +- * imitate some real hardware. +- */ +-#define X_TRANSFORM(value) \ +- ((3850 - ((int) (value) * (3850 - 250) / 32768)) << 4) +-#define Y_TRANSFORM(value) \ +- ((150 + ((int) (value) * (3037 - 150) / 32768)) << 4) ++#define X_TRANSFORM(s) \ ++ ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3]) ++#define Y_TRANSFORM(s) \ ++ ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7]) + #define Z1_TRANSFORM(s) \ + ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) + #define Z2_TRANSFORM(s) \ +@@ -161,6 +169,7 @@ static void tsc210x_reset(struct tsc210x_state_s *s) + s->audio_ctrl3 = 0x0000; + s->pll[0] = 0x1004; + s->pll[1] = 0x0000; ++ s->pll[2] = 0x1fff; + s->volume = 0xffff; + s->dac_power = 0x8540; + s->softstep = 1; +@@ -190,7 +199,15 @@ static void tsc210x_reset(struct tsc210x_state_s *s) + s->i2s_tx_rate = 0; + s->i2s_rx_rate = 0; + ++ s->kb.scan = 1; ++ s->kb.debounce = 0; ++ s->kb.mask = 0x0000; ++ s->kb.mode = 3; ++ s->kb.intr = 0; ++ + qemu_set_irq(s->pint, !s->irq); ++ qemu_set_irq(s->davint, !s->dav); ++ qemu_irq_raise(s->kbint); + } + + struct tsc210x_rate_info_s { +@@ -344,13 +361,13 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) + switch (reg) { + case 0x00: /* X */ + s->dav &= 0xfbff; +- return TSC_CUT_RESOLUTION(X_TRANSFORM(s->x), s->precision) + ++ return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) + + (s->noise & 3); + + case 0x01: /* Y */ + s->noise ++; + s->dav &= 0xfdff; +- return TSC_CUT_RESOLUTION(Y_TRANSFORM(s->y), s->precision) ^ ++ return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^ + (s->noise & 3); + + case 0x02: /* Z1 */ +@@ -364,6 +381,14 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) + (s->noise & 3); + + case 0x04: /* KPData */ ++ if ((s->model & 0xff00) == 0x2300) { ++ if (s->kb.intr && (s->kb.mode & 2)) { ++ s->kb.intr = 0; ++ qemu_irq_raise(s->kbint); ++ } ++ return s->kb.down; ++ } ++ + return 0xffff; + + case 0x05: /* BAT1 */ +@@ -414,9 +439,19 @@ static uint16_t tsc2102_control_register_read( + return (s->pressure << 15) | ((!s->busy) << 14) | + (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; + +- case 0x01: /* Status */ +- return (s->pin_func << 14) | ((!s->enabled) << 13) | +- (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav; ++ case 0x01: /* Status / Keypad Control */ ++ if ((s->model & 0xff00) == 0x2100) ++ return (s->pin_func << 14) | ((!s->enabled) << 13) | ++ (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav; ++ else ++ return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) | ++ (s->kb.debounce << 11); ++ ++ case 0x02: /* DAC Control */ ++ if ((s->model & 0xff00) == 0x2300) ++ return s->dac_power & 0x8000; ++ else ++ goto bad_reg; + + case 0x03: /* Reference */ + return s->ref; +@@ -427,7 +462,18 @@ static uint16_t tsc2102_control_register_read( + case 0x05: /* Configuration */ + return s->timing; + ++ case 0x06: /* Secondary configuration */ ++ if ((s->model & 0xff00) == 0x2100) ++ goto bad_reg; ++ return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2]; ++ ++ case 0x10: /* Keypad Mask */ ++ if ((s->model & 0xff00) == 0x2100) ++ goto bad_reg; ++ return s->kb.mask; ++ + default: ++ bad_reg: + #ifdef TSC_VERBOSE + fprintf(stderr, "tsc2102_control_register_read: " + "no such register: 0x%02x\n", reg); +@@ -556,10 +602,27 @@ static void tsc2102_control_register_write( + s->filter = value & 0xff; + return; + +- case 0x01: /* Status */ +- s->pin_func = value >> 14; ++ case 0x01: /* Status / Keypad Control */ ++ if ((s->model & 0xff00) == 0x2100) ++ s->pin_func = value >> 14; ++ else { ++ s->kb.scan = (value >> 14) & 1; ++ s->kb.debounce = (value >> 11) & 7; ++ if (s->kb.intr && s->kb.scan) { ++ s->kb.intr = 0; ++ qemu_irq_raise(s->kbint); ++ } ++ } + return; + ++ case 0x02: /* DAC Control */ ++ if ((s->model & 0xff00) == 0x2300) { ++ s->dac_power &= 0x7fff; ++ s->dac_power |= 0x8000 & value; ++ } else ++ goto bad_reg; ++ break; ++ + case 0x03: /* Reference */ + s->ref = value & 0x1f; + return; +@@ -586,7 +649,21 @@ static void tsc2102_control_register_write( + #endif + return; + ++ case 0x06: /* Secondary configuration */ ++ if ((s->model & 0xff00) == 0x2100) ++ goto bad_reg; ++ s->kb.mode = value >> 14; ++ s->pll[2] = value & 0x3ffff; ++ return; ++ ++ case 0x10: /* Keypad Mask */ ++ if ((s->model & 0xff00) == 0x2100) ++ goto bad_reg; ++ s->kb.mask = value; ++ return; ++ + default: ++ bad_reg: + #ifdef TSC_VERBOSE + fprintf(stderr, "tsc2102_control_register_write: " + "no such register: 0x%02x\n", reg); +@@ -785,7 +862,7 @@ static void tsc210x_pin_update(struct tsc210x_state_s *s) + return; + } + +- if (!s->enabled || s->busy) ++ if (!s->enabled || s->busy || s->dav) + return; + + s->busy = 1; +@@ -805,6 +882,8 @@ static uint16_t tsc210x_read(struct tsc210x_state_s *s) + switch (s->page) { + case TSC_DATA_REGISTERS_PAGE: + ret = tsc2102_data_register_read(s, s->offset); ++ if (!s->dav) ++ qemu_irq_raise(s->davint); + break; + case TSC_CONTROL_REGISTERS_PAGE: + ret = tsc2102_control_register_read(s, s->offset); +@@ -859,6 +938,22 @@ static void tsc210x_write(struct tsc210x_state_s *s, uint16_t value) + } + } + ++uint32_t tsc210x_txrx(void *opaque, uint32_t value) ++{ ++ struct tsc210x_state_s *s = opaque; ++ uint32_t ret = 0; ++ ++ /* TODO: sequential reads etc - how do we make sure the host doesn't ++ * unintentionally read out a conversion result from a register while ++ * transmitting the command word of the next command? */ ++ if (!value || (s->state && s->command)) ++ ret = tsc210x_read(s); ++ if (value || (s->state && !s->command)) ++ tsc210x_write(s, value); ++ ++ return ret; ++} ++ + static void tsc210x_timer_tick(void *opaque) + { + struct tsc210x_state_s *s = opaque; +@@ -871,6 +966,7 @@ static void tsc210x_timer_tick(void *opaque) + s->busy = 0; + s->dav |= mode_regs[s->function]; + tsc210x_pin_update(s); ++ qemu_irq_lower(s->davint); + } + + static void tsc210x_touchscreen_event(void *opaque, +@@ -1001,6 +1097,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) + + s->busy = qemu_timer_pending(s->timer); + qemu_set_irq(s->pint, !s->irq); ++ qemu_set_irq(s->davint, !s->dav); + + return 0; + } +@@ -1020,9 +1117,19 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) + s->precision = s->nextprecision = 0; + s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); + s->pint = pint; ++ s->model = 0x2102; + s->name = "tsc2102"; + s->audio = audio; + ++ s->tr[0] = 0; ++ s->tr[1] = 1; ++ s->tr[2] = 0; ++ s->tr[3] = 1; ++ s->tr[4] = 1; ++ s->tr[5] = 0; ++ s->tr[6] = 0; ++ s->tr[7] = 1; ++ + s->chip.opaque = s; + s->chip.send = (void *) tsc210x_write; + s->chip.receive = (void *) tsc210x_read; +@@ -1048,9 +1155,147 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) + return &s->chip; + } + ++struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, ++ qemu_irq dav, AudioState *audio) ++{ ++ struct tsc210x_state_s *s; ++ ++ s = (struct tsc210x_state_s *) ++ qemu_mallocz(sizeof(struct tsc210x_state_s)); ++ memset(s, 0, sizeof(struct tsc210x_state_s)); ++ s->x = 400; ++ s->y = 240; ++ s->pressure = 0; ++ s->precision = s->nextprecision = 0; ++ s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); ++ s->pint = penirq; ++ s->kbint = kbirq; ++ s->davint = dav; ++ s->model = 0x2301; ++ s->name = "tsc2301"; ++ s->audio = audio; ++ ++ s->tr[0] = 0; ++ s->tr[1] = 1; ++ s->tr[2] = 0; ++ s->tr[3] = 1; ++ s->tr[4] = 1; ++ s->tr[5] = 0; ++ s->tr[6] = 0; ++ s->tr[7] = 1; ++ ++ s->chip.opaque = s; ++ s->chip.send = (void *) tsc210x_write; ++ s->chip.receive = (void *) tsc210x_read; ++ ++ s->codec.opaque = s; ++ s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; ++ s->codec.set_rate = (void *) tsc210x_i2s_set_rate; ++ s->codec.in.fifo = s->in_fifo; ++ s->codec.out.fifo = s->out_fifo; ++ ++ tsc210x_reset(s); ++ ++ qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, ++ "QEMU TSC2301-driven Touchscreen"); ++ ++ if (s->audio) ++ AUD_register_card(s->audio, s->name, &s->card); ++ ++ qemu_register_reset((void *) tsc210x_reset, s); ++ register_savevm(s->name, tsc2102_iid ++, 0, ++ tsc210x_save, tsc210x_load, s); ++ ++ return &s->chip; ++} ++ + struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip) + { + struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; + + return &s->codec; + } ++ ++/* ++ * Use tslib generated calibration data to generate ADC input values ++ * from the touchscreen. Assuming 12-bit precision was used during ++ * tslib calibration. ++ */ ++void tsc210x_set_transform(struct uwire_slave_s *chip, ++ struct mouse_transform_info_s *info) ++{ ++ struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; ++#if 0 ++ int64_t ltr[8]; ++ ++ ltr[0] = (int64_t) info->a[1] * info->y; ++ ltr[1] = (int64_t) info->a[4] * info->x; ++ ltr[2] = (int64_t) info->a[1] * info->a[3] - ++ (int64_t) info->a[4] * info->a[0]; ++ ltr[3] = (int64_t) info->a[2] * info->a[4] - ++ (int64_t) info->a[5] * info->a[1]; ++ ltr[4] = (int64_t) info->a[0] * info->y; ++ ltr[5] = (int64_t) info->a[3] * info->x; ++ ltr[6] = (int64_t) info->a[4] * info->a[0] - ++ (int64_t) info->a[1] * info->a[3]; ++ ltr[7] = (int64_t) info->a[2] * info->a[3] - ++ (int64_t) info->a[5] * info->a[0]; ++ ++ /* Avoid integer overflow */ ++ s->tr[0] = ltr[0] >> 11; ++ s->tr[1] = ltr[1] >> 11; ++ s->tr[2] = muldiv64(ltr[2], 1, info->a[6]); ++ s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]); ++ s->tr[4] = ltr[4] >> 11; ++ s->tr[5] = ltr[5] >> 11; ++ s->tr[6] = muldiv64(ltr[6], 1, info->a[6]); ++ s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]); ++#else ++ ++ if (abs(info->a[0]) > abs(info->a[1])) { ++ s->tr[0] = 0; ++ s->tr[1] = -info->a[6] * info->x; ++ s->tr[2] = info->a[0]; ++ s->tr[3] = -info->a[2] / info->a[0]; ++ s->tr[4] = info->a[6] * info->y; ++ s->tr[5] = 0; ++ s->tr[6] = info->a[4]; ++ s->tr[7] = -info->a[5] / info->a[4]; ++ } else { ++ s->tr[0] = info->a[6] * info->y; ++ s->tr[1] = 0; ++ s->tr[2] = info->a[1]; ++ s->tr[3] = -info->a[2] / info->a[1]; ++ s->tr[4] = 0; ++ s->tr[5] = -info->a[6] * info->x; ++ s->tr[6] = info->a[3]; ++ s->tr[7] = -info->a[5] / info->a[3]; ++ } ++ ++ s->tr[0] >>= 11; ++ s->tr[1] >>= 11; ++ s->tr[3] <<= 4; ++ s->tr[4] >>= 11; ++ s->tr[5] >>= 11; ++ s->tr[7] <<= 4; ++#endif ++} ++ ++void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down) ++{ ++ struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; ++ ++ if (down) ++ s->kb.down |= 1 << key; ++ else ++ s->kb.down &= ~(1 << key); ++ ++ if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) { ++ s->kb.intr = 1; ++ qemu_irq_lower(s->kbint); ++ } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) && ++ !(s->kb.mode & 1)) { ++ s->kb.intr = 0; ++ qemu_irq_raise(s->kbint); ++ } ++} +diff --git a/hw/twl92230.c b/hw/twl92230.c +new file mode 100644 +index 0000000..11a5d1a +--- /dev/null ++++ b/hw/twl92230.c +@@ -0,0 +1,923 @@ ++/* ++ * TI TWL92230C energy-management companion device for the OMAP24xx. ++ * Aka. Menelaus (N4200 MENELAUS1_V2.2) ++ * ++ * Copyright (C) 2008 Nokia Corporation ++ * Written by Andrzej Zaborowski <andrew@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * 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" ++ ++#define VERBOSE 1 ++ ++struct menelaus_s { ++ i2c_slave i2c; ++ qemu_irq irq; ++ ++ int firstbyte; ++ uint8_t reg; ++ ++ uint8_t vcore[5]; ++ uint8_t dcdc[3]; ++ uint8_t ldo[8]; ++ uint8_t sleep[2]; ++ uint8_t osc; ++ uint8_t detect; ++ uint16_t mask; ++ uint16_t status; ++ uint8_t dir; ++ uint8_t inputs; ++ uint8_t outputs; ++ uint8_t bbsms; ++ uint8_t pull[4]; ++ uint8_t mmc_ctrl[3]; ++ uint8_t mmc_debounce; ++ struct { ++ uint8_t ctrl; ++ uint16_t comp; ++ QEMUTimer *hz; ++ int64_t next; ++ struct tm tm; ++ struct tm new; ++ struct tm alm; ++ time_t sec; ++ time_t alm_sec; ++ time_t next_comp; ++ struct tm *(*gettime)(const time_t *timep, struct tm *result); ++ } rtc; ++ qemu_irq handler[3]; ++ qemu_irq *in; ++ int pwrbtn_state; ++ qemu_irq pwrbtn; ++}; ++ ++static inline void menelaus_update(struct menelaus_s *s) ++{ ++ qemu_set_irq(s->irq, s->status & ~s->mask); ++} ++ ++static inline void menelaus_rtc_start(struct menelaus_s *s) ++{ ++ s->rtc.next =+ qemu_get_clock(rt_clock); ++ qemu_mod_timer(s->rtc.hz, s->rtc.next); ++} ++ ++static inline void menelaus_rtc_stop(struct menelaus_s *s) ++{ ++ qemu_del_timer(s->rtc.hz); ++ s->rtc.next =- qemu_get_clock(rt_clock); ++ if (s->rtc.next < 1) ++ s->rtc.next = 1; ++} ++ ++static void menelaus_rtc_update(struct menelaus_s *s) ++{ ++ s->rtc.gettime(&s->rtc.sec, &s->rtc.tm); ++} ++ ++static void menelaus_alm_update(struct menelaus_s *s) ++{ ++ if ((s->rtc.ctrl & 3) == 3) ++ s->rtc.alm_sec = mktime(&s->rtc.alm); ++} ++ ++static void menelaus_rtc_hz(void *opaque) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) opaque; ++ ++ s->rtc.sec ++; ++ s->rtc.next += 1000; ++ qemu_mod_timer(s->rtc.hz, s->rtc.next); ++ if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */ ++ menelaus_rtc_update(s); ++ if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec) ++ s->status |= 1 << 8; /* RTCTMR */ ++ else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min) ++ s->status |= 1 << 8; /* RTCTMR */ ++ else if (!s->rtc.tm.tm_hour) ++ s->status |= 1 << 8; /* RTCTMR */ ++ } else ++ s->status |= 1 << 8; /* RTCTMR */ ++ if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */ ++ if (s->rtc.sec == s->rtc.alm_sec) ++ s->status |= 1 << 9; /* RTCALM */ ++ /* TODO: wake-up */ ++ } ++ if (s->rtc.next_comp >= s->rtc.sec) { ++ s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000); ++ s->rtc.next_comp = s->rtc.sec + 3600; ++ } ++ menelaus_update(s); ++} ++ ++void menelaus_reset(i2c_slave *i2c) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) i2c; ++ time_t ti; ++ s->reg = 0x00; ++ ++ s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */ ++ s->vcore[1] = 0x05; ++ s->vcore[2] = 0x02; ++ s->vcore[3] = 0x0c; ++ s->vcore[4] = 0x03; ++ s->dcdc[0] = 0x33; /* Depends on wiring */ ++ s->dcdc[1] = 0x03; ++ s->dcdc[2] = 0x00; ++ s->ldo[0] = 0x95; ++ s->ldo[1] = 0x7e; ++ s->ldo[2] = 0x00; ++ s->ldo[3] = 0x00; /* Depends on wiring */ ++ s->ldo[4] = 0x03; /* Depends on wiring */ ++ s->ldo[5] = 0x00; ++ s->ldo[6] = 0x00; ++ s->ldo[7] = 0x00; ++ s->sleep[0] = 0x00; ++ s->sleep[1] = 0x00; ++ s->osc = 0x01; ++ s->detect = 0x09; ++ s->mask = 0x0fff; ++ s->status = 0; ++ s->dir = 0x07; ++ s->outputs = 0x00; ++ s->bbsms = 0x00; ++ s->pull[0] = 0x00; ++ s->pull[1] = 0x00; ++ s->pull[2] = 0x00; ++ s->pull[3] = 0x00; ++ s->mmc_ctrl[0] = 0x03; ++ s->mmc_ctrl[1] = 0xc0; ++ s->mmc_ctrl[2] = 0x00; ++ s->mmc_debounce = 0x05; ++ ++ time(&ti); ++ if (s->rtc.ctrl & 1) ++ menelaus_rtc_stop(s); ++ s->rtc.ctrl = 0x00; ++ s->rtc.comp = 0x0000; ++ s->rtc.next = 1000; ++ s->rtc.sec = ti; ++ s->rtc.next_comp = s->rtc.sec + 1800; ++ s->rtc.alm.tm_sec = 0x00; ++ s->rtc.alm.tm_min = 0x00; ++ s->rtc.alm.tm_hour = 0x00; ++ s->rtc.alm.tm_mday = 0x01; ++ s->rtc.alm.tm_mon = 0x00; ++ s->rtc.alm.tm_year = 2004; ++ menelaus_update(s); ++} ++ ++static inline uint8_t to_bcd(int val) ++{ ++ return ((val / 10) << 4) | (val % 10); ++} ++ ++static inline int from_bcd(uint8_t val) ++{ ++ return ((val >> 4) * 10) + (val & 0x0f); ++} ++ ++static void menelaus_gpio_set(void *opaque, int line, int level) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) opaque; ++ ++ /* No interrupt generated */ ++ s->inputs &= ~(1 << line); ++ s->inputs |= level << line; ++} ++ ++static void menelaus_pwrbtn_set(void *opaque, int line, int level) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) opaque; ++ ++ if (!s->pwrbtn_state && level) { ++ s->status |= 1 << 11; /* PSHBTN */ ++ menelaus_update(s); ++ } ++ s->pwrbtn_state = level; ++} ++ ++#define MENELAUS_REV 0x01 ++#define MENELAUS_VCORE_CTRL1 0x02 ++#define MENELAUS_VCORE_CTRL2 0x03 ++#define MENELAUS_VCORE_CTRL3 0x04 ++#define MENELAUS_VCORE_CTRL4 0x05 ++#define MENELAUS_VCORE_CTRL5 0x06 ++#define MENELAUS_DCDC_CTRL1 0x07 ++#define MENELAUS_DCDC_CTRL2 0x08 ++#define MENELAUS_DCDC_CTRL3 0x09 ++#define MENELAUS_LDO_CTRL1 0x0a ++#define MENELAUS_LDO_CTRL2 0x0b ++#define MENELAUS_LDO_CTRL3 0x0c ++#define MENELAUS_LDO_CTRL4 0x0d ++#define MENELAUS_LDO_CTRL5 0x0e ++#define MENELAUS_LDO_CTRL6 0x0f ++#define MENELAUS_LDO_CTRL7 0x10 ++#define MENELAUS_LDO_CTRL8 0x11 ++#define MENELAUS_SLEEP_CTRL1 0x12 ++#define MENELAUS_SLEEP_CTRL2 0x13 ++#define MENELAUS_DEVICE_OFF 0x14 ++#define MENELAUS_OSC_CTRL 0x15 ++#define MENELAUS_DETECT_CTRL 0x16 ++#define MENELAUS_INT_MASK1 0x17 ++#define MENELAUS_INT_MASK2 0x18 ++#define MENELAUS_INT_STATUS1 0x19 ++#define MENELAUS_INT_STATUS2 0x1a ++#define MENELAUS_INT_ACK1 0x1b ++#define MENELAUS_INT_ACK2 0x1c ++#define MENELAUS_GPIO_CTRL 0x1d ++#define MENELAUS_GPIO_IN 0x1e ++#define MENELAUS_GPIO_OUT 0x1f ++#define MENELAUS_BBSMS 0x20 ++#define MENELAUS_RTC_CTRL 0x21 ++#define MENELAUS_RTC_UPDATE 0x22 ++#define MENELAUS_RTC_SEC 0x23 ++#define MENELAUS_RTC_MIN 0x24 ++#define MENELAUS_RTC_HR 0x25 ++#define MENELAUS_RTC_DAY 0x26 ++#define MENELAUS_RTC_MON 0x27 ++#define MENELAUS_RTC_YR 0x28 ++#define MENELAUS_RTC_WKDAY 0x29 ++#define MENELAUS_RTC_AL_SEC 0x2a ++#define MENELAUS_RTC_AL_MIN 0x2b ++#define MENELAUS_RTC_AL_HR 0x2c ++#define MENELAUS_RTC_AL_DAY 0x2d ++#define MENELAUS_RTC_AL_MON 0x2e ++#define MENELAUS_RTC_AL_YR 0x2f ++#define MENELAUS_RTC_COMP_MSB 0x30 ++#define MENELAUS_RTC_COMP_LSB 0x31 ++#define MENELAUS_S1_PULL_EN 0x32 ++#define MENELAUS_S1_PULL_DIR 0x33 ++#define MENELAUS_S2_PULL_EN 0x34 ++#define MENELAUS_S2_PULL_DIR 0x35 ++#define MENELAUS_MCT_CTRL1 0x36 ++#define MENELAUS_MCT_CTRL2 0x37 ++#define MENELAUS_MCT_CTRL3 0x38 ++#define MENELAUS_MCT_PIN_ST 0x39 ++#define MENELAUS_DEBOUNCE1 0x3a ++ ++static uint8_t menelaus_read(void *opaque, uint8_t addr) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) opaque; ++ int reg = 0; ++ ++ switch (addr) { ++ case MENELAUS_REV: ++ return 0x22; ++ ++ case MENELAUS_VCORE_CTRL5: reg ++; ++ case MENELAUS_VCORE_CTRL4: reg ++; ++ case MENELAUS_VCORE_CTRL3: reg ++; ++ case MENELAUS_VCORE_CTRL2: reg ++; ++ case MENELAUS_VCORE_CTRL1: ++ return s->vcore[reg]; ++ ++ case MENELAUS_DCDC_CTRL3: reg ++; ++ case MENELAUS_DCDC_CTRL2: reg ++; ++ case MENELAUS_DCDC_CTRL1: ++ return s->dcdc[reg]; ++ ++ case MENELAUS_LDO_CTRL8: reg ++; ++ case MENELAUS_LDO_CTRL7: reg ++; ++ case MENELAUS_LDO_CTRL6: reg ++; ++ case MENELAUS_LDO_CTRL5: reg ++; ++ case MENELAUS_LDO_CTRL4: reg ++; ++ case MENELAUS_LDO_CTRL3: reg ++; ++ case MENELAUS_LDO_CTRL2: reg ++; ++ case MENELAUS_LDO_CTRL1: ++ return s->ldo[reg]; ++ ++ case MENELAUS_SLEEP_CTRL2: reg ++; ++ case MENELAUS_SLEEP_CTRL1: ++ return s->sleep[reg]; ++ ++ case MENELAUS_DEVICE_OFF: ++ return 0; ++ ++ case MENELAUS_OSC_CTRL: ++ return s->osc | (1 << 7); /* CLK32K_GOOD */ ++ ++ case MENELAUS_DETECT_CTRL: ++ return s->detect; ++ ++ case MENELAUS_INT_MASK1: ++ return (s->mask >> 0) & 0xff; ++ case MENELAUS_INT_MASK2: ++ return (s->mask >> 8) & 0xff; ++ ++ case MENELAUS_INT_STATUS1: ++ return (s->status >> 0) & 0xff; ++ case MENELAUS_INT_STATUS2: ++ return (s->status >> 8) & 0xff; ++ ++ case MENELAUS_INT_ACK1: ++ case MENELAUS_INT_ACK2: ++ return 0; ++ ++ case MENELAUS_GPIO_CTRL: ++ return s->dir; ++ case MENELAUS_GPIO_IN: ++ return s->inputs | (~s->dir & s->outputs); ++ case MENELAUS_GPIO_OUT: ++ return s->outputs; ++ ++ case MENELAUS_BBSMS: ++ return s->bbsms; ++ ++ case MENELAUS_RTC_CTRL: ++ return s->rtc.ctrl; ++ case MENELAUS_RTC_UPDATE: ++ return 0x00; ++ case MENELAUS_RTC_SEC: ++ menelaus_rtc_update(s); ++ return to_bcd(s->rtc.tm.tm_sec); ++ case MENELAUS_RTC_MIN: ++ menelaus_rtc_update(s); ++ return to_bcd(s->rtc.tm.tm_min); ++ case MENELAUS_RTC_HR: ++ menelaus_rtc_update(s); ++ if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ ++ return to_bcd((s->rtc.tm.tm_hour % 12) + 1) | ++ (!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */ ++ else ++ return to_bcd(s->rtc.tm.tm_hour); ++ case MENELAUS_RTC_DAY: ++ menelaus_rtc_update(s); ++ return to_bcd(s->rtc.tm.tm_mday); ++ case MENELAUS_RTC_MON: ++ menelaus_rtc_update(s); ++ return to_bcd(s->rtc.tm.tm_mon + 1); ++ case MENELAUS_RTC_YR: ++ menelaus_rtc_update(s); ++ return to_bcd(s->rtc.tm.tm_year - 2000); ++ case MENELAUS_RTC_WKDAY: ++ menelaus_rtc_update(s); ++ return to_bcd(s->rtc.tm.tm_wday); ++ case MENELAUS_RTC_AL_SEC: ++ return to_bcd(s->rtc.alm.tm_sec); ++ case MENELAUS_RTC_AL_MIN: ++ return to_bcd(s->rtc.alm.tm_min); ++ case MENELAUS_RTC_AL_HR: ++ if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ ++ return to_bcd((s->rtc.alm.tm_hour % 12) + 1) | ++ (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */ ++ else ++ return to_bcd(s->rtc.alm.tm_hour); ++ case MENELAUS_RTC_AL_DAY: ++ return to_bcd(s->rtc.alm.tm_mday); ++ case MENELAUS_RTC_AL_MON: ++ return to_bcd(s->rtc.alm.tm_mon + 1); ++ case MENELAUS_RTC_AL_YR: ++ return to_bcd(s->rtc.alm.tm_year - 2000); ++ case MENELAUS_RTC_COMP_MSB: ++ return (s->rtc.comp >> 8) & 0xff; ++ case MENELAUS_RTC_COMP_LSB: ++ return (s->rtc.comp >> 0) & 0xff; ++ ++ case MENELAUS_S1_PULL_EN: ++ return s->pull[0]; ++ case MENELAUS_S1_PULL_DIR: ++ return s->pull[1]; ++ case MENELAUS_S2_PULL_EN: ++ return s->pull[2]; ++ case MENELAUS_S2_PULL_DIR: ++ return s->pull[3]; ++ ++ case MENELAUS_MCT_CTRL3: reg ++; ++ case MENELAUS_MCT_CTRL2: reg ++; ++ case MENELAUS_MCT_CTRL1: ++ return s->mmc_ctrl[reg]; ++ case MENELAUS_MCT_PIN_ST: ++ /* TODO: return the real Card Detect */ ++ return 0; ++ case MENELAUS_DEBOUNCE1: ++ return s->mmc_debounce; ++ ++ default: ++#ifdef VERBOSE ++ printf("%s: unknown register %02x\n", __FUNCTION__, addr); ++#endif ++ break; ++ } ++ return 0; ++} ++ ++static void menelaus_write(void *opaque, uint8_t addr, uint8_t value) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) opaque; ++ int line; ++ int reg = 0; ++ struct tm tm; ++ ++ switch (addr) { ++ case MENELAUS_VCORE_CTRL1: ++ s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12); ++ break; ++ case MENELAUS_VCORE_CTRL2: ++ s->vcore[1] = value; ++ break; ++ case MENELAUS_VCORE_CTRL3: ++ s->vcore[2] = MIN(value & 0x1f, 0x12); ++ break; ++ case MENELAUS_VCORE_CTRL4: ++ s->vcore[3] = MIN(value & 0x1f, 0x12); ++ break; ++ case MENELAUS_VCORE_CTRL5: ++ s->vcore[4] = value & 3; ++ /* XXX ++ * auto set to 3 on M_Active, nRESWARM ++ * auto set to 0 on M_WaitOn, M_Backup ++ */ ++ break; ++ ++ case MENELAUS_DCDC_CTRL1: ++ s->dcdc[0] = value & 0x3f; ++ break; ++ case MENELAUS_DCDC_CTRL2: ++ s->dcdc[1] = value & 0x07; ++ /* XXX ++ * auto set to 3 on M_Active, nRESWARM ++ * auto set to 0 on M_WaitOn, M_Backup ++ */ ++ break; ++ case MENELAUS_DCDC_CTRL3: ++ s->dcdc[2] = value & 0x07; ++ break; ++ ++ case MENELAUS_LDO_CTRL1: ++ s->ldo[0] = value; ++ break; ++ case MENELAUS_LDO_CTRL2: ++ s->ldo[1] = value & 0x7f; ++ /* XXX ++ * auto set to 0x7e on M_WaitOn, M_Backup ++ */ ++ break; ++ case MENELAUS_LDO_CTRL3: ++ s->ldo[2] = value & 3; ++ /* XXX ++ * auto set to 3 on M_Active, nRESWARM ++ * auto set to 0 on M_WaitOn, M_Backup ++ */ ++ break; ++ case MENELAUS_LDO_CTRL4: ++ s->ldo[3] = value & 3; ++ /* XXX ++ * auto set to 3 on M_Active, nRESWARM ++ * auto set to 0 on M_WaitOn, M_Backup ++ */ ++ break; ++ case MENELAUS_LDO_CTRL5: ++ s->ldo[4] = value & 3; ++ /* XXX ++ * auto set to 3 on M_Active, nRESWARM ++ * auto set to 0 on M_WaitOn, M_Backup ++ */ ++ break; ++ case MENELAUS_LDO_CTRL6: ++ s->ldo[5] = value & 3; ++ break; ++ case MENELAUS_LDO_CTRL7: ++ s->ldo[6] = value & 3; ++ break; ++ case MENELAUS_LDO_CTRL8: ++ s->ldo[7] = value & 3; ++ break; ++ ++ case MENELAUS_SLEEP_CTRL2: reg ++; ++ case MENELAUS_SLEEP_CTRL1: ++ s->sleep[reg] = value; ++ break; ++ ++ case MENELAUS_DEVICE_OFF: ++ if (value & 1) ++ menelaus_reset(&s->i2c); ++ break; ++ ++ case MENELAUS_OSC_CTRL: ++ s->osc = value & 7; ++ break; ++ ++ case MENELAUS_DETECT_CTRL: ++ s->detect = value & 0x7f; ++ break; ++ ++ case MENELAUS_INT_MASK1: ++ s->mask &= 0xf00; ++ s->mask |= value << 0; ++ menelaus_update(s); ++ break; ++ case MENELAUS_INT_MASK2: ++ s->mask &= 0x0ff; ++ s->mask |= value << 8; ++ menelaus_update(s); ++ break; ++ ++ case MENELAUS_INT_ACK1: ++ s->status &= ~(((uint16_t) value) << 0); ++ menelaus_update(s); ++ break; ++ case MENELAUS_INT_ACK2: ++ s->status &= ~(((uint16_t) value) << 8); ++ menelaus_update(s); ++ break; ++ ++ case MENELAUS_GPIO_CTRL: ++ for (line = 0; line < 3; line ++) ++ if (((s->dir ^ value) >> line) & 1) ++ if (s->handler[line]) ++ qemu_set_irq(s->handler[line], ++ ((s->outputs & ~s->dir) >> line) & 1); ++ s->dir = value & 0x67; ++ break; ++ case MENELAUS_GPIO_OUT: ++ for (line = 0; line < 3; line ++) ++ if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) ++ if (s->handler[line]) ++ qemu_set_irq(s->handler[line], (s->outputs >> line) & 1); ++ s->outputs = value & 0x07; ++ break; ++ ++ case MENELAUS_BBSMS: ++ s->bbsms = 0x0d; ++ break; ++ ++ case MENELAUS_RTC_CTRL: ++ if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */ ++ if (value & 1) ++ menelaus_rtc_start(s); ++ else ++ menelaus_rtc_stop(s); ++ } ++ s->rtc.ctrl = value & 0x1f; ++ menelaus_alm_update(s); ++ break; ++ case MENELAUS_RTC_UPDATE: ++ menelaus_rtc_update(s); ++ memcpy(&tm, &s->rtc.tm, sizeof(tm)); ++ switch (value & 0xf) { ++ case 0: ++ break; ++ case 1: ++ tm.tm_sec = s->rtc.new.tm_sec; ++ break; ++ case 2: ++ tm.tm_min = s->rtc.new.tm_min; ++ break; ++ case 3: ++ if (s->rtc.new.tm_hour > 23) ++ goto rtc_badness; ++ tm.tm_hour = s->rtc.new.tm_hour; ++ break; ++ case 4: ++ if (s->rtc.new.tm_mday < 1) ++ goto rtc_badness; ++ /* TODO check range */ ++ tm.tm_mday = s->rtc.new.tm_mday; ++ break; ++ case 5: ++ if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) ++ goto rtc_badness; ++ tm.tm_mon = s->rtc.new.tm_mon; ++ break; ++ case 6: ++ tm.tm_year = s->rtc.new.tm_year; ++ break; ++ case 7: ++ /* TODO set .tm_mday instead */ ++ tm.tm_wday = s->rtc.new.tm_wday; ++ break; ++ case 8: ++ if (s->rtc.new.tm_hour > 23) ++ goto rtc_badness; ++ if (s->rtc.new.tm_mday < 1) ++ goto rtc_badness; ++ if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) ++ goto rtc_badness; ++ tm.tm_sec = s->rtc.new.tm_sec; ++ tm.tm_min = s->rtc.new.tm_min; ++ tm.tm_hour = s->rtc.new.tm_hour; ++ tm.tm_mday = s->rtc.new.tm_mday; ++ tm.tm_mon = s->rtc.new.tm_mon; ++ tm.tm_year = s->rtc.new.tm_year; ++ break; ++ rtc_badness: ++ default: ++ fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n", ++ __FUNCTION__, value); ++ s->status |= 1 << 10; /* RTCERR */ ++ menelaus_update(s); ++ } ++ s->rtc.sec += difftime(mktime(&tm), mktime(&s->rtc.tm)); ++ break; ++ case MENELAUS_RTC_SEC: ++ s->rtc.tm.tm_sec = from_bcd(value & 0x7f); ++ break; ++ case MENELAUS_RTC_MIN: ++ s->rtc.tm.tm_min = from_bcd(value & 0x7f); ++ break; ++ case MENELAUS_RTC_HR: ++ s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ ++ MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : ++ from_bcd(value & 0x3f); ++ break; ++ case MENELAUS_RTC_DAY: ++ s->rtc.tm.tm_mday = from_bcd(value); ++ break; ++ case MENELAUS_RTC_MON: ++ s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1; ++ break; ++ case MENELAUS_RTC_YR: ++ s->rtc.tm.tm_year = 2000 + from_bcd(value); ++ break; ++ case MENELAUS_RTC_WKDAY: ++ s->rtc.tm.tm_mday = from_bcd(value); ++ break; ++ case MENELAUS_RTC_AL_SEC: ++ s->rtc.alm.tm_sec = from_bcd(value & 0x7f); ++ menelaus_alm_update(s); ++ break; ++ case MENELAUS_RTC_AL_MIN: ++ s->rtc.alm.tm_min = from_bcd(value & 0x7f); ++ menelaus_alm_update(s); ++ break; ++ case MENELAUS_RTC_AL_HR: ++ s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ ++ MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : ++ from_bcd(value & 0x3f); ++ menelaus_alm_update(s); ++ break; ++ case MENELAUS_RTC_AL_DAY: ++ s->rtc.alm.tm_mday = from_bcd(value); ++ menelaus_alm_update(s); ++ break; ++ case MENELAUS_RTC_AL_MON: ++ s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1; ++ menelaus_alm_update(s); ++ break; ++ case MENELAUS_RTC_AL_YR: ++ s->rtc.alm.tm_year = 2000 + from_bcd(value); ++ menelaus_alm_update(s); ++ break; ++ case MENELAUS_RTC_COMP_MSB: ++ s->rtc.comp &= 0xff; ++ s->rtc.comp |= value << 8; ++ break; ++ case MENELAUS_RTC_COMP_LSB: ++ s->rtc.comp &= 0xff << 8; ++ s->rtc.comp |= value; ++ break; ++ ++ case MENELAUS_S1_PULL_EN: ++ s->pull[0] = value; ++ break; ++ case MENELAUS_S1_PULL_DIR: ++ s->pull[1] = value & 0x1f; ++ break; ++ case MENELAUS_S2_PULL_EN: ++ s->pull[2] = value; ++ break; ++ case MENELAUS_S2_PULL_DIR: ++ s->pull[3] = value & 0x1f; ++ break; ++ ++ case MENELAUS_MCT_CTRL1: ++ s->mmc_ctrl[0] = value & 0x7f; ++ break; ++ case MENELAUS_MCT_CTRL2: ++ s->mmc_ctrl[1] = value; ++ /* TODO update Card Detect interrupts */ ++ break; ++ case MENELAUS_MCT_CTRL3: ++ s->mmc_ctrl[2] = value & 0xf; ++ break; ++ case MENELAUS_DEBOUNCE1: ++ s->mmc_debounce = value & 0x3f; ++ break; ++ ++ default: ++#ifdef VERBOSE ++ printf("%s: unknown register %02x\n", __FUNCTION__, addr); ++#endif ++ } ++} ++ ++static void menelaus_event(i2c_slave *i2c, enum i2c_event event) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) i2c; ++ ++ if (event == I2C_START_SEND) ++ s->firstbyte = 1; ++} ++ ++static int menelaus_tx(i2c_slave *i2c, uint8_t data) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) i2c; ++ /* Interpret register address byte */ ++ if (s->firstbyte) { ++ s->reg = data; ++ s->firstbyte = 0; ++ } else ++ menelaus_write(s, s->reg ++, data); ++ ++ return 0; ++} ++ ++static int menelaus_rx(i2c_slave *i2c) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) i2c; ++ ++ return menelaus_read(s, s->reg ++); ++} ++ ++static void tm_put(QEMUFile *f, struct tm *tm) { ++ qemu_put_be16(f, tm->tm_sec); ++ qemu_put_be16(f, tm->tm_min); ++ qemu_put_be16(f, tm->tm_hour); ++ qemu_put_be16(f, tm->tm_mday); ++ qemu_put_be16(f, tm->tm_min); ++ qemu_put_be16(f, tm->tm_year); ++} ++ ++static void tm_get(QEMUFile *f, struct tm *tm) { ++ tm->tm_sec = qemu_get_be16(f); ++ tm->tm_min = qemu_get_be16(f); ++ tm->tm_hour = qemu_get_be16(f); ++ tm->tm_mday = qemu_get_be16(f); ++ tm->tm_min = qemu_get_be16(f); ++ tm->tm_year = qemu_get_be16(f); ++} ++ ++static void menelaus_save(QEMUFile *f, void *opaque) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) opaque; ++ ++ qemu_put_be32(f, s->firstbyte); ++ qemu_put_8s(f, &s->reg); ++ ++ qemu_put_8s(f, &s->vcore[0]); ++ qemu_put_8s(f, &s->vcore[1]); ++ qemu_put_8s(f, &s->vcore[2]); ++ qemu_put_8s(f, &s->vcore[3]); ++ qemu_put_8s(f, &s->vcore[4]); ++ qemu_put_8s(f, &s->dcdc[3]); ++ qemu_put_8s(f, &s->dcdc[3]); ++ qemu_put_8s(f, &s->dcdc[3]); ++ qemu_put_8s(f, &s->ldo[0]); ++ qemu_put_8s(f, &s->ldo[1]); ++ qemu_put_8s(f, &s->ldo[2]); ++ qemu_put_8s(f, &s->ldo[3]); ++ qemu_put_8s(f, &s->ldo[4]); ++ qemu_put_8s(f, &s->ldo[5]); ++ qemu_put_8s(f, &s->ldo[6]); ++ qemu_put_8s(f, &s->ldo[7]); ++ qemu_put_8s(f, &s->sleep[0]); ++ qemu_put_8s(f, &s->sleep[1]); ++ qemu_put_8s(f, &s->osc); ++ qemu_put_8s(f, &s->detect); ++ qemu_put_be16s(f, &s->mask); ++ qemu_put_be16s(f, &s->status); ++ qemu_put_8s(f, &s->dir); ++ qemu_put_8s(f, &s->inputs); ++ qemu_put_8s(f, &s->outputs); ++ qemu_put_8s(f, &s->bbsms); ++ qemu_put_8s(f, &s->pull[0]); ++ qemu_put_8s(f, &s->pull[1]); ++ qemu_put_8s(f, &s->pull[2]); ++ qemu_put_8s(f, &s->pull[3]); ++ qemu_put_8s(f, &s->mmc_ctrl[0]); ++ qemu_put_8s(f, &s->mmc_ctrl[1]); ++ qemu_put_8s(f, &s->mmc_ctrl[2]); ++ qemu_put_8s(f, &s->mmc_debounce); ++ qemu_put_8s(f, &s->rtc.ctrl); ++ qemu_put_be16s(f, &s->rtc.comp); ++ /* Should be <= 1000 */ ++ qemu_put_be16(f, s->rtc.next - qemu_get_clock(rt_clock)); ++ tm_put(f, &s->rtc.new); ++ tm_put(f, &s->rtc.alm); ++ qemu_put_byte(f, s->pwrbtn_state); ++ ++ i2c_slave_save(f, &s->i2c); ++} ++ ++static int menelaus_load(QEMUFile *f, void *opaque, int version_id) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) opaque; ++ ++ s->firstbyte = qemu_get_be32(f); ++ qemu_get_8s(f, &s->reg); ++ ++ if (s->rtc.ctrl & 1) /* RTC_EN */ ++ menelaus_rtc_stop(s); ++ qemu_get_8s(f, &s->vcore[0]); ++ qemu_get_8s(f, &s->vcore[1]); ++ qemu_get_8s(f, &s->vcore[2]); ++ qemu_get_8s(f, &s->vcore[3]); ++ qemu_get_8s(f, &s->vcore[4]); ++ qemu_get_8s(f, &s->dcdc[3]); ++ qemu_get_8s(f, &s->dcdc[3]); ++ qemu_get_8s(f, &s->dcdc[3]); ++ qemu_get_8s(f, &s->ldo[0]); ++ qemu_get_8s(f, &s->ldo[1]); ++ qemu_get_8s(f, &s->ldo[2]); ++ qemu_get_8s(f, &s->ldo[3]); ++ qemu_get_8s(f, &s->ldo[4]); ++ qemu_get_8s(f, &s->ldo[5]); ++ qemu_get_8s(f, &s->ldo[6]); ++ qemu_get_8s(f, &s->ldo[7]); ++ qemu_get_8s(f, &s->sleep[0]); ++ qemu_get_8s(f, &s->sleep[1]); ++ qemu_get_8s(f, &s->osc); ++ qemu_get_8s(f, &s->detect); ++ qemu_get_be16s(f, &s->mask); ++ qemu_get_be16s(f, &s->status); ++ qemu_get_8s(f, &s->dir); ++ qemu_get_8s(f, &s->inputs); ++ qemu_get_8s(f, &s->outputs); ++ qemu_get_8s(f, &s->bbsms); ++ qemu_get_8s(f, &s->pull[0]); ++ qemu_get_8s(f, &s->pull[1]); ++ qemu_get_8s(f, &s->pull[2]); ++ qemu_get_8s(f, &s->pull[3]); ++ qemu_get_8s(f, &s->mmc_ctrl[0]); ++ qemu_get_8s(f, &s->mmc_ctrl[1]); ++ qemu_get_8s(f, &s->mmc_ctrl[2]); ++ qemu_get_8s(f, &s->mmc_debounce); ++ qemu_get_8s(f, &s->rtc.ctrl); ++ qemu_get_be16s(f, &s->rtc.comp); ++ s->rtc.next = qemu_get_be16(f); ++ tm_get(f, &s->rtc.new); ++ tm_get(f, &s->rtc.alm); ++ s->pwrbtn_state = qemu_get_byte(f); ++ menelaus_alm_update(s); ++ menelaus_update(s); ++ if (s->rtc.ctrl & 1) /* RTC_EN */ ++ menelaus_rtc_start(s); ++ ++ i2c_slave_load(f, &s->i2c); ++ return 0; ++} ++ ++static int menelaus_iid = 0; ++ ++i2c_slave *twl92230_init(i2c_bus *bus, qemu_irq irq) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) ++ i2c_slave_init(bus, 0, sizeof(struct menelaus_s)); ++ ++ s->i2c.event = menelaus_event; ++ s->i2c.recv = menelaus_rx; ++ s->i2c.send = menelaus_tx; ++ ++ /* TODO: use the qemu gettime functions */ ++ s->rtc.gettime = localtime_r; ++ ++ s->irq = irq; ++ s->rtc.hz = qemu_new_timer(rt_clock, menelaus_rtc_hz, s); ++ s->in = qemu_allocate_irqs(menelaus_gpio_set, s, 3); ++ s->pwrbtn = qemu_allocate_irqs(menelaus_pwrbtn_set, s, 1)[0]; ++ ++ menelaus_reset(&s->i2c); ++ ++ register_savevm("menelaus", menelaus_iid ++, ++ 0, menelaus_save, menelaus_load, s); ++ ++ return &s->i2c; ++} ++ ++qemu_irq *twl92230_gpio_in_get(i2c_slave *i2c) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) i2c; ++ ++ return s->in; ++} ++ ++void twl92230_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler) ++{ ++ struct menelaus_s *s = (struct menelaus_s *) i2c; ++ ++ if (line >= 3 || line < 0) { ++ fprintf(stderr, "%s: No GPO line %i\n", __FUNCTION__, line); ++ exit(-1); ++ } ++ s->handler[line] = handler; ++} +diff --git a/hw/versatilepb.c b/hw/versatilepb.c +index da6e4ec..ecc0037 100644 +--- a/hw/versatilepb.c ++++ b/hw/versatilepb.c +@@ -157,6 +157,8 @@ static qemu_irq *vpb_sic_init(uint32_t base, qemu_irq *parent, int irq) + peripherans and expansion busses. For now we emulate a subset of the + PB peripherals and just change the board ID. */ + ++static struct arm_boot_info versatile_binfo; ++ + static void versatile_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, +@@ -283,8 +285,12 @@ static void versatile_init(int ram_size, int vga_ram_size, + /* 0x101f3000 UART2. */ + /* 0x101f4000 SSPI. */ + +- arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, +- initrd_filename, board_id, 0x0); ++ versatile_binfo.ram_size = ram_size; ++ versatile_binfo.kernel_filename = kernel_filename; ++ versatile_binfo.kernel_cmdline = kernel_cmdline; ++ versatile_binfo.initrd_filename = initrd_filename; ++ versatile_binfo.board_id = board_id; ++ arm_load_kernel(env, &versatile_binfo); + } + + static void vpb_init(int ram_size, int vga_ram_size, +diff --git a/softmmu_template.h b/softmmu_template.h +index 0a4bc7e..d480f34 100644 +--- a/softmmu_template.h ++++ b/softmmu_template.h +@@ -51,12 +51,15 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + int mmu_idx, + void *retaddr); + static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, +- target_ulong tlb_addr) ++ target_ulong tlb_addr, ++ target_ulong tlb_io) + { + DATA_TYPE res; + int index; + +- index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); ++ index = (tlb_addr & ~TARGET_PAGE_MASK) >> IO_MEM_SHIFT; ++ if (index > 4) ++ index = (tlb_io >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + #if SHIFT <= 2 + res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr); + #else +@@ -95,7 +98,9 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; +- res = glue(io_read, SUFFIX)(physaddr, tlb_addr); ++ res = glue(io_read, SUFFIX)(physaddr, tlb_addr, ++ env->tlb_table[mmu_idx] ++ [index].addr_code); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + /* slow unaligned access (it spans two pages or IO) */ + do_unaligned_access: +@@ -147,7 +152,9 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; +- res = glue(io_read, SUFFIX)(physaddr, tlb_addr); ++ res = glue(io_read, SUFFIX)(physaddr, tlb_addr, ++ env->tlb_table[mmu_idx] ++ [index].addr_code); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* slow unaligned access (it spans two pages) */ +@@ -186,11 +193,14 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, + static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, + DATA_TYPE val, + target_ulong tlb_addr, +- void *retaddr) ++ void *retaddr, ++ target_ulong tlb_io) + { + int index; + +- index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); ++ index = (tlb_addr & ~TARGET_PAGE_MASK) >> IO_MEM_SHIFT; ++ if (index > 4) ++ index = (tlb_io >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + env->mem_write_vaddr = tlb_addr; + env->mem_write_pc = (unsigned long)retaddr; + #if SHIFT <= 2 +@@ -228,7 +238,8 @@ void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + retaddr = GETPC(); +- glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr); ++ glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr, ++ env->tlb_table[mmu_idx][index].addr_code); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + retaddr = GETPC(); +@@ -278,7 +289,8 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; +- glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr); ++ glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr, ++ env->tlb_table[mmu_idx][index].addr_code); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* XXX: not efficient, but simple */ +diff --git a/target-arm/cpu.h b/target-arm/cpu.h +index b284a21..633b335 100644 +--- a/target-arm/cpu.h ++++ b/target-arm/cpu.h +@@ -198,12 +198,16 @@ typedef struct CPUARMState { + CPU_COMMON + + /* These fields after the common ones so they are preserved on reset. */ +- int ram_size; +- const char *kernel_filename; +- const char *kernel_cmdline; +- const char *initrd_filename; +- int board_id; +- target_phys_addr_t loader_start; ++ struct arm_boot_info { ++ int ram_size; ++ const char *kernel_filename; ++ const char *kernel_cmdline; ++ const char *initrd_filename; ++ target_phys_addr_t loader_start; ++ int nb_cpus; ++ int board_id; ++ int (*atag_board)(struct arm_boot_info *info, void *p); ++ } *boot_info; + } CPUARMState; + + CPUARMState *cpu_arm_init(const char *cpu_model); +@@ -377,6 +381,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, + #define ARM_CPUID_PXA270_C0 0x69054114 + #define ARM_CPUID_PXA270_C5 0x69054117 + #define ARM_CPUID_ARM1136 0x4117b363 ++#define ARM_CPUID_ARM1136_R2 0x4107b362 + #define ARM_CPUID_ARM11MPCORE 0x410fb022 + #define ARM_CPUID_CORTEXA8 0x410fc080 + #define ARM_CPUID_CORTEXM3 0x410fc231 +diff --git a/target-arm/helper.c b/target-arm/helper.c +index 86470db..0709129 100644 +--- a/target-arm/helper.c ++++ b/target-arm/helper.c +@@ -53,6 +53,9 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) + env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c1_sys = 0x00090078; + break; ++ case ARM_CPUID_ARM1136_R2: ++ /* TODO! */ ++ env->GE = 0x5; + case ARM_CPUID_ARM1136: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_VFP); +@@ -198,6 +201,7 @@ static const struct arm_cpu_t arm_cpu_names[] = { + { ARM_CPUID_ARM946, "arm946"}, + { ARM_CPUID_ARM1026, "arm1026"}, + { ARM_CPUID_ARM1136, "arm1136"}, ++ { ARM_CPUID_ARM1136_R2, "arm1136-r2"}, + { ARM_CPUID_ARM11MPCORE, "arm11mpcore"}, + { ARM_CPUID_CORTEXM3, "cortex-m3"}, + { ARM_CPUID_CORTEXA8, "cortex-a8"}, +@@ -1539,6 +1543,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) + case ARM_CPUID_ARM1026: + return 1; + case ARM_CPUID_ARM1136: ++ case ARM_CPUID_ARM1136_R2: + return 7; + case ARM_CPUID_ARM11MPCORE: + return 1; +@@ -1721,6 +1726,10 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) + case 8: /* TI925T_status */ + return 0; + } ++ /* TODO: Peripheral port remap register: ++ * On OMAP2 mcr p15, 0, rn, c15, c2, 4 sets up the interrupt ++ * controller base address at $rn & ~0xfff and map size of ++ * 0x200 << ($rn & 0xfff), when MMU is off. */ + goto bad_reg; + } + return 0; +diff --git a/vl.c b/vl.c +index d371af7..76d8def 100644 +--- a/vl.c ++++ b/vl.c +@@ -8006,6 +8006,7 @@ static void register_machines(void) + qemu_register_machine(&borzoipda_machine); + qemu_register_machine(&terrierpda_machine); + qemu_register_machine(&palmte_machine); ++ qemu_register_machine(&n800_machine); + qemu_register_machine(&lm3s811evb_machine); + qemu_register_machine(&lm3s6965evb_machine); + qemu_register_machine(&connex_machine); diff --git a/meta/packages/qemu/qemu-native-0.9.1+cvs20080307/series b/meta/packages/qemu/qemu-native-0.9.1+cvs20080307/series index 9f6ca0cd5..126da8828 100644 --- a/meta/packages/qemu/qemu-native-0.9.1+cvs20080307/series +++ b/meta/packages/qemu/qemu-native-0.9.1+cvs20080307/series @@ -22,3 +22,4 @@ qemu-amd64-32b-mapping-0.9.0.patch -p1 workaround_bad_futex_headers.patch -p1 fix_segfault.patch -p1 no-strip.patch -p1 +qemu-n800-support.patch -p1 diff --git a/meta/packages/qemu/qemu_cvs.bb b/meta/packages/qemu/qemu_cvs.bb index 4af21f4a8..dd74aeee6 100644 --- a/meta/packages/qemu/qemu_cvs.bb +++ b/meta/packages/qemu/qemu_cvs.bb @@ -1,7 +1,7 @@ LICENSE = "GPL" DEPENDS = "zlib" PV = "0.9.1+cvs${SRCDATE}" -PR = "r1" +PR = "r2" DEFAULT_PREFERENCE = "-1" FILESDIR = "${WORKDIR}" @@ -31,7 +31,8 @@ SRC_URI = "\ file://qemu-amd64-32b-mapping-0.9.0.patch;patch=1 \ file://workaround_bad_futex_headers.patch;patch=1 \ file://fix_segfault.patch;patch=1 \ - file://no-strip.patch;patch=1" + file://no-strip.patch;patch=1 \ + file://qemu-n800-support.patch;patch=1" S = "${WORKDIR}/qemu" |