From cdef10bb9373c2c22c517a4deef2363c7ebd5d48 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:56 +0000 Subject: hw/vexpress: Pass proc_id via VEDBoardInfo Pass the daughterboard-specific proc_id property to the code that creates the sysctl device via the VEDBoardInfo struct, rather than by having the daughterboard init function write to a uint32_t* argument. This is a cleaner way to pass the info around, and is in line with the way we are going to handle voltage and oscillator initialization. Signed-off-by: Peter Maydell --- hw/arm/vexpress.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'hw') diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 02922c3..47a844f 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -147,19 +147,20 @@ typedef struct VEDBoardInfo VEDBoardInfo; typedef void DBoardInitFn(const VEDBoardInfo *daughterboard, ram_addr_t ram_size, const char *cpu_model, - qemu_irq *pic, uint32_t *proc_id); + qemu_irq *pic); struct VEDBoardInfo { const hwaddr *motherboard_map; hwaddr loader_start; const hwaddr gic_cpu_if_addr; + uint32_t proc_id; DBoardInitFn *init; }; static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, ram_addr_t ram_size, const char *cpu_model, - qemu_irq *pic, uint32_t *proc_id) + qemu_irq *pic) { MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -175,8 +176,6 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, cpu_model = "cortex-a9"; } - *proc_id = 0x0c000191; - for (n = 0; n < smp_cpus; n++) { ARMCPU *cpu = cpu_arm_init(cpu_model); if (!cpu) { @@ -251,13 +250,14 @@ static const VEDBoardInfo a9_daughterboard = { .motherboard_map = motherboard_legacy_map, .loader_start = 0x60000000, .gic_cpu_if_addr = 0x1e000100, + .proc_id = 0x0c000191, .init = a9_daughterboard_init, }; static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, ram_addr_t ram_size, const char *cpu_model, - qemu_irq *pic, uint32_t *proc_id) + qemu_irq *pic) { int n; MemoryRegion *sysmem = get_system_memory(); @@ -271,8 +271,6 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, cpu_model = "cortex-a15"; } - *proc_id = 0x14000237; - for (n = 0; n < smp_cpus; n++) { ARMCPU *cpu; qemu_irq *irqp; @@ -344,6 +342,7 @@ static const VEDBoardInfo a15_daughterboard = { .motherboard_map = motherboard_aseries_map, .loader_start = 0x80000000, .gic_cpu_if_addr = 0x2c002000, + .proc_id = 0x14000237, .init = a15_daughterboard_init, }; @@ -352,7 +351,6 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, { DeviceState *dev, *sysctl, *pl041; qemu_irq pic[64]; - uint32_t proc_id; uint32_t sys_id; DriveInfo *dinfo; ram_addr_t vram_size, sram_size; @@ -361,8 +359,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, MemoryRegion *sram = g_new(MemoryRegion, 1); const hwaddr *map = daughterboard->motherboard_map; - daughterboard->init(daughterboard, args->ram_size, args->cpu_model, - pic, &proc_id); + daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic); /* Motherboard peripherals: the wiring is the same but the * addresses vary between the legacy and A-Series memory maps. @@ -372,7 +369,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, sysctl = qdev_create(NULL, "realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", sys_id); - qdev_prop_set_uint32(sysctl, "proc_id", proc_id); + qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id); qdev_init_nofail(sysctl); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); -- cgit v1.1 From 71538323358d77f6472d66a30e948a1c23bd9e87 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:56 +0000 Subject: hw/arm_sysctl: Handle SYS_CFGCTRL in a more structured way The SYS_CFGCTRL register consists of separate fields for DCC, function, site, position and device, as well as a read/write bit. Refactor the code handling SYS_CFGCTRL writes to make it easier to add support for functions like SYS_CFG_OSC which support multiple device fields. We also pull the handling out into its own function for clarity, as there are potentially a lot of implementable subfunctions. Signed-off-by: Peter Maydell --- hw/arm_sysctl.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 132 insertions(+), 11 deletions(-) (limited to 'hw') diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index a46f8d4..05a3200 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -9,6 +9,7 @@ #include "hw/hw.h" #include "qemu/timer.h" +#include "qemu/bitops.h" #include "hw/sysbus.h" #include "hw/primecell.h" #include "sysemu/sysemu.h" @@ -191,6 +192,110 @@ static uint64_t arm_sysctl_read(void *opaque, hwaddr offset, } } +/* SYS_CFGCTRL functions */ +#define SYS_CFG_OSC 1 +#define SYS_CFG_VOLT 2 +#define SYS_CFG_AMP 3 +#define SYS_CFG_TEMP 4 +#define SYS_CFG_RESET 5 +#define SYS_CFG_SCC 6 +#define SYS_CFG_MUXFPGA 7 +#define SYS_CFG_SHUTDOWN 8 +#define SYS_CFG_REBOOT 9 +#define SYS_CFG_DVIMODE 11 +#define SYS_CFG_POWER 12 +#define SYS_CFG_ENERGY 13 + +/* SYS_CFGCTRL site field values */ +#define SYS_CFG_SITE_MB 0 +#define SYS_CFG_SITE_DB1 1 +#define SYS_CFG_SITE_DB2 2 + +/** + * vexpress_cfgctrl_read: + * @s: arm_sysctl_state pointer + * @dcc, @function, @site, @position, @device: split out values from + * SYS_CFGCTRL register + * @val: pointer to where to put the read data on success + * + * Handle a VExpress SYS_CFGCTRL register read. On success, return true and + * write the read value to *val. On failure, return false (and val may + * or may not be written to). + */ +static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc, + unsigned int function, unsigned int site, + unsigned int position, unsigned int device, + uint32_t *val) +{ + /* We don't support anything other than DCC 0, board stack position 0 + * or sites other than motherboard/daughterboard: + */ + if (dcc != 0 || position != 0 || + (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { + goto cfgctrl_unimp; + } + + switch (function) { + default: + break; + } + +cfgctrl_unimp: + qemu_log_mask(LOG_UNIMP, + "arm_sysctl: Unimplemented SYS_CFGCTRL read of function " + "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", + function, dcc, site, position, device); + return false; +} + +/** + * vexpress_cfgctrl_write: + * @s: arm_sysctl_state pointer + * @dcc, @function, @site, @position, @device: split out values from + * SYS_CFGCTRL register + * @val: data to write + * + * Handle a VExpress SYS_CFGCTRL register write. On success, return true. + * On failure, return false. + */ +static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, + unsigned int function, unsigned int site, + unsigned int position, unsigned int device, + uint32_t val) +{ + /* We don't support anything other than DCC 0, board stack position 0 + * or sites other than motherboard/daughterboard: + */ + if (dcc != 0 || position != 0 || + (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { + goto cfgctrl_unimp; + } + + switch (function) { + case SYS_CFG_SHUTDOWN: + if (site == SYS_CFG_SITE_MB && device == 0) { + qemu_system_shutdown_request(); + return true; + } + break; + case SYS_CFG_REBOOT: + if (site == SYS_CFG_SITE_MB && device == 0) { + qemu_system_reset_request(); + return true; + } + break; + default: + break; + } + +cfgctrl_unimp: + qemu_log_mask(LOG_UNIMP, + "arm_sysctl: Unimplemented SYS_CFGCTRL write of function " + "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", + function, dcc, site, position, device); + return false; +} + static void arm_sysctl_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { @@ -322,17 +427,33 @@ static void arm_sysctl_write(void *opaque, hwaddr offset, if (board_id(s) != BOARD_ID_VEXPRESS) { goto bad_reg; } - s->sys_cfgctrl = val & ~(3 << 18); - s->sys_cfgstat = 1; /* complete */ - switch (s->sys_cfgctrl) { - case 0xc0800000: /* SYS_CFG_SHUTDOWN to motherboard */ - qemu_system_shutdown_request(); - break; - case 0xc0900000: /* SYS_CFG_REBOOT to motherboard */ - qemu_system_reset_request(); - break; - default: - s->sys_cfgstat |= 2; /* error */ + /* Undefined bits [19:18] are RAZ/WI, and writing to + * the start bit just triggers the action; it always reads + * as zero. + */ + s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31)); + if (val & (1 << 31)) { + /* Start bit set -- actually do something */ + unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4); + unsigned int function = extract32(s->sys_cfgctrl, 20, 6); + unsigned int site = extract32(s->sys_cfgctrl, 16, 2); + unsigned int position = extract32(s->sys_cfgctrl, 12, 4); + unsigned int device = extract32(s->sys_cfgctrl, 0, 12); + s->sys_cfgstat = 1; /* complete */ + if (s->sys_cfgctrl & (1 << 30)) { + if (!vexpress_cfgctrl_write(s, dcc, function, site, position, + device, s->sys_cfgdata)) { + s->sys_cfgstat |= 2; /* error */ + } + } else { + uint32_t val; + if (!vexpress_cfgctrl_read(s, dcc, function, site, position, + device, &val)) { + s->sys_cfgstat |= 2; /* error */ + } else { + s->sys_cfgdata = val; + } + } } s->sys_cfgctrl &= ~(1 << 31); return; -- cgit v1.1 From 8ff05c9842e28888b936dbd960f6416cee5addb6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:56 +0000 Subject: hw/arm_sysctl: Implement SYS_CFG_MUXFPGA writes as a no-op SYS_CFG_MUXFPGA allows the guest to select whether the video output should come from the motherboard's LCD controller or the daughterboard's one. Since QEMU doesn't currently support selecting the video output like this, implement as a no-op, so Linux doesn't complain about the register not being implemented. Signed-off-by: Peter Maydell --- hw/arm_sysctl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'hw') diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 05a3200..a6e5ed4 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -272,6 +272,17 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, } switch (function) { + case SYS_CFG_MUXFPGA: + if (site == SYS_CFG_SITE_MB && device == 0) { + /* Select whether video output comes from motherboard + * or daughterboard: log and ignore as QEMU doesn't + * support this. + */ + qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output " + "not supported, ignoring\n"); + return true; + } + break; case SYS_CFG_SHUTDOWN: if (site == SYS_CFG_SITE_MB && device == 0) { qemu_system_shutdown_request(); -- cgit v1.1 From 291155cbc54212a451d0b899a01b6e3e14ed9135 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:56 +0000 Subject: hw/arm_sysctl: Implement SYS_CFG_DVIMODE as a no-op SYS_CFG_DVIMODE allows the guest to select whether the output DVI signal is VGA, SVGA, XGA, SGA or UXGA. Since this makes no difference to QEMU, implement writes as a no-op so Linux doesn't complain. Signed-off-by: Peter Maydell --- hw/arm_sysctl.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'hw') diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index a6e5ed4..840bfad 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -295,6 +295,14 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, return true; } break; + case SYS_CFG_DVIMODE: + if (site == SYS_CFG_SITE_MB && device == 0) { + /* Selecting DVI mode is meaningless for QEMU: we will + * always display the output correctly according to the + * pixel height/width programmed into the CLCD controller. + */ + return true; + } default: break; } -- cgit v1.1 From 1f56f50ac484653fe996c37ac894418a34f92b89 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:56 +0000 Subject: hw/arm_sysctl: Convert from qdev init to instance_init Convert this device from old-style qdev init to an instance_init function. We don't need a realize function yet, though. Signed-off-by: Peter Maydell --- hw/arm_sysctl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'hw') diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 840bfad..7c94b78 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -525,15 +525,16 @@ static void arm_sysctl_gpio_set(void *opaque, int line, int level) } } -static int arm_sysctl_init(SysBusDevice *dev) +static void arm_sysctl_init(Object *obj) { - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev); + DeviceState *dev = DEVICE(obj); + SysBusDevice *sd = SYS_BUS_DEVICE(obj); + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sd); memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - qdev_init_gpio_in(&s->busdev.qdev, arm_sysctl_gpio_set, 2); - qdev_init_gpio_out(&s->busdev.qdev, &s->pl110_mux_ctrl, 1); - return 0; + sysbus_init_mmio(sd, &s->iomem); + qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2); + qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1); } static Property arm_sysctl_properties[] = { @@ -545,9 +546,7 @@ static Property arm_sysctl_properties[] = { static void arm_sysctl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = arm_sysctl_init; dc->reset = arm_sysctl_reset; dc->vmsd = &vmstate_arm_sysctl; dc->props = arm_sysctl_properties; @@ -557,6 +556,7 @@ static const TypeInfo arm_sysctl_info = { .name = "realview_sysctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(arm_sysctl_state), + .instance_init = arm_sysctl_init, .class_init = arm_sysctl_class_init, }; -- cgit v1.1 From 0be6bfac6262900425c10847de513ee2490078d3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:57 +0000 Subject: qdev: Implement (variable length) array properties Add support for declaring array properties for qdev devices. These work by defining an initial static property 'len-arrayname' which the user of the device should set to the desired size of the array. When this property is set, memory is allocated for the array elements, and dynamic properties "arrayname[0]", "arrayname[1]"... are created so the user of the device can then set the values of the individual array elements. Signed-off-by: Peter Maydell --- hw/qdev-core.h | 3 ++ hw/qdev-properties.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/qdev-properties.h | 39 +++++++++++++++++++ 3 files changed, 146 insertions(+) (limited to 'hw') diff --git a/hw/qdev-core.h b/hw/qdev-core.h index 2486f36..547fbc7 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -175,6 +175,9 @@ struct Property { uint8_t bitnr; uint8_t qtype; int64_t defval; + int arrayoffset; + PropertyInfo *arrayinfo; + int arrayfieldsize; }; struct PropertyInfo { diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 0307a78..247ca6c 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -779,6 +779,110 @@ PropertyInfo qdev_prop_pci_host_devaddr = { .set = set_pci_host_devaddr, }; +/* --- support for array properties --- */ + +/* Used as an opaque for the object properties we add for each + * array element. Note that the struct Property must be first + * in the struct so that a pointer to this works as the opaque + * for the underlying element's property hooks as well as for + * our own release callback. + */ +typedef struct { + struct Property prop; + char *propname; + ObjectPropertyRelease *release; +} ArrayElementProperty; + +/* object property release callback for array element properties: + * we call the underlying element's property release hook, and + * then free the memory we allocated when we added the property. + */ +static void array_element_release(Object *obj, const char *name, void *opaque) +{ + ArrayElementProperty *p = opaque; + if (p->release) { + p->release(obj, name, opaque); + } + g_free(p->propname); + g_free(p); +} + +static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + /* Setter for the property which defines the length of a + * variable-sized property array. As well as actually setting the + * array-length field in the device struct, we have to create the + * array itself and dynamically add the corresponding properties. + */ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *alenptr = qdev_get_prop_ptr(dev, prop); + void **arrayptr = (void *)dev + prop->arrayoffset; + void *eltptr; + const char *arrayname; + int i; + + if (dev->realized) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + if (*alenptr) { + error_setg(errp, "array size property %s may not be set more than once", + name); + return; + } + visit_type_uint32(v, alenptr, name, errp); + if (error_is_set(errp)) { + return; + } + if (!*alenptr) { + return; + } + + /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix; + * strip it off so we can get the name of the array itself. + */ + assert(strncmp(name, PROP_ARRAY_LEN_PREFIX, + strlen(PROP_ARRAY_LEN_PREFIX)) == 0); + arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX); + + /* Note that it is the responsibility of the individual device's deinit + * to free the array proper. + */ + *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize); + for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) { + char *propname = g_strdup_printf("%s[%d]", arrayname, i); + ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1); + arrayprop->release = prop->arrayinfo->release; + arrayprop->propname = propname; + arrayprop->prop.info = prop->arrayinfo; + arrayprop->prop.name = propname; + /* This ugly piece of pointer arithmetic sets up the offset so + * that when the underlying get/set hooks call qdev_get_prop_ptr + * they get the right answer despite the array element not actually + * being inside the device struct. + */ + arrayprop->prop.offset = eltptr - (void *)dev; + assert(qdev_get_prop_ptr(dev, &arrayprop->prop) == eltptr); + object_property_add(obj, propname, + arrayprop->prop.info->name, + arrayprop->prop.info->get, + arrayprop->prop.info->set, + array_element_release, + arrayprop, errp); + if (error_is_set(errp)) { + return; + } + } +} + +PropertyInfo qdev_prop_arraylen = { + .name = "uint32", + .get = get_uint32, + .set = set_prop_arraylen, +}; + /* --- public helpers --- */ static Property *qdev_prop_walk(Property *props, const char *name) diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h index 0b0465c..c9bb246 100644 --- a/hw/qdev-properties.h +++ b/hw/qdev-properties.h @@ -26,6 +26,7 @@ extern PropertyInfo qdev_prop_vlan; extern PropertyInfo qdev_prop_pci_devfn; extern PropertyInfo qdev_prop_blocksize; extern PropertyInfo qdev_prop_pci_host_devaddr; +extern PropertyInfo qdev_prop_arraylen; #define DEFINE_PROP(_name, _state, _field, _prop, _type) { \ .name = (_name), \ @@ -51,6 +52,44 @@ extern PropertyInfo qdev_prop_pci_host_devaddr; .defval = (bool)_defval, \ } +#define PROP_ARRAY_LEN_PREFIX "len-" + +/** + * DEFINE_PROP_ARRAY: + * @_name: name of the array + * @_state: name of the device state structure type + * @_field: uint32_t field in @_state to hold the array length + * @_arrayfield: field in @_state (of type '@_arraytype *') which + * will point to the array + * @_arrayprop: PropertyInfo defining what property the array elements have + * @_arraytype: C type of the array elements + * + * Define device properties for a variable-length array _name. A + * static property "len-arrayname" is defined. When the device creator + * sets this property to the desired length of array, further dynamic + * properties "arrayname[0]", "arrayname[1]", ... are defined so the + * device creator can set the array element values. Setting the + * "len-arrayname" property more than once is an error. + * + * When the array length is set, the @_field member of the device + * struct is set to the array length, and @_arrayfield is set to point + * to (zero-initialised) memory allocated for the array. For a zero + * length array, @_field will be set to 0 and @_arrayfield to NULL. + * It is the responsibility of the device deinit code to free the + * @_arrayfield memory. + */ +#define DEFINE_PROP_ARRAY(_name, _state, _field, \ + _arrayfield, _arrayprop, _arraytype) { \ + .name = (PROP_ARRAY_LEN_PREFIX _name), \ + .info = &(qdev_prop_arraylen), \ + .offset = offsetof(_state, _field) \ + + type_check(uint32_t, typeof_field(_state, _field)), \ + .qtype = QTYPE_QINT, \ + .arrayinfo = &(_arrayprop), \ + .arrayfieldsize = sizeof(_arraytype), \ + .arrayoffset = offsetof(_state, _arrayfield), \ + } + #define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) #define DEFINE_PROP_UINT16(_n, _s, _f, _d) \ -- cgit v1.1 From 8bd4824a6122292060a318741595927e0d05ff5e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:57 +0000 Subject: hw/arm_sysctl: Implement SYS_CFG_VOLT Implement the SYS_CFG_VOLT registers which return the voltage of various supplies on motherboard and daughterboard. Since QEMU implements a perfectly stable power supply these registers always return a constant value. The number and value of the daughterboard voltages is dependent on the specific daughterboard, so we use a property array to allow the board to configure them appropriately. Signed-off-by: Peter Maydell --- hw/arm_sysctl.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'hw') diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 7c94b78..e2f00d3 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -35,6 +35,8 @@ typedef struct { uint32_t sys_cfgctrl; uint32_t sys_cfgstat; uint32_t sys_clcd; + uint32_t db_num_vsensors; + uint32_t *db_voltage; } arm_sysctl_state; static const VMStateDescription vmstate_arm_sysctl = { @@ -236,6 +238,19 @@ static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc, } switch (function) { + case SYS_CFG_VOLT: + if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) { + *val = s->db_voltage[device]; + return true; + } + if (site == SYS_CFG_SITE_MB && device == 0) { + /* There is only one motherboard voltage sensor: + * VIO : 3.3V : bus voltage between mother and daughterboard + */ + *val = 3300000; + return true; + } + break; default: break; } @@ -537,9 +552,19 @@ static void arm_sysctl_init(Object *obj) qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1); } +static void arm_sysctl_finalize(Object *obj) +{ + SysBusDevice *dev = SYS_BUS_DEVICE(obj); + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev); + g_free(s->db_voltage); +} + static Property arm_sysctl_properties[] = { DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0), DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0), + /* Daughterboard power supply voltages (as reported via SYS_CFG) */ + DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors, + db_voltage, qdev_prop_uint32, uint32_t), DEFINE_PROP_END_OF_LIST(), }; @@ -557,6 +582,7 @@ static const TypeInfo arm_sysctl_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(arm_sysctl_state), .instance_init = arm_sysctl_init, + .instance_finalize = arm_sysctl_finalize, .class_init = arm_sysctl_class_init, }; -- cgit v1.1 From 31410948bc1c8001098b076caf35aab8a5cf063d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:57 +0000 Subject: hw/vexpress: Pass voltage sensor properties to sysctl device Pass voltage sensor properties to the sysctl device. Since these are daughterboard specific, we specify them via the VEDBoardInfo structure. Signed-off-by: Peter Maydell Message-id: 1359985476-29380-9-git-send-email-peter.maydell@linaro.org --- hw/arm/vexpress.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'hw') diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 47a844f..a2dc759 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -154,6 +154,8 @@ struct VEDBoardInfo { hwaddr loader_start; const hwaddr gic_cpu_if_addr; uint32_t proc_id; + uint32_t num_voltage_sensors; + const uint32_t *voltages; DBoardInitFn *init; }; @@ -246,11 +248,25 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, sysbus_create_varargs("l2x0", 0x1e00a000, NULL); } +/* Voltage values for SYS_CFG_VOLT daughterboard registers; + * values are in microvolts. + */ +static const uint32_t a9_voltages[] = { + 1000000, /* VD10 : 1.0V : SoC internal logic voltage */ + 1000000, /* VD10_S2 : 1.0V : PL310, L2 cache, RAM, non-PL310 logic */ + 1000000, /* VD10_S3 : 1.0V : Cortex-A9, cores, MPEs, SCU, PL310 logic */ + 1800000, /* VCC1V8 : 1.8V : DDR2 SDRAM, test chip DDR2 I/O supply */ + 900000, /* DDR2VTT : 0.9V : DDR2 SDRAM VTT termination voltage */ + 3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */ +}; + static const VEDBoardInfo a9_daughterboard = { .motherboard_map = motherboard_legacy_map, .loader_start = 0x60000000, .gic_cpu_if_addr = 0x1e000100, .proc_id = 0x0c000191, + .num_voltage_sensors = ARRAY_SIZE(a9_voltages), + .voltages = a9_voltages, .init = a9_daughterboard_init, }; @@ -338,11 +354,17 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, /* 0x7ffd0000: PL354 static memory controller: not modelled */ } +static const uint32_t a15_voltages[] = { + 900000, /* Vcore: 0.9V : CPU core voltage */ +}; + static const VEDBoardInfo a15_daughterboard = { .motherboard_map = motherboard_aseries_map, .loader_start = 0x80000000, .gic_cpu_if_addr = 0x2c002000, .proc_id = 0x14000237, + .num_voltage_sensors = ARRAY_SIZE(a15_voltages), + .voltages = a15_voltages, .init = a15_daughterboard_init, }; @@ -358,6 +380,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, MemoryRegion *vram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); const hwaddr *map = daughterboard->motherboard_map; + int i; daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic); @@ -370,6 +393,13 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, sysctl = qdev_create(NULL, "realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", sys_id); qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id); + qdev_prop_set_uint32(sysctl, "len-db-voltage", + daughterboard->num_voltage_sensors); + for (i = 0; i < daughterboard->num_voltage_sensors; i++) { + char *propname = g_strdup_printf("db-voltage[%d]", i); + qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]); + g_free(propname); + } qdev_init_nofail(sysctl); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); -- cgit v1.1 From 1f81f94bebc2f8c4b32a89910d071099a67dc44d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:57 +0000 Subject: hw/arm_sysctl: Implement SYS_CFG_OSC function Implement the SYS_CFG_OSC function. Since the idea of programmable clock rates doesn't make much sense for QEMU, we simply allow the clock rate to be read back as written. The number and value of the daughterboard oscillators varies between daughterboards, so we provide an array property to allow their reset values to be configured. Signed-off-by: Peter Maydell --- hw/arm_sysctl.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index e2f00d3..25fc6ea 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -35,13 +35,17 @@ typedef struct { uint32_t sys_cfgctrl; uint32_t sys_cfgstat; uint32_t sys_clcd; + uint32_t mb_clock[6]; + uint32_t *db_clock; uint32_t db_num_vsensors; uint32_t *db_voltage; + uint32_t db_num_clocks; + uint32_t *db_clock_reset; } arm_sysctl_state; static const VMStateDescription vmstate_arm_sysctl = { .name = "realview_sysctl", - .version_id = 3, + .version_id = 4, .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(leds, arm_sysctl_state), @@ -56,6 +60,9 @@ static const VMStateDescription vmstate_arm_sysctl = { VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2), VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2), VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3), + VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4), + VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks, + 4, vmstate_info_uint32, uint32_t), VMSTATE_END_OF_LIST() } }; @@ -79,6 +86,7 @@ static int board_id(arm_sysctl_state *s) static void arm_sysctl_reset(DeviceState *d) { arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); + int i; s->leds = 0; s->lockval = 0; @@ -86,6 +94,17 @@ static void arm_sysctl_reset(DeviceState *d) s->cfgdata2 = 0; s->flags = 0; s->resetlevel = 0; + /* Motherboard oscillators (in Hz) */ + s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */ + s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */ + s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */ + s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */ + s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */ + s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */ + /* Daughterboard oscillators: reset from property values */ + for (i = 0; i < s->db_num_clocks; i++) { + s->db_clock[i] = s->db_clock_reset[i]; + } if (board_id(s) == BOARD_ID_VEXPRESS) { /* On VExpress this register will RAZ/WI */ s->sys_clcd = 0; @@ -251,6 +270,18 @@ static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc, return true; } break; + case SYS_CFG_OSC: + if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { + /* motherboard clock */ + *val = s->mb_clock[device]; + return true; + } + if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { + /* daughterboard clock */ + *val = s->db_clock[device]; + return true; + } + break; default: break; } @@ -287,6 +318,18 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, } switch (function) { + case SYS_CFG_OSC: + if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { + /* motherboard clock */ + s->mb_clock[device] = val; + return true; + } + if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { + /* daughterboard clock */ + s->db_clock[device] = val; + return true; + } + break; case SYS_CFG_MUXFPGA: if (site == SYS_CFG_SITE_MB && device == 0) { /* Select whether video output comes from motherboard @@ -552,11 +595,19 @@ static void arm_sysctl_init(Object *obj) qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1); } +static void arm_sysctl_realize(DeviceState *d, Error **errp) +{ + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); + s->db_clock = g_new0(uint32_t, s->db_num_clocks); +} + static void arm_sysctl_finalize(Object *obj) { SysBusDevice *dev = SYS_BUS_DEVICE(obj); arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev); g_free(s->db_voltage); + g_free(s->db_clock); + g_free(s->db_clock_reset); } static Property arm_sysctl_properties[] = { @@ -565,6 +616,9 @@ static Property arm_sysctl_properties[] = { /* Daughterboard power supply voltages (as reported via SYS_CFG) */ DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors, db_voltage, qdev_prop_uint32, uint32_t), + /* Daughterboard clock reset values (as reported via SYS_CFG) */ + DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks, + db_clock_reset, qdev_prop_uint32, uint32_t), DEFINE_PROP_END_OF_LIST(), }; @@ -572,6 +626,7 @@ static void arm_sysctl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = arm_sysctl_realize; dc->reset = arm_sysctl_reset; dc->vmsd = &vmstate_arm_sysctl; dc->props = arm_sysctl_properties; -- cgit v1.1 From 9c7d489379c2a2923b4805d337dfd54f2f432449 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Mar 2013 16:41:58 +0000 Subject: hw/vexpress: Set reset values for daughterboard oscillators Set the reset values for the VExpress daughterboard oscillators via the new sysctl properties. Signed-off-by: Peter Maydell --- hw/arm/vexpress.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'hw') diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index a2dc759..2e1a5d0 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -156,6 +156,8 @@ struct VEDBoardInfo { uint32_t proc_id; uint32_t num_voltage_sensors; const uint32_t *voltages; + uint32_t num_clocks; + const uint32_t *clocks; DBoardInitFn *init; }; @@ -260,6 +262,13 @@ static const uint32_t a9_voltages[] = { 3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */ }; +/* Reset values for daughterboard oscillators (in Hz) */ +static const uint32_t a9_clocks[] = { + 45000000, /* AMBA AXI ACLK: 45MHz */ + 23750000, /* daughterboard CLCD clock: 23.75MHz */ + 66670000, /* Test chip reference clock: 66.67MHz */ +}; + static const VEDBoardInfo a9_daughterboard = { .motherboard_map = motherboard_legacy_map, .loader_start = 0x60000000, @@ -267,6 +276,8 @@ static const VEDBoardInfo a9_daughterboard = { .proc_id = 0x0c000191, .num_voltage_sensors = ARRAY_SIZE(a9_voltages), .voltages = a9_voltages, + .num_clocks = ARRAY_SIZE(a9_clocks), + .clocks = a9_clocks, .init = a9_daughterboard_init, }; @@ -358,6 +369,18 @@ static const uint32_t a15_voltages[] = { 900000, /* Vcore: 0.9V : CPU core voltage */ }; +static const uint32_t a15_clocks[] = { + 60000000, /* OSCCLK0: 60MHz : CPU_CLK reference */ + 0, /* OSCCLK1: reserved */ + 0, /* OSCCLK2: reserved */ + 0, /* OSCCLK3: reserved */ + 40000000, /* OSCCLK4: 40MHz : external AXI master clock */ + 23750000, /* OSCCLK5: 23.75MHz : HDLCD PLL reference */ + 50000000, /* OSCCLK6: 50MHz : static memory controller clock */ + 60000000, /* OSCCLK7: 60MHz : SYSCLK reference */ + 40000000, /* OSCCLK8: 40MHz : DDR2 PLL reference */ +}; + static const VEDBoardInfo a15_daughterboard = { .motherboard_map = motherboard_aseries_map, .loader_start = 0x80000000, @@ -365,6 +388,8 @@ static const VEDBoardInfo a15_daughterboard = { .proc_id = 0x14000237, .num_voltage_sensors = ARRAY_SIZE(a15_voltages), .voltages = a15_voltages, + .num_clocks = ARRAY_SIZE(a15_clocks), + .clocks = a15_clocks, .init = a15_daughterboard_init, }; @@ -400,6 +425,13 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]); g_free(propname); } + qdev_prop_set_uint32(sysctl, "len-db-clock", + daughterboard->num_clocks); + for (i = 0; i < daughterboard->num_clocks; i++) { + char *propname = g_strdup_printf("db-clock[%d]", i); + qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]); + g_free(propname); + } qdev_init_nofail(sysctl); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); -- cgit v1.1 From 06a1cea5f631f6ac69f85ae07bb47ef47b88f5f7 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Fri, 15 Mar 2013 16:41:58 +0000 Subject: pl330: Initial version Device model for Primecell PL330 DMA controller. Signed-off-by: Peter Crosthwaite Signed-off-by: Kirill Batuzov Tested-by: Igor Mitsyanko Reviewed-by: Igor Mitsyanko Reviewed-by: Peter Maydell Message-id: 098aac26233d7334bed2bca4f06f539638ca6d24.1361853677.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/Makefile.objs | 1 + hw/pl330.c | 1654 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1655 insertions(+) create mode 100644 hw/pl330.c (limited to 'hw') diff --git a/hw/Makefile.objs b/hw/Makefile.objs index eb7eb31..11812c6 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -98,6 +98,7 @@ common-obj-$(CONFIG_PL110) += pl110.o common-obj-$(CONFIG_PL181) += pl181.o common-obj-$(CONFIG_PL190) += pl190.o common-obj-$(CONFIG_PL310) += arm_l2x0.o +common-obj-$(CONFIG_PL330) += pl330.o common-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o common-obj-$(CONFIG_CADENCE) += cadence_uart.o diff --git a/hw/pl330.c b/hw/pl330.c new file mode 100644 index 0000000..1a04773 --- /dev/null +++ b/hw/pl330.c @@ -0,0 +1,1654 @@ +/* + * ARM PrimeCell PL330 DMA Controller + * + * Copyright (c) 2009 Samsung Electronics. + * Contributed by Kirill Batuzov + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) + * Copyright (c) 2012 PetaLogix Pty Ltd. + * + * 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; version 2 or later. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "sysbus.h" +#include "qemu/timer.h" +#include "sysemu/dma.h" + +#ifndef PL330_ERR_DEBUG +#define PL330_ERR_DEBUG 0 +#endif + +#define DB_PRINT_L(lvl, fmt, args...) do {\ + if (PL330_ERR_DEBUG >= lvl) {\ + fprintf(stderr, "PL330: %s:" fmt, __func__, ## args);\ + } \ +} while (0); + +#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) + +#define PL330_PERIPH_NUM 32 +#define PL330_MAX_BURST_LEN 128 +#define PL330_INSN_MAXSIZE 6 + +#define PL330_FIFO_OK 0 +#define PL330_FIFO_STALL 1 +#define PL330_FIFO_ERR (-1) + +#define PL330_FAULT_UNDEF_INSTR (1 << 0) +#define PL330_FAULT_OPERAND_INVALID (1 << 1) +#define PL330_FAULT_DMAGO_ERR (1 << 4) +#define PL330_FAULT_EVENT_ERR (1 << 5) +#define PL330_FAULT_CH_PERIPH_ERR (1 << 6) +#define PL330_FAULT_CH_RDWR_ERR (1 << 7) +#define PL330_FAULT_ST_DATA_UNAVAILABLE (1 << 12) +#define PL330_FAULT_FIFOEMPTY_ERR (1 << 13) +#define PL330_FAULT_INSTR_FETCH_ERR (1 << 16) +#define PL330_FAULT_DATA_WRITE_ERR (1 << 17) +#define PL330_FAULT_DATA_READ_ERR (1 << 18) +#define PL330_FAULT_DBG_INSTR (1 << 30) +#define PL330_FAULT_LOCKUP_ERR (1 << 31) + +#define PL330_UNTAGGED 0xff + +#define PL330_SINGLE 0x0 +#define PL330_BURST 0x1 + +#define PL330_WATCHDOG_LIMIT 1024 + +/* IOMEM mapped registers */ +#define PL330_REG_DSR 0x000 +#define PL330_REG_DPC 0x004 +#define PL330_REG_INTEN 0x020 +#define PL330_REG_INT_EVENT_RIS 0x024 +#define PL330_REG_INTMIS 0x028 +#define PL330_REG_INTCLR 0x02C +#define PL330_REG_FSRD 0x030 +#define PL330_REG_FSRC 0x034 +#define PL330_REG_FTRD 0x038 +#define PL330_REG_FTR_BASE 0x040 +#define PL330_REG_CSR_BASE 0x100 +#define PL330_REG_CPC_BASE 0x104 +#define PL330_REG_CHANCTRL 0x400 +#define PL330_REG_DBGSTATUS 0xD00 +#define PL330_REG_DBGCMD 0xD04 +#define PL330_REG_DBGINST0 0xD08 +#define PL330_REG_DBGINST1 0xD0C +#define PL330_REG_CR0_BASE 0xE00 +#define PL330_REG_PERIPH_ID 0xFE0 + +#define PL330_IOMEM_SIZE 0x1000 + +#define CFG_BOOT_ADDR 2 +#define CFG_INS 3 +#define CFG_PNS 4 +#define CFG_CRD 5 + +static const uint32_t pl330_id[] = { + 0x30, 0x13, 0x24, 0x00, 0x0D, 0xF0, 0x05, 0xB1 +}; + +/* DMA channel states as they are described in PL330 Technical Reference Manual + * Most of them will not be used in emulation. + */ +typedef enum { + pl330_chan_stopped = 0, + pl330_chan_executing = 1, + pl330_chan_cache_miss = 2, + pl330_chan_updating_pc = 3, + pl330_chan_waiting_event = 4, + pl330_chan_at_barrier = 5, + pl330_chan_queue_busy = 6, + pl330_chan_waiting_periph = 7, + pl330_chan_killing = 8, + pl330_chan_completing = 9, + pl330_chan_fault_completing = 14, + pl330_chan_fault = 15, +} PL330ChanState; + +typedef struct PL330State PL330State; + +typedef struct PL330Chan { + uint32_t src; + uint32_t dst; + uint32_t pc; + uint32_t control; + uint32_t status; + uint32_t lc[2]; + uint32_t fault_type; + uint32_t watchdog_timer; + + bool ns; + uint8_t request_flag; + uint8_t wakeup; + uint8_t wfp_sbp; + + uint8_t state; + uint8_t stall; + + bool is_manager; + PL330State *parent; + uint8_t tag; +} PL330Chan; + +static const VMStateDescription vmstate_pl330_chan = { + .name = "pl330_chan", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(src, PL330Chan), + VMSTATE_UINT32(dst, PL330Chan), + VMSTATE_UINT32(pc, PL330Chan), + VMSTATE_UINT32(control, PL330Chan), + VMSTATE_UINT32(status, PL330Chan), + VMSTATE_UINT32_ARRAY(lc, PL330Chan, 2), + VMSTATE_UINT32(fault_type, PL330Chan), + VMSTATE_UINT32(watchdog_timer, PL330Chan), + VMSTATE_BOOL(ns, PL330Chan), + VMSTATE_UINT8(request_flag, PL330Chan), + VMSTATE_UINT8(wakeup, PL330Chan), + VMSTATE_UINT8(wfp_sbp, PL330Chan), + VMSTATE_UINT8(state, PL330Chan), + VMSTATE_UINT8(stall, PL330Chan), + VMSTATE_END_OF_LIST() + } +}; + +typedef struct PL330Fifo { + uint8_t *buf; + uint8_t *tag; + uint32_t head; + uint32_t num; + uint32_t buf_size; +} PL330Fifo; + +static const VMStateDescription vmstate_pl330_fifo = { + .name = "pl330_chan", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size), + VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size), + VMSTATE_UINT32(head, PL330Fifo), + VMSTATE_UINT32(num, PL330Fifo), + VMSTATE_UINT32(buf_size, PL330Fifo), + VMSTATE_END_OF_LIST() + } +}; + +typedef struct PL330QueueEntry { + uint32_t addr; + uint32_t len; + uint8_t n; + bool inc; + bool z; + uint8_t tag; + uint8_t seqn; +} PL330QueueEntry; + +static const VMStateDescription vmstate_pl330_queue_entry = { + .name = "pl330_queue_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(addr, PL330QueueEntry), + VMSTATE_UINT32(len, PL330QueueEntry), + VMSTATE_UINT8(n, PL330QueueEntry), + VMSTATE_BOOL(inc, PL330QueueEntry), + VMSTATE_BOOL(z, PL330QueueEntry), + VMSTATE_UINT8(tag, PL330QueueEntry), + VMSTATE_UINT8(seqn, PL330QueueEntry), + VMSTATE_END_OF_LIST() + } +}; + +typedef struct PL330Queue { + PL330State *parent; + PL330QueueEntry *queue; + uint32_t queue_size; +} PL330Queue; + +static const VMStateDescription vmstate_pl330_queue = { + .name = "pl330_queue", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1, + vmstate_pl330_queue_entry, PL330QueueEntry), + VMSTATE_END_OF_LIST() + } +}; + +struct PL330State { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq irq_abort; + qemu_irq *irq; + + /* Config registers. cfg[5] = CfgDn. */ + uint32_t cfg[6]; +#define EVENT_SEC_STATE 3 +#define PERIPH_SEC_STATE 4 + /* cfg 0 bits and pieces */ + uint32_t num_chnls; + uint8_t num_periph_req; + uint8_t num_events; + uint8_t mgr_ns_at_rst; + /* cfg 1 bits and pieces */ + uint8_t i_cache_len; + uint8_t num_i_cache_lines; + /* CRD bits and pieces */ + uint8_t data_width; + uint8_t wr_cap; + uint8_t wr_q_dep; + uint8_t rd_cap; + uint8_t rd_q_dep; + uint16_t data_buffer_dep; + + PL330Chan manager; + PL330Chan *chan; + PL330Fifo fifo; + PL330Queue read_queue; + PL330Queue write_queue; + uint8_t *lo_seqn; + uint8_t *hi_seqn; + QEMUTimer *timer; /* is used for restore dma. */ + + uint32_t inten; + uint32_t int_status; + uint32_t ev_status; + uint32_t dbg[2]; + uint8_t debug_status; + uint8_t num_faulting; + uint8_t periph_busy[PL330_PERIPH_NUM]; + +}; + +#define TYPE_PL330 "pl330" +#define PL330(obj) OBJECT_CHECK(PL330State, (obj), TYPE_PL330) + +static const VMStateDescription vmstate_pl330 = { + .name = "pl330", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan), + VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0, + vmstate_pl330_chan, PL330Chan), + VMSTATE_VBUFFER_UINT32(lo_seqn, PL330State, 1, NULL, 0, num_chnls), + VMSTATE_VBUFFER_UINT32(hi_seqn, PL330State, 1, NULL, 0, num_chnls), + VMSTATE_STRUCT(fifo, PL330State, 0, vmstate_pl330_fifo, PL330Fifo), + VMSTATE_STRUCT(read_queue, PL330State, 0, vmstate_pl330_queue, + PL330Queue), + VMSTATE_STRUCT(write_queue, PL330State, 0, vmstate_pl330_queue, + PL330Queue), + VMSTATE_TIMER(timer, PL330State), + VMSTATE_UINT32(inten, PL330State), + VMSTATE_UINT32(int_status, PL330State), + VMSTATE_UINT32(ev_status, PL330State), + VMSTATE_UINT32_ARRAY(dbg, PL330State, 2), + VMSTATE_UINT8(debug_status, PL330State), + VMSTATE_UINT8(num_faulting, PL330State), + VMSTATE_UINT8_ARRAY(periph_busy, PL330State, PL330_PERIPH_NUM), + VMSTATE_END_OF_LIST() + } +}; + +typedef struct PL330InsnDesc { + /* OPCODE of the instruction */ + uint8_t opcode; + /* Mask so we can select several sibling instructions, such as + DMALD, DMALDS and DMALDB */ + uint8_t opmask; + /* Size of instruction in bytes */ + uint8_t size; + /* Interpreter */ + void (*exec)(PL330Chan *, uint8_t opcode, uint8_t *args, int len); +} PL330InsnDesc; + + +/* MFIFO Implementation + * + * MFIFO is implemented as a cyclic buffer of BUF_SIZE size. Tagged bytes are + * stored in this buffer. Data is stored in BUF field, tags - in the + * corresponding array elements of TAG field. + */ + +/* Initialize queue. */ + +static void pl330_fifo_init(PL330Fifo *s, uint32_t size) +{ + s->buf = g_malloc0(size); + s->tag = g_malloc0(size); + s->buf_size = size; +} + +/* Cyclic increment */ + +static inline int pl330_fifo_inc(PL330Fifo *s, int x) +{ + return (x + 1) % s->buf_size; +} + +/* Number of empty bytes in MFIFO */ + +static inline int pl330_fifo_num_free(PL330Fifo *s) +{ + return s->buf_size - s->num; +} + +/* Push LEN bytes of data stored in BUF to MFIFO and tag it with TAG. + * Zero returned on success, PL330_FIFO_STALL if there is no enough free + * space in MFIFO to store requested amount of data. If push was unsuccessful + * no data is stored to MFIFO. + */ + +static int pl330_fifo_push(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag) +{ + int i; + + if (s->buf_size - s->num < len) { + return PL330_FIFO_STALL; + } + for (i = 0; i < len; i++) { + int push_idx = (s->head + s->num + i) % s->buf_size; + s->buf[push_idx] = buf[i]; + s->tag[push_idx] = tag; + } + s->num += len; + return PL330_FIFO_OK; +} + +/* Get LEN bytes of data from MFIFO and store it to BUF. Tag value of each + * byte is verified. Zero returned on success, PL330_FIFO_ERR on tag mismatch + * and PL330_FIFO_STALL if there is no enough data in MFIFO. If get was + * unsuccessful no data is removed from MFIFO. + */ + +static int pl330_fifo_get(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag) +{ + int i; + + if (s->num < len) { + return PL330_FIFO_STALL; + } + for (i = 0; i < len; i++) { + if (s->tag[s->head] == tag) { + int get_idx = (s->head + i) % s->buf_size; + buf[i] = s->buf[get_idx]; + } else { /* Tag mismatch - Rollback transaction */ + return PL330_FIFO_ERR; + } + } + s->head = (s->head + len) % s->buf_size; + s->num -= len; + return PL330_FIFO_OK; +} + +/* Reset MFIFO. This completely erases all data in it. */ + +static inline void pl330_fifo_reset(PL330Fifo *s) +{ + s->head = 0; + s->num = 0; +} + +/* Return tag of the first byte stored in MFIFO. If MFIFO is empty + * PL330_UNTAGGED is returned. + */ + +static inline uint8_t pl330_fifo_tag(PL330Fifo *s) +{ + return (!s->num) ? PL330_UNTAGGED : s->tag[s->head]; +} + +/* Returns non-zero if tag TAG is present in fifo or zero otherwise */ + +static int pl330_fifo_has_tag(PL330Fifo *s, uint8_t tag) +{ + int i, n; + + i = s->head; + for (n = 0; n < s->num; n++) { + if (s->tag[i] == tag) { + return 1; + } + i = pl330_fifo_inc(s, i); + } + return 0; +} + +/* Remove all entry tagged with TAG from MFIFO */ + +static void pl330_fifo_tagged_remove(PL330Fifo *s, uint8_t tag) +{ + int i, t, n; + + t = i = s->head; + for (n = 0; n < s->num; n++) { + if (s->tag[i] != tag) { + s->buf[t] = s->buf[i]; + s->tag[t] = s->tag[i]; + t = pl330_fifo_inc(s, t); + } else { + s->num = s->num - 1; + } + i = pl330_fifo_inc(s, i); + } +} + +/* Read-Write Queue implementation + * + * A Read-Write Queue stores up to QUEUE_SIZE instructions (loads or stores). + * Each instruction is described by source (for loads) or destination (for + * stores) address ADDR, width of data to be loaded/stored LEN, number of + * stores/loads to be performed N, INC bit, Z bit and TAG to identify channel + * this instruction belongs to. Queue does not store any information about + * nature of the instruction: is it load or store. PL330 has different queues + * for loads and stores so this is already known at the top level where it + * matters. + * + * Queue works as FIFO for instructions with equivalent tags, but can issue + * instructions with different tags in arbitrary order. SEQN field attached to + * each instruction helps to achieve this. For each TAG queue contains + * instructions with consecutive SEQN values ranging from LO_SEQN[TAG] to + * HI_SEQN[TAG]-1 inclusive. SEQN is 8-bit unsigned integer, so SEQN=255 is + * followed by SEQN=0. + * + * Z bit indicates that zeroes should be stored. No MFIFO fetches are performed + * in this case. + */ + +static void pl330_queue_reset(PL330Queue *s) +{ + int i; + + for (i = 0; i < s->queue_size; i++) { + s->queue[i].tag = PL330_UNTAGGED; + } +} + +/* Initialize queue */ +static void pl330_queue_init(PL330Queue *s, int size, PL330State *parent) +{ + s->parent = parent; + s->queue = g_new0(PL330QueueEntry, size); + s->queue_size = size; +} + +/* Returns pointer to an empty slot or NULL if queue is full */ +static PL330QueueEntry *pl330_queue_find_empty(PL330Queue *s) +{ + int i; + + for (i = 0; i < s->queue_size; i++) { + if (s->queue[i].tag == PL330_UNTAGGED) { + return &s->queue[i]; + } + } + return NULL; +} + +/* Put instruction in queue. + * Return value: + * - zero - OK + * - non-zero - queue is full + */ + +static int pl330_queue_put_insn(PL330Queue *s, uint32_t addr, + int len, int n, bool inc, bool z, uint8_t tag) +{ + PL330QueueEntry *entry = pl330_queue_find_empty(s); + + if (!entry) { + return 1; + } + entry->tag = tag; + entry->addr = addr; + entry->len = len; + entry->n = n; + entry->z = z; + entry->inc = inc; + entry->seqn = s->parent->hi_seqn[tag]; + s->parent->hi_seqn[tag]++; + return 0; +} + +/* Returns a pointer to queue slot containing instruction which satisfies + * following conditions: + * - it has valid tag value (not PL330_UNTAGGED) + * - if enforce_seq is set it has to be issuable without violating queue + * logic (see above) + * - if TAG argument is not PL330_UNTAGGED this instruction has tag value + * equivalent to the argument TAG value. + * If such instruction cannot be found NULL is returned. + */ + +static PL330QueueEntry *pl330_queue_find_insn(PL330Queue *s, uint8_t tag, + bool enforce_seq) +{ + int i; + + for (i = 0; i < s->queue_size; i++) { + if (s->queue[i].tag != PL330_UNTAGGED) { + if ((!enforce_seq || + s->queue[i].seqn == s->parent->lo_seqn[s->queue[i].tag]) && + (s->queue[i].tag == tag || tag == PL330_UNTAGGED || + s->queue[i].z)) { + return &s->queue[i]; + } + } + } + return NULL; +} + +/* Removes instruction from queue. */ + +static inline void pl330_queue_remove_insn(PL330Queue *s, PL330QueueEntry *e) +{ + s->parent->lo_seqn[e->tag]++; + e->tag = PL330_UNTAGGED; +} + +/* Removes all instructions tagged with TAG from queue. */ + +static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag) +{ + int i; + + for (i = 0; i < s->queue_size; i++) { + if (s->queue[i].tag == tag) { + s->queue[i].tag = PL330_UNTAGGED; + } + } +} + +/* DMA instruction execution engine */ + +/* Moves DMA channel to the FAULT state and updates it's status. */ + +static inline void pl330_fault(PL330Chan *ch, uint32_t flags) +{ + DB_PRINT("ch: %p, flags: %x\n", ch, flags); + ch->fault_type |= flags; + if (ch->state == pl330_chan_fault) { + return; + } + ch->state = pl330_chan_fault; + ch->parent->num_faulting++; + if (ch->parent->num_faulting == 1) { + DB_PRINT("abort interrupt raised\n"); + qemu_irq_raise(ch->parent->irq_abort); + } +} + +/* + * For information about instructions see PL330 Technical Reference Manual. + * + * Arguments: + * CH - channel executing the instruction + * OPCODE - opcode + * ARGS - array of 8-bit arguments + * LEN - number of elements in ARGS array + */ + +static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint16_t im = (((uint16_t)args[1]) << 8) | ((uint16_t)args[0]); + uint8_t ra = (opcode >> 1) & 1; + + if (ch->is_manager) { + pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); + return; + } + if (ra) { + ch->dst += im; + } else { + ch->src += im; + } +} + +static void pl330_dmaend(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + PL330State *s = ch->parent; + + if (ch->state == pl330_chan_executing && !ch->is_manager) { + /* Wait for all transfers to complete */ + if (pl330_fifo_has_tag(&s->fifo, ch->tag) || + pl330_queue_find_insn(&s->read_queue, ch->tag, false) != NULL || + pl330_queue_find_insn(&s->write_queue, ch->tag, false) != NULL) { + + ch->stall = 1; + return; + } + } + DB_PRINT("DMA ending!\n"); + pl330_fifo_tagged_remove(&s->fifo, ch->tag); + pl330_queue_remove_tagged(&s->read_queue, ch->tag); + pl330_queue_remove_tagged(&s->write_queue, ch->tag); + ch->state = pl330_chan_stopped; +} + +static void pl330_dmaflushp(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t periph_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + periph_id = (args[0] >> 3) & 0x1f; + if (periph_id >= ch->parent->num_periph_req) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { + pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); + return; + } + /* Do nothing */ +} + +static void pl330_dmago(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t chan_id; + uint8_t ns; + uint32_t pc; + PL330Chan *s; + + DB_PRINT("\n"); + + if (!ch->is_manager) { + pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); + return; + } + ns = !!(opcode & 2); + chan_id = args[0] & 7; + if ((args[0] >> 3)) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (chan_id >= ch->parent->num_chnls) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + pc = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) | + (((uint32_t)args[2]) << 8) | (((uint32_t)args[1])); + if (ch->parent->chan[chan_id].state != pl330_chan_stopped) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !ns) { + pl330_fault(ch, PL330_FAULT_DMAGO_ERR); + return; + } + s = &ch->parent->chan[chan_id]; + s->ns = ns; + s->pc = pc; + s->state = pl330_chan_executing; +} + +static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t bs = opcode & 3; + uint32_t size, num; + bool inc; + + if (bs == 2) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if ((bs == 1 && ch->request_flag == PL330_BURST) || + (bs == 3 && ch->request_flag == PL330_SINGLE)) { + /* Perform NOP */ + return; + } + if (bs == 1 && ch->request_flag == PL330_SINGLE) { + num = 1; + } else { + num = ((ch->control >> 4) & 0xf) + 1; + } + size = (uint32_t)1 << ((ch->control >> 1) & 0x7); + inc = !!(ch->control & 1); + ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src, + size, num, inc, 0, ch->tag); + if (!ch->stall) { + DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n", + ch->tag, ch->src, size, num, inc ? 'Y' : 'N'); + ch->src += inc ? size * num - (ch->src & (size - 1)) : 0; + } +} + +static void pl330_dmaldp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t periph_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + periph_id = (args[0] >> 3) & 0x1f; + if (periph_id >= ch->parent->num_periph_req) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { + pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); + return; + } + pl330_dmald(ch, opcode, args, len); +} + +static void pl330_dmalp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t lc = (opcode & 2) >> 1; + + ch->lc[lc] = args[0]; +} + +static void pl330_dmakill(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + if (ch->state == pl330_chan_fault || + ch->state == pl330_chan_fault_completing) { + /* This is the only way for a channel to leave the faulting state */ + ch->fault_type = 0; + ch->parent->num_faulting--; + if (ch->parent->num_faulting == 0) { + DB_PRINT("abort interrupt lowered\n"); + qemu_irq_lower(ch->parent->irq_abort); + } + } + ch->state = pl330_chan_killing; + pl330_fifo_tagged_remove(&ch->parent->fifo, ch->tag); + pl330_queue_remove_tagged(&ch->parent->read_queue, ch->tag); + pl330_queue_remove_tagged(&ch->parent->write_queue, ch->tag); + ch->state = pl330_chan_stopped; +} + +static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t nf = (opcode & 0x10) >> 4; + uint8_t bs = opcode & 3; + uint8_t lc = (opcode & 4) >> 2; + + if (bs == 2) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if ((bs == 1 && ch->request_flag == PL330_BURST) || + (bs == 3 && ch->request_flag == PL330_SINGLE)) { + /* Perform NOP */ + return; + } + if (!nf || ch->lc[lc]) { + if (nf) { + ch->lc[lc]--; + } + DB_PRINT("loop reiteration\n"); + ch->pc -= args[0]; + ch->pc -= len + 1; + /* "ch->pc -= args[0] + len + 1" is incorrect when args[0] == 256 */ + } else { + DB_PRINT("loop fallthrough\n"); + } +} + + +static void pl330_dmamov(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t rd = args[0] & 7; + uint32_t im; + + if ((args[0] >> 3)) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + im = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) | + (((uint32_t)args[2]) << 8) | (((uint32_t)args[1])); + switch (rd) { + case 0: + ch->src = im; + break; + case 1: + ch->control = im; + break; + case 2: + ch->dst = im; + break; + default: + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } +} + +static void pl330_dmanop(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + /* NOP is NOP. */ +} + +static void pl330_dmarmb(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + if (pl330_queue_find_insn(&ch->parent->read_queue, ch->tag, false)) { + ch->state = pl330_chan_at_barrier; + ch->stall = 1; + return; + } else { + ch->state = pl330_chan_executing; + } +} + +static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t ev_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + ev_id = (args[0] >> 3) & 0x1f; + if (ev_id >= ch->parent->num_events) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) { + pl330_fault(ch, PL330_FAULT_EVENT_ERR); + return; + } + if (ch->parent->inten & (1 << ev_id)) { + ch->parent->int_status |= (1 << ev_id); + DB_PRINT("event interrupt raised %d\n", ev_id); + qemu_irq_raise(ch->parent->irq[ev_id]); + } else { + ch->parent->ev_status |= (1 << ev_id); + } +} + +static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t bs = opcode & 3; + uint32_t size, num; + bool inc; + + if (bs == 2) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if ((bs == 1 && ch->request_flag == PL330_BURST) || + (bs == 3 && ch->request_flag == PL330_SINGLE)) { + /* Perform NOP */ + return; + } + num = ((ch->control >> 18) & 0xf) + 1; + size = (uint32_t)1 << ((ch->control >> 15) & 0x7); + inc = !!((ch->control >> 14) & 1); + ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst, + size, num, inc, 0, ch->tag); + if (!ch->stall) { + DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n", + ch->tag, ch->dst, size, num, inc ? 'Y' : 'N'); + ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0; + } +} + +static void pl330_dmastp(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t periph_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + periph_id = (args[0] >> 3) & 0x1f; + if (periph_id >= ch->parent->num_periph_req) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { + pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); + return; + } + pl330_dmast(ch, opcode, args, len); +} + +static void pl330_dmastz(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint32_t size, num; + bool inc; + + num = ((ch->control >> 18) & 0xf) + 1; + size = (uint32_t)1 << ((ch->control >> 15) & 0x7); + inc = !!((ch->control >> 14) & 1); + ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst, + size, num, inc, 1, ch->tag); + if (inc) { + ch->dst += size * num; + } +} + +static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t ev_id; + int i; + + if (args[0] & 5) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + ev_id = (args[0] >> 3) & 0x1f; + if (ev_id >= ch->parent->num_events) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) { + pl330_fault(ch, PL330_FAULT_EVENT_ERR); + return; + } + ch->wakeup = ev_id; + ch->state = pl330_chan_waiting_event; + if (~ch->parent->inten & ch->parent->ev_status & 1 << ev_id) { + ch->state = pl330_chan_executing; + /* If anyone else is currently waiting on the same event, let them + * clear the ev_status so they pick up event as well + */ + for (i = 0; i < ch->parent->num_chnls; ++i) { + PL330Chan *peer = &ch->parent->chan[i]; + if (peer->state == pl330_chan_waiting_event && + peer->wakeup == ev_id) { + return; + } + } + ch->parent->ev_status &= ~(1 << ev_id); + } else { + ch->stall = 1; + } +} + +static void pl330_dmawfp(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t bs = opcode & 3; + uint8_t periph_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + periph_id = (args[0] >> 3) & 0x1f; + if (periph_id >= ch->parent->num_periph_req) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { + pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); + return; + } + switch (bs) { + case 0: /* S */ + ch->request_flag = PL330_SINGLE; + ch->wfp_sbp = 0; + break; + case 1: /* P */ + ch->request_flag = PL330_BURST; + ch->wfp_sbp = 2; + break; + case 2: /* B */ + ch->request_flag = PL330_BURST; + ch->wfp_sbp = 1; + break; + default: + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + + if (ch->parent->periph_busy[periph_id]) { + ch->state = pl330_chan_waiting_periph; + ch->stall = 1; + } else if (ch->state == pl330_chan_waiting_periph) { + ch->state = pl330_chan_executing; + } +} + +static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + if (pl330_queue_find_insn(&ch->parent->write_queue, ch->tag, false)) { + ch->state = pl330_chan_at_barrier; + ch->stall = 1; + return; + } else { + ch->state = pl330_chan_executing; + } +} + +/* NULL terminated array of the instruction descriptions. */ +static const PL330InsnDesc insn_desc[] = { + { .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, }, + { .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, }, + { .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, }, + { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, }, + { .opcode = 0x04, .opmask = 0xFC, .size = 1, .exec = pl330_dmald, }, + { .opcode = 0x25, .opmask = 0xFD, .size = 2, .exec = pl330_dmaldp, }, + { .opcode = 0x20, .opmask = 0xFD, .size = 2, .exec = pl330_dmalp, }, + /* dmastp must be before dmalpend in this list, because their maps + * are overlapping + */ + { .opcode = 0x29, .opmask = 0xFD, .size = 2, .exec = pl330_dmastp, }, + { .opcode = 0x28, .opmask = 0xE8, .size = 2, .exec = pl330_dmalpend, }, + { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, }, + { .opcode = 0xBC, .opmask = 0xFF, .size = 6, .exec = pl330_dmamov, }, + { .opcode = 0x18, .opmask = 0xFF, .size = 1, .exec = pl330_dmanop, }, + { .opcode = 0x12, .opmask = 0xFF, .size = 1, .exec = pl330_dmarmb, }, + { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, }, + { .opcode = 0x08, .opmask = 0xFC, .size = 1, .exec = pl330_dmast, }, + { .opcode = 0x0C, .opmask = 0xFF, .size = 1, .exec = pl330_dmastz, }, + { .opcode = 0x36, .opmask = 0xFF, .size = 2, .exec = pl330_dmawfe, }, + { .opcode = 0x30, .opmask = 0xFC, .size = 2, .exec = pl330_dmawfp, }, + { .opcode = 0x13, .opmask = 0xFF, .size = 1, .exec = pl330_dmawmb, }, + { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, } +}; + +/* Instructions which can be issued via debug registers. */ +static const PL330InsnDesc debug_insn_desc[] = { + { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, }, + { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, }, + { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, }, + { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, } +}; + +static inline const PL330InsnDesc *pl330_fetch_insn(PL330Chan *ch) +{ + uint8_t opcode; + int i; + + dma_memory_read(&dma_context_memory, ch->pc, &opcode, 1); + for (i = 0; insn_desc[i].size; i++) { + if ((opcode & insn_desc[i].opmask) == insn_desc[i].opcode) { + return &insn_desc[i]; + } + } + return NULL; +} + +static inline void pl330_exec_insn(PL330Chan *ch, const PL330InsnDesc *insn) +{ + uint8_t buf[PL330_INSN_MAXSIZE]; + + assert(insn->size <= PL330_INSN_MAXSIZE); + dma_memory_read(&dma_context_memory, ch->pc, buf, insn->size); + insn->exec(ch, buf[0], &buf[1], insn->size - 1); +} + +static inline void pl330_update_pc(PL330Chan *ch, + const PL330InsnDesc *insn) +{ + ch->pc += insn->size; +} + +/* Try to execute current instruction in channel CH. Number of executed + instructions is returned (0 or 1). */ +static int pl330_chan_exec(PL330Chan *ch) +{ + const PL330InsnDesc *insn; + + if (ch->state != pl330_chan_executing && + ch->state != pl330_chan_waiting_periph && + ch->state != pl330_chan_at_barrier && + ch->state != pl330_chan_waiting_event) { + DB_PRINT("%d\n", ch->state); + return 0; + } + ch->stall = 0; + insn = pl330_fetch_insn(ch); + if (!insn) { + DB_PRINT("pl330 undefined instruction\n"); + pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); + return 0; + } + pl330_exec_insn(ch, insn); + if (!ch->stall) { + pl330_update_pc(ch, insn); + ch->watchdog_timer = 0; + return 1; + /* WDT only active in exec state */ + } else if (ch->state == pl330_chan_executing) { + ch->watchdog_timer++; + if (ch->watchdog_timer >= PL330_WATCHDOG_LIMIT) { + pl330_fault(ch, PL330_FAULT_LOCKUP_ERR); + } + } + return 0; +} + +/* Try to execute 1 instruction in each channel, one instruction from read + queue and one instruction from write queue. Number of successfully executed + instructions is returned. */ +static int pl330_exec_cycle(PL330Chan *channel) +{ + PL330State *s = channel->parent; + PL330QueueEntry *q; + int i; + int num_exec = 0; + int fifo_res = 0; + uint8_t buf[PL330_MAX_BURST_LEN]; + + /* Execute one instruction in each channel */ + num_exec += pl330_chan_exec(channel); + + /* Execute one instruction from read queue */ + q = pl330_queue_find_insn(&s->read_queue, PL330_UNTAGGED, true); + if (q != NULL && q->len <= pl330_fifo_num_free(&s->fifo)) { + int len = q->len - (q->addr & (q->len - 1)); + + dma_memory_read(&dma_context_memory, q->addr, buf, len); + if (PL330_ERR_DEBUG > 1) { + DB_PRINT("PL330 read from memory @%08x (size = %08x):\n", + q->addr, len); + hexdump((char *)buf, stderr, "", len); + } + fifo_res = pl330_fifo_push(&s->fifo, buf, len, q->tag); + if (fifo_res == PL330_FIFO_OK) { + if (q->inc) { + q->addr += len; + } + q->n--; + if (!q->n) { + pl330_queue_remove_insn(&s->read_queue, q); + } + num_exec++; + } + } + + /* Execute one instruction from write queue. */ + q = pl330_queue_find_insn(&s->write_queue, pl330_fifo_tag(&s->fifo), true); + if (q != NULL) { + int len = q->len - (q->addr & (q->len - 1)); + + if (q->z) { + for (i = 0; i < len; i++) { + buf[i] = 0; + } + } else { + fifo_res = pl330_fifo_get(&s->fifo, buf, len, q->tag); + } + if (fifo_res == PL330_FIFO_OK || q->z) { + dma_memory_write(&dma_context_memory, q->addr, buf, len); + if (PL330_ERR_DEBUG > 1) { + DB_PRINT("PL330 read from memory @%08x (size = %08x):\n", + q->addr, len); + hexdump((char *)buf, stderr, "", len); + } + if (q->inc) { + q->addr += len; + } + num_exec++; + } else if (fifo_res == PL330_FIFO_STALL) { + pl330_fault(&channel->parent->chan[q->tag], + PL330_FAULT_FIFOEMPTY_ERR); + } + q->n--; + if (!q->n) { + pl330_queue_remove_insn(&s->write_queue, q); + } + } + + return num_exec; +} + +static int pl330_exec_channel(PL330Chan *channel) +{ + int insr_exec = 0; + + /* TODO: Is it all right to execute everything or should we do per-cycle + simulation? */ + while (pl330_exec_cycle(channel)) { + insr_exec++; + } + + /* Detect deadlock */ + if (channel->state == pl330_chan_executing) { + pl330_fault(channel, PL330_FAULT_LOCKUP_ERR); + } + /* Situation when one of the queues has deadlocked but all channels + * have finished their programs should be impossible. + */ + + return insr_exec; +} + +static inline void pl330_exec(PL330State *s) +{ + DB_PRINT("\n"); + int i, insr_exec; + do { + insr_exec = pl330_exec_channel(&s->manager); + + for (i = 0; i < s->num_chnls; i++) { + insr_exec += pl330_exec_channel(&s->chan[i]); + } + } while (insr_exec); +} + +static void pl330_exec_cycle_timer(void *opaque) +{ + PL330State *s = (PL330State *)opaque; + pl330_exec(s); +} + +/* Stop or restore dma operations */ + +static void pl330_dma_stop_irq(void *opaque, int irq, int level) +{ + PL330State *s = (PL330State *)opaque; + + if (s->periph_busy[irq] != level) { + s->periph_busy[irq] = level; + qemu_mod_timer(s->timer, qemu_get_clock_ns(vm_clock)); + } +} + +static void pl330_debug_exec(PL330State *s) +{ + uint8_t args[5]; + uint8_t opcode; + uint8_t chan_id; + int i; + PL330Chan *ch; + const PL330InsnDesc *insn; + + s->debug_status = 1; + chan_id = (s->dbg[0] >> 8) & 0x07; + opcode = (s->dbg[0] >> 16) & 0xff; + args[0] = (s->dbg[0] >> 24) & 0xff; + args[1] = (s->dbg[1] >> 0) & 0xff; + args[2] = (s->dbg[1] >> 8) & 0xff; + args[3] = (s->dbg[1] >> 16) & 0xff; + args[4] = (s->dbg[1] >> 24) & 0xff; + DB_PRINT("chan id: %d\n", chan_id); + if (s->dbg[0] & 1) { + ch = &s->chan[chan_id]; + } else { + ch = &s->manager; + } + insn = NULL; + for (i = 0; debug_insn_desc[i].size; i++) { + if ((opcode & debug_insn_desc[i].opmask) == debug_insn_desc[i].opcode) { + insn = &debug_insn_desc[i]; + } + } + if (!insn) { + pl330_fault(ch, PL330_FAULT_UNDEF_INSTR | PL330_FAULT_DBG_INSTR); + return ; + } + ch->stall = 0; + insn->exec(ch, opcode, args, insn->size - 1); + if (ch->fault_type) { + ch->fault_type |= PL330_FAULT_DBG_INSTR; + } + if (ch->stall) { + qemu_log_mask(LOG_UNIMP, "pl330: stall of debug instruction not " + "implemented\n"); + } + s->debug_status = 0; +} + +/* IOMEM mapped registers */ + +static void pl330_iomem_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PL330State *s = (PL330State *) opaque; + uint32_t i; + + DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value); + + switch (offset) { + case PL330_REG_INTEN: + s->inten = value; + break; + case PL330_REG_INTCLR: + for (i = 0; i < s->num_events; i++) { + if (s->int_status & s->inten & value & (1 << i)) { + DB_PRINT("event interrupt lowered %d\n", i); + qemu_irq_lower(s->irq[i]); + } + } + s->ev_status &= ~(value & s->inten); + s->int_status &= ~(value & s->inten); + break; + case PL330_REG_DBGCMD: + if ((value & 3) == 0) { + pl330_debug_exec(s); + pl330_exec(s); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "pl330: write of illegal value %u " + "for offset " TARGET_FMT_plx "\n", (unsigned)value, + offset); + } + break; + case PL330_REG_DBGINST0: + DB_PRINT("s->dbg[0] = %08x\n", (unsigned)value); + s->dbg[0] = value; + break; + case PL330_REG_DBGINST1: + DB_PRINT("s->dbg[1] = %08x\n", (unsigned)value); + s->dbg[1] = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad write offset " TARGET_FMT_plx + "\n", offset); + break; + } +} + +static inline uint32_t pl330_iomem_read_imp(void *opaque, + hwaddr offset) +{ + PL330State *s = (PL330State *)opaque; + int chan_id; + int i; + uint32_t res; + + if (offset >= PL330_REG_PERIPH_ID && offset < PL330_REG_PERIPH_ID + 32) { + return pl330_id[(offset - PL330_REG_PERIPH_ID) >> 2]; + } + if (offset >= PL330_REG_CR0_BASE && offset < PL330_REG_CR0_BASE + 24) { + return s->cfg[(offset - PL330_REG_CR0_BASE) >> 2]; + } + if (offset >= PL330_REG_CHANCTRL && offset < PL330_REG_DBGSTATUS) { + offset -= PL330_REG_CHANCTRL; + chan_id = offset >> 5; + if (chan_id >= s->num_chnls) { + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + return 0; + } + switch (offset & 0x1f) { + case 0x00: + return s->chan[chan_id].src; + case 0x04: + return s->chan[chan_id].dst; + case 0x08: + return s->chan[chan_id].control; + case 0x0C: + return s->chan[chan_id].lc[0]; + case 0x10: + return s->chan[chan_id].lc[1]; + default: + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + return 0; + } + } + if (offset >= PL330_REG_CSR_BASE && offset < 0x400) { + offset -= PL330_REG_CSR_BASE; + chan_id = offset >> 3; + if (chan_id >= s->num_chnls) { + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + return 0; + } + switch ((offset >> 2) & 1) { + case 0x0: + res = (s->chan[chan_id].ns << 21) | + (s->chan[chan_id].wakeup << 4) | + (s->chan[chan_id].state) | + (s->chan[chan_id].wfp_sbp << 14); + return res; + case 0x1: + return s->chan[chan_id].pc; + default: + qemu_log_mask(LOG_GUEST_ERROR, "pl330: read error\n"); + return 0; + } + } + if (offset >= PL330_REG_FTR_BASE && offset < 0x100) { + offset -= PL330_REG_FTR_BASE; + chan_id = offset >> 2; + if (chan_id >= s->num_chnls) { + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + return 0; + } + return s->chan[chan_id].fault_type; + } + switch (offset) { + case PL330_REG_DSR: + return (s->manager.ns << 9) | (s->manager.wakeup << 4) | + (s->manager.state & 0xf); + case PL330_REG_DPC: + return s->manager.pc; + case PL330_REG_INTEN: + return s->inten; + case PL330_REG_INT_EVENT_RIS: + return s->ev_status; + case PL330_REG_INTMIS: + return s->int_status; + case PL330_REG_INTCLR: + /* Documentation says that we can't read this register + * but linux kernel does it + */ + return 0; + case PL330_REG_FSRD: + return s->manager.state ? 1 : 0; + case PL330_REG_FSRC: + res = 0; + for (i = 0; i < s->num_chnls; i++) { + if (s->chan[i].state == pl330_chan_fault || + s->chan[i].state == pl330_chan_fault_completing) { + res |= 1 << i; + } + } + return res; + case PL330_REG_FTRD: + return s->manager.fault_type; + case PL330_REG_DBGSTATUS: + return s->debug_status; + default: + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + } + return 0; +} + +static uint64_t pl330_iomem_read(void *opaque, hwaddr offset, + unsigned size) +{ + int ret = pl330_iomem_read_imp(opaque, offset); + DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, ret); + return ret; +} + +static const MemoryRegionOps pl330_ops = { + .read = pl330_iomem_read, + .write = pl330_iomem_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + +/* Controller logic and initialization */ + +static void pl330_chan_reset(PL330Chan *ch) +{ + ch->src = 0; + ch->dst = 0; + ch->pc = 0; + ch->state = pl330_chan_stopped; + ch->watchdog_timer = 0; + ch->stall = 0; + ch->control = 0; + ch->status = 0; + ch->fault_type = 0; +} + +static void pl330_reset(DeviceState *d) +{ + int i; + PL330State *s = PL330(d); + + s->inten = 0; + s->int_status = 0; + s->ev_status = 0; + s->debug_status = 0; + s->num_faulting = 0; + s->manager.ns = s->mgr_ns_at_rst; + pl330_fifo_reset(&s->fifo); + pl330_queue_reset(&s->read_queue); + pl330_queue_reset(&s->write_queue); + + for (i = 0; i < s->num_chnls; i++) { + pl330_chan_reset(&s->chan[i]); + } + for (i = 0; i < s->num_periph_req; i++) { + s->periph_busy[i] = 0; + } + + qemu_del_timer(s->timer); +} + +static void pl330_realize(DeviceState *dev, Error **errp) +{ + int i; + PL330State *s = PL330(dev); + + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq_abort); + memory_region_init_io(&s->iomem, &pl330_ops, s, "dma", PL330_IOMEM_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + + s->timer = qemu_new_timer_ns(vm_clock, pl330_exec_cycle_timer, s); + + s->cfg[0] = (s->mgr_ns_at_rst ? 0x4 : 0) | + (s->num_periph_req > 0 ? 1 : 0) | + ((s->num_chnls - 1) & 0x7) << 4 | + ((s->num_periph_req - 1) & 0x1f) << 12 | + ((s->num_events - 1) & 0x1f) << 17; + + switch (s->i_cache_len) { + case (4): + s->cfg[1] |= 2; + break; + case (8): + s->cfg[1] |= 3; + break; + case (16): + s->cfg[1] |= 4; + break; + case (32): + s->cfg[1] |= 5; + break; + default: + error_setg(errp, "Bad value for i-cache_len property: %d\n", + s->i_cache_len); + return; + } + s->cfg[1] |= ((s->num_i_cache_lines - 1) & 0xf) << 4; + + s->chan = g_new0(PL330Chan, s->num_chnls); + s->hi_seqn = g_new0(uint8_t, s->num_chnls); + s->lo_seqn = g_new0(uint8_t, s->num_chnls); + for (i = 0; i < s->num_chnls; i++) { + s->chan[i].parent = s; + s->chan[i].tag = (uint8_t)i; + } + s->manager.parent = s; + s->manager.tag = s->num_chnls; + s->manager.is_manager = true; + + s->irq = g_new0(qemu_irq, s->num_events); + for (i = 0; i < s->num_events; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); + } + + qdev_init_gpio_in(dev, pl330_dma_stop_irq, PL330_PERIPH_NUM); + + switch (s->data_width) { + case (32): + s->cfg[CFG_CRD] |= 0x2; + break; + case (64): + s->cfg[CFG_CRD] |= 0x3; + break; + case (128): + s->cfg[CFG_CRD] |= 0x4; + break; + default: + error_setg(errp, "Bad value for data_width property: %d\n", + s->data_width); + return; + } + + s->cfg[CFG_CRD] |= ((s->wr_cap - 1) & 0x7) << 4 | + ((s->wr_q_dep - 1) & 0xf) << 8 | + ((s->rd_cap - 1) & 0x7) << 12 | + ((s->rd_q_dep - 1) & 0xf) << 16 | + ((s->data_buffer_dep - 1) & 0x1ff) << 20; + + pl330_queue_init(&s->read_queue, s->rd_q_dep, s); + pl330_queue_init(&s->write_queue, s->wr_q_dep, s); + pl330_fifo_init(&s->fifo, s->data_buffer_dep); +} + +static Property pl330_properties[] = { + /* CR0 */ + DEFINE_PROP_UINT32("num_chnls", PL330State, num_chnls, 8), + DEFINE_PROP_UINT8("num_periph_req", PL330State, num_periph_req, 4), + DEFINE_PROP_UINT8("num_events", PL330State, num_events, 16), + DEFINE_PROP_UINT8("mgr_ns_at_rst", PL330State, mgr_ns_at_rst, 0), + /* CR1 */ + DEFINE_PROP_UINT8("i-cache_len", PL330State, i_cache_len, 4), + DEFINE_PROP_UINT8("num_i-cache_lines", PL330State, num_i_cache_lines, 8), + /* CR2-4 */ + DEFINE_PROP_UINT32("boot_addr", PL330State, cfg[CFG_BOOT_ADDR], 0), + DEFINE_PROP_UINT32("INS", PL330State, cfg[CFG_INS], 0), + DEFINE_PROP_UINT32("PNS", PL330State, cfg[CFG_PNS], 0), + /* CRD */ + DEFINE_PROP_UINT8("data_width", PL330State, data_width, 64), + DEFINE_PROP_UINT8("wr_cap", PL330State, wr_cap, 8), + DEFINE_PROP_UINT8("wr_q_dep", PL330State, wr_q_dep, 16), + DEFINE_PROP_UINT8("rd_cap", PL330State, rd_cap, 8), + DEFINE_PROP_UINT8("rd_q_dep", PL330State, rd_q_dep, 16), + DEFINE_PROP_UINT16("data_buffer_dep", PL330State, data_buffer_dep, 256), + + DEFINE_PROP_END_OF_LIST(), +}; + +static void pl330_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = pl330_realize; + dc->reset = pl330_reset; + dc->props = pl330_properties; + dc->vmsd = &vmstate_pl330; +} + +static const TypeInfo pl330_type_info = { + .name = TYPE_PL330, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PL330State), + .class_init = pl330_class_init, +}; + +static void pl330_register_types(void) +{ + type_register_static(&pl330_type_info); +} + +type_init(pl330_register_types) -- cgit v1.1 From 7451afb67136275f2461f2d23139f2abed1f15b3 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Fri, 15 Mar 2013 16:41:58 +0000 Subject: xilinx_zynq: added pl330 to machine model Signed-off-by: Peter Crosthwaite Reviewed-by: Peter Maydell Message-id: 5bc295bd2aa50dfe573f428574dbd7d8add7b3f8.1361853677.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/arm/xilinx_zynq.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'hw') diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index f78c47e..6f36286 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -35,6 +35,10 @@ #define IRQ_OFFSET 32 /* pic interrupts start from index 32 */ +static const int dma_irqs[8] = { + 46, 47, 48, 49, 72, 73, 74, 75 +}; + static struct arm_boot_info zynq_binfo = {}; static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) @@ -196,6 +200,26 @@ static void zynq_init(QEMUMachineInitArgs *args) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); + dev = qdev_create(NULL, "pl330"); + qdev_prop_set_uint8(dev, "num_chnls", 8); + qdev_prop_set_uint8(dev, "num_periph_req", 4); + qdev_prop_set_uint8(dev, "num_events", 16); + + qdev_prop_set_uint8(dev, "data_width", 64); + qdev_prop_set_uint8(dev, "wr_cap", 8); + qdev_prop_set_uint8(dev, "wr_q_dep", 16); + qdev_prop_set_uint8(dev, "rd_cap", 8); + qdev_prop_set_uint8(dev, "rd_q_dep", 16); + qdev_prop_set_uint16(dev, "data_buffer_dep", 256); + + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0xF8003000); + sysbus_connect_irq(busdev, 0, pic[45-IRQ_OFFSET]); /* abort irq line */ + for (n = 0; n < 8; ++n) { /* event irqs */ + sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]); + } + zynq_binfo.ram_size = ram_size; zynq_binfo.kernel_filename = kernel_filename; zynq_binfo.kernel_cmdline = kernel_cmdline; -- cgit v1.1 From 2790cd911e563f7fec7eeb7856b7f5f54437cc0a Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Fri, 15 Mar 2013 16:41:58 +0000 Subject: xilinx_spips: Set unused IRQs to NULL Unused CS lines should init to 0 to avoid segfaulting when accessing an unattached QSPI controller. Signed-off-by: Peter Crosthwaite Message-id: c1e45198032106e69e8fe9339fc2e6348d524fcd.1362373359.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/xilinx_spips.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index 6c21b96..853f4e0 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -497,7 +497,7 @@ static int xilinx_spips_init(SysBusDevice *dev) s->spi[i] = ssi_create_bus(&dev->qdev, bus_name); } - s->cs_lines = g_new(qemu_irq, s->num_cs * s->num_busses); + s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses); ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]); ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]); sysbus_init_irq(dev, &s->irq); -- cgit v1.1 From e0891bd8bfd3349fc3fecde30e51900059f53f11 Mon Sep 17 00:00:00 2001 From: Nathan Rossi Date: Fri, 15 Mar 2013 16:41:59 +0000 Subject: xilinx_spips: Fix bus setup conditional check The R_LQPSI_CFG register has the LQSPI_CFG_SEP_BUS and LQSPI_CFG_TWO_MEM bits. Signed-off-by: Nathan Rossi Signed-off-by: Peter Crosthwaite Message-id: d76c8e364c80a42352ae4f0661aff2cd17ad32a4.1362373359.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/xilinx_spips.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index 853f4e0..efa1449 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -143,8 +143,8 @@ typedef struct { static inline int num_effective_busses(XilinxSPIPS *s) { - return (s->regs[R_LQSPI_STS] & LQSPI_CFG_SEP_BUS && - s->regs[R_LQSPI_STS] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1; + return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS && + s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1; } static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) -- cgit v1.1 From 08a9635b68757e18a6a8bf8569353b40bb6c1fd1 Mon Sep 17 00:00:00 2001 From: Nathan Rossi Date: Fri, 15 Mar 2013 16:41:59 +0000 Subject: xilinx_spips: Add missing dual-bus snoop commands Added additional commands to the switch to check for when snooping commands in dual bus mode setups. Cleaned up code to use an enum. Signed-off-by: Nathan Rossi Signed-off-by: Peter Crosthwaite Message-id: 848c116c711dab0af10729a487968384aadd9faf.1362373359.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/xilinx_spips.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index efa1449..3183f7a 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -115,6 +115,19 @@ #define SNOOP_NONE 0xFE #define SNOOP_STRIPING 0 +typedef enum { + READ = 0x3, + FAST_READ = 0xb, + DOR = 0x3b, + QOR = 0x6b, + DIOR = 0xbb, + QIOR = 0xeb, + + PP = 0x2, + DPP = 0xa2, + QPP = 0x32, +} FlashCMD; + typedef struct { SysBusDevice busdev; MemoryRegion iomem; @@ -251,15 +264,19 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) switch (s->snoop_state) { case (SNOOP_CHECKING): switch (tx) { /* new instruction code */ - case 0x0b: /* dual/quad output read DOR/QOR */ - case 0x6b: - s->snoop_state = 4; + case READ: /* 3 address bytes, no dummy bytes/cycles */ + case PP: + case DPP: + case QPP: + s->snoop_state = 3; break; - /* FIXME: these vary between vendor - set to spansion */ - case 0xbb: /* high performance dual read DIOR */ + case FAST_READ: /* 3 address bytes, 1 dummy byte */ + case DOR: + case QOR: + case DIOR: /* FIXME: these vary between vendor - set to spansion */ s->snoop_state = 4; break; - case 0xeb: /* high performance quad read QIOR */ + case QIOR: /* 3 address bytes, 2 dummy bytes */ s->snoop_state = 6; break; default: -- cgit v1.1 From f8b9fe249a706bfed61e0bb66c73394553696382 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Fri, 15 Mar 2013 16:41:59 +0000 Subject: xilinx_spips: QOM styling fixes Few fixes for the latest QOM styling guides. Signed-off-by: Peter Crosthwaite Message-id: de9daeee6c142e8b57ad042fd680cedcdc94d2fc.1362373359.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/xilinx_spips.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index 3183f7a..b2397f4 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -154,6 +154,11 @@ typedef struct { hwaddr lqspi_cached_addr; } XilinxSPIPS; +#define TYPE_XILINX_SPIPS "xilinx,spips" + +#define XILINX_SPIPS(obj) \ + OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS) + static inline int num_effective_busses(XilinxSPIPS *s) { return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS && @@ -210,7 +215,7 @@ static void xilinx_spips_update_ixr(XilinxSPIPS *s) static void xilinx_spips_reset(DeviceState *d) { - XilinxSPIPS *s = DO_UPCAST(XilinxSPIPS, busdev.qdev, d); + XilinxSPIPS *s = XILINX_SPIPS(d); int i; for (i = 0; i < R_MAX; i++) { @@ -500,9 +505,10 @@ static const MemoryRegionOps lqspi_ops = { } }; -static int xilinx_spips_init(SysBusDevice *dev) +static void xilinx_spips_realize(DeviceState *dev, Error **errp) { - XilinxSPIPS *s = FROM_SYSBUS(typeof(*s), dev); + XilinxSPIPS *s = XILINX_SPIPS(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); int i; DB_PRINT("inited device model\n"); @@ -511,31 +517,29 @@ static int xilinx_spips_init(SysBusDevice *dev) for (i = 0; i < s->num_busses; ++i) { char bus_name[16]; snprintf(bus_name, 16, "spi%d", i); - s->spi[i] = ssi_create_bus(&dev->qdev, bus_name); + s->spi[i] = ssi_create_bus(dev, bus_name); } s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses); ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]); ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); for (i = 0; i < s->num_cs * s->num_busses; ++i) { - sysbus_init_irq(dev, &s->cs_lines[i]); + sysbus_init_irq(sbd, &s->cs_lines[i]); } memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi", (1 << LQSPI_ADDRESS_BITS) * 2); - sysbus_init_mmio(dev, &s->mmlqspi); + sysbus_init_mmio(sbd, &s->mmlqspi); s->irqline = -1; s->lqspi_cached_addr = ~0ULL; fifo8_create(&s->rx_fifo, RXFF_A); fifo8_create(&s->tx_fifo, TXFF_A); - - return 0; } static int xilinx_spips_post_load(void *opaque, int version_id) @@ -569,16 +573,15 @@ static Property xilinx_spips_properties[] = { static void xilinx_spips_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - sdc->init = xilinx_spips_init; + dc->realize = xilinx_spips_realize; dc->reset = xilinx_spips_reset; dc->props = xilinx_spips_properties; dc->vmsd = &vmstate_xilinx_spips; } static const TypeInfo xilinx_spips_info = { - .name = "xilinx,spips", + .name = TYPE_XILINX_SPIPS, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(XilinxSPIPS), .class_init = xilinx_spips_class_init, -- cgit v1.1 From 7c20b4a374d0016e3fce005690fb428354a56621 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 13 Nov 2012 14:51:41 +0100 Subject: console: fix displaychangelisteners interface Split callbacks into separate Ops struct. Pass DisplayChangeListener pointer as first argument to all callbacks. Uninline a bunch of display functions and move them from console.h to console.c Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/qxl.c b/hw/qxl.c index ef69348..fe1c4f1 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1866,21 +1866,25 @@ static void qxl_vm_change_state_handler(void *opaque, int running, /* display change listener */ -static void display_update(struct DisplayState *ds, int x, int y, int w, int h) +static void display_update(DisplayChangeListener *dcl, + struct DisplayState *ds, + int x, int y, int w, int h) { if (qxl0->mode == QXL_MODE_VGA) { qemu_spice_display_update(&qxl0->ssd, x, y, w, h); } } -static void display_resize(struct DisplayState *ds) +static void display_resize(DisplayChangeListener *dcl, + struct DisplayState *ds) { if (qxl0->mode == QXL_MODE_VGA) { qemu_spice_display_resize(&qxl0->ssd); } } -static void display_refresh(struct DisplayState *ds) +static void display_refresh(DisplayChangeListener *dcl, + struct DisplayState *ds) { if (qxl0->mode == QXL_MODE_VGA) { qemu_spice_display_refresh(&qxl0->ssd); @@ -1891,10 +1895,11 @@ static void display_refresh(struct DisplayState *ds) } } -static DisplayChangeListener display_listener = { +static DisplayChangeListenerOps display_listener_ops = { + .dpy_name = "spice/qxl", .dpy_gfx_update = display_update, .dpy_gfx_resize = display_resize, - .dpy_refresh = display_refresh, + .dpy_refresh = display_refresh, }; static void qxl_init_ramsize(PCIQXLDevice *qxl) @@ -2076,7 +2081,8 @@ static int qxl_init_primary(PCIDevice *dev) return rc; } - register_displaychangelistener(vga->ds, &display_listener); + qxl->ssd.dcl.ops = &display_listener_ops; + register_displaychangelistener(vga->ds, &qxl->ssd.dcl); return rc; } -- cgit v1.1 From c6c06853d99127c03778fc1bf9bc2d96a05c108e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Feb 2013 12:15:00 +0100 Subject: qxl: zap qxl0 global DisplayChangeListener is passed now to all DisplayChangeListenerOps callbacks, so we can use that to access the qxl state and kill the qxl0 global variable. Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/qxl.c b/hw/qxl.c index fe1c4f1..54a8d91 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -118,8 +118,6 @@ static QXLMode qxl_modes[] = { QXL_MODE_EX(3200, 2400), }; -static PCIQXLDevice *qxl0; - static void qxl_send_events(PCIQXLDevice *d, uint32_t events); static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async); static void qxl_reset_memslots(PCIQXLDevice *d); @@ -1870,28 +1868,34 @@ static void display_update(DisplayChangeListener *dcl, struct DisplayState *ds, int x, int y, int w, int h) { - if (qxl0->mode == QXL_MODE_VGA) { - qemu_spice_display_update(&qxl0->ssd, x, y, w, h); + PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); + + if (qxl->mode == QXL_MODE_VGA) { + qemu_spice_display_update(&qxl->ssd, x, y, w, h); } } static void display_resize(DisplayChangeListener *dcl, struct DisplayState *ds) { - if (qxl0->mode == QXL_MODE_VGA) { - qemu_spice_display_resize(&qxl0->ssd); + PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); + + if (qxl->mode == QXL_MODE_VGA) { + qemu_spice_display_resize(&qxl->ssd); } } static void display_refresh(DisplayChangeListener *dcl, struct DisplayState *ds) { - if (qxl0->mode == QXL_MODE_VGA) { - qemu_spice_display_refresh(&qxl0->ssd); + PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); + + if (qxl->mode == QXL_MODE_VGA) { + qemu_spice_display_refresh(&qxl->ssd); } else { - qemu_mutex_lock(&qxl0->ssd.lock); - qemu_spice_cursor_refresh_unlocked(&qxl0->ssd); - qemu_mutex_unlock(&qxl0->ssd.lock); + qemu_mutex_lock(&qxl->ssd.lock); + qemu_spice_cursor_refresh_unlocked(&qxl->ssd); + qemu_mutex_unlock(&qxl->ssd.lock); } } @@ -2074,8 +2078,6 @@ static int qxl_init_primary(PCIDevice *dev) qxl_hw_screen_dump, qxl_hw_text_update, qxl); qemu_spice_display_init_common(&qxl->ssd, vga->ds); - qxl0 = qxl; - rc = qxl_init_common(qxl); if (rc != 0) { return rc; -- cgit v1.1 From c099e7aa0295678859d58e9e60b7619f6ae3bac8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Feb 2013 11:08:50 +0100 Subject: qxl: better vga init in enter_vga_mode Ask the vga core to update the display. Will trigger dpy_gfx_resize if needed. More complete than just calling dpy_gfx_resize. Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/qxl.c b/hw/qxl.c index 54a8d91..5d830f0 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1073,8 +1073,8 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) trace_qxl_enter_vga_mode(d->id); qemu_spice_create_host_primary(&d->ssd); d->mode = QXL_MODE_VGA; - dpy_gfx_resize(d->ssd.ds); vga_dirty_log_start(&d->vga); + vga_hw_update(); } static void qxl_exit_vga_mode(PCIQXLDevice *d) -- cgit v1.1 From da229ef3b3c5709b01d62e7a6e213b31bca33d16 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Feb 2013 10:48:02 +0100 Subject: console: rework DisplaySurface handling [vga emu side] Decouple DisplaySurface allocation & deallocation from DisplayState. Replace dpy_gfx_resize + dpy_gfx_setdata with a dpy_gfx_replace_surface function. This handles the graphic hardware emulation. Signed-off-by: Gerd Hoffmann --- hw/arm/nseries.c | 7 ------- hw/arm/palm.c | 7 ------- hw/qxl-render.c | 12 ++++++------ hw/vga.c | 17 ++++++++--------- hw/xenfb.c | 8 ++++---- 5 files changed, 18 insertions(+), 33 deletions(-) (limited to 'hw') diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index c5bf9f9..6747c1c 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -1290,7 +1290,6 @@ static void n8x0_init(QEMUMachineInitArgs *args, MemoryRegion *sysmem = get_system_memory(); struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); int sdram_size = binfo->ram_size; - DisplayState *ds; s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model); @@ -1370,12 +1369,6 @@ static void n8x0_init(QEMUMachineInitArgs *args, n800_setup_nolo_tags(nolo_tags); cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000); } - /* FIXME: We shouldn't really be doing this here. The LCD controller - will set the size once configured, so this just sets an initial - size until the guest activates the display. */ - ds = get_displaystate(); - ds->surface = qemu_resize_displaysurface(ds, 800, 480); - dpy_gfx_resize(ds); } static struct arm_boot_info n800_binfo = { diff --git a/hw/arm/palm.c b/hw/arm/palm.c index 91bc74a..baeb585 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -205,7 +205,6 @@ static void palmte_init(QEMUMachineInitArgs *args) static uint32_t cs2val = 0x0000e1a0; static uint32_t cs3val = 0xe1a0e1a0; int rom_size, rom_loaded = 0; - DisplayState *ds = get_displaystate(); MemoryRegion *flash = g_new(MemoryRegion, 1); MemoryRegion *cs = g_new(MemoryRegion, 4); @@ -268,12 +267,6 @@ static void palmte_init(QEMUMachineInitArgs *args) palmte_binfo.initrd_filename = initrd_filename; arm_load_kernel(mpu->cpu, &palmte_binfo); } - - /* FIXME: We shouldn't really be doing this here. The LCD controller - will set the size once configured, so this just sets an initial - size until the guest activates the display. */ - ds->surface = qemu_resize_displaysurface(ds, 320, 320); - dpy_gfx_resize(ds); } static QEMUMachine palmte_machine = { diff --git a/hw/qxl-render.c b/hw/qxl-render.c index d77df42..8a19272 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -98,6 +98,7 @@ static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area) static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) { VGACommonState *vga = &qxl->vga; + DisplaySurface *surface; int i; if (qxl->guest_primary.resized) { @@ -112,8 +113,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.bytes_pp, qxl->guest_primary.bits_pp); if (qxl->guest_primary.qxl_stride > 0) { - qemu_free_displaysurface(vga->ds); - vga->ds->surface = qemu_create_displaysurface_from + surface = qemu_create_displaysurface_from (qxl->guest_primary.surface.width, qxl->guest_primary.surface.height, qxl->guest_primary.bits_pp, @@ -121,11 +121,11 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.data, false); } else { - qemu_resize_displaysurface(vga->ds, - qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height); + surface = qemu_create_displaysurface + (qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height); } - dpy_gfx_resize(vga->ds); + dpy_gfx_replace_surface(vga->ds, surface); } for (i = 0; i < qxl->num_dirty_rects; i++) { if (qemu_spice_rect_is_empty(qxl->dirty+i)) { diff --git a/hw/vga.c b/hw/vga.c index 2213bc1..13d5066 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1691,11 +1691,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) height != s->last_height || s->last_depth != depth) { if (depth == 32 || (depth == 16 && !byteswap)) { - qemu_free_displaysurface(s->ds); - s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth, - s->line_offset, + DisplaySurface *surface; + surface = qemu_create_displaysurface_from(disp_width, + height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4), byteswap); - dpy_gfx_resize(s->ds); + dpy_gfx_replace_surface(s->ds, surface); } else { qemu_console_resize(s->ds, disp_width, height); } @@ -1709,12 +1709,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } else if (is_buffer_shared(s->ds->surface) && (full_update || ds_get_data(s->ds) != s->vram_ptr + (s->start_addr * 4))) { - qemu_free_displaysurface(s->ds); - s->ds->surface = qemu_create_displaysurface_from(disp_width, - height, depth, - s->line_offset, + DisplaySurface *surface; + surface = qemu_create_displaysurface_from(disp_width, + height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4), byteswap); - dpy_gfx_setdata(s->ds); + dpy_gfx_replace_surface(s->ds, surface); } s->rgb_to_pixel = diff --git a/hw/xenfb.c b/hw/xenfb.c index 3462ded..7779097 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -703,6 +703,7 @@ static void xenfb_send_refresh_period(struct XenFB *xenfb, int period) static void xenfb_update(void *opaque) { struct XenFB *xenfb = opaque; + DisplaySurface *surface; int i; if (xenfb->c.xendev.be_state != XenbusStateConnected) @@ -753,21 +754,20 @@ static void xenfb_update(void *opaque) case 16: case 32: /* console.c supported depth -> buffer can be used directly */ - qemu_free_displaysurface(xenfb->c.ds); - xenfb->c.ds->surface = qemu_create_displaysurface_from + surface = qemu_create_displaysurface_from (xenfb->width, xenfb->height, xenfb->depth, xenfb->row_stride, xenfb->pixels + xenfb->offset, false); break; default: /* we must convert stuff */ - qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height); + surface = qemu_create_displaysurface(xenfb->width, xenfb->height); break; } + dpy_gfx_replace_surface(xenfb->c.ds, surface); xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n", xenfb->width, xenfb->height, xenfb->depth, is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : ""); - dpy_gfx_resize(xenfb->c.ds); xenfb->up_fullscreen = 1; } -- cgit v1.1 From c12aeb860c63ba83190f962e2f0a1c5fe18ad3a6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Feb 2013 15:03:04 +0100 Subject: console: rework DisplaySurface handling [dcl/ui side] Replace the dpy_gfx_resize and dpy_gfx_setdata DisplayChangeListener callbacks with a dpy_gfx_switch callback which notifies the ui code when the framebuffer backing storage changes. Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/qxl.c b/hw/qxl.c index 5d830f0..fbaadde 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1875,13 +1875,14 @@ static void display_update(DisplayChangeListener *dcl, } } -static void display_resize(DisplayChangeListener *dcl, - struct DisplayState *ds) +static void display_switch(DisplayChangeListener *dcl, + struct DisplayState *ds, + struct DisplaySurface *surface) { PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); if (qxl->mode == QXL_MODE_VGA) { - qemu_spice_display_resize(&qxl->ssd); + qemu_spice_display_switch(&qxl->ssd, surface); } } @@ -1902,7 +1903,7 @@ static void display_refresh(DisplayChangeListener *dcl, static DisplayChangeListenerOps display_listener_ops = { .dpy_name = "spice/qxl", .dpy_gfx_update = display_update, - .dpy_gfx_resize = display_resize, + .dpy_gfx_switch = display_switch, .dpy_refresh = display_refresh, }; -- cgit v1.1 From 71874c1751ebb7368eaa023a35ac919d2c1c5e4c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Feb 2013 16:42:28 +0100 Subject: spice: stop using DisplayState Rework DisplayStateListener callbacks to not use the DisplayState any more. Signed-off-by: Gerd Hoffmann --- hw/qxl-render.c | 2 +- hw/qxl.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/qxl-render.c b/hw/qxl-render.c index 8a19272..087679e 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -236,7 +236,7 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) return 1; } - if (!dpy_cursor_define_supported(qxl->ssd.ds)) { + if (!dpy_cursor_define_supported(qxl->ssd.dcl.ds)) { return 0; } diff --git a/hw/qxl.c b/hw/qxl.c index fbaadde..6ed61be 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1782,7 +1782,7 @@ static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch, case QXL_MODE_COMPAT: case QXL_MODE_NATIVE: qxl_render_update(qxl); - ppm_save(filename, qxl->ssd.ds->surface, errp); + ppm_save(filename, qxl->ssd.ds, errp); break; case QXL_MODE_VGA: vga->screen_dump(vga, filename, cswitch, errp); @@ -1881,6 +1881,7 @@ static void display_switch(DisplayChangeListener *dcl, { PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); + qxl->ssd.ds = surface; if (qxl->mode == QXL_MODE_VGA) { qemu_spice_display_switch(&qxl->ssd, surface); } -- cgit v1.1 From bc2ed9704fff2c721e4056ab5281f0291718bfa6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Mar 2013 13:03:04 +0100 Subject: console: zap displaystate from dcl callbacks Now that nobody depends on DisplayState in DisplayChangeListener callbacks any more we can remove the parameter from all callbacks. Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/qxl.c b/hw/qxl.c index 6ed61be..0939ace 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1865,7 +1865,6 @@ static void qxl_vm_change_state_handler(void *opaque, int running, /* display change listener */ static void display_update(DisplayChangeListener *dcl, - struct DisplayState *ds, int x, int y, int w, int h) { PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); @@ -1876,7 +1875,6 @@ static void display_update(DisplayChangeListener *dcl, } static void display_switch(DisplayChangeListener *dcl, - struct DisplayState *ds, struct DisplaySurface *surface) { PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); @@ -1887,8 +1885,7 @@ static void display_switch(DisplayChangeListener *dcl, } } -static void display_refresh(DisplayChangeListener *dcl, - struct DisplayState *ds) +static void display_refresh(DisplayChangeListener *dcl) { PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); -- cgit v1.1 From c78f71378a345ea240c288993ca1378ded5504b9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 5 Mar 2013 15:24:14 +0100 Subject: console: stop using DisplayState in gfx hardware emulation Use QemuConsole instead. Updates interfaces in console.[ch] and adapts gfx hardware emulation code. Signed-off-by: Gerd Hoffmann --- hw/arm/musicpal.c | 20 ++++----- hw/blizzard.c | 37 ++++++++++------- hw/cirrus_vga.c | 22 +++++----- hw/exynos4210_fimd.c | 17 ++++---- hw/framebuffer.c | 4 +- hw/framebuffer.h | 2 +- hw/g364fb.c | 43 +++++++++++--------- hw/jazz_led.c | 88 ++++++++++++++++++++++------------------ hw/milkymist-vgafb.c | 17 ++++---- hw/omap_lcdc.c | 47 ++++++++++++---------- hw/pl110.c | 24 ++++++----- hw/pxa2xx_lcd.c | 39 ++++++++++-------- hw/qxl-render.c | 11 ++--- hw/qxl.c | 12 ++++-- hw/sm501.c | 34 +++++++++------- hw/ssd0303.c | 17 ++++---- hw/ssd0323.c | 19 ++++----- hw/tc6393xb.c | 28 ++++++++----- hw/tc6393xb_template.h | 5 ++- hw/tcx.c | 62 ++++++++++++++++------------ hw/vga-isa-mm.c | 5 ++- hw/vga-isa.c | 4 +- hw/vga-pci.c | 4 +- hw/vga.c | 98 ++++++++++++++++++++++++-------------------- hw/vga_int.h | 2 +- hw/vmware_vga.c | 107 ++++++++++++++++++++++++++----------------------- hw/xenfb.c | 51 +++++++++++------------ 27 files changed, 452 insertions(+), 367 deletions(-) (limited to 'hw') diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index a37dbd7..edd5282 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -462,7 +462,7 @@ typedef struct musicpal_lcd_state { uint32_t irqctrl; uint32_t page; uint32_t page_off; - DisplayState *ds; + QemuConsole *con; uint8_t video_ram[128*64/8]; } musicpal_lcd_state; @@ -483,7 +483,8 @@ static inline void glue(set_lcd_pixel, depth) \ (musicpal_lcd_state *s, int x, int y, type col) \ { \ int dx, dy; \ - type *pixel = &((type *) ds_get_data(s->ds))[(y * 128 * 3 + x) * 3]; \ + DisplaySurface *surface = qemu_console_surface(s->con); \ + type *pixel = &((type *) surface_data(surface))[(y * 128 * 3 + x) * 3]; \ \ for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \ for (dx = 0; dx < 3; dx++, pixel++) \ @@ -496,9 +497,10 @@ SET_LCD_PIXEL(32, uint32_t) static void lcd_refresh(void *opaque) { musicpal_lcd_state *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int x, y, col; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; #define LCD_REFRESH(depth, func) \ @@ -518,14 +520,14 @@ static void lcd_refresh(void *opaque) break; LCD_REFRESH(8, rgb_to_pixel8) LCD_REFRESH(16, rgb_to_pixel16) - LCD_REFRESH(32, (is_surface_bgr(s->ds->surface) ? + LCD_REFRESH(32, (is_surface_bgr(surface) ? rgb_to_pixel32bgr : rgb_to_pixel32)) default: hw_error("unsupported colour depth %i\n", - ds_get_bits_per_pixel(s->ds)); + surface_bits_per_pixel(surface)); } - dpy_gfx_update(s->ds, 0, 0, 128*3, 64*3); + dpy_gfx_update(s->con, 0, 0, 128*3, 64*3); } static void lcd_invalidate(void *opaque) @@ -609,9 +611,9 @@ static int musicpal_lcd_init(SysBusDevice *dev) "musicpal-lcd", MP_LCD_SIZE); sysbus_init_mmio(dev, &s->iomem); - s->ds = graphic_console_init(lcd_refresh, lcd_invalidate, - NULL, NULL, s); - qemu_console_resize(s->ds, 128*3, 64*3); + s->con = graphic_console_init(lcd_refresh, lcd_invalidate, + NULL, NULL, s); + qemu_console_resize(s->con, 128*3, 64*3); qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3); diff --git a/hw/blizzard.c b/hw/blizzard.c index 805f4d5..020d3de 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -69,7 +69,7 @@ typedef struct { uint8_t effect; uint8_t iformat; uint8_t source; - DisplayState *state; + QemuConsole *con; blizzard_fn_t *line_fn_tab[2]; void *fb; @@ -144,6 +144,7 @@ static inline void blizzard_rgb2yuv(int r, int g, int b, static void blizzard_window(BlizzardState *s) { + DisplaySurface *surface = qemu_console_surface(s->con); uint8_t *src, *dst; int bypp[2]; int bypl[3]; @@ -162,7 +163,7 @@ static void blizzard_window(BlizzardState *s) s->my[1] = s->data.y + s->data.dy; bypp[0] = s->bpp; - bypp[1] = (ds_get_bits_per_pixel(s->state) + 7) >> 3; + bypp[1] = surface_bytes_per_pixel(surface); bypl[0] = bypp[0] * s->data.pitch; bypl[1] = bypp[1] * s->x; bypl[2] = bypp[0] * s->data.dx; @@ -883,23 +884,25 @@ void s1d13745_write_block(void *opaque, int dc, static void blizzard_update_display(void *opaque) { BlizzardState *s = (BlizzardState *) opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int y, bypp, bypl, bwidth; uint8_t *src, *dst; if (!s->enable) return; - if (s->x != ds_get_width(s->state) || s->y != ds_get_height(s->state)) { + if (s->x != surface_width(surface) || s->y != surface_height(surface)) { s->invalidate = 1; - qemu_console_resize(s->state, s->x, s->y); + qemu_console_resize(s->con, s->x, s->y); + surface = qemu_console_surface(s->con); } if (s->invalidate) { s->invalidate = 0; if (s->blank) { - bypp = (ds_get_bits_per_pixel(s->state) + 7) >> 3; - memset(ds_get_data(s->state), 0, bypp * s->x * s->y); + bypp = surface_bytes_per_pixel(surface); + memset(surface_data(surface), 0, bypp * s->x * s->y); return; } @@ -912,16 +915,16 @@ static void blizzard_update_display(void *opaque) if (s->mx[1] <= s->mx[0]) return; - bypp = (ds_get_bits_per_pixel(s->state) + 7) >> 3; + bypp = surface_bytes_per_pixel(surface); bypl = bypp * s->x; bwidth = bypp * (s->mx[1] - s->mx[0]); y = s->my[0]; src = s->fb + bypl * y + bypp * s->mx[0]; - dst = ds_get_data(s->state) + bypl * y + bypp * s->mx[0]; + dst = surface_data(surface) + bypl * y + bypp * s->mx[0]; for (; y < s->my[1]; y ++, src += bypl, dst += bypl) memcpy(dst, src, bwidth); - dpy_gfx_update(s->state, s->mx[0], s->my[0], + dpy_gfx_update(s->con, s->mx[0], s->my[0], s->mx[1] - s->mx[0], y - s->my[0]); s->mx[0] = s->x; @@ -934,10 +937,12 @@ static void blizzard_screen_dump(void *opaque, const char *filename, bool cswitch, Error **errp) { BlizzardState *s = (BlizzardState *) opaque; + DisplaySurface *surface = qemu_console_surface(s->con); blizzard_update_display(opaque); - if (s && ds_get_data(s->state)) - ppm_save(filename, s->state->surface, errp); + if (s && surface_data(surface)) { + ppm_save(filename, surface, errp); + } } #define DEPTH 8 @@ -954,14 +959,16 @@ static void blizzard_screen_dump(void *opaque, const char *filename, void *s1d13745_init(qemu_irq gpio_int) { BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s)); + DisplaySurface *surface; s->fb = g_malloc(0x180000); - s->state = graphic_console_init(blizzard_update_display, - blizzard_invalidate_display, - blizzard_screen_dump, NULL, s); + s->con = graphic_console_init(blizzard_update_display, + blizzard_invalidate_display, + blizzard_screen_dump, NULL, s); + surface = qemu_console_surface(s->con); - switch (ds_get_bits_per_pixel(s->state)) { + switch (surface_bits_per_pixel(surface)) { case 0: s->line_fn_tab[0] = s->line_fn_tab[1] = g_malloc0(sizeof(blizzard_fn_t) * 0x10); diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 7babcb6..7a4d634 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -729,11 +729,12 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, s->cirrus_blt_width, s->cirrus_blt_height); - if (notify) - qemu_console_copy(s->vga.ds, + if (notify) { + qemu_console_copy(s->vga.con, sx, sy, dx, dy, s->cirrus_blt_width / depth, s->cirrus_blt_height); + } /* we don't have to notify the display that this portion has changed since qemu_console_copy implies this */ @@ -2176,6 +2177,7 @@ static void cirrus_cursor_invalidate(VGACommonState *s1) static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y) { CirrusVGAState *s = container_of(s1, CirrusVGAState, vga); + DisplaySurface *surface = qemu_console_surface(s->vga.con); int w, h, bpp, x1, x2, poffset; unsigned int color0, color1; const uint8_t *palette, *src; @@ -2228,9 +2230,9 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y) color1 = s->vga.rgb_to_pixel(c6_to_8(palette[0xf * 3]), c6_to_8(palette[0xf * 3 + 1]), c6_to_8(palette[0xf * 3 + 2])); - bpp = ((ds_get_bits_per_pixel(s->vga.ds) + 7) >> 3); + bpp = surface_bytes_per_pixel(surface); d1 += x1 * bpp; - switch(ds_get_bits_per_pixel(s->vga.ds)) { + switch (surface_bits_per_pixel(surface)) { default: break; case 8: @@ -2908,9 +2910,9 @@ static int vga_initfn(ISADevice *dev) vga_common_init(s); cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0, isa_address_space(dev), isa_address_space_io(dev)); - s->ds = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, - s); + s->con = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, + s); rom_add_vga(VGABIOS_CIRRUS_FILENAME); /* XXX ISA-LFB support */ /* FIXME not qdev yet */ @@ -2957,9 +2959,9 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) vga_common_init(&s->vga); cirrus_init_common(s, device_id, 1, pci_address_space(dev), pci_address_space_io(dev)); - s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate, - s->vga.screen_dump, s->vga.text_update, - &s->vga); + s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate, + s->vga.screen_dump, s->vga.text_update, + &s->vga); /* setup PCI */ diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c index 6b31ae3..bf316c6 100644 --- a/hw/exynos4210_fimd.c +++ b/hw/exynos4210_fimd.c @@ -296,7 +296,7 @@ struct Exynos4210fimdWindow { typedef struct { SysBusDevice busdev; MemoryRegion iomem; - DisplayState *console; + QemuConsole *console; qemu_irq irq[3]; uint32_t vidcon[4]; /* Video main control registers 0-3 */ @@ -1221,16 +1221,18 @@ static void exynos4210_fimd_invalidate(void *opaque) static void exynos4210_update_resolution(Exynos4210fimdState *s) { + DisplaySurface *surface = qemu_console_surface(s->console); + /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */ uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) & FIMD_VIDTCON2_SIZE_MASK) + 1; uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) & FIMD_VIDTCON2_SIZE_MASK) + 1; - if (s->ifb == NULL || ds_get_width(s->console) != width || - ds_get_height(s->console) != height) { + if (s->ifb == NULL || surface_width(surface) != width || + surface_height(surface) != height) { DPRINT_L1("Resolution changed from %ux%u to %ux%u\n", - ds_get_width(s->console), ds_get_height(s->console), width, height); + surface_width(surface), surface_height(surface), width, height); qemu_console_resize(s->console, width, height); s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1); memset(s->ifb, 0, width * height * RGBA_SIZE + 1); @@ -1241,6 +1243,7 @@ static void exynos4210_update_resolution(Exynos4210fimdState *s) static void exynos4210_fimd_update(void *opaque) { Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; + DisplaySurface *surface = qemu_console_surface(s->console); Exynos4210fimdWindow *w; int i, line; hwaddr fb_line_addr, inc_size; @@ -1253,7 +1256,7 @@ static void exynos4210_fimd_update(void *opaque) const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) & FIMD_VIDTCON2_SIZE_MASK) + 1; - if (!s || !s->console || !ds_get_bits_per_pixel(s->console) || + if (!s || !s->console || !surface_bits_per_pixel(surface) || !s->enabled) { return; } @@ -1299,10 +1302,10 @@ static void exynos4210_fimd_update(void *opaque) uint8_t *d; int bpp; - bpp = ds_get_bits_per_pixel(s->console); + bpp = surface_bits_per_pixel(surface); fimd_update_putpix_qemu(bpp); bpp = (bpp + 1) >> 3; - d = ds_get_data(s->console); + d = surface_data(surface); for (line = first_line; line <= last_line; line++) { fimd_copy_line_toqemu(global_width, s->ifb + global_width * line * RGBA_SIZE, d + global_width * line * bpp); diff --git a/hw/framebuffer.c b/hw/framebuffer.c index d341aa0..7326a98 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -24,7 +24,7 @@ /* Render an image from a shared memory framebuffer. */ void framebuffer_update_display( - DisplayState *ds, + DisplaySurface *ds, MemoryRegion *address_space, hwaddr base, int cols, /* Width in pixels. */ @@ -73,7 +73,7 @@ void framebuffer_update_display( return; } src = src_base; - dest = ds_get_data(ds); + dest = surface_data(ds); if (dest_col_pitch < 0) dest -= dest_col_pitch * (cols - 1); if (dest_row_pitch < 0) { diff --git a/hw/framebuffer.h b/hw/framebuffer.h index 11f53ed..6eae035 100644 --- a/hw/framebuffer.h +++ b/hw/framebuffer.h @@ -8,7 +8,7 @@ typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int); void framebuffer_update_display( - DisplayState *ds, + DisplaySurface *ds, MemoryRegion *address_space, hwaddr base, int cols, diff --git a/hw/g364fb.c b/hw/g364fb.c index 7b69815..f7014e9 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -39,7 +39,7 @@ typedef struct G364State { uint32_t top_of_screen; uint32_t width, height; /* in pixels */ /* display refresh support */ - DisplayState *ds; + QemuConsole *con; int depth; int blanked; } G364State; @@ -77,6 +77,7 @@ static inline void reset_dirty(G364State *s, static void g364fb_draw_graphic8(G364State *s) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, w; uint8_t *vram; uint8_t *data_display, *dd; @@ -87,7 +88,7 @@ static void g364fb_draw_graphic8(G364State *s) int xcursor, ycursor; unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b); - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 8: rgb_to_pixel = rgb_to_pixel8; w = 1; @@ -106,7 +107,7 @@ static void g364fb_draw_graphic8(G364State *s) break; default: hw_error("g364: unknown host depth %d", - ds_get_bits_per_pixel(s->ds)); + surface_bits_per_pixel(surface)); return; } @@ -129,7 +130,7 @@ static void g364fb_draw_graphic8(G364State *s) vram = s->vram + s->top_of_screen; /* XXX: out of range in vram? */ - data_display = dd = ds_get_data(s->ds); + data_display = dd = surface_data(surface); while (y < s->height) { if (check_dirty(s, page)) { if (y < ymin) @@ -182,7 +183,7 @@ static void g364fb_draw_graphic8(G364State *s) ymax = s->height - 1; goto done; } - data_display = dd = data_display + ds_get_linesize(s->ds); + data_display = dd = data_display + surface_stride(surface); xmin = 0; x = 0; } @@ -197,7 +198,7 @@ static void g364fb_draw_graphic8(G364State *s) reset_dirty(s, page_min, page_max); page_min = (ram_addr_t)-1; page_max = 0; - dpy_gfx_update(s->ds, xmin, ymin, + dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); xmin = s->width; xmax = 0; @@ -209,7 +210,7 @@ static void g364fb_draw_graphic8(G364State *s) x = x % s->width; y += dy; vram += G364_PAGE_SIZE; - data_display += dy * ds_get_linesize(s->ds); + data_display += dy * surface_stride(surface); dd = data_display + x * w; } page += G364_PAGE_SIZE; @@ -217,13 +218,14 @@ static void g364fb_draw_graphic8(G364State *s) done: if (page_min != (ram_addr_t)-1) { - dpy_gfx_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); + dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); reset_dirty(s, page_min, page_max); } } static void g364fb_draw_blank(G364State *s) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, w; uint8_t *d; @@ -232,28 +234,30 @@ static void g364fb_draw_blank(G364State *s) return; } - w = s->width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); - d = ds_get_data(s->ds); + w = s->width * surface_bytes_per_pixel(surface); + d = surface_data(surface); for (i = 0; i < s->height; i++) { memset(d, 0, w); - d += ds_get_linesize(s->ds); + d += surface_stride(surface); } - dpy_gfx_update(s->ds, 0, 0, s->width, s->height); + dpy_gfx_update(s->con, 0, 0, s->width, s->height); s->blanked = 1; } static void g364fb_update_display(void *opaque) { G364State *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); qemu_flush_coalesced_mmio_buffer(); if (s->width == 0 || s->height == 0) return; - if (s->width != ds_get_width(s->ds) || s->height != ds_get_height(s->ds)) { - qemu_console_resize(s->ds, s->width, s->height); + if (s->width != surface_width(surface) || + s->height != surface_height(surface)) { + qemu_console_resize(s->con, s->width, s->height); } if (s->ctla & CTLA_FORCE_BLANK) { @@ -413,13 +417,14 @@ static void g364fb_update_depth(G364State *s) static void g364_invalidate_cursor_position(G364State *s) { + DisplaySurface *surface = qemu_console_surface(s->con); int ymin, ymax, start, end; /* invalidate only near the cursor */ ymin = s->cursor_position & 0xfff; ymax = MIN(s->height, ymin + 64); - start = ymin * ds_get_linesize(s->ds); - end = (ymax + 1) * ds_get_linesize(s->ds); + start = ymin * surface_stride(surface); + end = (ymax + 1) * surface_stride(surface); memory_region_set_dirty(&s->mem_vram, start, end - start); } @@ -545,9 +550,9 @@ static void g364fb_init(DeviceState *dev, G364State *s) { s->vram = g_malloc0(s->vram_size); - s->ds = graphic_console_init(g364fb_update_display, - g364fb_invalidate_display, - g364fb_screen_dump, NULL, s); + s->con = graphic_console_init(g364fb_update_display, + g364fb_invalidate_display, + g364fb_screen_dump, NULL, s); memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000); memory_region_init_ram_ptr(&s->mem_vram, "vram", diff --git a/hw/jazz_led.c b/hw/jazz_led.c index a418a7d..05528c7 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -36,7 +36,7 @@ typedef struct LedState { SysBusDevice busdev; MemoryRegion iomem; uint8_t segments; - DisplayState *ds; + QemuConsole *con; screen_state_t state; } LedState; @@ -75,13 +75,15 @@ static const MemoryRegionOps led_ops = { /***********************************************************/ /* jazz_led display */ -static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx2, uint32_t color) +static void draw_horizontal_line(DisplaySurface *ds, + int posy, int posx1, int posx2, + uint32_t color) { uint8_t *d; int x, bpp; - bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; - d = ds_get_data(ds) + ds_get_linesize(ds) * posy + bpp * posx1; + bpp = (surface_bits_per_pixel(ds) + 7) >> 3; + d = surface_data(ds) + surface_stride(ds) * posy + bpp * posx1; switch(bpp) { case 1: for (x = posx1; x <= posx2; x++) { @@ -104,30 +106,32 @@ static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx } } -static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, uint32_t color) +static void draw_vertical_line(DisplaySurface *ds, + int posx, int posy1, int posy2, + uint32_t color) { uint8_t *d; int y, bpp; - bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; - d = ds_get_data(ds) + ds_get_linesize(ds) * posy1 + bpp * posx; + bpp = (surface_bits_per_pixel(ds) + 7) >> 3; + d = surface_data(ds) + surface_stride(ds) * posy1 + bpp * posx; switch(bpp) { case 1: for (y = posy1; y <= posy2; y++) { *((uint8_t *)d) = color; - d += ds_get_linesize(ds); + d += surface_stride(ds); } break; case 2: for (y = posy1; y <= posy2; y++) { *((uint16_t *)d) = color; - d += ds_get_linesize(ds); + d += surface_stride(ds); } break; case 4: for (y = posy1; y <= posy2; y++) { *((uint32_t *)d) = color; - d += ds_get_linesize(ds); + d += surface_stride(ds); } break; } @@ -136,24 +140,24 @@ static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, static void jazz_led_update_display(void *opaque) { LedState *s = opaque; - DisplayState *ds = s->ds; + DisplaySurface *surface = qemu_console_surface(s->con); uint8_t *d1; uint32_t color_segment, color_led; int y, bpp; if (s->state & REDRAW_BACKGROUND) { /* clear screen */ - bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; - d1 = ds_get_data(ds); - for (y = 0; y < ds_get_height(ds); y++) { - memset(d1, 0x00, ds_get_width(ds) * bpp); - d1 += ds_get_linesize(ds); + bpp = (surface_bits_per_pixel(surface) + 7) >> 3; + d1 = surface_data(surface); + for (y = 0; y < surface_height(surface); y++) { + memset(d1, 0x00, surface_width(surface) * bpp); + d1 += surface_stride(surface); } } if (s->state & REDRAW_SEGMENTS) { /* set colors according to bpp */ - switch (ds_get_bits_per_pixel(ds)) { + switch (surface_bits_per_pixel(surface)) { case 8: color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa); color_led = rgb_to_pixel8(0x00, 0xff, 0x00); @@ -178,26 +182,34 @@ static void jazz_led_update_display(void *opaque) } /* display segments */ - draw_horizontal_line(ds, 40, 10, 40, (s->segments & 0x02) ? color_segment : 0); - draw_vertical_line(ds, 10, 10, 40, (s->segments & 0x04) ? color_segment : 0); - draw_vertical_line(ds, 10, 40, 70, (s->segments & 0x08) ? color_segment : 0); - draw_horizontal_line(ds, 70, 10, 40, (s->segments & 0x10) ? color_segment : 0); - draw_vertical_line(ds, 40, 40, 70, (s->segments & 0x20) ? color_segment : 0); - draw_vertical_line(ds, 40, 10, 40, (s->segments & 0x40) ? color_segment : 0); - draw_horizontal_line(ds, 10, 10, 40, (s->segments & 0x80) ? color_segment : 0); + draw_horizontal_line(surface, 40, 10, 40, + (s->segments & 0x02) ? color_segment : 0); + draw_vertical_line(surface, 10, 10, 40, + (s->segments & 0x04) ? color_segment : 0); + draw_vertical_line(surface, 10, 40, 70, + (s->segments & 0x08) ? color_segment : 0); + draw_horizontal_line(surface, 70, 10, 40, + (s->segments & 0x10) ? color_segment : 0); + draw_vertical_line(surface, 40, 40, 70, + (s->segments & 0x20) ? color_segment : 0); + draw_vertical_line(surface, 40, 10, 40, + (s->segments & 0x40) ? color_segment : 0); + draw_horizontal_line(surface, 10, 10, 40, + (s->segments & 0x80) ? color_segment : 0); /* display led */ if (!(s->segments & 0x01)) color_led = 0; /* black */ - draw_horizontal_line(ds, 68, 50, 50, color_led); - draw_horizontal_line(ds, 69, 49, 51, color_led); - draw_horizontal_line(ds, 70, 48, 52, color_led); - draw_horizontal_line(ds, 71, 49, 51, color_led); - draw_horizontal_line(ds, 72, 50, 50, color_led); + draw_horizontal_line(surface, 68, 50, 50, color_led); + draw_horizontal_line(surface, 69, 49, 51, color_led); + draw_horizontal_line(surface, 70, 48, 52, color_led); + draw_horizontal_line(surface, 71, 49, 51, color_led); + draw_horizontal_line(surface, 72, 50, 50, color_led); } s->state = REDRAW_NONE; - dpy_gfx_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds)); + dpy_gfx_update(s->con, 0, 0, + surface_width(surface), surface_height(surface)); } static void jazz_led_invalidate_display(void *opaque) @@ -211,15 +223,15 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata) LedState *s = opaque; char buf[2]; - dpy_text_cursor(s->ds, -1, -1); - qemu_console_resize(s->ds, 2, 1); + dpy_text_cursor(s->con, -1, -1); + qemu_console_resize(s->con, 2, 1); /* TODO: draw the segments */ snprintf(buf, 2, "%02hhx\n", s->segments); console_write_ch(chardata++, 0x00200100 | buf[0]); console_write_ch(chardata++, 0x00200100 | buf[1]); - dpy_text_update(s->ds, 0, 0, 2, 1); + dpy_text_update(s->con, 0, 0, 2, 1); } static int jazz_led_post_load(void *opaque, int version_id) @@ -249,10 +261,10 @@ static int jazz_led_init(SysBusDevice *dev) memory_region_init_io(&s->iomem, &led_ops, s, "led", 1); sysbus_init_mmio(dev, &s->iomem); - s->ds = graphic_console_init(jazz_led_update_display, - jazz_led_invalidate_display, - NULL, - jazz_led_text_update, s); + s->con = graphic_console_init(jazz_led_update_display, + jazz_led_invalidate_display, + NULL, + jazz_led_text_update, s); return 0; } @@ -263,7 +275,7 @@ static void jazz_led_reset(DeviceState *d) s->segments = 0; s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND; - qemu_console_resize(s->ds, 60, 80); + qemu_console_resize(s->con, 60, 80); } static void jazz_led_class_init(ObjectClass *klass, void *data) diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 85ebb85..98762ec 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -66,7 +66,7 @@ enum { struct MilkymistVgafbState { SysBusDevice busdev; MemoryRegion regs_region; - DisplayState *ds; + QemuConsole *con; int invalidate; uint32_t fb_offset; @@ -84,6 +84,7 @@ static int vgafb_enabled(MilkymistVgafbState *s) static void vgafb_update_display(void *opaque) { MilkymistVgafbState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int first = 0; int last = 0; drawfn fn; @@ -94,7 +95,7 @@ static void vgafb_update_display(void *opaque) int dest_width = s->regs[R_HRES]; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; case 8: @@ -121,7 +122,7 @@ static void vgafb_update_display(void *opaque) break; } - framebuffer_update_display(s->ds, sysbus_address_space(&s->busdev), + framebuffer_update_display(surface, sysbus_address_space(&s->busdev), s->regs[R_BASEADDRESS] + s->fb_offset, s->regs[R_HRES], s->regs[R_VRES], @@ -134,7 +135,7 @@ static void vgafb_update_display(void *opaque) &first, &last); if (first >= 0) { - dpy_gfx_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1); + dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1); } s->invalidate = 0; } @@ -151,7 +152,7 @@ static void vgafb_resize(MilkymistVgafbState *s) return; } - qemu_console_resize(s->ds, s->regs[R_HRES], s->regs[R_VRES]); + qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]); s->invalidate = 1; } @@ -277,9 +278,9 @@ static int milkymist_vgafb_init(SysBusDevice *dev) "milkymist-vgafb", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); - s->ds = graphic_console_init(vgafb_update_display, - vgafb_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(vgafb_update_display, + vgafb_invalidate_display, + NULL, NULL, s); return 0; } diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index c426f3a..4f5b094 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -26,7 +26,7 @@ struct omap_lcd_panel_s { MemoryRegion *sysmem; MemoryRegion iomem; qemu_irq irq; - DisplayState *state; + QemuConsole *con; int plm; int tft; @@ -113,14 +113,16 @@ static draw_line_func draw_line_table2[33] = { static void omap_update_display(void *opaque) { struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque; + DisplaySurface *surface = qemu_console_surface(omap_lcd->con); draw_line_func draw_line; int size, height, first, last; int width, linesize, step, bpp, frame_offset; hwaddr frame_base; - if (!omap_lcd || omap_lcd->plm == 1 || - !omap_lcd->enable || !ds_get_bits_per_pixel(omap_lcd->state)) + if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable || + !surface_bits_per_pixel(surface)) { return; + } frame_offset = 0; if (omap_lcd->plm != 2) { @@ -139,25 +141,25 @@ static void omap_update_display(void *opaque) /* Colour depth */ switch ((omap_lcd->palette[0] >> 12) & 7) { case 1: - draw_line = draw_line_table2[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table2[surface_bits_per_pixel(surface)]; bpp = 2; break; case 2: - draw_line = draw_line_table4[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table4[surface_bits_per_pixel(surface)]; bpp = 4; break; case 3: - draw_line = draw_line_table8[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table8[surface_bits_per_pixel(surface)]; bpp = 8; break; case 4 ... 7: if (!omap_lcd->tft) - draw_line = draw_line_table12[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table12[surface_bits_per_pixel(surface)]; else - draw_line = draw_line_table16[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table16[surface_bits_per_pixel(surface)]; bpp = 16; break; @@ -168,10 +170,11 @@ static void omap_update_display(void *opaque) /* Resolution */ width = omap_lcd->width; - if (width != ds_get_width(omap_lcd->state) || - omap_lcd->height != ds_get_height(omap_lcd->state)) { - qemu_console_resize(omap_lcd->state, + if (width != surface_width(surface) || + omap_lcd->height != surface_height(surface)) { + qemu_console_resize(omap_lcd->con, omap_lcd->width, omap_lcd->height); + surface = qemu_console_surface(omap_lcd->con); omap_lcd->invalidate = 1; } @@ -196,8 +199,9 @@ static void omap_update_display(void *opaque) if (omap_lcd->dma->dual) omap_lcd->dma->current_frame ^= 1; - if (!ds_get_bits_per_pixel(omap_lcd->state)) + if (!surface_bits_per_pixel(surface)) { return; + } first = 0; height = omap_lcd->height; @@ -210,15 +214,15 @@ static void omap_update_display(void *opaque) } step = width * bpp >> 3; - linesize = ds_get_linesize(omap_lcd->state); - framebuffer_update_display(omap_lcd->state, omap_lcd->sysmem, + linesize = surface_stride(surface); + framebuffer_update_display(surface, omap_lcd->sysmem, frame_base, width, height, step, linesize, 0, omap_lcd->invalidate, draw_line, omap_lcd->palette, &first, &last); if (first >= 0) { - dpy_gfx_update(omap_lcd->state, 0, first, width, last - first + 1); + dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1); } omap_lcd->invalidate = 0; } @@ -298,12 +302,13 @@ static void omap_screen_dump(void *opaque, const char *filename, bool cswitch, Error **errp) { struct omap_lcd_panel_s *omap_lcd = opaque; + DisplaySurface *surface = qemu_console_surface(omap_lcd->con); omap_update_display(opaque); - if (omap_lcd && ds_get_data(omap_lcd->state)) - omap_ppm_save(filename, ds_get_data(omap_lcd->state), + if (omap_lcd && surface_data(surface)) + omap_ppm_save(filename, surface_data(surface), omap_lcd->width, omap_lcd->height, - ds_get_linesize(omap_lcd->state), errp); + surface_stride(surface), errp); } static void omap_invalidate_display(void *opaque) { @@ -480,9 +485,9 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, memory_region_init_io(&s->iomem, &omap_lcdc_ops, s, "omap.lcdc", 0x100); memory_region_add_subregion(sysmem, base, &s->iomem); - s->state = graphic_console_init(omap_update_display, - omap_invalidate_display, - omap_screen_dump, NULL, s); + s->con = graphic_console_init(omap_update_display, + omap_invalidate_display, + omap_screen_dump, NULL, s); return s; } diff --git a/hw/pl110.c b/hw/pl110.c index 924642d..fbef675 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -42,7 +42,7 @@ enum pl110_version typedef struct { SysBusDevice busdev; MemoryRegion iomem; - DisplayState *ds; + QemuConsole *con; int version; uint32_t timing[4]; @@ -129,6 +129,7 @@ static int pl110_enabled(pl110_state *s) static void pl110_update_display(void *opaque) { pl110_state *s = (pl110_state *)opaque; + DisplaySurface *surface = qemu_console_surface(s->con); drawfn* fntable; drawfn fn; int dest_width; @@ -140,7 +141,7 @@ static void pl110_update_display(void *opaque) if (!pl110_enabled(s)) return; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; case 8: @@ -231,14 +232,14 @@ static void pl110_update_display(void *opaque) } dest_width *= s->cols; first = 0; - framebuffer_update_display(s->ds, sysbus_address_space(&s->busdev), + framebuffer_update_display(surface, sysbus_address_space(&s->busdev), s->upbase, s->cols, s->rows, src_width, dest_width, 0, s->invalidate, fn, s->palette, &first, &last); if (first >= 0) { - dpy_gfx_update(s->ds, 0, first, s->cols, last - first + 1); + dpy_gfx_update(s->con, 0, first, s->cols, last - first + 1); } s->invalidate = 0; } @@ -248,12 +249,13 @@ static void pl110_invalidate_display(void * opaque) pl110_state *s = (pl110_state *)opaque; s->invalidate = 1; if (pl110_enabled(s)) { - qemu_console_resize(s->ds, s->cols, s->rows); + qemu_console_resize(s->con, s->cols, s->rows); } } static void pl110_update_palette(pl110_state *s, int n) { + DisplaySurface *surface = qemu_console_surface(s->con); int i; uint32_t raw; unsigned int r, g, b; @@ -268,7 +270,7 @@ static void pl110_update_palette(pl110_state *s, int n) b = (raw & 0x1f) << 3; /* The I bit is ignored. */ raw >>= 6; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 8: s->palette[n] = rgb_to_pixel8(r, g, b); break; @@ -291,7 +293,7 @@ static void pl110_resize(pl110_state *s, int width, int height) { if (width != s->cols || height != s->rows) { if (pl110_enabled(s)) { - qemu_console_resize(s->ds, width, height); + qemu_console_resize(s->con, width, height); } } s->cols = width; @@ -409,7 +411,7 @@ static void pl110_write(void *opaque, hwaddr offset, s->cr = val; s->bpp = (val >> 1) & 7; if (pl110_enabled(s)) { - qemu_console_resize(s->ds, s->cols, s->rows); + qemu_console_resize(s->con, s->cols, s->rows); } break; case 10: /* LCDICR */ @@ -450,9 +452,9 @@ static int pl110_init(SysBusDevice *dev) 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); + s->con = graphic_console_init(pl110_update_display, + pl110_invalidate_display, + NULL, NULL, s); return 0; } diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 6484d27..f2b0c93 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -39,7 +39,7 @@ struct PXA2xxLCDState { int irqlevel; int invalidated; - DisplayState *ds; + QemuConsole *con; drawfn *line_fn[2]; int dest_width; int xres, yres; @@ -579,6 +579,7 @@ static const MemoryRegionOps pxa2xx_lcdc_ops = { /* Load new palette for a given DMA channel, convert to internal format */ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, n, format, r, g, b, alpha; uint32_t *dest; uint8_t *src; @@ -652,7 +653,7 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) src += 4; break; } - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 8: *dest = rgb_to_pixel8(r, g, b) | alpha; break; @@ -676,6 +677,7 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, hwaddr addr, int *miny, int *maxy) { + DisplaySurface *surface = qemu_console_surface(s->con); int src_width, dest_width; drawfn fn = NULL; if (s->dest_width) @@ -693,7 +695,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, dest_width = s->xres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, s->sysmem, + framebuffer_update_display(surface, s->sysmem, addr, s->xres, s->yres, src_width, dest_width, s->dest_width, s->invalidated, @@ -703,6 +705,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, hwaddr addr, int *miny, int *maxy) { + DisplaySurface *surface = qemu_console_surface(s->con); int src_width, dest_width; drawfn fn = NULL; if (s->dest_width) @@ -720,7 +723,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, dest_width = s->yres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, s->sysmem, + framebuffer_update_display(surface, s->sysmem, addr, s->xres, s->yres, src_width, s->dest_width, -dest_width, s->invalidated, @@ -731,6 +734,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, hwaddr addr, int *miny, int *maxy) { + DisplaySurface *surface = qemu_console_surface(s->con); int src_width, dest_width; drawfn fn = NULL; if (s->dest_width) { @@ -751,7 +755,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, dest_width = s->xres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, s->sysmem, + framebuffer_update_display(surface, s->sysmem, addr, s->xres, s->yres, src_width, -dest_width, -s->dest_width, s->invalidated, @@ -761,6 +765,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s, hwaddr addr, int *miny, int *maxy) { + DisplaySurface *surface = qemu_console_surface(s->con); int src_width, dest_width; drawfn fn = NULL; if (s->dest_width) { @@ -781,7 +786,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s, dest_width = s->yres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, s->sysmem, + framebuffer_update_display(surface, s->sysmem, addr, s->xres, s->yres, src_width, -s->dest_width, dest_width, s->invalidated, @@ -800,9 +805,9 @@ static void pxa2xx_lcdc_resize(PXA2xxLCDState *s) if (width != s->xres || height != s->yres) { if (s->orientation == 90 || s->orientation == 270) { - qemu_console_resize(s->ds, height, width); + qemu_console_resize(s->con, height, width); } else { - qemu_console_resize(s->ds, width, height); + qemu_console_resize(s->con, width, height); } s->invalidated = 1; s->xres = width; @@ -871,20 +876,20 @@ static void pxa2xx_update_display(void *opaque) if (miny >= 0) { switch (s->orientation) { case 0: - dpy_gfx_update(s->ds, 0, miny, s->xres, maxy - miny + 1); + dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1); break; case 90: - dpy_gfx_update(s->ds, miny, 0, maxy - miny + 1, s->xres); + dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres); break; case 180: maxy = s->yres - maxy - 1; miny = s->yres - miny - 1; - dpy_gfx_update(s->ds, 0, maxy, s->xres, miny - maxy + 1); + dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1); break; case 270: maxy = s->yres - maxy - 1; miny = s->yres - miny - 1; - dpy_gfx_update(s->ds, maxy, 0, miny - maxy + 1, s->xres); + dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres); break; } } @@ -990,6 +995,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, hwaddr base, qemu_irq irq) { PXA2xxLCDState *s; + DisplaySurface *surface; s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState)); s->invalidated = 1; @@ -1002,11 +1008,12 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, "pxa2xx-lcd-controller", 0x00100000); memory_region_add_subregion(sysmem, base, &s->iomem); - s->ds = graphic_console_init(pxa2xx_update_display, - pxa2xx_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(pxa2xx_update_display, + pxa2xx_invalidate_display, + NULL, NULL, s); + surface = qemu_console_surface(s->con); - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: s->dest_width = 0; break; diff --git a/hw/qxl-render.c b/hw/qxl-render.c index 087679e..8cd9be4 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -23,11 +23,12 @@ static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) { + DisplaySurface *surface = qemu_console_surface(qxl->vga.con); + uint8_t *dst = surface_data(surface); uint8_t *src; - uint8_t *dst = ds_get_data(qxl->vga.ds); int len, i; - if (is_buffer_shared(qxl->vga.ds->surface)) { + if (is_buffer_shared(surface)) { return; } if (!qxl->guest_primary.data) { @@ -125,14 +126,14 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) (qxl->guest_primary.surface.width, qxl->guest_primary.surface.height); } - dpy_gfx_replace_surface(vga->ds, surface); + dpy_gfx_replace_surface(vga->con, surface); } for (i = 0; i < qxl->num_dirty_rects; i++) { if (qemu_spice_rect_is_empty(qxl->dirty+i)) { break; } qxl_blit(qxl, qxl->dirty+i); - dpy_gfx_update(vga->ds, + dpy_gfx_update(vga->con, qxl->dirty[i].left, qxl->dirty[i].top, qxl->dirty[i].right - qxl->dirty[i].left, qxl->dirty[i].bottom - qxl->dirty[i].top); @@ -236,7 +237,7 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) return 1; } - if (!dpy_cursor_define_supported(qxl->ssd.dcl.ds)) { + if (!dpy_cursor_define_supported(qxl->vga.con)) { return 0; } diff --git a/hw/qxl.c b/hw/qxl.c index 0939ace..b66b414 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -2063,6 +2063,7 @@ static int qxl_init_primary(PCIDevice *dev) PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); VGACommonState *vga = &qxl->vga; PortioList *qxl_vga_port_list = g_new(PortioList, 1); + DisplayState *ds; int rc; qxl->id = 0; @@ -2073,9 +2074,11 @@ static int qxl_init_primary(PCIDevice *dev) portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga"); portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); - vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, - qxl_hw_screen_dump, qxl_hw_text_update, qxl); - qemu_spice_display_init_common(&qxl->ssd, vga->ds); + vga->con = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, + qxl_hw_screen_dump, qxl_hw_text_update, + qxl); + qxl->ssd.con = vga->con, + qemu_spice_display_init_common(&qxl->ssd); rc = qxl_init_common(qxl); if (rc != 0) { @@ -2083,7 +2086,8 @@ static int qxl_init_primary(PCIDevice *dev) } qxl->ssd.dcl.ops = &display_listener_ops; - register_displaychangelistener(vga->ds, &qxl->ssd.dcl); + ds = qemu_console_displaystate(vga->con); + register_displaychangelistener(ds, &qxl->ssd.dcl); return rc; } diff --git a/hw/sm501.c b/hw/sm501.c index 0e01911..93a06c9 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -454,7 +454,7 @@ static const uint32_t sm501_mem_local_size[] = { typedef struct SM501State { /* graphic console status */ - DisplayState *ds; + QemuConsole *con; /* status & internal resources */ hwaddr base; @@ -1234,9 +1234,9 @@ static draw_hwc_line_func * draw_hwc_line_funcs[] = { draw_hwc_line_16bgr, }; -static inline int get_depth_index(DisplayState *s) +static inline int get_depth_index(DisplaySurface *surface) { - switch(ds_get_bits_per_pixel(s)) { + switch (surface_bits_per_pixel(surface)) { default: case 8: return 0; @@ -1245,26 +1245,28 @@ static inline int get_depth_index(DisplayState *s) case 16: return 2; case 32: - if (is_surface_bgr(s->surface)) - return 4; - else - return 3; + if (is_surface_bgr(surface)) { + return 4; + } else { + return 3; + } } } static void sm501_draw_crt(SM501State * s) { + DisplaySurface *surface = qemu_console_surface(s->con); int y; int width = (s->dc_crt_h_total & 0x00000FFF) + 1; int height = (s->dc_crt_v_total & 0x00000FFF) + 1; uint8_t * src = s->local_mem; int src_bpp = 0; - int dst_bpp = ds_get_bytes_per_pixel(s->ds) + (ds_get_bits_per_pixel(s->ds) % 8 ? 1 : 0); + int dst_bpp = surface_bytes_per_pixel(surface); uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE - SM501_DC_PANEL_PALETTE]; uint8_t hwc_palette[3 * 3]; - int ds_depth_index = get_depth_index(s->ds); + int ds_depth_index = get_depth_index(surface); draw_line_func * draw_line = NULL; draw_hwc_line_func * draw_hwc_line = NULL; int full_update = 0; @@ -1312,7 +1314,8 @@ static void sm501_draw_crt(SM501State * s) /* adjust console size */ if (s->last_width != width || s->last_height != height) { - qemu_console_resize(s->ds, width, height); + qemu_console_resize(s->con, width, height); + surface = qemu_console_surface(s->con); s->last_width = width; s->last_height = height; full_update = 1; @@ -1331,7 +1334,8 @@ static void sm501_draw_crt(SM501State * s) /* draw line and change status */ if (update) { - uint8_t * d = &(ds_get_data(s->ds)[y * width * dst_bpp]); + uint8_t *d = surface_data(surface); + d += y * width * dst_bpp; /* draw graphics layer */ draw_line(d, src, width, palette); @@ -1350,7 +1354,7 @@ static void sm501_draw_crt(SM501State * s) } else { if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(s->ds, 0, y_start, width, y - y_start); + dpy_gfx_update(s->con, 0, y_start, width, y - y_start); y_start = -1; } } @@ -1361,7 +1365,7 @@ static void sm501_draw_crt(SM501State * s) /* complete flush to display */ if (y_start >= 0) - dpy_gfx_update(s->ds, 0, y_start, width, y - y_start); + dpy_gfx_update(s->con, 0, y_start, width, y - y_start); /* clear dirty flags */ if (page_min != ~0l) { @@ -1441,6 +1445,6 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, } /* create qemu graphic console */ - s->ds = graphic_console_init(sm501_update_display, NULL, - NULL, NULL, s); + s->con = graphic_console_init(sm501_update_display, NULL, + NULL, NULL, s); } diff --git a/hw/ssd0303.c b/hw/ssd0303.c index db50909..68d1f24 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -43,7 +43,7 @@ enum ssd0303_cmd { typedef struct { I2CSlave i2c; - DisplayState *ds; + QemuConsole *con; int row; int col; int start_line; @@ -191,6 +191,7 @@ static void ssd0303_event(I2CSlave *i2c, enum i2c_event event) static void ssd0303_update_display(void *opaque) { ssd0303_state *s = (ssd0303_state *)opaque; + DisplaySurface *surface = qemu_console_surface(s->con); uint8_t *dest; uint8_t *src; int x; @@ -204,7 +205,7 @@ static void ssd0303_update_display(void *opaque) if (!s->redraw) return; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; case 15: @@ -236,7 +237,7 @@ static void ssd0303_update_display(void *opaque) colors[0] = colortab + dest_width; colors[1] = colortab; } - dest = ds_get_data(s->ds); + dest = surface_data(surface); for (y = 0; y < 16; y++) { line = (y + s->start_line) & 63; src = s->framebuffer + 132 * (line >> 3) + 36; @@ -252,7 +253,7 @@ static void ssd0303_update_display(void *opaque) } } s->redraw = 0; - dpy_gfx_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY); + dpy_gfx_update(s->con, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY); } static void ssd0303_invalidate_display(void * opaque) @@ -287,10 +288,10 @@ static int ssd0303_init(I2CSlave *i2c) { ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c); - s->ds = graphic_console_init(ssd0303_update_display, - ssd0303_invalidate_display, - NULL, NULL, s); - qemu_console_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); + s->con = graphic_console_init(ssd0303_update_display, + ssd0303_invalidate_display, + NULL, NULL, s); + qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY); return 0; } diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 27b4151..5cf2f70 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -45,7 +45,7 @@ enum ssd0323_mode typedef struct { SSISlave ssidev; - DisplayState *ds; + QemuConsole *con; int cmd_len; int cmd; @@ -175,6 +175,7 @@ static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data) static void ssd0323_update_display(void *opaque) { ssd0323_state *s = (ssd0323_state *)opaque; + DisplaySurface *surface = qemu_console_surface(s->con); uint8_t *dest; uint8_t *src; int x; @@ -189,7 +190,7 @@ static void ssd0323_update_display(void *opaque) if (!s->redraw) return; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; case 15: @@ -212,7 +213,7 @@ static void ssd0323_update_display(void *opaque) for (i = 0; i < 16; i++) { int n; colors[i] = p; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 15: n = i * 2 + (i >> 3); p[0] = n | (n << 5); @@ -235,7 +236,7 @@ static void ssd0323_update_display(void *opaque) p += dest_width; } /* TODO: Implement row/column remapping. */ - dest = ds_get_data(s->ds); + dest = surface_data(surface); for (y = 0; y < 64; y++) { line = y; src = s->framebuffer + 64 * line; @@ -260,7 +261,7 @@ static void ssd0323_update_display(void *opaque) } } s->redraw = 0; - dpy_gfx_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY); + dpy_gfx_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY); } static void ssd0323_invalidate_display(void * opaque) @@ -336,10 +337,10 @@ static int ssd0323_init(SSISlave *dev) s->col_end = 63; s->row_end = 79; - s->ds = graphic_console_init(ssd0323_update_display, - ssd0323_invalidate_display, - NULL, NULL, s); - qemu_console_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY); + s->con = graphic_console_init(ssd0323_update_display, + ssd0323_invalidate_display, + NULL, NULL, s); + qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY); qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1); diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index 0755463..79c971b 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -125,7 +125,7 @@ struct TC6393xbState { DeviceState *flash; ECCState ecc; - DisplayState *ds; + QemuConsole *con; MemoryRegion vram; uint16_t *vram_ptr; uint32_t scr_width, scr_height; /* in pixels */ @@ -433,7 +433,9 @@ static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update) { - switch (ds_get_bits_per_pixel(s->ds)) { + DisplaySurface *surface = qemu_console_surface(s->con); + + switch (surface_bits_per_pixel(surface)) { case 8: tc6393xb_draw_graphic8(s); break; @@ -450,34 +452,37 @@ static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update) tc6393xb_draw_graphic32(s); break; default: - printf("tc6393xb: unknown depth %d\n", ds_get_bits_per_pixel(s->ds)); + printf("tc6393xb: unknown depth %d\n", + surface_bits_per_pixel(surface)); return; } - dpy_gfx_update(s->ds, 0, 0, s->scr_width, s->scr_height); + dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height); } static void tc6393xb_draw_blank(TC6393xbState *s, int full_update) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, w; uint8_t *d; if (!full_update) return; - w = s->scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); - d = ds_get_data(s->ds); + w = s->scr_width * surface_bytes_per_pixel(surface); + d = surface_data(surface); for(i = 0; i < s->scr_height; i++) { memset(d, 0, w); - d += ds_get_linesize(s->ds); + d += surface_stride(surface); } - dpy_gfx_update(s->ds, 0, 0, s->scr_width, s->scr_height); + dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height); } static void tc6393xb_update_display(void *opaque) { TC6393xbState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int full_update; if (s->scr_width == 0 || s->scr_height == 0) @@ -488,8 +493,9 @@ static void tc6393xb_update_display(void *opaque) s->blanked = s->blank; full_update = 1; } - if (s->scr_width != ds_get_width(s->ds) || s->scr_height != ds_get_height(s->ds)) { - qemu_console_resize(s->ds, s->scr_width, s->scr_height); + if (s->scr_width != surface_width(surface) || + s->scr_height != surface_height(surface)) { + qemu_console_resize(s->con, s->scr_width, s->scr_height); full_update = 1; } if (s->blanked) @@ -577,7 +583,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq) memory_region_add_subregion(sysmem, base + 0x100000, &s->vram); s->scr_width = 480; s->scr_height = 640; - s->ds = graphic_console_init(tc6393xb_update_display, + s->con = graphic_console_init(tc6393xb_update_display, NULL, /* invalidate */ NULL, /* screen_dump */ NULL, /* text_update */ diff --git a/hw/tc6393xb_template.h b/hw/tc6393xb_template.h index 4cbbad5..154aafd 100644 --- a/hw/tc6393xb_template.h +++ b/hw/tc6393xb_template.h @@ -37,17 +37,18 @@ static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s) { + DisplaySurface *surface = qemu_console_surface(s->con); int i; uint16_t *data_buffer; uint8_t *data_display; data_buffer = s->vram_ptr; - data_display = ds_get_data(s->ds); + data_display = surface_data(surface); 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 += ds_get_linesize(s->ds); + data_display += surface_stride(surface); #else int j; for (j = 0; j < s->scr_width; j++, data_display += BITS / 8, data_buffer++) { diff --git a/hw/tcx.c b/hw/tcx.c index 896407d..f1edffd 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -38,7 +38,7 @@ typedef struct TCXState { SysBusDevice busdev; hwaddr addr; - DisplayState *ds; + QemuConsole *con; uint8_t *vram; uint32_t *vram24, *cplane; MemoryRegion vram_mem; @@ -75,9 +75,11 @@ static void tcx24_set_dirty(TCXState *s) static void update_palette_entries(TCXState *s, int start, int end) { + DisplaySurface *surface = qemu_console_surface(s->con); int i; - for(i = start; i < end; i++) { - switch(ds_get_bits_per_pixel(s->ds)) { + + for (i = start; i < end; i++) { + switch (surface_bits_per_pixel(surface)) { default: case 8: s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]); @@ -89,10 +91,11 @@ static void update_palette_entries(TCXState *s, int start, int end) s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); break; case 32: - if (is_surface_bgr(s->ds->surface)) + if (is_surface_bgr(surface)) { s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]); - else + } else { s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); + } break; } } @@ -151,12 +154,13 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, const uint32_t *cplane, const uint32_t *s24) { + DisplaySurface *surface = qemu_console_surface(s1->con); int x, bgr, r, g, b; uint8_t val, *p8; uint32_t *p = (uint32_t *)d; uint32_t dval; - bgr = is_surface_bgr(s1->ds->surface); + bgr = is_surface_bgr(surface); for(x = 0; x < width; x++, s++, s24++) { if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) { // 24-bit direct, BGR order @@ -213,23 +217,26 @@ static inline void reset_dirty(TCXState *ts, ram_addr_t page_min, static void tcx_update_display(void *opaque) { TCXState *ts = opaque; + DisplaySurface *surface = qemu_console_surface(ts->con); ram_addr_t page, page_min, page_max; int y, y_start, dd, ds; uint8_t *d, *s; void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); - if (ds_get_bits_per_pixel(ts->ds) == 0) + if (surface_bits_per_pixel(surface) == 0) { return; + } + page = 0; y_start = -1; page_min = -1; page_max = 0; - d = ds_get_data(ts->ds); + d = surface_data(surface); s = ts->vram; - dd = ds_get_linesize(ts->ds); + dd = surface_stride(surface); ds = 1024; - switch (ds_get_bits_per_pixel(ts->ds)) { + switch (surface_bits_per_pixel(surface)) { case 32: f = tcx_draw_line32; break; @@ -269,7 +276,7 @@ static void tcx_update_display(void *opaque) } else { if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(ts->ds, 0, y_start, + dpy_gfx_update(ts->con, 0, y_start, ts->width, y - y_start); y_start = -1; } @@ -279,7 +286,7 @@ static void tcx_update_display(void *opaque) } if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(ts->ds, 0, y_start, + dpy_gfx_update(ts->con, 0, y_start, ts->width, y - y_start); } /* reset modified pages */ @@ -293,24 +300,27 @@ static void tcx_update_display(void *opaque) static void tcx24_update_display(void *opaque) { TCXState *ts = opaque; + DisplaySurface *surface = qemu_console_surface(ts->con); ram_addr_t page, page_min, page_max, cpage, page24; int y, y_start, dd, ds; uint8_t *d, *s; uint32_t *cptr, *s24; - if (ds_get_bits_per_pixel(ts->ds) != 32) + if (surface_bits_per_pixel(surface) != 32) { return; + } + page = 0; page24 = ts->vram24_offset; cpage = ts->cplane_offset; y_start = -1; page_min = -1; page_max = 0; - d = ds_get_data(ts->ds); + d = surface_data(surface); s = ts->vram; s24 = ts->vram24; cptr = ts->cplane; - dd = ds_get_linesize(ts->ds); + dd = surface_stride(surface); ds = 1024; for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE, @@ -345,7 +355,7 @@ static void tcx24_update_display(void *opaque) } else { if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(ts->ds, 0, y_start, + dpy_gfx_update(ts->con, 0, y_start, ts->width, y - y_start); y_start = -1; } @@ -357,7 +367,7 @@ static void tcx24_update_display(void *opaque) } if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(ts->ds, 0, y_start, + dpy_gfx_update(ts->con, 0, y_start, ts->width, y - y_start); } /* reset modified pages */ @@ -371,7 +381,7 @@ static void tcx_invalidate_display(void *opaque) TCXState *s = opaque; tcx_set_dirty(s); - qemu_console_resize(s->ds, s->width, s->height); + qemu_console_resize(s->con, s->width, s->height); } static void tcx24_invalidate_display(void *opaque) @@ -380,7 +390,7 @@ static void tcx24_invalidate_display(void *opaque) tcx_set_dirty(s); tcx24_set_dirty(s); - qemu_console_resize(s->ds, s->width, s->height); + qemu_console_resize(s->con, s->width, s->height); } static int vmstate_tcx_post_load(void *opaque, int version_id) @@ -558,21 +568,21 @@ static int tcx_init1(SysBusDevice *dev) &s->vram_mem, vram_offset, size); sysbus_init_mmio(dev, &s->vram_cplane); - s->ds = graphic_console_init(tcx24_update_display, - tcx24_invalidate_display, - tcx24_screen_dump, NULL, s); + s->con = graphic_console_init(tcx24_update_display, + tcx24_invalidate_display, + tcx24_screen_dump, NULL, s); } else { /* THC 8 bit (dummy) */ memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8", TCX_THC_NREGS_8); sysbus_init_mmio(dev, &s->thc8); - s->ds = graphic_console_init(tcx_update_display, - tcx_invalidate_display, - tcx_screen_dump, NULL, s); + s->con = graphic_console_init(tcx_update_display, + tcx_invalidate_display, + tcx_screen_dump, NULL, s); } - qemu_console_resize(s->ds, s->width, s->height); + qemu_console_resize(s->con, s->width, s->height); return 0; } diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c index 4aa62bf..02356d4 100644 --- a/hw/vga-isa-mm.c +++ b/hw/vga-isa-mm.c @@ -135,8 +135,9 @@ int isa_vga_mm_init(hwaddr vram_base, vga_common_init(&s->vga); vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space); - s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate, - s->vga.screen_dump, s->vga.text_update, s); + s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate, + s->vga.screen_dump, s->vga.text_update, + s); vga_init_vbe(&s->vga, address_space); return 0; diff --git a/hw/vga-isa.c b/hw/vga-isa.c index ffad522..9e29321 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -62,8 +62,8 @@ static int vga_initfn(ISADevice *dev) isa_mem_base + 0x000a0000, vga_io_memory, 1); memory_region_set_coalescing(vga_io_memory); - s->ds = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, s); + s->con = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, s); vga_init_vbe(s, isa_address_space(dev)); /* ROM BIOS */ diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 18018ff..05fa9bc 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -150,8 +150,8 @@ static int pci_std_vga_initfn(PCIDevice *dev) vga_common_init(s); vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true); - s->ds = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, s); + s->con = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, s); /* XXX: VGA_RAM_SIZE must be a power of two */ pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); diff --git a/hw/vga.c b/hw/vga.c index 13d5066..59bfb22 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1174,9 +1174,9 @@ static int update_basic_params(VGACommonState *s) #define NB_DEPTHS 7 -static inline int get_depth_index(DisplayState *s) +static inline int get_depth_index(DisplaySurface *s) { - switch(ds_get_bits_per_pixel(s)) { + switch (surface_bits_per_pixel(s)) { default: case 8: return 0; @@ -1185,10 +1185,11 @@ static inline int get_depth_index(DisplayState *s) case 16: return 2; case 32: - if (is_surface_bgr(s->surface)) + if (is_surface_bgr(s)) { return 4; - else + } else { return 3; + } } } @@ -1294,6 +1295,7 @@ static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = { */ static void vga_draw_text(VGACommonState *s, int full_update) { + DisplaySurface *surface = qemu_console_surface(s->con); int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr; int cx_min, cx_max, linesize, x_incr, line, line1; uint32_t offset, fgcol, bgcol, v, cursor_offset; @@ -1345,8 +1347,9 @@ static void vga_draw_text(VGACommonState *s, int full_update) cw != s->last_cw || cheight != s->last_ch || s->last_depth) { s->last_scr_width = width * cw; s->last_scr_height = height * cheight; - qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height); - dpy_text_resize(s->ds, width, height); + qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height); + surface = qemu_console_surface(s->con); + dpy_text_resize(s->con, width, height); s->last_depth = 0; s->last_width = width; s->last_height = height; @@ -1355,10 +1358,10 @@ static void vga_draw_text(VGACommonState *s, int full_update) full_update = 1; } s->rgb_to_pixel = - rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + rgb_to_pixel_dup_table[get_depth_index(surface)]; full_update |= update_palette16(s); palette = s->last_palette; - x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); + x_incr = cw * surface_bytes_per_pixel(surface); if (full_update) { s->full_update_text = 1; @@ -1389,15 +1392,15 @@ static void vga_draw_text(VGACommonState *s, int full_update) s->cursor_visible_phase = !s->cursor_visible_phase; } - depth_index = get_depth_index(s->ds); + depth_index = get_depth_index(surface); if (cw == 16) vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; else vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; - dest = ds_get_data(s->ds); - linesize = ds_get_linesize(s->ds); + dest = surface_data(surface); + linesize = surface_stride(surface); ch_attr_ptr = s->last_ch_attr; line = 0; offset = s->start_addr * 4; @@ -1465,7 +1468,7 @@ static void vga_draw_text(VGACommonState *s, int full_update) ch_attr_ptr++; } if (cx_max != -1) { - dpy_gfx_update(s->ds, cx_min * cw, cy * cheight, + dpy_gfx_update(s->con, cx_min * cw, cy * cheight, (cx_max - cx_min + 1) * cw, cheight); } dest += linesize * cheight; @@ -1636,6 +1639,7 @@ void vga_dirty_log_stop(VGACommonState *s) */ static void vga_draw_graphic(VGACommonState *s, int full_update) { + DisplaySurface *surface = qemu_console_surface(s->con); int y1, y, update, linesize, y_start, double_scan, mask, depth; int width, height, shift_control, line_offset, bwidth, bits; ram_addr_t page0, page1, page_min, page_max; @@ -1691,13 +1695,13 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) height != s->last_height || s->last_depth != depth) { if (depth == 32 || (depth == 16 && !byteswap)) { - DisplaySurface *surface; surface = qemu_create_displaysurface_from(disp_width, height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4), byteswap); - dpy_gfx_replace_surface(s->ds, surface); + dpy_gfx_replace_surface(s->con, surface); } else { - qemu_console_resize(s->ds, disp_width, height); + qemu_console_resize(s->con, disp_width, height); + surface = qemu_console_surface(s->con); } s->last_scr_width = disp_width; s->last_scr_height = height; @@ -1706,18 +1710,18 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) s->last_line_offset = s->line_offset; s->last_depth = depth; full_update = 1; - } else if (is_buffer_shared(s->ds->surface) && - (full_update || ds_get_data(s->ds) != s->vram_ptr + } else if (is_buffer_shared(surface) && + (full_update || surface_data(surface) != s->vram_ptr + (s->start_addr * 4))) { DisplaySurface *surface; surface = qemu_create_displaysurface_from(disp_width, height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4), byteswap); - dpy_gfx_replace_surface(s->ds, surface); + dpy_gfx_replace_surface(s->con, surface); } s->rgb_to_pixel = - rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + rgb_to_pixel_dup_table[get_depth_index(surface)]; if (shift_control == 0) { full_update |= update_palette16(s); @@ -1766,10 +1770,12 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) break; } } - vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; + vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + + get_depth_index(surface)]; - if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate) + if (!is_buffer_shared(surface) && s->cursor_invalidate) { s->cursor_invalidate(s); + } line_offset = s->line_offset; #if 0 @@ -1782,8 +1788,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) y_start = -1; page_min = -1; page_max = 0; - d = ds_get_data(s->ds); - linesize = ds_get_linesize(s->ds); + d = surface_data(surface); + linesize = surface_stride(surface); y1 = 0; for(y = 0; y < height; y++) { addr = addr1; @@ -1810,7 +1816,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) page_min = page0; if (page1 > page_max) page_max = page1; - if (!(is_buffer_shared(s->ds->surface))) { + if (!(is_buffer_shared(surface))) { vga_draw_line(s, d, s->vram_ptr + addr, width); if (s->cursor_draw_line) s->cursor_draw_line(s, d, y); @@ -1818,7 +1824,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } else { if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(s->ds, 0, y_start, + dpy_gfx_update(s->con, 0, y_start, disp_width, y - y_start); y_start = -1; } @@ -1839,7 +1845,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(s->ds, 0, y_start, + dpy_gfx_update(s->con, 0, y_start, disp_width, y - y_start); } /* reset modified pages */ @@ -1854,6 +1860,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) static void vga_draw_blank(VGACommonState *s, int full_update) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, w, val; uint8_t *d; @@ -1863,18 +1870,19 @@ static void vga_draw_blank(VGACommonState *s, int full_update) return; s->rgb_to_pixel = - rgb_to_pixel_dup_table[get_depth_index(s->ds)]; - if (ds_get_bits_per_pixel(s->ds) == 8) + rgb_to_pixel_dup_table[get_depth_index(surface)]; + if (surface_bits_per_pixel(surface) == 8) { val = s->rgb_to_pixel(0, 0, 0); - else + } else { val = 0; - w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); - d = ds_get_data(s->ds); + } + w = s->last_scr_width * surface_bytes_per_pixel(surface); + d = surface_data(surface); for(i = 0; i < s->last_scr_height; i++) { memset(d, val, w); - d += ds_get_linesize(s->ds); + d += surface_stride(surface); } - dpy_gfx_update(s->ds, 0, 0, + dpy_gfx_update(s->con, 0, 0, s->last_scr_width, s->last_scr_height); } @@ -1885,11 +1893,12 @@ static void vga_draw_blank(VGACommonState *s, int full_update) static void vga_update_display(void *opaque) { VGACommonState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int full_update, graphic_mode; qemu_flush_coalesced_mmio_buffer(); - if (ds_get_bits_per_pixel(s->ds) == 0) { + if (surface_bits_per_pixel(surface) == 0) { /* nothing to do */ } else { full_update = 0; @@ -2063,8 +2072,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) cw != s->last_cw || cheight != s->last_ch) { s->last_scr_width = width * cw; s->last_scr_height = height * cheight; - qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height); - dpy_text_resize(s->ds, width, height); + qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height); + dpy_text_resize(s->con, width, height); s->last_depth = 0; s->last_width = width; s->last_height = height; @@ -2089,11 +2098,11 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) { cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20); if (cursor_visible && cursor_offset < size && cursor_offset >= 0) - dpy_text_cursor(s->ds, + dpy_text_cursor(s->con, TEXTMODE_X(cursor_offset), TEXTMODE_Y(cursor_offset)); else - dpy_text_cursor(s->ds, -1, -1); + dpy_text_cursor(s->con, -1, -1); s->cursor_offset = cursor_offset; s->cursor_start = s->cr[VGA_CRTC_CURSOR_START]; s->cursor_end = s->cr[VGA_CRTC_CURSOR_END]; @@ -2106,7 +2115,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) for (i = 0; i < size; src ++, dst ++, i ++) console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src))); - dpy_text_update(s->ds, 0, 0, width, height); + dpy_text_update(s->con, 0, 0, width, height); } else { c_max = 0; @@ -2129,7 +2138,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) if (c_min <= c_max) { i = TEXTMODE_Y(c_min); - dpy_text_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); + dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1); } } @@ -2154,8 +2163,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) /* Display a message */ s->last_width = 60; s->last_height = height = 3; - dpy_text_cursor(s->ds, -1, -1); - dpy_text_resize(s->ds, s->last_width, height); + dpy_text_cursor(s->con, -1, -1); + dpy_text_resize(s->con, s->last_width, height); for (dst = chardata, i = 0; i < s->last_width * height; i ++) console_write_ch(dst ++, ' '); @@ -2166,7 +2175,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) for (i = 0; i < size; i ++) console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); - dpy_text_update(s->ds, 0, 0, s->last_width, height); + dpy_text_update(s->con, 0, 0, s->last_width, height); } static uint64_t vga_mem_read(void *opaque, hwaddr addr, @@ -2438,10 +2447,11 @@ static void vga_screen_dump(void *opaque, const char *filename, bool cswitch, Error **errp) { VGACommonState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); if (cswitch) { vga_invalidate_display(s); } vga_hw_update(); - ppm_save(filename, s->ds->surface, errp); + ppm_save(filename, surface, errp); } diff --git a/hw/vga_int.h b/hw/vga_int.h index 8d496ea..260f7d6 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -132,7 +132,7 @@ typedef struct VGACommonState { uint32_t vbe_bank_mask; int vbe_mapped; /* display refresh support */ - DisplayState *ds; + QemuConsole *con; uint32_t font_offsets[2]; int graphic_mode; uint8_t shift_control; diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index db2f187..5b9ce8f 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -57,9 +57,6 @@ struct vmsvga_state_s { int new_height; uint32_t guest; uint32_t svgaid; - uint32_t wred; - uint32_t wgreen; - uint32_t wblue; int syncing; MemoryRegion fifo_ram; @@ -289,6 +286,7 @@ enum { static inline void vmsvga_update_rect(struct vmsvga_state_s *s, int x, int y, int w, int h) { + DisplaySurface *surface = qemu_console_surface(s->vga.con); int line; int bypl; int width; @@ -305,11 +303,11 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w); w = 0; } - if (x + w > ds_get_width(s->vga.ds)) { + if (x + w > surface_width(surface)) { fprintf(stderr, "%s: update width too large x: %d, w: %d\n", __func__, x, w); - x = MIN(x, ds_get_width(s->vga.ds)); - w = ds_get_width(s->vga.ds) - x; + x = MIN(x, surface_width(surface)); + w = surface_width(surface) - x; } if (y < 0) { @@ -321,23 +319,23 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, fprintf(stderr, "%s: update h was < 0 (%d)\n", __func__, h); h = 0; } - if (y + h > ds_get_height(s->vga.ds)) { + if (y + h > surface_height(surface)) { fprintf(stderr, "%s: update height too large y: %d, h: %d\n", __func__, y, h); - y = MIN(y, ds_get_height(s->vga.ds)); - h = ds_get_height(s->vga.ds) - y; + y = MIN(y, surface_height(surface)); + h = surface_height(surface) - y; } - bypl = ds_get_linesize(s->vga.ds); - width = ds_get_bytes_per_pixel(s->vga.ds) * w; - start = ds_get_bytes_per_pixel(s->vga.ds) * x + bypl * y; + bypl = surface_stride(surface); + width = surface_bytes_per_pixel(surface) * w; + start = surface_bytes_per_pixel(surface) * x + bypl * y; src = s->vga.vram_ptr + start; - dst = ds_get_data(s->vga.ds) + start; + dst = surface_data(surface) + start; for (line = h; line > 0; line--, src += bypl, dst += bypl) { memcpy(dst, src, width); } - dpy_gfx_update(s->vga.ds, x, y, w, h); + dpy_gfx_update(s->vga.con, x, y, w, h); } static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s, @@ -373,9 +371,10 @@ static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s) static inline void vmsvga_copy_rect(struct vmsvga_state_s *s, int x0, int y0, int x1, int y1, int w, int h) { + DisplaySurface *surface = qemu_console_surface(s->vga.con); uint8_t *vram = s->vga.vram_ptr; - int bypl = ds_get_linesize(s->vga.ds); - int bypp = ds_get_bytes_per_pixel(s->vga.ds); + int bypl = surface_stride(surface); + int bypp = surface_bytes_per_pixel(surface); int width = bypp * w; int line = h; uint8_t *ptr[2]; @@ -402,8 +401,9 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s, static inline void vmsvga_fill_rect(struct vmsvga_state_s *s, uint32_t c, int x, int y, int w, int h) { - int bypl = ds_get_linesize(s->vga.ds); - int width = ds_get_bytes_per_pixel(s->vga.ds) * w; + DisplaySurface *surface = qemu_console_surface(s->vga.con); + int bypl = surface_stride(surface); + int width = surface_bytes_per_pixel(surface) * w; int line = h; int column; uint8_t *fst; @@ -416,14 +416,14 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s, col[2] = c >> 16; col[3] = c >> 24; - fst = s->vga.vram_ptr + ds_get_bytes_per_pixel(s->vga.ds) * x + bypl * y; + fst = s->vga.vram_ptr + surface_bytes_per_pixel(surface) * x + bypl * y; if (line--) { dst = fst; src = col; for (column = width; column > 0; column--) { *(dst++) = *(src++); - if (src - col == ds_get_bytes_per_pixel(s->vga.ds)) { + if (src - col == surface_bytes_per_pixel(surface)) { src = col; } } @@ -490,7 +490,7 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s, qc = cursor_builtin_left_ptr(); } - dpy_cursor_define(s->vga.ds, qc); + dpy_cursor_define(s->vga.con, qc); cursor_put(qc); } #endif @@ -720,6 +720,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) { uint32_t caps; struct vmsvga_state_s *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->vga.con); switch (s->index) { case SVGA_REG_ID: @@ -729,10 +730,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) return s->enable; case SVGA_REG_WIDTH: - return ds_get_width(s->vga.ds); + return surface_width(surface); case SVGA_REG_HEIGHT: - return ds_get_height(s->vga.ds); + return surface_height(surface); case SVGA_REG_MAX_WIDTH: return SVGA_MAX_WIDTH; @@ -750,13 +751,13 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) return 0x0; case SVGA_REG_RED_MASK: - return s->wred; + return surface->pf.rmask; case SVGA_REG_GREEN_MASK: - return s->wgreen; + return surface->pf.gmask; case SVGA_REG_BLUE_MASK: - return s->wblue; + return surface->pf.bmask; case SVGA_REG_BYTES_PER_LINE: return s->bypp * s->new_width; @@ -785,7 +786,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) caps |= SVGA_CAP_RECT_FILL; #endif #ifdef HW_MOUSE_ACCEL - if (dpy_cursor_define_supported(s->vga.ds)) { + if (dpy_cursor_define_supported(s->vga.con)) { caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 | SVGA_CAP_CURSOR_BYPASS; } @@ -947,7 +948,7 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE); #ifdef HW_MOUSE_ACCEL if (value <= SVGA_CURSOR_ON_SHOW) { - dpy_mouse_set(s->vga.ds, s->cursor.x, s->cursor.y, s->cursor.on); + dpy_mouse_set(s->vga.con, s->cursor.x, s->cursor.y, s->cursor.on); } #endif break; @@ -982,9 +983,11 @@ static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data) static inline void vmsvga_check_size(struct vmsvga_state_s *s) { - if (s->new_width != ds_get_width(s->vga.ds) || - s->new_height != ds_get_height(s->vga.ds)) { - qemu_console_resize(s->vga.ds, s->new_width, s->new_height); + DisplaySurface *surface = qemu_console_surface(s->vga.con); + + if (s->new_width != surface_width(surface) || + s->new_height != surface_height(surface)) { + qemu_console_resize(s->vga.con, s->new_width, s->new_height); s->invalidated = 1; } } @@ -992,6 +995,7 @@ static inline void vmsvga_check_size(struct vmsvga_state_s *s) static void vmsvga_update_display(void *opaque) { struct vmsvga_state_s *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->vga.con); bool dirty = false; if (!s->enable) { @@ -1011,19 +1015,19 @@ static void vmsvga_update_display(void *opaque) if (memory_region_is_logging(&s->vga.vram)) { vga_sync_dirty_bitmap(&s->vga); dirty = memory_region_get_dirty(&s->vga.vram, 0, - ds_get_linesize(s->vga.ds) * ds_get_height(s->vga.ds), + surface_stride(surface) * surface_height(surface), DIRTY_MEMORY_VGA); } if (s->invalidated || dirty) { s->invalidated = 0; - memcpy(ds_get_data(s->vga.ds), s->vga.vram_ptr, - ds_get_linesize(s->vga.ds) * ds_get_height(s->vga.ds)); - dpy_gfx_update(s->vga.ds, 0, 0, - ds_get_width(s->vga.ds), ds_get_height(s->vga.ds)); + memcpy(surface_data(surface), s->vga.vram_ptr, + surface_stride(surface) * surface_height(surface)); + dpy_gfx_update(s->vga.con, 0, 0, + surface_width(surface), surface_height(surface)); } if (dirty) { memory_region_reset_dirty(&s->vga.vram, 0, - ds_get_linesize(s->vga.ds) * ds_get_height(s->vga.ds), + surface_stride(surface) * surface_height(surface), DIRTY_MEMORY_VGA); } } @@ -1063,17 +1067,19 @@ static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch, Error **errp) { struct vmsvga_state_s *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->vga.con); + if (!s->enable) { s->vga.screen_dump(&s->vga, filename, cswitch, errp); return; } - if (ds_get_bits_per_pixel(s->vga.ds) == 32) { + if (surface_bits_per_pixel(surface) == 32) { DisplaySurface *ds = qemu_create_displaysurface_from( - ds_get_width(s->vga.ds), - ds_get_height(s->vga.ds), + surface_width(surface), + surface_height(surface), 32, - ds_get_linesize(s->vga.ds), + surface_stride(surface), s->vga.vram_ptr, false); ppm_save(filename, ds, errp); g_free(ds); @@ -1143,14 +1149,16 @@ static const VMStateDescription vmstate_vmware_vga = { static void vmsvga_init(struct vmsvga_state_s *s, MemoryRegion *address_space, MemoryRegion *io) { + DisplaySurface *surface; + s->scratch_size = SVGA_SCRATCH_SIZE; s->scratch = g_malloc(s->scratch_size * 4); - s->vga.ds = graphic_console_init(vmsvga_update_display, - vmsvga_invalidate_display, - vmsvga_screen_dump, - vmsvga_text_update, s); - + s->vga.con = graphic_console_init(vmsvga_update_display, + vmsvga_invalidate_display, + vmsvga_screen_dump, + vmsvga_text_update, s); + surface = qemu_console_surface(s->vga.con); s->fifo_size = SVGA_FIFO_SIZE; memory_region_init_ram(&s->fifo_ram, "vmsvga.fifo", s->fifo_size); @@ -1162,11 +1170,8 @@ static void vmsvga_init(struct vmsvga_state_s *s, vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga); /* Save some values here in case they are changed later. * This is suspicious and needs more though why it is needed. */ - s->depth = ds_get_bits_per_pixel(s->vga.ds); - s->bypp = ds_get_bytes_per_pixel(s->vga.ds); - s->wred = ds_get_rmask(s->vga.ds); - s->wgreen = ds_get_gmask(s->vga.ds); - s->wblue = ds_get_bmask(s->vga.ds); + s->depth = surface_bits_per_pixel(surface); + s->bypp = surface_bytes_per_pixel(surface); } static uint64_t vmsvga_io_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/xenfb.c b/hw/xenfb.c index 7779097..7c46a2f 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -54,7 +54,7 @@ struct common { struct XenDevice xendev; /* must be first */ void *page; - DisplayState *ds; + QemuConsole *con; }; struct XenInput { @@ -318,8 +318,9 @@ static void xenfb_mouse_event(void *opaque, int dx, int dy, int dz, int button_state) { struct XenInput *xenfb = opaque; - int dw = ds_get_width(xenfb->c.ds); - int dh = ds_get_height(xenfb->c.ds); + DisplaySurface *surface = qemu_console_surface(xenfb->c.con); + int dw = surface_width(surface); + int dh = surface_height(surface); int i; if (xenfb->abs_pointer_wanted) @@ -353,16 +354,9 @@ static int input_initialise(struct XenDevice *xendev) struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); int rc; - if (!in->c.ds) { - char *vfb = xenstore_read_str(NULL, "device/vfb"); - if (vfb == NULL) { - /* there is no vfb, run vkbd on its own */ - in->c.ds = get_displaystate(); - } else { - g_free(vfb); - xen_be_printf(xendev, 1, "ds not set (yet)\n"); - return -1; - } + if (!in->c.con) { + xen_be_printf(xendev, 1, "ds not set (yet)\n"); + return -1; } rc = common_bind(&in->c); @@ -615,12 +609,13 @@ static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim, */ static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h) { + DisplaySurface *surface = qemu_console_surface(xenfb->c.con); int line, oops = 0; - int bpp = ds_get_bits_per_pixel(xenfb->c.ds); - int linesize = ds_get_linesize(xenfb->c.ds); - uint8_t *data = ds_get_data(xenfb->c.ds); + int bpp = surface_bits_per_pixel(surface); + int linesize = surface_stride(surface); + uint8_t *data = surface_data(surface); - if (!is_buffer_shared(xenfb->c.ds->surface)) { + if (!is_buffer_shared(surface)) { switch (xenfb->depth) { case 8: if (bpp == 16) { @@ -648,10 +643,10 @@ static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h) xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n", __FUNCTION__, xenfb->depth, bpp); - dpy_gfx_update(xenfb->c.ds, x, y, w, h); + dpy_gfx_update(xenfb->c.con, x, y, w, h); } -#ifdef XENFB_TYPE_REFRESH_PERIOD +#if 0 /* def XENFB_TYPE_REFRESH_PERIOD */ static int xenfb_queue_full(struct XenFB *xenfb) { struct xenfb_page *page = xenfb->c.page; @@ -710,7 +705,7 @@ static void xenfb_update(void *opaque) return; if (xenfb->feature_update) { -#ifdef XENFB_TYPE_REFRESH_PERIOD +#if 0 /* XENFB_TYPE_REFRESH_PERIOD */ struct DisplayChangeListener *l; int period = 99999999; int idle = 1; @@ -764,10 +759,10 @@ static void xenfb_update(void *opaque) surface = qemu_create_displaysurface(xenfb->width, xenfb->height); break; } - dpy_gfx_replace_surface(xenfb->c.ds, surface); + dpy_gfx_replace_surface(xenfb->c.con, surface); xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n", xenfb->width, xenfb->height, xenfb->depth, - is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : ""); + is_buffer_shared(surface) ? " (shared)" : ""); xenfb->up_fullscreen = 1; } @@ -1009,16 +1004,16 @@ wait_more: /* vfb */ fb = container_of(xfb, struct XenFB, c.xendev); - fb->c.ds = graphic_console_init(xenfb_update, - xenfb_invalidate, - NULL, - NULL, - fb); + fb->c.con = graphic_console_init(xenfb_update, + xenfb_invalidate, + NULL, + NULL, + fb); fb->have_console = 1; /* vkbd */ in = container_of(xin, struct XenInput, c.xendev); - in->c.ds = fb->c.ds; + in->c.con = fb->c.con; /* retry ->init() */ xen_be_check_state(xin); -- cgit v1.1