[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCHv2 1/2] sun4m: Add Sun CG3 framebuffer and corres
From: |
Peter Crosthwaite |
Subject: |
Re: [Qemu-devel] [PATCHv2 1/2] sun4m: Add Sun CG3 framebuffer and corresponding OpenBIOS FCode ROM |
Date: |
Sun, 9 Feb 2014 14:14:45 +1000 |
On Sun, Feb 9, 2014 at 2:38 AM, Mark Cave-Ayland
<address@hidden> wrote:
> 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 <address@hidden>
> CC: Blue Swirl <address@hidden>
> CC: Anthony Liguori <address@hidden>
> CC: Peter Maydell <address@hidden>
> CC: Bob Breuer <address@hidden>
> CC: Artyom Tarasenko <address@hidden>
> ---
> 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 -> 850 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 807054b..c3c7ccc 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -293,7 +293,7 @@ ifdef INSTALL_BLOBS
> BLOBS=bios.bin bios-256k.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
> +
With debug macros its better to use a regular if. Something like:
#ifndef DEBUG_CG3
#define DEBUG_CG3 0
#endif
#define DPRINTF(...) do { \
if (DEBUG_CG3) { \
printf(...) \
} \
} while (0);
The reason being your debug code will always be compile checked
allowing contributors to apply type changes without breaking your
debug code accidently.
> +#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:
What are these magic numbers? You should define macros matching the
names in your register specs.
> + val = s->regs[0];
Same for these hardcoded indicies into regs[].
> + 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;
Is this guest error or unimplemented behaviour? You should
qemu_log_mask( accordingly.
> + }
> + 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 */
Very strange. Is it not just a case of generic big-endian accessible
rather than just such a very specific exception here?
> + 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) {
Define macros for register field bits.
> + /* 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,
Your hander switch statements stride in 4, are you only doing this for
your one exception case of that one-byte big-endian access I commented
earlier.
> + },
> +};
> +
> +static const GraphicHwOps cg3_ops = {
> + .invalidate = cg3_invalidate_display,
> + .gfx_update = cg3_update_display,
> +};
> +
> +static int cg3_init1(SysBusDevice *dev)
Use of SysBusDevice::init functions is depracated. Please use object
init fns or Device::Realize functions instead.
Regards,
Peter
> +{
> + 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..6fec9462070bf9a0f88024c7bf66f444d1d11d61
> GIT binary patch
> literal 850
> zcmZ{i&2HL25XX10!NXT-76XB#Rk_y^s6|SoR%&la53Q7_>KX6`yTvxLO)GA>_ch=J
> zP_0Ed5~+vw1^OC&address@hidden|address@hidden<wjX;&#S`O9L)^D4_Nujb2jiXgca
> zPDC*9!r1=eIU=;bdQRdZo4=yUd6i|Ci{<)%MIyz_ir4;eaD_K=6J(UtR=nVdN#fcA
> zFNrruCp7i~VGm}B*rM#FYA_wy$!sE!rI=f#Xh;N$<uT(|S$=6UrZaVA++l5xwGGbi
> zu)fC(Rdr#9vwOTXDN4*eUYqPSqhX~xGG|XyEYsmuks~^k)Zx)xil*!=AoCkEsCJ<O
> zoLnnXbubf1(BxVqMqm=>vIAO|=luS}_JT~FP*rk6h2b=zc%GuQBB{~))address@hidden
> address@hidden>Ha6q}>address@hidden>Jz5ksB_3_=s6dTCOX4v$*W4J65;qbe1Ke=D
> address@hidden@nkk;p^!ZDR`PfpU9u9?JLjiUu4_oRe`bNojC4ddA
> z-NOJr!DrG6H~Nkfi8uxm4a5uZ+ZQly!#DLmP9;_lsVKMI5>-P{cC&R96e!56_1J6&
> zm}<Z|R2J&PbKMJ)NOcg^Z|U+yl{R+kL90s5Wj_qOB#i7>1hD{<>+03P;w8TyOmF(b
> yWEu%F;rYw!_h)ClbGu8)^3d%^loP5i*^VudTX8sz;xLL`?}lgvPvCTor|d5SYsmWm
>
> literal 0
> HcmV?d00001
>
> diff --git a/pc-bios/README b/pc-bios/README
> index f190068..af6250a 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 1246.
> + Sparc32 (including QEMU,tcx.bin and QEMU,cgthree.bin) and Sparc64 are built
> + from OpenBIOS SVN revision 1246.
>
> - 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
>
>
Re: [Qemu-devel] [PATCHv2 1/2] sun4m: Add Sun CG3 framebuffer and corresponding OpenBIOS FCode ROM, Peter Maydell, 2014/02/09
Re: [Qemu-devel] [PATCHv2 1/2] sun4m: Add Sun CG3 framebuffer and corresponding OpenBIOS FCode ROM, Andreas Färber, 2014/02/09