]> Git Repo - qemu.git/blobdiff - hw/misc/bcm2835_property.c
Merge remote-tracking branch 'remotes/riscv/tags/riscv-for-master-3.1-sf0' into staging
[qemu.git] / hw / misc / bcm2835_property.c
index 581922abd75e12bf8be1df194089b02f2827d5fd..145427ae0f8462d39e1b74177e723a3a684d6d1c 100644 (file)
@@ -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,25 +19,35 @@ 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;
 
     s->addr = value;
 
-    tot_len = ldl_phys(&s->dma_as, value);
+    tot_len = ldl_le_phys(&s->dma_as, value);
 
     /* @(addr + 4) : Buffer response code */
     value = s->addr + 8;
     while (value + 8 <= s->addr + tot_len) {
-        tag = ldl_phys(&s->dma_as, value);
-        bufsize = ldl_phys(&s->dma_as, value + 4);
+        tag = ldl_le_phys(&s->dma_as, value);
+        bufsize = ldl_le_phys(&s->dma_as, value + 4);
         /* @(value + 8) : Request/response indicator */
         resplen = 0;
         switch (tag) {
         case 0x00000000: /* End tag */
             break;
         case 0x00000001: /* Get firmware revision */
-            stl_phys(&s->dma_as, value + 12, 346337);
+            stl_le_phys(&s->dma_as, value + 12, 346337);
             resplen = 4;
             break;
         case 0x00010001: /* Get board model */
@@ -44,7 +56,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
             resplen = 4;
             break;
         case 0x00010002: /* Get board revision */
-            stl_phys(&s->dma_as, value + 12, s->board_rev);
+            stl_le_phys(&s->dma_as, value + 12, s->board_rev);
             resplen = 4;
             break;
         case 0x00010003: /* Get board MAC address */
@@ -58,24 +70,31 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
             break;
         case 0x00010005: /* Get ARM memory */
             /* base */
-            stl_phys(&s->dma_as, value + 12, 0);
+            stl_le_phys(&s->dma_as, value + 12, 0);
+            /* 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_phys(&s->dma_as, value + 16, s->ram_size);
+            stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size);
             resplen = 8;
             break;
         case 0x00028001: /* Set power state */
             /* Assume that whatever device they asked for exists,
              * and we'll just claim we set it to the desired state
              */
-            tmp = ldl_phys(&s->dma_as, value + 16);
-            stl_phys(&s->dma_as, value + 16, (tmp & 1));
+            tmp = ldl_le_phys(&s->dma_as, value + 16);
+            stl_le_phys(&s->dma_as, value + 16, (tmp & 1));
             resplen = 8;
             break;
 
         /* Clocks */
 
         case 0x00030001: /* Get clock state */
-            stl_phys(&s->dma_as, value + 16, 0x1);
+            stl_le_phys(&s->dma_as, value + 16, 0x1);
             resplen = 8;
             break;
 
@@ -88,15 +107,15 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
         case 0x00030002: /* Get clock rate */
         case 0x00030004: /* Get max clock rate */
         case 0x00030007: /* Get min clock rate */
-            switch (ldl_phys(&s->dma_as, value + 12)) {
+            switch (ldl_le_phys(&s->dma_as, value + 12)) {
             case 1: /* EMMC */
-                stl_phys(&s->dma_as, value + 16, 50000000);
+                stl_le_phys(&s->dma_as, value + 16, 50000000);
                 break;
             case 2: /* UART */
-                stl_phys(&s->dma_as, value + 16, 3000000);
+                stl_le_phys(&s->dma_as, value + 16, 3000000);
                 break;
             default:
-                stl_phys(&s->dma_as, value + 16, 700000000);
+                stl_le_phys(&s->dma_as, value + 16, 700000000);
                 break;
             }
             resplen = 8;
@@ -113,19 +132,136 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
         /* Temperature */
 
         case 0x00030006: /* Get temperature */
-            stl_phys(&s->dma_as, value + 16, 25000);
+            stl_le_phys(&s->dma_as, value + 16, 25000);
             resplen = 8;
             break;
 
         case 0x0003000A: /* Get max temperature */
-            stl_phys(&s->dma_as, value + 16, 99000);
+            stl_le_phys(&s->dma_as, value + 16, 99000);
             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 */
-            stl_phys(&s->dma_as, value + 12, 0x003C);
+            stl_le_phys(&s->dma_as, value + 12, 0x003C);
             resplen = 4;
             break;
 
@@ -143,12 +279,17 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
             break;
         }
 
-        stl_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
+        stl_le_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
         value += bufsize + 12;
     }
 
+    /* Reconfigure framebuffer if required */
+    if (fbconfig_updated) {
+        bcm2835_fb_reconfigure(s->fbdev, &fbconfig);
+    }
+
     /* Buffer response code */
-    stl_phys(&s->dma_as, s->addr + 4, (1 << 31));
+    stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31));
 }
 
 static uint64_t bcm2835_property_read(void *opaque, hwaddr offset,
@@ -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()
 };
 
This page took 0.049165 seconds and 4 git commands to generate.