From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41463) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VrXVq-000546-0E for qemu-devel@nongnu.org; Fri, 13 Dec 2013 13:31:03 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VrXVk-0007ue-EP for qemu-devel@nongnu.org; Fri, 13 Dec 2013 13:30:57 -0500 Received: from s16892447.onlinehome-server.info ([82.165.15.123]:43196) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VrXVj-0007uW-V9 for qemu-devel@nongnu.org; Fri, 13 Dec 2013 13:30:52 -0500 From: Mark Cave-Ayland Date: Fri, 13 Dec 2013 18:27:47 +0000 Message-Id: <1386959268-1335-2-git-send-email-mark.cave-ayland@ilande.co.uk> In-Reply-To: <1386959268-1335-1-git-send-email-mark.cave-ayland@ilande.co.uk> References: <1386959268-1335-1-git-send-email-mark.cave-ayland@ilande.co.uk> Subject: [Qemu-devel] [PATCH 1/2] sun4m: Add Sun CG3 framebuffer and corresponding OpenBIOS FCode ROM List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Blue Swirl , Bob Breuer , Mark Cave-Ayland , Artyom Tarasenko , Anthony Liguori The CG3 framebuffer is a simple 8-bit framebuffer for use with operating systems such as early Solaris that do not have drivers for TCX. Signed-off-by: Mark Cave-Ayland CC: Blue Swirl CC: Anthony Liguori CC: Bob Breuer CC: Artyom Tarasenko --- Makefile | 2 +- default-configs/sparc-softmmu.mak | 1 + hw/display/Makefile.objs | 1 + hw/display/cg3.c | 358 +++++++++++++++++++++++++++++++++++++ pc-bios/QEMU,cgthree.bin | Bin 0 -> 682 bytes pc-bios/README | 4 +- 6 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 hw/display/cg3.c create mode 100644 pc-bios/QEMU,cgthree.bin diff --git a/Makefile b/Makefile index bdff4e4..f5d0f55 100644 --- a/Makefile +++ b/Makefile @@ -293,7 +293,7 @@ ifdef INSTALL_BLOBS BLOBS=bios.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \ vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \ acpi-dsdt.aml q35-acpi-dsdt.aml \ -ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin \ +ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \ efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \ diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak index 8fc93dd..ab796b3 100644 --- a/default-configs/sparc-softmmu.mak +++ b/default-configs/sparc-softmmu.mak @@ -10,6 +10,7 @@ CONFIG_EMPTY_SLOT=y CONFIG_PCNET_COMMON=y CONFIG_LANCE=y CONFIG_TCX=y +CONFIG_CG3=y CONFIG_SLAVIO=y CONFIG_CS4231=y CONFIG_GRLIB=y diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 540df82..7ed76a9 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -28,6 +28,7 @@ obj-$(CONFIG_OMAP) += omap_lcdc.o obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o obj-$(CONFIG_SM501) += sm501.o obj-$(CONFIG_TCX) += tcx.o +obj-$(CONFIG_CG3) += cg3.o obj-$(CONFIG_VGA) += vga.o diff --git a/hw/display/cg3.c b/hw/display/cg3.c new file mode 100644 index 0000000..3e96356 --- /dev/null +++ b/hw/display/cg3.c @@ -0,0 +1,358 @@ +/* + * QEMU CG3 Frame buffer + * + * Copyright (c) 2012 Bob Breuer + * Copyright (c) 2013 Mark Cave-Ayland + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu-common.h" +#include "ui/console.h" +#include "hw/sysbus.h" +#include "hw/loader.h" + +/* #define DEBUG_CG3 */ + +#define CG3_ROM_FILE "QEMU,cgthree.bin" +#define FCODE_MAX_ROM_SIZE 0x10000 + +#define CG3_REG_SIZE 0x20 +#define CG3_VRAM_SIZE 0x100000 +#define CG3_VRAM_OFFSET 0x800000 + +#ifdef DEBUG_CG3 +#define DPRINTF(fmt, ...) \ + printf("CG3: " fmt , ## __VA_ARGS__) +#else +#define DPRINTF(fmt, ...) +#endif + +#define TYPE_CG3 "SUNW,cgthree" +#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3) + +typedef struct CG3State { + SysBusDevice parent_obj; + + QemuConsole *con; + qemu_irq irq; + hwaddr prom_addr; + MemoryRegion vram_mem; + MemoryRegion rom; + MemoryRegion reg; + uint32_t vram_size; + int full_update; + uint8_t regs[16]; + uint8_t r[256], g[256], b[256]; + uint16_t width, height, depth; + uint8_t dac_index, dac_state; +} CG3State; + +static void cg3_update_display(void *opaque) +{ + CG3State *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); + const uint8_t *pix; + uint32_t *data; + uint32_t dval; + int x, y, y_start; + unsigned int width, height; + ram_addr_t page, page_min, page_max; + + if (surface_bits_per_pixel(surface) != 32) { + return; + } + width = s->width; + height = s->height; + + y_start = -1; + page_min = -1; + page_max = 0; + page = 0; + pix = memory_region_get_ram_ptr(&s->vram_mem); + data = (uint32_t *)surface_data(surface); + + for (y = 0; y < height; y++) { + int update = s->full_update; + + page = (y * width) & TARGET_PAGE_MASK; + update |= memory_region_get_dirty(&s->vram_mem, page, page + width, + DIRTY_MEMORY_VGA); + if (update) { + if (y_start < 0) { + y_start = y; + } + if (page < page_min) { + page_min = page; + } + if (page > page_max) { + page_max = page; + } + + for (x = 0; x < width; x++) { + dval = *pix++; + dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval]; + *data++ = dval; + } + } else { + if (y_start >= 0) { + dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start); + y_start = -1; + } + pix += width; + data += width; + } + } + s->full_update = 0; + if (y_start >= 0) { + dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start); + } + if (page_max >= page_min) { + memory_region_reset_dirty(&s->vram_mem, + page_min, page_max - page_min + TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + } + /* vsync interrupt? */ + if (s->regs[0] & 0x80) { + s->regs[1] |= 0x80; + qemu_irq_raise(s->irq); + } +} + +static void cg3_invalidate_display(void *opaque) +{ + CG3State *s = opaque; + + memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE); +} + +static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size) +{ + CG3State *s = opaque; + int val; + + switch (addr) { + case 0x10: + val = s->regs[0]; + break; + case 0x11: + val = s->regs[1] | 0x71; /* monitor ID 7, board type = 1 (color) */ + break; + case 0x12 ... 0x1f: + val = s->regs[addr - 0x10]; + break; + default: + val = 0; + break; + } + DPRINTF("read %02x from reg %x\n", val, (int)addr); + return val; +} + +static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + CG3State *s = opaque; + uint8_t regval; + int i; + + DPRINTF("write %02lx to reg %x size %d\n", val, (int)addr, size); + + switch (addr) { + case 0: + s->dac_index = val; + s->dac_state = 0; + break; + case 4: + /* This register can be written to as either a long word or a byte. + * According to the SBus specification, byte transfers are placed + * in bits 31-28 */ + if (size == 1) { + val <<= 24; + } + + for (i = 0; i < size; i++) { + regval = val >> 24; + + switch (s->dac_state) { + case 0: + s->r[s->dac_index] = regval; + s->dac_state++; + break; + case 1: + s->g[s->dac_index] = regval; + s->dac_state++; + break; + case 2: + s->b[s->dac_index] = regval; + /* Index autoincrement */ + s->dac_index = (s->dac_index + 1) & 255; + default: + s->dac_state = 0; + break; + } + val <<= 8; + } + s->full_update = 1; + break; + case 0x10: + s->regs[0] = val; + break; + case 0x11: + if (s->regs[1] & 0x80) { + /* clear interrupt */ + s->regs[1] &= ~0x80; + qemu_irq_lower(s->irq); + } + break; + case 0x12 ... 0x1f: + s->regs[addr - 0x10] = val; + break; + default: + break; + } +} + +static const MemoryRegionOps cg3_reg_ops = { + .read = cg3_reg_read, + .write = cg3_reg_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + +static const GraphicHwOps cg3_ops = { + .invalidate = cg3_invalidate_display, + .gfx_update = cg3_update_display, +}; + +static int cg3_init1(SysBusDevice *dev) +{ + CG3State *s = CG3(dev); + int ret; + char *fcode_filename; + + /* FCode ROM */ + memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE); + vmstate_register_ram_global(&s->rom); + memory_region_set_readonly(&s->rom, true); + sysbus_init_mmio(dev, &s->rom); + + fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE); + if (fcode_filename) { + ret = load_image_targphys(fcode_filename, s->prom_addr, + FCODE_MAX_ROM_SIZE); + if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { + fprintf(stderr, "cg3: could not load prom '%s'\n", CG3_ROM_FILE); + return -1; + } + } + + memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg", + CG3_REG_SIZE); + sysbus_init_mmio(dev, &s->reg); + + memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size); + vmstate_register_ram_global(&s->vram_mem); + sysbus_init_mmio(dev, &s->vram_mem); + + sysbus_init_irq(dev, &s->irq); + + s->con = graphic_console_init(DEVICE(dev), &cg3_ops, s); + qemu_console_resize(s->con, s->width, s->height); + + return 0; +} + +static int vmstate_cg3_post_load(void *opaque, int version_id) +{ + CG3State *s = opaque; + + cg3_invalidate_display(s); + + return 0; +} + +static const VMStateDescription vmstate_cg3 = { + .name = "cg3", + .version_id = 1, + .minimum_version_id = 1, + .post_load = vmstate_cg3_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT16(height, CG3State), + VMSTATE_UINT16(width, CG3State), + VMSTATE_UINT16(depth, CG3State), + VMSTATE_BUFFER(r, CG3State), + VMSTATE_BUFFER(g, CG3State), + VMSTATE_BUFFER(b, CG3State), + VMSTATE_UINT8(dac_index, CG3State), + VMSTATE_UINT8(dac_state, CG3State), + VMSTATE_END_OF_LIST() + } +}; + +static void cg3_reset(DeviceState *d) +{ + CG3State *s = CG3(d); + + /* Initialize palette */ + memset(s->r, 0, 256); + memset(s->g, 0, 256); + memset(s->b, 0, 256); + + s->dac_state = 0; + s->full_update = 1; + qemu_irq_lower(s->irq); +} + +static Property cg3_properties[] = { + DEFINE_PROP_HEX32("vram_size", CG3State, vram_size, -1), + DEFINE_PROP_UINT16("width", CG3State, width, -1), + DEFINE_PROP_UINT16("height", CG3State, height, -1), + DEFINE_PROP_UINT16("depth", CG3State, depth, -1), + DEFINE_PROP_HEX64("prom_addr", CG3State, prom_addr, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void cg3_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = cg3_init1; + dc->reset = cg3_reset; + dc->vmsd = &vmstate_cg3; + dc->props = cg3_properties; +} + +static const TypeInfo cg3_info = { + .name = TYPE_CG3, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(CG3State), + .class_init = cg3_class_init, +}; + +static void cg3_register_types(void) +{ + type_register_static(&cg3_info); +} + +type_init(cg3_register_types) diff --git a/pc-bios/QEMU,cgthree.bin b/pc-bios/QEMU,cgthree.bin new file mode 100644 index 0000000000000000000000000000000000000000..e2ecfc6f34edace2d39b411454768cd3a1366e71 GIT binary patch literal 682 zcmZ8e&2G~`5Z+0gc-$n^UOTi&0g*FU#DYkz#DQbW0S*=7?8MvHkl2xbK)LnKYb2K* zBUu~u=-%K3cn#iwS?2_onfbn%Z)SGq58l0EtZ`Q&lfN9MzqVOxx7k(PNme4BMoH#= zivp3j-=iQ8k%8Sfzs-#X)$;6 z^-3Tsv9&L;EfJPgiMqsw@+h&XydhCj{zzi$X=So^j0Bx~lQH(Z#4ZK5is@0%Rl%eC z5|8D03yt5<1lt1(ILS?^6wCxNc+8urn1e~YCCAY8czfxu+$e4sL~+S=1(PBtyeZM% zlW}OrzC`<3QT=Ssl0}k^@Uh%t|LVQ!tYQCOM~zM-cCd@q1KNa6CHCqa72yyuka&Wp z71w9;JWPdX0M~;kTP^%G40-SR(}&M5Cu7g`-gpxjlsKg6o3{>ofdh0NUX)z_UBY4nKXx?aOrnW86}1m{QZw@l(FPf|A%aVEgznpzwj-d*}}apTYOA{Eqx8&}sK p&(9|pu1Cq#38l*qW4qL?Gb_?8NwYAzA=bhnJgM-E{ROoYtgZk6 literal 0 HcmV?d00001 diff --git a/pc-bios/README b/pc-bios/README index a110125..d6a62b1 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -11,8 +11,8 @@ firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. The included images for PowerPC (for 32 and 64 bit PPC CPUs), - Sparc32 (including QEMU,tcx.bin) and Sparc64 are built from OpenBIOS SVN - revision 1229. + Sparc32 (including QEMU,tcx.bin and QEMU,cgthree.bin) and Sparc64 are built + from OpenBIOS SVN revision 1229. - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at -- 1.7.10.4