From 64b40bc54a92beb5958e78c915629bbe4a9bc28c Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 4 Nov 2008 09:04:41 +0000 Subject: [PATCH] tc6393xb: non-accelerated FB support (Dmitry Baryshkov). Signed-off-by: Dmitry Baryshkov Signed-off-by: Andrzej Zaborowski git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5617 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/devices.h | 4 +- hw/tc6393xb.c | 122 ++++++++++++++++++++++++++++++++++++++++- hw/tc6393xb_template.h | 72 ++++++++++++++++++++++++ hw/tosa.c | 17 ++++-- 4 files changed, 207 insertions(+), 8 deletions(-) create mode 100644 hw/tc6393xb_template.h diff --git a/hw/devices.h b/hw/devices.h index 45fead9c27..9572a63337 100644 --- a/hw/devices.h +++ b/hw/devices.h @@ -66,9 +66,11 @@ void tusb6010_power(struct tusb_s *s, int on); /* tc6393xb.c */ struct tc6393xb_s; -struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq); +#define TC6393XB_RAM 0x110000 /* amount of ram for Video and USB */ +struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq, DisplayState *ds); void tc6393xb_gpio_out_set(struct tc6393xb_s *s, int line, qemu_irq handler); qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s); +qemu_irq tc6393xb_l3v_get(struct tc6393xb_s *s); #endif diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index fa10557f5a..1fe57bd769 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -11,6 +11,8 @@ #include "pxa.h" #include "devices.h" #include "flash.h" +#include "console.h" +#include "pixel_ops.h" #define IRQ_TC6393_NAND 0 #define IRQ_TC6393_MMC 1 @@ -119,6 +121,14 @@ struct tc6393xb_s { uint32_t nand_phys; struct nand_flash_s *flash; struct ecc_state_s ecc; + + DisplayState *ds; + QEMUConsole *console; + ram_addr_t vram_addr; + uint32_t scr_width, scr_height; /* in pixels */ + qemu_irq l3v; + unsigned blank : 1, + blanked : 1; }; qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s) @@ -164,6 +174,18 @@ static void tc6393xb_gpio_handler_update(struct tc6393xb_s *s) s->prev_level = level; } +qemu_irq tc6393xb_l3v_get(struct tc6393xb_s *s) +{ + return s->l3v; +} + +static void tc6393xb_l3v(void *opaque, int line, int level) +{ + struct tc6393xb_s *s = opaque; + s->blank = !level; + fprintf(stderr, "L3V: %d\n", level); +} + static void tc6393xb_sub_irq(void *opaque, int line, int level) { struct tc6393xb_s *s = opaque; uint8_t isr = s->scr.ISR; @@ -395,6 +417,85 @@ static void tc6393xb_nand_writeb(struct tc6393xb_s *s, target_phys_addr_t addr, (uint32_t) addr, value & 0xff); } +#define BITS 8 +#include "tc6393xb_template.h" +#define BITS 15 +#include "tc6393xb_template.h" +#define BITS 16 +#include "tc6393xb_template.h" +#define BITS 24 +#include "tc6393xb_template.h" +#define BITS 32 +#include "tc6393xb_template.h" + +static void tc6393xb_draw_graphic(struct tc6393xb_s *s, int full_update) +{ + switch (s->ds->depth) { + case 8: + tc6393xb_draw_graphic8(s); + break; + case 15: + tc6393xb_draw_graphic15(s); + break; + case 16: + tc6393xb_draw_graphic16(s); + break; + case 24: + tc6393xb_draw_graphic24(s); + break; + case 32: + tc6393xb_draw_graphic32(s); + break; + default: + printf("tc6393xb: unknown depth %d\n", s->ds->depth); + return; + } + + dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); +} + +static void tc6393xb_draw_blank(struct tc6393xb_s *s, int full_update) +{ + int i, w; + uint8_t *d; + + if (!full_update) + return; + + w = s->scr_width * ((s->ds->depth + 7) >> 3); + d = s->ds->data; + for(i = 0; i < s->scr_height; i++) { + memset(d, 0, w); + d += s->ds->linesize; + } + + dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); +} + +static void tc6393xb_update_display(void *opaque) +{ + struct tc6393xb_s *s = opaque; + int full_update; + + if (s->scr_width == 0 || s->scr_height == 0) + return; + + full_update = 0; + if (s->blanked != s->blank) { + s->blanked = s->blank; + full_update = 1; + } + if (s->scr_width != s->ds->width || s->scr_height != s->ds->height) { + qemu_console_resize(s->console, s->scr_width, s->scr_height); + full_update = 1; + } + if (s->blanked) + tc6393xb_draw_blank(s, full_update); + else + tc6393xb_draw_graphic(s, full_update); +} + + static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) { struct tc6393xb_s *s = opaque; addr -= s->target_base; @@ -465,7 +566,7 @@ static void tc6393xb_writel(void *opaque, target_phys_addr_t addr, uint32_t valu tc6393xb_writeb(opaque, addr + 3, value >> 24); } -struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq) +struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq, DisplayState *ds) { int iomemtype; struct tc6393xb_s *s; @@ -485,13 +586,30 @@ struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq) s->irq = irq; s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS); + s->l3v = *qemu_allocate_irqs(tc6393xb_l3v, s, 1); + s->blanked = 1; + s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS); s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76); iomemtype = cpu_register_io_memory(0, tc6393xb_readfn, tc6393xb_writefn, s); - cpu_register_physical_memory(s->target_base, 0x200000, iomemtype); + cpu_register_physical_memory(s->target_base, 0x10000, iomemtype); + + if (ds) { + s->ds = ds; + s->vram_addr = qemu_ram_alloc(0x100000); + cpu_register_physical_memory(s->target_base + 0x100000, 0x100000, s->vram_addr); + s->scr_width = 480; + s->scr_height = 640; + s->console = graphic_console_init(ds, + tc6393xb_update_display, + NULL, /* invalidate */ + NULL, /* screen_dump */ + NULL, /* text_update */ + s); + } return s; } diff --git a/hw/tc6393xb_template.h b/hw/tc6393xb_template.h new file mode 100644 index 0000000000..e882c98a07 --- /dev/null +++ b/hw/tc6393xb_template.h @@ -0,0 +1,72 @@ +/* + * Toshiba TC6393XB I/O Controller. + * Found in Sharp Zaurus SL-6000 (tosa) or some + * Toshiba e-Series PDAs. + * + * FB support code. Based on G364 fb emulator + * + * Copyright (c) 2007 Hervé Poussineau + * + * 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 + */ + +#if BITS == 8 +# define SET_PIXEL(addr, color) *(uint8_t*)addr = color; +#elif BITS == 15 || BITS == 16 +# define SET_PIXEL(addr, color) *(uint16_t*)addr = color; +#elif BITS == 24 +# define SET_PIXEL(addr, color) \ + addr[0] = color; addr[1] = (color) >> 8; addr[2] = (color) >> 16; +#elif BITS == 32 +# define SET_PIXEL(addr, color) *(uint32_t*)addr = color; +#else +# error unknown bit depth +#endif + + +static void glue(tc6393xb_draw_graphic, BITS)(struct tc6393xb_s *s) +{ + int i; + int w_display; + uint16_t *data_buffer; + uint8_t *data_display; + + data_buffer = (uint16_t*)(phys_ram_base + s->vram_addr); + w_display = s->scr_width * BITS / 8; + data_display = s->ds->data; + for(i = 0; i < s->scr_height; i++) { +#if (BITS == 16) + memcpy(data_display, data_buffer, s->scr_width * 2); + data_buffer += s->scr_width; + data_display += s->ds->linesize; +#else + int j; + for (j = 0; j < s->scr_width; j++, data_display += BITS / 8, data_buffer++) { + uint16_t color = *data_buffer; + uint32_t dest_color = glue(rgb_to_pixel, BITS)( + ((color & 0xf800) * 0x108) >> 11, + ((color & 0x7e0) * 0x41) >> 9, + ((color & 0x1f) * 0x21) >> 2 + ); + SET_PIXEL(data_display, dest_color); + } +#endif + } +} + +#undef BITS +#undef SET_PIXEL + diff --git a/hw/tosa.c b/hw/tosa.c index 144685adcb..effba4246a 100644 --- a/hw/tosa.c +++ b/hw/tosa.c @@ -38,6 +38,7 @@ #define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0) #define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1) #define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2) +#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5) #define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7) #define DAC_BASE 0x4e @@ -84,7 +85,8 @@ static void tosa_out_switch(void *opaque, int line, int level) static void tosa_gpio_setup(struct pxa2xx_state_s *cpu, struct scoop_info_s *scp0, - struct scoop_info_s *scp1) + struct scoop_info_s *scp1, + struct tc6393xb_s *tmio) { qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4); /* MMC/SD host */ @@ -108,6 +110,8 @@ static void tosa_gpio_setup(struct pxa2xx_state_s *cpu, scoop_gpio_out_set(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]); scoop_gpio_out_set(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]); scoop_gpio_out_set(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]); + + scoop_gpio_out_set(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio)); } static uint32_t tosa_ssp_read(void *opaque) @@ -198,9 +202,10 @@ static void tosa_init(ram_addr_t ram_size, int vga_ram_size, const char *initrd_filename, const char *cpu_model) { struct pxa2xx_state_s *cpu; + struct tc6393xb_s *tmio; struct scoop_info_s *scp0, *scp1; - if (ram_size < (TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE)) { + if (ram_size < (TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE + TC6393XB_RAM)) { fprintf(stderr, "This platform requires %i bytes of memory\n", TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE); exit(1); @@ -214,12 +219,14 @@ static void tosa_init(ram_addr_t ram_size, int vga_ram_size, cpu_register_physical_memory(0, TOSA_ROM, qemu_ram_alloc(TOSA_ROM) | IO_MEM_ROM); - tc6393xb_init(0x10000000, pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_TC6393XB_INT]); + tmio = tc6393xb_init(0x10000000, + pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_TC6393XB_INT], + ds); scp0 = scoop_init(cpu, 0, 0x08800000); scp1 = scoop_init(cpu, 1, 0x14800040); - tosa_gpio_setup(cpu, scp0, scp1); + tosa_gpio_setup(cpu, scp0, scp1, tmio); tosa_microdrive_attach(cpu); @@ -240,5 +247,5 @@ QEMUMachine tosapda_machine = { .name = "tosa", .desc = "Tosa PDA (PXA255)", .init = tosa_init, - .ram_require = TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED, + .ram_require = TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED + TC6393XB_RAM, };