X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/eab713941ab83c6d30739e430357e817bf81dad1..808ebd66e467f77c0d1f8c6346235f81e9c99cf2:/hw/misc/bcm2835_property.c diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index 41fbbe3e7f..145427ae0f 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -4,9 +4,11 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/misc/bcm2835_property.h" #include "hw/misc/bcm2835_mbox_defs.h" #include "sysemu/dma.h" +#include "qemu/log.h" /* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ @@ -17,6 +19,16 @@ 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; + + /* + * Copy the current state of the framebuffer config; we will update + * this copy as we process tags and then ask the framebuffer to use + * it at the end. + */ + BCM2835FBConfig fbconfig = s->fbdev->config; + bool fbconfig_updated = false; value &= ~0xf; @@ -60,7 +72,14 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) /* base */ stl_le_phys(&s->dma_as, value + 12, 0); /* size */ - stl_le_phys(&s->dma_as, value + 16, s->ram_size); + stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_base); + resplen = 8; + break; + case 0x00010006: /* Get VC memory */ + /* base */ + stl_le_phys(&s->dma_as, value + 12, s->fbdev->vcram_base); + /* size */ + stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size); resplen = 8; break; case 0x00028001: /* Set power state */ @@ -122,6 +141,123 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) resplen = 8; break; + /* Frame buffer */ + + case 0x00040001: /* Allocate buffer */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.base); + stl_le_phys(&s->dma_as, value + 16, + bcm2835_fb_get_size(&fbconfig)); + resplen = 8; + break; + case 0x00048001: /* Release buffer */ + resplen = 0; + break; + case 0x00040002: /* Blank screen */ + resplen = 4; + break; + case 0x00044003: /* Test physical display width/height */ + case 0x00044004: /* Test virtual display width/height */ + resplen = 8; + break; + case 0x00048003: /* Set physical display width/height */ + fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12); + fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040003: /* Get physical display width/height */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.xres); + stl_le_phys(&s->dma_as, value + 16, fbconfig.yres); + resplen = 8; + break; + case 0x00048004: /* Set virtual display width/height */ + fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12); + fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040004: /* Get virtual display width/height */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual); + stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual); + resplen = 8; + break; + case 0x00044005: /* Test depth */ + resplen = 4; + break; + case 0x00048005: /* Set depth */ + fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040005: /* Get depth */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp); + resplen = 4; + break; + case 0x00044006: /* Test pixel order */ + resplen = 4; + break; + case 0x00048006: /* Set pixel order */ + fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040006: /* Get pixel order */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo); + resplen = 4; + break; + case 0x00044007: /* Test pixel alpha */ + resplen = 4; + break; + case 0x00048007: /* Set alpha */ + fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040007: /* Get alpha */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha); + resplen = 4; + break; + case 0x00040008: /* Get pitch */ + stl_le_phys(&s->dma_as, value + 12, + bcm2835_fb_get_pitch(&fbconfig)); + resplen = 4; + break; + case 0x00044009: /* Test virtual offset */ + resplen = 8; + break; + case 0x00048009: /* Set virtual offset */ + fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12); + fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040009: /* Get virtual offset */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset); + stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset); + resplen = 8; + break; + case 0x0004000a: /* Get/Test/Set overscan */ + case 0x0004400a: + case 0x0004800a: + stl_le_phys(&s->dma_as, value + 12, 0); + stl_le_phys(&s->dma_as, value + 16, 0); + stl_le_phys(&s->dma_as, value + 20, 0); + stl_le_phys(&s->dma_as, value + 24, 0); + resplen = 16; + break; + case 0x0004800b: /* Set palette */ + offset = ldl_le_phys(&s->dma_as, value + 12); + length = ldl_le_phys(&s->dma_as, value + 16); + n = 0; + while (n < length - offset) { + color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2)); + stl_le_phys(&s->dma_as, + s->fbdev->vcram_base + ((offset + n) << 2), color); + n++; + } + stl_le_phys(&s->dma_as, value + 12, 0); + resplen = 4; + break; case 0x00060001: /* Get DMA channels */ /* channels 2-5 */ @@ -147,6 +283,11 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) value += bufsize + 12; } + /* Reconfigure framebuffer if required */ + if (fbconfig_updated) { + bcm2835_fb_reconfigure(s->fbdev, &fbconfig); + } + /* Buffer response code */ stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31)); } @@ -241,6 +382,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 +409,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() };