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 | |
| parent | 37ddd0087fac5868851113d3d7b11c262653f782 (diff) | |
| download | openembedded-core-5091c0bd8842b2a5f94e47c391dc6fe73eac8901.tar.gz openembedded-core-5091c0bd8842b2a5f94e47c391dc6fe73eac8901.tar.bz2 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
| -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 0000000000..b1b6649efc --- /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 & |
