*/
#include "sysbus.h"
-#include "console.h"
+#include "ui/console.h"
#include "framebuffer.h"
+#include "ui/pixel_ops.h"
#define PL110_CR_EN 0x001
#define PL110_CR_BGR 0x100
typedef struct {
SysBusDevice busdev;
+ MemoryRegion iomem;
DisplayState *ds;
int version;
int rows;
enum pl110_bppmode bpp;
int invalidate;
- uint32_t pallette[256];
- uint32_t raw_pallette[128];
+ uint32_t mux_ctrl;
+ uint32_t palette[256];
+ uint32_t raw_palette[128];
qemu_irq irq;
} pl110_state;
+static int vmstate_pl110_post_load(void *opaque, int version_id);
+
static const VMStateDescription vmstate_pl110 = {
.name = "pl110",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
+ .post_load = vmstate_pl110_post_load,
.fields = (VMStateField[]) {
VMSTATE_INT32(version, pl110_state),
VMSTATE_UINT32_ARRAY(timing, pl110_state, 4),
VMSTATE_INT32(rows, pl110_state),
VMSTATE_UINT32(bpp, pl110_state),
VMSTATE_INT32(invalidate, pl110_state),
- VMSTATE_UINT32_ARRAY(pallette, pl110_state, 256),
- VMSTATE_UINT32_ARRAY(raw_pallette, pl110_state, 128),
+ VMSTATE_UINT32_ARRAY(palette, pl110_state, 256),
+ VMSTATE_UINT32_ARRAY(raw_palette, pl110_state, 128),
+ VMSTATE_UINT32_V(mux_ctrl, pl110_state, 2),
VMSTATE_END_OF_LIST()
}
};
pl111_id
};
-#include "pixel_ops.h"
-
#define BITS 8
#include "pl110_template.h"
#define BITS 15
* mux which allows bits to be reshuffled to give
* 565 format. The mux is typically controlled by
* an external system register.
- * This should be controlled by a GPIO input pin
+ * This is controlled by a GPIO input pin
* so boards can wire it up to their register.
- * For now, force 16 bit to be 565, to match
- * previous QEMU PL110 model behaviour.
*
* The PL111 straightforwardly implements both
* 5551 and 565 under control of the bpp field
* in the LCDControl register.
*/
- bpp_offset += (BPP_16_565 - BPP_16);
+ switch (s->mux_ctrl) {
+ case 3: /* 565 BGR */
+ bpp_offset = (BPP_16_565 - BPP_16);
+ break;
+ case 1: /* 5551 */
+ break;
+ case 0: /* 888; also if we have loaded vmstate from an old version */
+ case 2: /* 565 RGB */
+ default:
+ /* treat as 565 but honour BGR bit */
+ bpp_offset += (BPP_16_565 - BPP_16);
+ break;
+ }
}
if (s->cr & PL110_CR_BEBO)
}
dest_width *= s->cols;
first = 0;
- framebuffer_update_display(s->ds,
+ framebuffer_update_display(s->ds, sysbus_address_space(&s->busdev),
s->upbase, s->cols, s->rows,
src_width, dest_width, 0,
s->invalidate,
- fn, s->pallette,
+ fn, s->palette,
&first, &last);
if (first >= 0) {
- dpy_update(s->ds, 0, first, s->cols, last - first + 1);
+ dpy_gfx_update(s->ds, 0, first, s->cols, last - first + 1);
}
s->invalidate = 0;
}
}
}
-static void pl110_update_pallette(pl110_state *s, int n)
+static void pl110_update_palette(pl110_state *s, int n)
{
int i;
uint32_t raw;
unsigned int r, g, b;
- raw = s->raw_pallette[n];
+ raw = s->raw_palette[n];
n <<= 1;
for (i = 0; i < 2; i++) {
r = (raw & 0x1f) << 3;
raw >>= 6;
switch (ds_get_bits_per_pixel(s->ds)) {
case 8:
- s->pallette[n] = rgb_to_pixel8(r, g, b);
+ s->palette[n] = rgb_to_pixel8(r, g, b);
break;
case 15:
- s->pallette[n] = rgb_to_pixel15(r, g, b);
+ s->palette[n] = rgb_to_pixel15(r, g, b);
break;
case 16:
- s->pallette[n] = rgb_to_pixel16(r, g, b);
+ s->palette[n] = rgb_to_pixel16(r, g, b);
break;
case 24:
case 32:
- s->pallette[n] = rgb_to_pixel32(r, g, b);
+ s->palette[n] = rgb_to_pixel32(r, g, b);
break;
}
n++;
/* TODO: Implement interrupts. */
}
-static uint32_t pl110_read(void *opaque, target_phys_addr_t offset)
+static uint64_t pl110_read(void *opaque, hwaddr offset,
+ unsigned size)
{
pl110_state *s = (pl110_state *)opaque;
return idregs[s->version][(offset - 0xfe0) >> 2];
}
if (offset >= 0x200 && offset < 0x400) {
- return s->raw_pallette[(offset - 0x200) >> 2];
+ return s->raw_palette[(offset - 0x200) >> 2];
}
switch (offset >> 2) {
case 0: /* LCDTiming0 */
case 12: /* LCDLPCURR */
return s->lpbase;
default:
- hw_error("pl110_read: Bad offset %x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "pl110_read: Bad offset %x\n", (int)offset);
return 0;
}
}
-static void pl110_write(void *opaque, target_phys_addr_t offset,
- uint32_t val)
+static void pl110_write(void *opaque, hwaddr offset,
+ uint64_t val, unsigned size)
{
pl110_state *s = (pl110_state *)opaque;
int n;
/* For simplicity invalidate the display whenever a control register
- is writen to. */
+ is written to. */
s->invalidate = 1;
if (offset >= 0x200 && offset < 0x400) {
- /* Pallette. */
+ /* Palette. */
n = (offset - 0x200) >> 2;
- s->raw_pallette[(offset - 0x200) >> 2] = val;
- pl110_update_pallette(s, n);
+ s->raw_palette[(offset - 0x200) >> 2] = val;
+ pl110_update_palette(s, n);
return;
}
switch (offset >> 2) {
pl110_update(s);
break;
default:
- hw_error("pl110_write: Bad offset %x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "pl110_write: Bad offset %x\n", (int)offset);
}
}
-static CPUReadMemoryFunc * const pl110_readfn[] = {
- pl110_read,
- pl110_read,
- pl110_read
+static const MemoryRegionOps pl110_ops = {
+ .read = pl110_read,
+ .write = pl110_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
-static CPUWriteMemoryFunc * const pl110_writefn[] = {
- pl110_write,
- pl110_write,
- pl110_write
-};
+static void pl110_mux_ctrl_set(void *opaque, int line, int level)
+{
+ pl110_state *s = (pl110_state *)opaque;
+ s->mux_ctrl = level;
+}
+
+static int vmstate_pl110_post_load(void *opaque, int version_id)
+{
+ pl110_state *s = opaque;
+ /* Make sure we redraw, and at the right size */
+ pl110_invalidate_display(s);
+ return 0;
+}
static int pl110_init(SysBusDevice *dev)
{
pl110_state *s = FROM_SYSBUS(pl110_state, dev);
- int iomemtype;
- iomemtype = cpu_register_io_memory(pl110_readfn,
- pl110_writefn, s,
- DEVICE_NATIVE_ENDIAN);
- sysbus_init_mmio(dev, 0x1000, iomemtype);
+ memory_region_init_io(&s->iomem, &pl110_ops, s, "pl110", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
+ qdev_init_gpio_in(&s->busdev.qdev, pl110_mux_ctrl_set, 1);
s->ds = graphic_console_init(pl110_update_display,
pl110_invalidate_display,
NULL, NULL, s);
return pl110_init(dev);
}
-static SysBusDeviceInfo pl110_info = {
- .init = pl110_init,
- .qdev.name = "pl110",
- .qdev.size = sizeof(pl110_state),
- .qdev.vmsd = &vmstate_pl110,
- .qdev.no_user = 1,
+static void pl110_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl110_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl110_info = {
+ .name = "pl110",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl110_state),
+ .class_init = pl110_class_init,
};
-static SysBusDeviceInfo pl110_versatile_info = {
- .init = pl110_versatile_init,
- .qdev.name = "pl110_versatile",
- .qdev.size = sizeof(pl110_state),
- .qdev.vmsd = &vmstate_pl110,
- .qdev.no_user = 1,
+static void pl110_versatile_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl110_versatile_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl110_versatile_info = {
+ .name = "pl110_versatile",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl110_state),
+ .class_init = pl110_versatile_class_init,
};
-static SysBusDeviceInfo pl111_info = {
- .init = pl111_init,
- .qdev.name = "pl111",
- .qdev.size = sizeof(pl110_state),
- .qdev.vmsd = &vmstate_pl110,
- .qdev.no_user = 1,
+static void pl111_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl111_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl111_info = {
+ .name = "pl111",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl110_state),
+ .class_init = pl111_class_init,
};
-static void pl110_register_devices(void)
+static void pl110_register_types(void)
{
- sysbus_register_withprop(&pl110_info);
- sysbus_register_withprop(&pl110_versatile_info);
- sysbus_register_withprop(&pl111_info);
+ type_register_static(&pl110_info);
+ type_register_static(&pl110_versatile_info);
+ type_register_static(&pl111_info);
}
-device_init(pl110_register_devices)
+type_init(pl110_register_types)