* [Qemu-devel] [PATCH 0/4] Raspberry Pi framebuffer and Windows support
@ 2016-02-27 0:16 Andrew Baumann
2016-02-27 0:16 ` [Qemu-devel] [PATCH 1/4] bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry pi Andrew Baumann
` (3 more replies)
0 siblings, 4 replies; 11+ messages in thread
From: Andrew Baumann @ 2016-02-27 0:16 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini
This patch series adds support for the AUX (second UART) and
framebuffer devices on Raspberry Pi 2, and enables booting Windows on
this device. As with the previous series, it is heavily based on the
original (out of tree) work of Gregory Estrade, Stefan Weil and others
to support Raspberry Pi 1.
After this series, it is possible to boot Windows by following the
instructions at https://github.com/0xabu/qemu/wiki. There's also
documentation for booting Linux on that page, but note that you can't
load bcm2709-rpi-2-b.dtb because the DMA controller is not included.
I plan to add DMA, USB, and reamining timers / system devices in
future patch series, along with support for pi1 (bcm2835). In the
meantime, the complete code is available at https://github.com/0xabu/qemu
Cheers,
Andrew
Andrew Baumann (4):
bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry
pi
bcm2835_aux: add emulation of BCM2835 AUX (aka UART1) block
bcm2835_fb: add framebuffer device for Raspberry Pi
bcm2835_property: implement framebuffer control/configuration
properties
hw/arm/bcm2835_peripherals.c | 63 +++++-
hw/arm/bcm2836.c | 2 +
hw/arm/raspi.c | 12 +-
hw/char/Makefile.objs | 1 +
hw/char/bcm2835_aux.c | 241 ++++++++++++++++++++
hw/display/Makefile.objs | 1 +
hw/display/bcm2835_fb.c | 421 +++++++++++++++++++++++++++++++++++
hw/misc/bcm2835_property.c | 139 +++++++++++-
include/hw/arm/bcm2835_peripherals.h | 4 +
include/hw/char/bcm2835_aux.h | 31 +++
include/hw/display/bcm2835_fb.h | 47 ++++
include/hw/misc/bcm2835_property.h | 5 +-
12 files changed, 954 insertions(+), 13 deletions(-)
create mode 100644 hw/char/bcm2835_aux.c
create mode 100644 hw/display/bcm2835_fb.c
create mode 100644 include/hw/char/bcm2835_aux.h
create mode 100644 include/hw/display/bcm2835_fb.h
--
2.5.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 1/4] bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry pi
2016-02-27 0:16 [Qemu-devel] [PATCH 0/4] Raspberry Pi framebuffer and Windows support Andrew Baumann
@ 2016-02-27 0:16 ` Andrew Baumann
2016-03-01 18:21 ` Peter Maydell
2016-02-27 0:16 ` [Qemu-devel] [PATCH 2/4] bcm2835_aux: add emulation of BCM2835 AUX (aka UART1) block Andrew Baumann
` (2 subsequent siblings)
3 siblings, 1 reply; 11+ messages in thread
From: Andrew Baumann @ 2016-02-27 0:16 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini
Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---
hw/arm/bcm2835_peripherals.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index 6d66fa0..6ce9cd1 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -171,6 +171,13 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
return;
}
+ object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk",
+ &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err);
if (err) {
error_propagate(errp, err);
--
2.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 2/4] bcm2835_aux: add emulation of BCM2835 AUX (aka UART1) block
2016-02-27 0:16 [Qemu-devel] [PATCH 0/4] Raspberry Pi framebuffer and Windows support Andrew Baumann
2016-02-27 0:16 ` [Qemu-devel] [PATCH 1/4] bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry pi Andrew Baumann
@ 2016-02-27 0:16 ` Andrew Baumann
2016-03-01 19:03 ` Peter Maydell
2016-02-27 0:16 ` [Qemu-devel] [PATCH 3/4] bcm2835_fb: add framebuffer device for Raspberry Pi Andrew Baumann
2016-02-27 0:16 ` [Qemu-devel] [PATCH 4/4] bcm2835_property: implement framebuffer control/configuration properties Andrew Baumann
3 siblings, 1 reply; 11+ messages in thread
From: Andrew Baumann @ 2016-02-27 0:16 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini
Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---
hw/arm/bcm2835_peripherals.c | 18 +++
hw/char/Makefile.objs | 1 +
hw/char/bcm2835_aux.c | 241 +++++++++++++++++++++++++++++++++++
include/hw/arm/bcm2835_peripherals.h | 2 +
include/hw/char/bcm2835_aux.h | 31 +++++
5 files changed, 293 insertions(+)
create mode 100644 hw/char/bcm2835_aux.c
create mode 100644 include/hw/char/bcm2835_aux.h
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index 6ce9cd1..103a330 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -48,6 +48,11 @@ static void bcm2835_peripherals_init(Object *obj)
object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL);
qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default());
+ /* AUX / UART1 */
+ object_initialize(&s->aux, sizeof(s->aux), TYPE_BCM2835_AUX);
+ object_property_add_child(obj, "aux", OBJECT(&s->aux), NULL);
+ qdev_set_parent_bus(DEVICE(&s->aux), sysbus_get_default());
+
/* Mailboxes */
object_initialize(&s->mboxes, sizeof(s->mboxes), TYPE_BCM2835_MBOX);
object_property_add_child(obj, "mbox", OBJECT(&s->mboxes), NULL);
@@ -131,6 +136,19 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
INTERRUPT_UART));
+ /* AUX / UART1 */
+ object_property_set_bool(OBJECT(&s->aux), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ memory_region_add_subregion(&s->peri_mr, UART1_OFFSET,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->aux), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->aux), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
+ INTERRUPT_AUX));
+
/* Mailboxes */
object_property_set_bool(OBJECT(&s->mboxes), true, "realized", &err);
if (err) {
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 5931cc8..69a553c 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -16,6 +16,7 @@ obj-$(CONFIG_SH4) += sh_serial.o
obj-$(CONFIG_PSERIES) += spapr_vty.o
obj-$(CONFIG_DIGIC) += digic-uart.o
obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o
+obj-$(CONFIG_RASPI) += bcm2835_aux.o
common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
new file mode 100644
index 0000000..c2f71e5
--- /dev/null
+++ b/hw/char/bcm2835_aux.c
@@ -0,0 +1,241 @@
+/*
+ * BCM2835 (Raspberry Pi / Pi 2) Aux block (mini UART and SPI).
+ * Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ * Based on pl011.c, copyright terms below:
+ *
+ * Arm PrimeCell PL011 UART
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/bcm2835_aux.h"
+
+#define AUX_ENABLES 0x4
+#define AUX_MU_IO_REG 0x40
+#define AUX_MU_IER_REG 0x44
+#define AUX_MU_IIR_REG 0x48
+#define AUX_MU_LSR_REG 0x54
+#define AUX_MU_STAT_REG 0x64
+
+static void bcm2835_aux_update(BCM2835AuxState *s)
+{
+ bool status = (s->rx_int_enable && s->read_count != 0) || s->tx_int_enable;
+ qemu_set_irq(s->irq, status);
+}
+
+static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
+{
+ BCM2835AuxState *s = opaque;
+ uint32_t c, res;
+
+ switch (offset) {
+ case AUX_ENABLES:
+ return 1; /* mini UART enabled */
+
+ case AUX_MU_IO_REG:
+ c = s->read_fifo[s->read_pos];
+ if (s->read_count > 0) {
+ s->read_count--;
+ if (++s->read_pos == 8) {
+ s->read_pos = 0;
+ }
+ }
+ if (s->chr) {
+ qemu_chr_accept_input(s->chr);
+ }
+ bcm2835_aux_update(s);
+ return c;
+
+ case AUX_MU_IER_REG:
+ res = 0;
+ if (s->rx_int_enable) {
+ res |= 0x2;
+ }
+ if (s->tx_int_enable) {
+ res |= 0x1;
+ }
+ return res;
+
+ case AUX_MU_IIR_REG:
+ res = 0xc0;
+ if (s->tx_int_enable) {
+ res |= 0x1;
+ } else if (s->rx_int_enable && s->read_count != 0) {
+ res |= 0x2;
+ }
+ return res;
+
+ case AUX_MU_LSR_REG:
+ res = 0x60; /* tx idle, empty */
+ if (s->read_count != 0) {
+ res |= 0x1;
+ }
+ return res;
+
+ case AUX_MU_STAT_REG:
+ res = 0x302; /* space in the output buffer, empty tx fifo */
+ if (s->read_count > 0) {
+ res |= 0x1; /* data in input buffer */
+ assert(s->read_count < 8);
+ res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */
+ }
+ return res;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ __func__, offset);
+ return 0;
+ }
+}
+
+static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ BCM2835AuxState *s = opaque;
+ unsigned char ch;
+
+ switch (offset) {
+ case AUX_ENABLES:
+ if (value != 1) {
+ qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI "
+ "or disable UART\n", __func__);
+ }
+ break;
+
+ case AUX_MU_IO_REG:
+ ch = value;
+ if (s->chr) {
+ qemu_chr_fe_write(s->chr, &ch, 1);
+ }
+ break;
+
+ case AUX_MU_IER_REG:
+ s->rx_int_enable = (value & 0x2) != 0;
+ s->tx_int_enable = (value & 0x1) != 0;
+ break;
+
+ case AUX_MU_IIR_REG:
+ if (value & 0x1) {
+ s->read_count = 0;
+ }
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ __func__, offset);
+ }
+
+ bcm2835_aux_update(s);
+}
+
+static int bcm2835_aux_can_receive(void *opaque)
+{
+ BCM2835AuxState *s = opaque;
+
+ return s->read_count < 8;
+}
+
+static void bcm2835_aux_put_fifo(void *opaque, uint32_t value)
+{
+ BCM2835AuxState *s = opaque;
+ int slot;
+
+ slot = s->read_pos + s->read_count;
+ if (slot >= 8) {
+ slot -= 8;
+ }
+ s->read_fifo[slot] = value;
+ s->read_count++;
+ if (s->read_count == 8) {
+ /* buffer full */
+ }
+ bcm2835_aux_update(s);
+}
+
+static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size)
+{
+ bcm2835_aux_put_fifo(opaque, *buf);
+}
+
+static void bcm2835_aux_event(void *opaque, int event)
+{
+ if (event == CHR_EVENT_BREAK) {
+ bcm2835_aux_put_fifo(opaque, 0x400);
+ }
+}
+
+static const MemoryRegionOps bcm2835_aux_ops = {
+ .read = bcm2835_aux_read,
+ .write = bcm2835_aux_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
+static const VMStateDescription vmstate_bcm2835_aux = {
+ .name = TYPE_BCM2835_AUX,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(read_fifo, BCM2835AuxState, 8),
+ VMSTATE_UINT8(read_pos, BCM2835AuxState),
+ VMSTATE_UINT8(read_count, BCM2835AuxState),
+ VMSTATE_BOOL(rx_int_enable, BCM2835AuxState),
+ VMSTATE_BOOL(tx_int_enable, BCM2835AuxState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void bcm2835_aux_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ BCM2835AuxState *s = BCM2835_AUX(obj);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_aux_ops, s,
+ TYPE_BCM2835_AUX, 0x100);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
+}
+
+static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
+{
+ BCM2835AuxState *s = BCM2835_AUX(dev);
+
+ /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
+ s->chr = qemu_char_get_next_serial();
+
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, bcm2835_aux_can_receive,
+ bcm2835_aux_receive, bcm2835_aux_event, s);
+ }
+}
+
+static void bcm2835_aux_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = bcm2835_aux_realize;
+ dc->vmsd = &vmstate_bcm2835_aux;
+ /* Reason: realize() method uses qemu_char_get_next_serial() */
+ dc->cannot_instantiate_with_device_add_yet = true;
+}
+
+static const TypeInfo bcm2835_aux_info = {
+ .name = TYPE_BCM2835_AUX,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BCM2835AuxState),
+ .instance_init = bcm2835_aux_init,
+ .class_init = bcm2835_aux_class_init,
+};
+
+static void bcm2835_aux_register_types(void)
+{
+ type_register_static(&bcm2835_aux_info);
+}
+
+type_init(bcm2835_aux_register_types)
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
index 5d888dc..889adf5 100644
--- a/include/hw/arm/bcm2835_peripherals.h
+++ b/include/hw/arm/bcm2835_peripherals.h
@@ -14,6 +14,7 @@
#include "qemu-common.h"
#include "exec/address-spaces.h"
#include "hw/sysbus.h"
+#include "hw/char/bcm2835_aux.h"
#include "hw/intc/bcm2835_ic.h"
#include "hw/misc/bcm2835_property.h"
#include "hw/misc/bcm2835_mbox.h"
@@ -33,6 +34,7 @@ typedef struct BCM2835PeripheralState {
qemu_irq irq, fiq;
SysBusDevice *uart0;
+ BCM2835AuxState aux;
BCM2835ICState ic;
BCM2835PropertyState property;
BCM2835MboxState mboxes;
diff --git a/include/hw/char/bcm2835_aux.h b/include/hw/char/bcm2835_aux.h
new file mode 100644
index 0000000..f917619
--- /dev/null
+++ b/include/hw/char/bcm2835_aux.h
@@ -0,0 +1,31 @@
+/*
+ * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ *
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2835_AUX_H
+#define BCM2835_AUX_H
+
+#include "hw/sysbus.h"
+#include "sysemu/char.h"
+
+#define TYPE_BCM2835_AUX "bcm2835-aux"
+#define BCM2835_AUX(obj) OBJECT_CHECK(BCM2835AuxState, (obj), TYPE_BCM2835_AUX)
+
+typedef struct {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ MemoryRegion iomem;
+ CharDriverState *chr;
+ qemu_irq irq;
+
+ uint32_t read_fifo[8];
+ uint8_t read_pos, read_count;
+ bool rx_int_enable, tx_int_enable;
+} BCM2835AuxState;
+
+#endif
--
2.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 3/4] bcm2835_fb: add framebuffer device for Raspberry Pi
2016-02-27 0:16 [Qemu-devel] [PATCH 0/4] Raspberry Pi framebuffer and Windows support Andrew Baumann
2016-02-27 0:16 ` [Qemu-devel] [PATCH 1/4] bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry pi Andrew Baumann
2016-02-27 0:16 ` [Qemu-devel] [PATCH 2/4] bcm2835_aux: add emulation of BCM2835 AUX (aka UART1) block Andrew Baumann
@ 2016-02-27 0:16 ` Andrew Baumann
2016-03-01 19:23 ` Peter Maydell
2016-02-27 0:16 ` [Qemu-devel] [PATCH 4/4] bcm2835_property: implement framebuffer control/configuration properties Andrew Baumann
3 siblings, 1 reply; 11+ messages in thread
From: Andrew Baumann @ 2016-02-27 0:16 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini
The framebuffer occupies the upper portion of memory (64MiB by
default), but it can only be controlled/configured via a system
mailbox or property channel (to be added by a subsequent patch).
Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---
hw/arm/bcm2835_peripherals.c | 38 +++-
hw/arm/bcm2836.c | 2 +
hw/arm/raspi.c | 12 +-
hw/display/Makefile.objs | 1 +
hw/display/bcm2835_fb.c | 421 +++++++++++++++++++++++++++++++++++
include/hw/arm/bcm2835_peripherals.h | 2 +
include/hw/display/bcm2835_fb.h | 47 ++++
7 files changed, 515 insertions(+), 8 deletions(-)
create mode 100644 hw/display/bcm2835_fb.c
create mode 100644 include/hw/display/bcm2835_fb.h
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index 103a330..eff4fa2 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -61,6 +61,16 @@ static void bcm2835_peripherals_init(Object *obj)
object_property_add_const_link(OBJECT(&s->mboxes), "mbox-mr",
OBJECT(&s->mbox_mr), &error_abort);
+ /* Framebuffer */
+ object_initialize(&s->fb, sizeof(s->fb), TYPE_BCM2835_FB);
+ object_property_add_child(obj, "fb", OBJECT(&s->fb), NULL);
+ object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size",
+ &error_abort);
+ qdev_set_parent_bus(DEVICE(&s->fb), sysbus_get_default());
+
+ object_property_add_const_link(OBJECT(&s->fb), "dma-mr",
+ OBJECT(&s->gpu_bus_mr), &error_abort);
+
/* Property channel */
object_initialize(&s->property, sizeof(s->property), TYPE_BCM2835_PROPERTY);
object_property_add_child(obj, "property", OBJECT(&s->property), NULL);
@@ -83,7 +93,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
Object *obj;
MemoryRegion *ram;
Error *err = NULL;
- uint32_t ram_size;
+ uint32_t ram_size, vcram_size;
int n;
obj = object_property_get_link(OBJECT(dev), "ram", &err);
@@ -162,6 +172,32 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ,
INTERRUPT_ARM_MAILBOX));
+ /* Framebuffer */
+ vcram_size = (uint32_t)object_property_get_int(OBJECT(s), "vcram-size",
+ &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_int(OBJECT(&s->fb), ram_size - vcram_size,
+ "vcram-base", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_bool(OBJECT(&s->fb), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ memory_region_add_subregion(&s->mbox_mr, MBOX_CHAN_FB << MBOX_AS_CHAN_SHIFT,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->fb), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->fb), 0,
+ qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB));
+
/* Property channel */
object_property_set_int(OBJECT(&s->property), ram_size, "ram-size", &err);
if (err) {
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
index 0321439..89a6b35 100644
--- a/hw/arm/bcm2836.c
+++ b/hw/arm/bcm2836.c
@@ -42,6 +42,8 @@ static void bcm2836_init(Object *obj)
&error_abort);
object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
"board-rev", &error_abort);
+ object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
+ "vcram-size", &error_abort);
qdev_set_parent_bus(DEVICE(&s->peripherals), sysbus_get_default());
}
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index 6582279..83fe809 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -113,6 +113,7 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size)
static void raspi2_init(MachineState *machine)
{
RasPiState *s = g_new0(RasPiState, 1);
+ uint32_t vcram_size;
DriveInfo *di;
BlockBackend *blk;
BusState *bus;
@@ -149,7 +150,9 @@ static void raspi2_init(MachineState *machine)
qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
- setup_boot(machine, 2, machine->ram_size);
+ vcram_size = object_property_get_int(OBJECT(&s->soc), "vcram-size",
+ &error_abort);
+ setup_boot(machine, 2, machine->ram_size - vcram_size);
}
static void raspi2_machine_init(MachineClass *mc)
@@ -161,11 +164,6 @@ static void raspi2_machine_init(MachineClass *mc)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->max_cpus = BCM2836_NCPUS;
-
- /* XXX: Temporary restriction in RAM size from the full 1GB. Since
- * we do not yet support the framebuffer / GPU, we need to limit
- * RAM usable by the OS to sit below the peripherals.
- */
- mc->default_ram_size = 0x3F000000; /* BCM2836_PERI_BASE */
+ mc->default_ram_size = 1024 * 1024 * 1024;
};
DEFINE_MACHINE("raspi2", raspi2_machine_init)
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index f0cf431..d99780e 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -27,6 +27,7 @@ endif
obj-$(CONFIG_OMAP) += omap_dss.o
obj-$(CONFIG_OMAP) += omap_lcdc.o
obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
+obj-$(CONFIG_RASPI) += bcm2835_fb.o
obj-$(CONFIG_SM501) += sm501.o
obj-$(CONFIG_TCX) += tcx.o
obj-$(CONFIG_CG3) += cg3.o
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
new file mode 100644
index 0000000..97079fb
--- /dev/null
+++ b/hw/display/bcm2835_fb.c
@@ -0,0 +1,421 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Refactoring for Pi2 Copyright (c) 2015, Microsoft. Written by Andrew Baumann.
+ * This code is licensed under the GNU GPLv2 and later.
+ *
+ * Heavily based on milkymist-vgafb.c, copyright terms below:
+ * QEMU model of the Milkymist VGA framebuffer.
+ *
+ * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/display/bcm2835_fb.h"
+#include "hw/display/framebuffer.h"
+#include "ui/pixel_ops.h"
+#include "hw/misc/bcm2835_mbox_defs.h"
+
+#define DEFAULT_VCRAM_SIZE 0x4000000
+#define BCM2835_FB_OFFSET 0x00100000
+
+static void fb_invalidate_display(void *opaque)
+{
+ BCM2835FBState *s = BCM2835_FB(opaque);
+
+ s->invalidate = true;
+}
+
+static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
+ int width, int deststep)
+{
+ BCM2835FBState *s = opaque;
+ uint16_t rgb565;
+ uint32_t rgb888;
+ uint8_t r, g, b;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ int bpp = surface_bits_per_pixel(surface);
+
+ while (width--) {
+ switch (s->bpp) {
+ case 8:
+ rgb888 = ldl_phys(&s->dma_as, s->vcram_base + (*src << 2));
+ r = (rgb888 >> 0) & 0xff;
+ g = (rgb888 >> 8) & 0xff;
+ b = (rgb888 >> 16) & 0xff;
+ src++;
+ break;
+ case 16:
+ rgb565 = lduw_p(src);
+ r = ((rgb565 >> 11) & 0x1f) << 3;
+ g = ((rgb565 >> 5) & 0x3f) << 2;
+ b = ((rgb565 >> 0) & 0x1f) << 3;
+ src += 2;
+ break;
+ case 24:
+ rgb888 = ldl_p(src);
+ r = (rgb888 >> 0) & 0xff;
+ g = (rgb888 >> 8) & 0xff;
+ b = (rgb888 >> 16) & 0xff;
+ src += 3;
+ break;
+ case 32:
+ rgb888 = ldl_p(src);
+ r = (rgb888 >> 0) & 0xff;
+ g = (rgb888 >> 8) & 0xff;
+ b = (rgb888 >> 16) & 0xff;
+ src += 4;
+ break;
+ default:
+ r = 0;
+ g = 0;
+ b = 0;
+ break;
+ }
+
+ if (s->pixo == 0) {
+ /* swap to BGR pixel format */
+ uint8_t tmp = r;
+ r = b;
+ b = tmp;
+ }
+
+ switch (bpp) {
+ case 8:
+ *dst++ = rgb_to_pixel8(r, g, b);
+ break;
+ case 15:
+ *(uint16_t *)dst = rgb_to_pixel15(r, g, b);
+ dst += 2;
+ break;
+ case 16:
+ *(uint16_t *)dst = rgb_to_pixel16(r, g, b);
+ dst += 2;
+ break;
+ case 24:
+ rgb888 = rgb_to_pixel24(r, g, b);
+ *dst++ = rgb888 & 0xff;
+ *dst++ = (rgb888 >> 8) & 0xff;
+ *dst++ = (rgb888 >> 16) & 0xff;
+ break;
+ case 32:
+ *(uint32_t *)dst = rgb_to_pixel32(r, g, b);
+ dst += 4;
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+static void fb_update_display(void *opaque)
+{
+ BCM2835FBState *s = opaque;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ int first = 0;
+ int last = 0;
+ int src_width = 0;
+ int dest_width = 0;
+
+ if (s->lock || !s->xres) {
+ return;
+ }
+
+ src_width = s->xres * (s->bpp >> 3);
+ dest_width = s->xres;
+
+ switch (surface_bits_per_pixel(surface)) {
+ case 0:
+ return;
+ case 8:
+ break;
+ case 15:
+ dest_width *= 2;
+ break;
+ case 16:
+ dest_width *= 2;
+ break;
+ case 24:
+ dest_width *= 3;
+ break;
+ case 32:
+ dest_width *= 4;
+ break;
+ default:
+ hw_error("bcm2835_fb: bad color depth\n");
+ break;
+ }
+
+ if (s->invalidate) {
+ framebuffer_update_memory_section(&s->fbsection, s->dma_mr, s->base,
+ s->yres, src_width);
+ }
+
+ framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
+ src_width, dest_width, 0, s->invalidate,
+ draw_line_src16, s, &first, &last);
+
+ if (first >= 0) {
+ dpy_gfx_update(s->con, 0, first, s->xres, last - first + 1);
+ }
+
+ s->invalidate = false;
+}
+
+static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
+{
+ value &= ~0xf;
+
+ s->lock = true;
+
+ s->xres = ldl_phys(&s->dma_as, value);
+ s->yres = ldl_phys(&s->dma_as, value + 4);
+ s->xres_virtual = ldl_phys(&s->dma_as, value + 8);
+ s->yres_virtual = ldl_phys(&s->dma_as, value + 12);
+ s->bpp = ldl_phys(&s->dma_as, value + 20);
+ s->xoffset = ldl_phys(&s->dma_as, value + 24);
+ s->yoffset = ldl_phys(&s->dma_as, value + 28);
+
+ s->base = s->vcram_base | (value & 0xc0000000);
+ s->base += BCM2835_FB_OFFSET;
+
+ /* TODO - Manage properly virtual resolution */
+
+ s->pitch = s->xres * (s->bpp >> 3);
+ s->size = s->yres * s->pitch;
+
+ stl_phys(&s->dma_as, value + 16, s->pitch);
+ stl_phys(&s->dma_as, value + 32, s->base);
+ stl_phys(&s->dma_as, value + 36, s->size);
+
+ s->invalidate = true;
+ qemu_console_resize(s->con, s->xres, s->yres);
+ s->lock = false;
+}
+
+void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
+ uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp,
+ uint32_t *pixo, uint32_t *alpha)
+{
+ s->lock = true;
+
+ /* TODO: input validation! */
+ if (xres) {
+ s->xres = *xres;
+ }
+ if (yres) {
+ s->yres = *yres;
+ }
+ if (xoffset) {
+ s->xoffset = *xoffset;
+ }
+ if (yoffset) {
+ s->yoffset = *yoffset;
+ }
+ if (bpp) {
+ s->bpp = *bpp;
+ }
+ if (pixo) {
+ s->pixo = *pixo;
+ }
+ if (alpha) {
+ s->alpha = *alpha;
+ }
+
+ /* TODO - Manage properly virtual resolution */
+
+ s->pitch = s->xres * (s->bpp >> 3);
+ s->size = s->yres * s->pitch;
+
+ s->invalidate = true;
+ qemu_console_resize(s->con, s->xres, s->yres);
+ s->lock = false;
+}
+
+static uint64_t bcm2835_fb_read(void *opaque, hwaddr offset, unsigned size)
+{
+ BCM2835FBState *s = opaque;
+ uint32_t res = 0;
+
+ switch (offset) {
+ case MBOX_AS_DATA:
+ res = MBOX_CHAN_FB;
+ s->pending = false;
+ qemu_set_irq(s->mbox_irq, 0);
+ break;
+
+ case MBOX_AS_PENDING:
+ res = s->pending;
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ __func__, offset);
+ return 0;
+ }
+
+ return res;
+}
+
+static void bcm2835_fb_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ BCM2835FBState *s = opaque;
+
+ switch (offset) {
+ case MBOX_AS_DATA:
+ /* bcm2835_mbox should check our pending status before pushing */
+ assert(!s->pending);
+ s->pending = true;
+ bcm2835_fb_mbox_push(s, value);
+ qemu_set_irq(s->mbox_irq, 1);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
+ __func__, offset);
+ return;
+ }
+}
+
+static const MemoryRegionOps bcm2835_fb_ops = {
+ .read = bcm2835_fb_read,
+ .write = bcm2835_fb_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
+static const VMStateDescription vmstate_bcm2835_fb = {
+ .name = TYPE_BCM2835_FB,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(lock, BCM2835FBState),
+ VMSTATE_BOOL(invalidate, BCM2835FBState),
+ VMSTATE_BOOL(pending, BCM2835FBState),
+ VMSTATE_UINT32(xres, BCM2835FBState),
+ VMSTATE_UINT32(yres, BCM2835FBState),
+ VMSTATE_UINT32(xres_virtual, BCM2835FBState),
+ VMSTATE_UINT32(yres_virtual, BCM2835FBState),
+ VMSTATE_UINT32(xoffset, BCM2835FBState),
+ VMSTATE_UINT32(yoffset, BCM2835FBState),
+ VMSTATE_UINT32(bpp, BCM2835FBState),
+ VMSTATE_UINT32(base, BCM2835FBState),
+ VMSTATE_UINT32(pitch, BCM2835FBState),
+ VMSTATE_UINT32(size, BCM2835FBState),
+ VMSTATE_UINT32(pixo, BCM2835FBState),
+ VMSTATE_UINT32(alpha, BCM2835FBState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const GraphicHwOps vgafb_ops = {
+ .invalidate = fb_invalidate_display,
+ .gfx_update = fb_update_display,
+};
+
+static void bcm2835_fb_init(Object *obj)
+{
+ BCM2835FBState *s = BCM2835_FB(obj);
+
+ memory_region_init_io(&s->iomem, obj, &bcm2835_fb_ops, s, TYPE_BCM2835_FB,
+ 0x10);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+ sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq);
+}
+
+static void bcm2835_fb_reset(DeviceState *dev)
+{
+ BCM2835FBState *s = BCM2835_FB(dev);
+
+ s->pending = false;
+
+ s->xres_virtual = s->xres;
+ s->yres_virtual = s->yres;
+ s->xoffset = 0;
+ s->yoffset = 0;
+ s->base = s->vcram_base + BCM2835_FB_OFFSET;
+ s->pitch = s->xres * (s->bpp >> 3);
+ s->size = s->yres * s->pitch;
+
+ s->invalidate = true;
+ s->lock = false;
+}
+
+static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
+{
+ BCM2835FBState *s = BCM2835_FB(dev);
+ Error *err = NULL;
+ Object *obj;
+
+ if (s->vcram_base == 0) {
+ error_setg(errp, "%s: required vcram-base property not set", __func__);
+ return;
+ }
+
+ obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
+ if (obj == NULL) {
+ error_setg(errp, "%s: required dma-mr link not found: %s",
+ __func__, error_get_pretty(err));
+ return;
+ }
+
+ s->dma_mr = MEMORY_REGION(obj);
+ address_space_init(&s->dma_as, s->dma_mr, NULL);
+
+ bcm2835_fb_reset(dev);
+
+ s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
+ qemu_console_resize(s->con, s->xres, s->yres);
+}
+
+static Property bcm2835_fb_props[] = {
+ DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/
+ DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size,
+ DEFAULT_VCRAM_SIZE),
+ DEFINE_PROP_UINT32("xres", BCM2835FBState, xres, 640),
+ DEFINE_PROP_UINT32("yres", BCM2835FBState, yres, 480),
+ DEFINE_PROP_UINT32("bpp", BCM2835FBState, bpp, 16),
+ DEFINE_PROP_UINT32("pixo", BCM2835FBState, pixo, 1), /* 1=RGB, 0=BGR */
+ DEFINE_PROP_UINT32("alpha", BCM2835FBState, alpha, 2), /* alpha ignored */
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void bcm2835_fb_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = bcm2835_fb_props;
+ dc->realize = bcm2835_fb_realize;
+ dc->reset = bcm2835_fb_reset;
+ dc->vmsd = &vmstate_bcm2835_fb;
+}
+
+static TypeInfo bcm2835_fb_info = {
+ .name = TYPE_BCM2835_FB,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BCM2835FBState),
+ .class_init = bcm2835_fb_class_init,
+ .instance_init = bcm2835_fb_init,
+};
+
+static void bcm2835_fb_register_types(void)
+{
+ type_register_static(&bcm2835_fb_info);
+}
+
+type_init(bcm2835_fb_register_types)
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
index 889adf5..e19d360 100644
--- a/include/hw/arm/bcm2835_peripherals.h
+++ b/include/hw/arm/bcm2835_peripherals.h
@@ -15,6 +15,7 @@
#include "exec/address-spaces.h"
#include "hw/sysbus.h"
#include "hw/char/bcm2835_aux.h"
+#include "hw/display/bcm2835_fb.h"
#include "hw/intc/bcm2835_ic.h"
#include "hw/misc/bcm2835_property.h"
#include "hw/misc/bcm2835_mbox.h"
@@ -35,6 +36,7 @@ typedef struct BCM2835PeripheralState {
SysBusDevice *uart0;
BCM2835AuxState aux;
+ BCM2835FBState fb;
BCM2835ICState ic;
BCM2835PropertyState property;
BCM2835MboxState mboxes;
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
new file mode 100644
index 0000000..9a12d7a
--- /dev/null
+++ b/include/hw/display/bcm2835_fb.h
@@ -0,0 +1,47 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous
+ *
+ * Rasperry Pi 2 emulation and refactoring Copyright (c) 2015, Microsoft
+ * Written by Andrew Baumann
+ *
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2835_FB_H
+#define BCM2835_FB_H
+
+#include "hw/sysbus.h"
+#include "exec/address-spaces.h"
+#include "ui/console.h"
+
+#define TYPE_BCM2835_FB "bcm2835-fb"
+#define BCM2835_FB(obj) OBJECT_CHECK(BCM2835FBState, (obj), TYPE_BCM2835_FB)
+
+typedef struct {
+ /*< private >*/
+ SysBusDevice busdev;
+ /*< public >*/
+
+ uint32_t vcram_base, vcram_size;
+ MemoryRegion *dma_mr;
+ AddressSpace dma_as;
+ MemoryRegion iomem;
+ MemoryRegionSection fbsection;
+ QemuConsole *con;
+ qemu_irq mbox_irq;
+
+ bool lock, invalidate, pending;
+ uint32_t xres, yres;
+ uint32_t xres_virtual, yres_virtual;
+ uint32_t xoffset, yoffset;
+ uint32_t bpp;
+ uint32_t base, pitch, size;
+ uint32_t pixo, alpha;
+} BCM2835FBState;
+
+void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
+ uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp,
+ uint32_t *pixo, uint32_t *alpha);
+
+#endif
--
2.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 4/4] bcm2835_property: implement framebuffer control/configuration properties
2016-02-27 0:16 [Qemu-devel] [PATCH 0/4] Raspberry Pi framebuffer and Windows support Andrew Baumann
` (2 preceding siblings ...)
2016-02-27 0:16 ` [Qemu-devel] [PATCH 3/4] bcm2835_fb: add framebuffer device for Raspberry Pi Andrew Baumann
@ 2016-02-27 0:16 ` Andrew Baumann
2016-03-01 19:26 ` Peter Maydell
3 siblings, 1 reply; 11+ messages in thread
From: Andrew Baumann @ 2016-02-27 0:16 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Grégory ESTRADE, Stefan Weil,
Peter Crosthwaite, Andrew Baumann, qemu-arm, Paolo Bonzini
The property channel driver now interfaces with the framebuffer device
to query and set framebuffer parameters. As a result of this, the "get
ARM RAM size" query now correctly returns the video RAM base address
(not total RAM size), and the ram-size property is no longer relevant
here.
Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
---
hw/arm/bcm2835_peripherals.c | 8 +--
hw/misc/bcm2835_property.c | 139 ++++++++++++++++++++++++++++++++++++-
include/hw/misc/bcm2835_property.h | 5 +-
3 files changed, 143 insertions(+), 9 deletions(-)
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index eff4fa2..c2b812a 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -78,6 +78,8 @@ static void bcm2835_peripherals_init(Object *obj)
"board-rev", &error_abort);
qdev_set_parent_bus(DEVICE(&s->property), sysbus_get_default());
+ object_property_add_const_link(OBJECT(&s->property), "fb",
+ OBJECT(&s->fb), &error_abort);
object_property_add_const_link(OBJECT(&s->property), "dma-mr",
OBJECT(&s->gpu_bus_mr), &error_abort);
@@ -199,12 +201,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_FB));
/* Property channel */
- object_property_set_int(OBJECT(&s->property), ram_size, "ram-size", &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
object_property_set_bool(OBJECT(&s->property), true, "realized", &err);
if (err) {
error_propagate(errp, err);
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
index 581922a..8bffad9 100644
--- a/hw/misc/bcm2835_property.c
+++ b/hw/misc/bcm2835_property.c
@@ -17,6 +17,11 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
uint32_t tot_len;
size_t resplen;
uint32_t tmp;
+ int n;
+ uint32_t offset, length, color;
+ uint32_t xres, yres, xoffset, yoffset, bpp, pixo, alpha;
+ uint32_t *newxres = NULL, *newyres = NULL, *newxoffset = NULL,
+ *newyoffset = NULL, *newbpp = NULL, *newpixo = NULL, *newalpha = NULL;
value &= ~0xf;
@@ -60,7 +65,14 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
/* base */
stl_phys(&s->dma_as, value + 12, 0);
/* size */
- stl_phys(&s->dma_as, value + 16, s->ram_size);
+ stl_phys(&s->dma_as, value + 16, s->fbdev->vcram_base);
+ resplen = 8;
+ break;
+ case 0x00010006: /* Get VC memory */
+ /* base */
+ stl_phys(&s->dma_as, value + 12, s->fbdev->vcram_base);
+ /* size */
+ stl_phys(&s->dma_as, value + 16, s->fbdev->vcram_size);
resplen = 8;
break;
case 0x00028001: /* Set power state */
@@ -122,6 +134,114 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
resplen = 8;
break;
+ /* Frame buffer */
+
+ case 0x00040001: /* Allocate buffer */
+ stl_phys(&s->dma_as, value + 12, s->fbdev->base);
+ stl_phys(&s->dma_as, value + 16, s->fbdev->size);
+ resplen = 8;
+ break;
+ case 0x00048001: /* Release buffer */
+ resplen = 0;
+ break;
+ case 0x00040002: /* Blank screen */
+ resplen = 4;
+ break;
+ case 0x00040003: /* Get display width/height */
+ case 0x00040004:
+ stl_phys(&s->dma_as, value + 12, s->fbdev->xres);
+ stl_phys(&s->dma_as, value + 16, s->fbdev->yres);
+ resplen = 8;
+ break;
+ case 0x00044003: /* Test display width/height */
+ case 0x00044004:
+ resplen = 8;
+ break;
+ case 0x00048003: /* Set display width/height */
+ case 0x00048004:
+ xres = ldl_phys(&s->dma_as, value + 12);
+ newxres = &xres;
+ yres = ldl_phys(&s->dma_as, value + 16);
+ newyres = &yres;
+ resplen = 8;
+ break;
+ case 0x00040005: /* Get depth */
+ stl_phys(&s->dma_as, value + 12, s->fbdev->bpp);
+ resplen = 4;
+ break;
+ case 0x00044005: /* Test depth */
+ resplen = 4;
+ break;
+ case 0x00048005: /* Set depth */
+ bpp = ldl_phys(&s->dma_as, value + 12);
+ newbpp = &bpp;
+ resplen = 4;
+ break;
+ case 0x00040006: /* Get pixel order */
+ stl_phys(&s->dma_as, value + 12, s->fbdev->pixo);
+ resplen = 4;
+ break;
+ case 0x00044006: /* Test pixel order */
+ resplen = 4;
+ break;
+ case 0x00048006: /* Set pixel order */
+ pixo = ldl_phys(&s->dma_as, value + 12);
+ newpixo = &pixo;
+ resplen = 4;
+ break;
+ case 0x00040007: /* Get alpha */
+ stl_phys(&s->dma_as, value + 12, s->fbdev->alpha);
+ resplen = 4;
+ break;
+ case 0x00044007: /* Test pixel alpha */
+ resplen = 4;
+ break;
+ case 0x00048007: /* Set alpha */
+ alpha = ldl_phys(&s->dma_as, value + 12);
+ newalpha = α
+ resplen = 4;
+ break;
+ case 0x00040008: /* Get pitch */
+ stl_phys(&s->dma_as, value + 12, s->fbdev->pitch);
+ resplen = 4;
+ break;
+ case 0x00040009: /* Get virtual offset */
+ stl_phys(&s->dma_as, value + 12, s->fbdev->xoffset);
+ stl_phys(&s->dma_as, value + 16, s->fbdev->yoffset);
+ resplen = 8;
+ break;
+ case 0x00044009: /* Test virtual offset */
+ resplen = 8;
+ break;
+ case 0x00048009: /* Set virtual offset */
+ xoffset = ldl_phys(&s->dma_as, value + 12);
+ newxoffset = &xoffset;
+ yoffset = ldl_phys(&s->dma_as, value + 16);
+ newyoffset = &yoffset;
+ resplen = 8;
+ break;
+ case 0x0004000a: /* Get/Test/Set overscan */
+ case 0x0004400a:
+ case 0x0004800a:
+ stl_phys(&s->dma_as, value + 12, 0);
+ stl_phys(&s->dma_as, value + 16, 0);
+ stl_phys(&s->dma_as, value + 20, 0);
+ stl_phys(&s->dma_as, value + 24, 0);
+ resplen = 16;
+ break;
+ case 0x0004800b: /* Set palette */
+ offset = ldl_phys(&s->dma_as, value + 12);
+ length = ldl_phys(&s->dma_as, value + 16);
+ n = 0;
+ while (n < length - offset) {
+ color = ldl_phys(&s->dma_as, value + 20 + (n << 2));
+ stl_phys(&s->dma_as,
+ s->fbdev->vcram_base + ((offset + n) << 2), color);
+ n++;
+ }
+ stl_phys(&s->dma_as, value + 12, 0);
+ resplen = 4;
+ break;
case 0x00060001: /* Get DMA channels */
/* channels 2-5 */
@@ -147,6 +267,13 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
value += bufsize + 12;
}
+ /* Reconfigure framebuffer if required */
+ if (newxres || newyres || newxoffset || newyoffset || newbpp || newpixo
+ || newalpha) {
+ bcm2835_fb_reconfigure(s->fbdev, newxres, newyres, newxoffset,
+ newyoffset, newbpp, newpixo, newalpha);
+ }
+
/* Buffer response code */
stl_phys(&s->dma_as, s->addr + 4, (1 << 31));
}
@@ -241,6 +368,15 @@ static void bcm2835_property_realize(DeviceState *dev, Error **errp)
Object *obj;
Error *err = NULL;
+ obj = object_property_get_link(OBJECT(dev), "fb", &err);
+ if (obj == NULL) {
+ error_setg(errp, "%s: required fb link not found: %s",
+ __func__, error_get_pretty(err));
+ return;
+ }
+
+ s->fbdev = BCM2835_FB(obj);
+
obj = object_property_get_link(OBJECT(dev), "dma-mr", &err);
if (obj == NULL) {
error_setg(errp, "%s: required dma-mr link not found: %s",
@@ -259,7 +395,6 @@ static void bcm2835_property_realize(DeviceState *dev, Error **errp)
static Property bcm2835_property_props[] = {
DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0),
- DEFINE_PROP_UINT32("ram-size", BCM2835PropertyState, ram_size, 0),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/include/hw/misc/bcm2835_property.h b/include/hw/misc/bcm2835_property.h
index df889ea..edcab60 100644
--- a/include/hw/misc/bcm2835_property.h
+++ b/include/hw/misc/bcm2835_property.h
@@ -9,6 +9,7 @@
#include "hw/sysbus.h"
#include "exec/address-spaces.h"
#include "net/net.h"
+#include "hw/display/bcm2835_fb.h"
#define TYPE_BCM2835_PROPERTY "bcm2835-property"
#define BCM2835_PROPERTY(obj) \
@@ -18,13 +19,15 @@ typedef struct {
/*< private >*/
SysBusDevice busdev;
/*< public >*/
+
MemoryRegion *dma_mr;
AddressSpace dma_as;
MemoryRegion iomem;
qemu_irq mbox_irq;
+ BCM2835FBState *fbdev;
+
MACAddr macaddr;
uint32_t board_rev;
- uint32_t ram_size;
uint32_t addr;
bool pending;
} BCM2835PropertyState;
--
2.5.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 1/4] bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry pi
2016-02-27 0:16 ` [Qemu-devel] [PATCH 1/4] bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry pi Andrew Baumann
@ 2016-03-01 18:21 ` Peter Maydell
0 siblings, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2016-03-01 18:21 UTC (permalink / raw)
To: Andrew Baumann
Cc: Grégory ESTRADE, Stefan Weil, Peter Crosthwaite,
QEMU Developers, qemu-arm, Paolo Bonzini
On 27 February 2016 at 00:16, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
> hw/arm/bcm2835_peripherals.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
> index 6d66fa0..6ce9cd1 100644
> --- a/hw/arm/bcm2835_peripherals.c
> +++ b/hw/arm/bcm2835_peripherals.c
> @@ -171,6 +171,13 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
> return;
> }
>
> + object_property_set_bool(OBJECT(&s->sdhci), true, "pending-insert-quirk",
> + &err);
> + if (err) {
> + error_propagate(errp, err);
> + return;
> + }
> +
> object_property_set_bool(OBJECT(&s->sdhci), true, "realized", &err);
> if (err) {
> error_propagate(errp, err);
> --
> 2.5.3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 2/4] bcm2835_aux: add emulation of BCM2835 AUX (aka UART1) block
2016-02-27 0:16 ` [Qemu-devel] [PATCH 2/4] bcm2835_aux: add emulation of BCM2835 AUX (aka UART1) block Andrew Baumann
@ 2016-03-01 19:03 ` Peter Maydell
0 siblings, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2016-03-01 19:03 UTC (permalink / raw)
To: Andrew Baumann
Cc: Grégory ESTRADE, Stefan Weil, Peter Crosthwaite,
QEMU Developers, qemu-arm, Paolo Bonzini
On 27 February 2016 at 00:16, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
This bit of the commit message is a good place to list the
"not yet implemented" parts of the device.
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
> ---
> +/*
> + * BCM2835 (Raspberry Pi / Pi 2) Aux block (mini UART and SPI).
> + * Copyright (c) 2015, Microsoft
> + * Written by Andrew Baumann
> + * Based on pl011.c, copyright terms below:
> + *
> + * Arm PrimeCell PL011 UART
> + *
> + * Copyright (c) 2006 CodeSourcery.
> + * Written by Paul Brook
> + *
> + * This code is licensed under the GPL.
> + */
>
I'm looking at the documentation at
https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf
for my review...
You should say in a comment that only the UART parts are
currently implemented.
> +#include "qemu/osdep.h"
> +#include "hw/char/bcm2835_aux.h"
> +
> +#define AUX_ENABLES 0x4
> +#define AUX_MU_IO_REG 0x40
> +#define AUX_MU_IER_REG 0x44
> +#define AUX_MU_IIR_REG 0x48
> +#define AUX_MU_LSR_REG 0x54
> +#define AUX_MU_STAT_REG 0x64
> +
> +static void bcm2835_aux_update(BCM2835AuxState *s)
> +{
> + bool status = (s->rx_int_enable && s->read_count != 0) || s->tx_int_enable;
> + qemu_set_irq(s->irq, status);
Could use a comment somewhere to the effect that since we model the
tx fifo as instantly-draining the 'tx fifo register empty' interrupt
is always asserted.
> +}
> +
> +static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
> +{
> + BCM2835AuxState *s = opaque;
> + uint32_t c, res;
> +
> + switch (offset) {
No AUX_IRQ implementation? (You need the current interrupt
status anyway for one of the other register bits.)
> + case AUX_ENABLES:
> + return 1; /* mini UART enabled */
> +
> + case AUX_MU_IO_REG:
> + c = s->read_fifo[s->read_pos];
The datasheet says this is a byte UART but you've implemented
the read_fifo and c as 32-bit.
> + if (s->read_count > 0) {
> + s->read_count--;
> + if (++s->read_pos == 8) {
> + s->read_pos = 0;
> + }
> + }
> + if (s->chr) {
> + qemu_chr_accept_input(s->chr);
> + }
> + bcm2835_aux_update(s);
This doesn't implement the "if line control DLAB bit is set, then read/write
the LS 8 bits of the baudrate register" behaviour described in the datasheet.
> + return c;
> +
> + case AUX_MU_IER_REG:
> + res = 0;
> + if (s->rx_int_enable) {
> + res |= 0x2;
> + }
> + if (s->tx_int_enable) {
> + res |= 0x1;
> + }
I suspect you'll find the code is clearer generally if you model this
register with a uint8_t ier in the state structure rather than two bools
(for instance "is interrupt asserted" is generally "enables | status".)
Doesn't implement "DLAB bit set means access MS 8 bits of the baudrate
register".
> + return res;
> +
> + case AUX_MU_IIR_REG:
> + res = 0xc0;
> + if (s->tx_int_enable) {
> + res |= 0x1;
> + } else if (s->rx_int_enable && s->read_count != 0) {
> + res |= 0x2;
> + }
This is kind of repeating the logic in bcm2835_aux_update(), would
be nice to factor it out.
The data sheet says that the bit allocation here is different:
bit 0 is zero when an interrupt is pending, and bits 1 and 2 are
the read and write information.
The data sheet also says that 0b11 for bits [2:1] is not possible, though
it doesn't say why. It's not clear what the hardware reads as if
the transmit holding register is empty *and* the receiver has a
valid byte...
> + return res;
> +
> + case AUX_MU_LSR_REG:
> + res = 0x60; /* tx idle, empty */
> + if (s->read_count != 0) {
> + res |= 0x1;
> + }
> + return res;
> +
> + case AUX_MU_STAT_REG:
> + res = 0x302; /* space in the output buffer, empty tx fifo */
Shouldn't we set the "transmitter idle" bit too?
> + if (s->read_count > 0) {
> + res |= 0x1; /* data in input buffer */
> + assert(s->read_count < 8);
> + res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */
> + }
> + return res;
> +
No AUX_MU_LCR_REG ? No AUX_MU_MCR_REG ? No AUX_MU_MSR_REG ?
AUX_MU_SCRATCH ? AUX_MU_CNTL_REG ? AUX_MU_BAUD ?
At least implementing them to log unimplemented would be nice.
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
> + __func__, offset);
> + return 0;
> + }
> +}
> +
> +static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
> + unsigned size)
> +{
> + BCM2835AuxState *s = opaque;
> + unsigned char ch;
> +
> + switch (offset) {
> + case AUX_ENABLES:
> + if (value != 1) {
> + qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI "
> + "or disable UART\n", __func__);
> + }
> + break;
> +
> + case AUX_MU_IO_REG:
> + ch = value;
> + if (s->chr) {
> + qemu_chr_fe_write(s->chr, &ch, 1);
> + }
> + break;
> +
> + case AUX_MU_IER_REG:
> + s->rx_int_enable = (value & 0x2) != 0;
> + s->tx_int_enable = (value & 0x1) != 0;
> + break;
> +
> + case AUX_MU_IIR_REG:
> + if (value & 0x1) {
> + s->read_count = 0;
> + }
Datasheet says bit 0 is read only, bit 1 clears the rx fifo.
> + break;
> +
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
> + __func__, offset);
> + }
> +
> + bcm2835_aux_update(s);
> +}
> +
> +static int bcm2835_aux_can_receive(void *opaque)
> +{
> + BCM2835AuxState *s = opaque;
> +
> + return s->read_count < 8;
> +}
> +
> +static void bcm2835_aux_put_fifo(void *opaque, uint32_t value)
> +{
> + BCM2835AuxState *s = opaque;
> + int slot;
> +
> + slot = s->read_pos + s->read_count;
> + if (slot >= 8) {
> + slot -= 8;
> + }
> + s->read_fifo[slot] = value;
> + s->read_count++;
> + if (s->read_count == 8) {
> + /* buffer full */
> + }
> + bcm2835_aux_update(s);
> +}
> +
> +static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size)
> +{
> + bcm2835_aux_put_fifo(opaque, *buf);
> +}
> +
> +static void bcm2835_aux_event(void *opaque, int event)
> +{
> + if (event == CHR_EVENT_BREAK) {
> + bcm2835_aux_put_fifo(opaque, 0x400);
> + }
Data sheet says the UART does not have break detection.
> +}
> +
> +static const MemoryRegionOps bcm2835_aux_ops = {
> + .read = bcm2835_aux_read,
> + .write = bcm2835_aux_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> + .valid.min_access_size = 4,
> + .valid.max_access_size = 4,
> +};
> +
> +static const VMStateDescription vmstate_bcm2835_aux = {
> + .name = TYPE_BCM2835_AUX,
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32_ARRAY(read_fifo, BCM2835AuxState, 8),
> + VMSTATE_UINT8(read_pos, BCM2835AuxState),
> + VMSTATE_UINT8(read_count, BCM2835AuxState),
> + VMSTATE_BOOL(rx_int_enable, BCM2835AuxState),
> + VMSTATE_BOOL(tx_int_enable, BCM2835AuxState),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void bcm2835_aux_init(Object *obj)
> +{
> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> + BCM2835AuxState *s = BCM2835_AUX(obj);
> +
> + memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_aux_ops, s,
> + TYPE_BCM2835_AUX, 0x100);
> + sysbus_init_mmio(sbd, &s->iomem);
> + sysbus_init_irq(sbd, &s->irq);
> +}
> +
> +static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
> +{
> + BCM2835AuxState *s = BCM2835_AUX(dev);
> + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */
Good idea :-) imx_serial.c has an example, you use
DEFINE_PROP_CHR and then wire it up in the board construction with
qdev_prop_set_chr(). (You probably want to create an alias property on
the SoC object as we now do for spi etc; see the xilinx soc for
an example.)
> + s->chr = qemu_char_get_next_serial();
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 3/4] bcm2835_fb: add framebuffer device for Raspberry Pi
2016-02-27 0:16 ` [Qemu-devel] [PATCH 3/4] bcm2835_fb: add framebuffer device for Raspberry Pi Andrew Baumann
@ 2016-03-01 19:23 ` Peter Maydell
2016-03-02 0:19 ` Andrew Baumann
0 siblings, 1 reply; 11+ messages in thread
From: Peter Maydell @ 2016-03-01 19:23 UTC (permalink / raw)
To: Andrew Baumann
Cc: Grégory ESTRADE, Stefan Weil, Peter Crosthwaite,
QEMU Developers, qemu-arm, Paolo Bonzini
On 27 February 2016 at 00:16, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> The framebuffer occupies the upper portion of memory (64MiB by
> default), but it can only be controlled/configured via a system
> mailbox or property channel (to be added by a subsequent patch).
>
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
Mostly looks ok, but a couple of points:
> +static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
> + int width, int deststep)
> +{
> + BCM2835FBState *s = opaque;
> + uint16_t rgb565;
> + uint32_t rgb888;
> + uint8_t r, g, b;
> + DisplaySurface *surface = qemu_console_surface(s->con);
> + int bpp = surface_bits_per_pixel(surface);
> +
> + while (width--) {
> + switch (s->bpp) {
> + case 8:
> + rgb888 = ldl_phys(&s->dma_as, s->vcram_base + (*src << 2));
Don't use ldl_phys() in device model code, please. It means "do
a load with the endianness of the CPU's bus", and generally
device behaviour doesn't depend on the what the CPU happens to
be doing. If you do a grep for 'ld[a-z]*_phys' in hw/ you'll find
that (apart from a few spurious matches) the only things doing this
are some bcm2835 code that you should fix and the spapr hypercall
device (which really is legitimately cpu-behaviour-dependent).
You need to determine what endianness the device uses to do
its DMA accesses, and use either ldl_le_phys() or ldl_be_phys()
as appropriate. (Or address_space_ldl_le/be if you care about
memory attributes.)
More interestingly, why can't you just read from the source
pointer you're passed in here? The framebuffer_update_display()
code should have obtained it by looking up the location of the
host RAM where the guest video RAM is, so if you ignore it and
do a complete physical-address-to-memory-region lookup for every
pixel it's going to make redraws unnecessarily slow.
> + r = (rgb888 >> 0) & 0xff;
> + g = (rgb888 >> 8) & 0xff;
> + b = (rgb888 >> 16) & 0xff;
> + src++;
> + break;
> + case 16:
> + rgb565 = lduw_p(src);
> + r = ((rgb565 >> 11) & 0x1f) << 3;
> + g = ((rgb565 >> 5) & 0x3f) << 2;
> + b = ((rgb565 >> 0) & 0x1f) << 3;
> + src += 2;
> + break;
> + case 24:
> + rgb888 = ldl_p(src);
> + r = (rgb888 >> 0) & 0xff;
> + g = (rgb888 >> 8) & 0xff;
> + b = (rgb888 >> 16) & 0xff;
> + src += 3;
> + break;
> + case 32:
> + rgb888 = ldl_p(src);
> + r = (rgb888 >> 0) & 0xff;
> + g = (rgb888 >> 8) & 0xff;
> + b = (rgb888 >> 16) & 0xff;
> + src += 4;
> + break;
> + default:
> + r = 0;
> + g = 0;
> + b = 0;
> + break;
> +static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
> +{
> + value &= ~0xf;
> +
> + s->lock = true;
> +
> + s->xres = ldl_phys(&s->dma_as, value);
> + s->yres = ldl_phys(&s->dma_as, value + 4);
> + s->xres_virtual = ldl_phys(&s->dma_as, value + 8);
> + s->yres_virtual = ldl_phys(&s->dma_as, value + 12);
> + s->bpp = ldl_phys(&s->dma_as, value + 20);
> + s->xoffset = ldl_phys(&s->dma_as, value + 24);
> + s->yoffset = ldl_phys(&s->dma_as, value + 28);
> +
> + s->base = s->vcram_base | (value & 0xc0000000);
> + s->base += BCM2835_FB_OFFSET;
> +
> + /* TODO - Manage properly virtual resolution */
> +
> + s->pitch = s->xres * (s->bpp >> 3);
> + s->size = s->yres * s->pitch;
> +
> + stl_phys(&s->dma_as, value + 16, s->pitch);
> + stl_phys(&s->dma_as, value + 32, s->base);
> + stl_phys(&s->dma_as, value + 36, s->size);
These should all be specifying which endianness to write
explicitly too.
> +
> + s->invalidate = true;
> + qemu_console_resize(s->con, s->xres, s->yres);
> + s->lock = false;
> +}
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 4/4] bcm2835_property: implement framebuffer control/configuration properties
2016-02-27 0:16 ` [Qemu-devel] [PATCH 4/4] bcm2835_property: implement framebuffer control/configuration properties Andrew Baumann
@ 2016-03-01 19:26 ` Peter Maydell
0 siblings, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2016-03-01 19:26 UTC (permalink / raw)
To: Andrew Baumann
Cc: Grégory ESTRADE, Stefan Weil, Peter Crosthwaite,
QEMU Developers, qemu-arm, Paolo Bonzini
On 27 February 2016 at 00:16, Andrew Baumann
<Andrew.Baumann@microsoft.com> wrote:
> The property channel driver now interfaces with the framebuffer device
> to query and set framebuffer parameters. As a result of this, the "get
> ARM RAM size" query now correctly returns the video RAM base address
> (not total RAM size), and the ram-size property is no longer relevant
> here.
>
> Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
This should all be specifying endianness of loads explicitly too,
but otherwise looks OK.
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 3/4] bcm2835_fb: add framebuffer device for Raspberry Pi
2016-03-01 19:23 ` Peter Maydell
@ 2016-03-02 0:19 ` Andrew Baumann
2016-03-02 12:33 ` Peter Maydell
0 siblings, 1 reply; 11+ messages in thread
From: Andrew Baumann @ 2016-03-02 0:19 UTC (permalink / raw)
To: Peter Maydell
Cc: Grégory ESTRADE, Stefan Weil, Peter Crosthwaite,
QEMU Developers, qemu-arm, Paolo Bonzini
> From: Peter Maydell [mailto:peter.maydell@linaro.org]
> Sent: Tuesday, 1 March 2016 11:23 AM
>
> On 27 February 2016 at 00:16, Andrew Baumann
> <Andrew.Baumann@microsoft.com> wrote:
> > The framebuffer occupies the upper portion of memory (64MiB by
> > default), but it can only be controlled/configured via a system
> > mailbox or property channel (to be added by a subsequent patch).
> >
> > Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
>
> Mostly looks ok, but a couple of points:
>
> > +static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t
> *src,
> > + int width, int deststep)
> > +{
> > + BCM2835FBState *s = opaque;
> > + uint16_t rgb565;
> > + uint32_t rgb888;
> > + uint8_t r, g, b;
> > + DisplaySurface *surface = qemu_console_surface(s->con);
> > + int bpp = surface_bits_per_pixel(surface);
> > +
> > + while (width--) {
> > + switch (s->bpp) {
> > + case 8:
> > + rgb888 = ldl_phys(&s->dma_as, s->vcram_base + (*src << 2));
>
> Don't use ldl_phys() in device model code, please. It means "do
> a load with the endianness of the CPU's bus", and generally
> device behaviour doesn't depend on the what the CPU happens to
> be doing. If you do a grep for 'ld[a-z]*_phys' in hw/ you'll find
> that (apart from a few spurious matches) the only things doing this
> are some bcm2835 code that you should fix and the spapr hypercall
> device (which really is legitimately cpu-behaviour-dependent).
>
> You need to determine what endianness the device uses to do
> its DMA accesses, and use either ldl_le_phys() or ldl_be_phys()
> as appropriate. (Or address_space_ldl_le/be if you care about
> memory attributes.)
Thanks for pointing this out. I'll get the other instances fixed (they are all le).
> More interestingly, why can't you just read from the source
> pointer you're passed in here? The framebuffer_update_display()
> code should have obtained it by looking up the location of the
> host RAM where the guest video RAM is, so if you ignore it and
> do a complete physical-address-to-memory-region lookup for every
> pixel it's going to make redraws unnecessarily slow.
That is what's happening for the 16-, 24- and 32-bit modes. For 8-bit, it appears to be doing a palette lookup (using the 8-bit value at the pointer as an index into the 256-colour palette starting at vcram_base). Your point that this is inefficient stands, but the translation afforded by the existing framebuffer code doesn't help. I'm tempted to replace it with ldl_le_phys as a quick fix.
Regards,
Andrew
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 3/4] bcm2835_fb: add framebuffer device for Raspberry Pi
2016-03-02 0:19 ` Andrew Baumann
@ 2016-03-02 12:33 ` Peter Maydell
0 siblings, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2016-03-02 12:33 UTC (permalink / raw)
To: Andrew Baumann
Cc: Grégory ESTRADE, Stefan Weil, Peter Crosthwaite,
QEMU Developers, qemu-arm, Paolo Bonzini
On 2 March 2016 at 00:19, Andrew Baumann <Andrew.Baumann@microsoft.com> wrote:
>> From: Peter Maydell [mailto:peter.maydell@linaro.org]
>> More interestingly, why can't you just read from the source
>> pointer you're passed in here? The framebuffer_update_display()
>> code should have obtained it by looking up the location of the
>> host RAM where the guest video RAM is, so if you ignore it and
>> do a complete physical-address-to-memory-region lookup for every
>> pixel it's going to make redraws unnecessarily slow.
>
> That is what's happening for the 16-, 24- and 32-bit modes. For
> 8-bit, it appears to be doing a palette lookup (using the 8-bit
> value at the pointer as an index into the 256-colour palette
> starting at vcram_base).
Oh, right, it's a palette lookup. That's fine, then. A
comment mentioning that this is doing palette lookup would
help. I wouldn't worry about efficiency for this mode because
who's using 8-bit colour in 2016 ?
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2016-03-02 12:33 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-02-27 0:16 [Qemu-devel] [PATCH 0/4] Raspberry Pi framebuffer and Windows support Andrew Baumann
2016-02-27 0:16 ` [Qemu-devel] [PATCH 1/4] bcm2835_peripherals: enable sdhci pending-insert quirk for raspberry pi Andrew Baumann
2016-03-01 18:21 ` Peter Maydell
2016-02-27 0:16 ` [Qemu-devel] [PATCH 2/4] bcm2835_aux: add emulation of BCM2835 AUX (aka UART1) block Andrew Baumann
2016-03-01 19:03 ` Peter Maydell
2016-02-27 0:16 ` [Qemu-devel] [PATCH 3/4] bcm2835_fb: add framebuffer device for Raspberry Pi Andrew Baumann
2016-03-01 19:23 ` Peter Maydell
2016-03-02 0:19 ` Andrew Baumann
2016-03-02 12:33 ` Peter Maydell
2016-02-27 0:16 ` [Qemu-devel] [PATCH 4/4] bcm2835_property: implement framebuffer control/configuration properties Andrew Baumann
2016-03-01 19:26 ` Peter Maydell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).