104f1ab15SAndrew Baumann /* 204f1ab15SAndrew Baumann * Raspberry Pi emulation (c) 2012 Gregory Estrade 36111a0c0SPhilippe Mathieu-Daudé * 46111a0c0SPhilippe Mathieu-Daudé * This work is licensed under the terms of the GNU GPL, version 2 or later. 56111a0c0SPhilippe Mathieu-Daudé * See the COPYING file in the top-level directory. 604f1ab15SAndrew Baumann */ 704f1ab15SAndrew Baumann 8c964b660SPeter Maydell #include "qemu/osdep.h" 9da34e65cSMarkus Armbruster #include "qapi/error.h" 1004f1ab15SAndrew Baumann #include "hw/misc/bcm2835_property.h" 11a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 12d6454270SMarkus Armbruster #include "migration/vmstate.h" 1364552b6bSMarkus Armbruster #include "hw/irq.h" 1404f1ab15SAndrew Baumann #include "hw/misc/bcm2835_mbox_defs.h" 1529ecf2deSThomas Huth #include "hw/arm/raspberrypi-fw-defs.h" 1604f1ab15SAndrew Baumann #include "sysemu/dma.h" 1703dd024fSPaolo Bonzini #include "qemu/log.h" 180b8fa32fSMarkus Armbruster #include "qemu/module.h" 1919845504SPhilippe Mathieu-Daudé #include "trace.h" 205dc49636SSergey Kambalin #include "hw/arm/raspi_platform.h" 2104f1ab15SAndrew Baumann 2204f1ab15SAndrew Baumann /* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ 2304f1ab15SAndrew Baumann 2404f1ab15SAndrew Baumann static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) 2504f1ab15SAndrew Baumann { 2604f1ab15SAndrew Baumann uint32_t tag; 2704f1ab15SAndrew Baumann uint32_t bufsize; 2804f1ab15SAndrew Baumann uint32_t tot_len; 2904f1ab15SAndrew Baumann size_t resplen; 3004f1ab15SAndrew Baumann uint32_t tmp; 31355a8cccSGrégory ESTRADE int n; 32355a8cccSGrégory ESTRADE uint32_t offset, length, color; 33193100b5SPeter Maydell 34193100b5SPeter Maydell /* 35193100b5SPeter Maydell * Copy the current state of the framebuffer config; we will update 36193100b5SPeter Maydell * this copy as we process tags and then ask the framebuffer to use 37193100b5SPeter Maydell * it at the end. 38193100b5SPeter Maydell */ 39193100b5SPeter Maydell BCM2835FBConfig fbconfig = s->fbdev->config; 40193100b5SPeter Maydell bool fbconfig_updated = false; 4104f1ab15SAndrew Baumann 4204f1ab15SAndrew Baumann value &= ~0xf; 4304f1ab15SAndrew Baumann 4404f1ab15SAndrew Baumann s->addr = value; 4504f1ab15SAndrew Baumann 46eab71394SAndrew Baumann tot_len = ldl_le_phys(&s->dma_as, value); 4704f1ab15SAndrew Baumann 4804f1ab15SAndrew Baumann /* @(addr + 4) : Buffer response code */ 4904f1ab15SAndrew Baumann value = s->addr + 8; 5004f1ab15SAndrew Baumann while (value + 8 <= s->addr + tot_len) { 51eab71394SAndrew Baumann tag = ldl_le_phys(&s->dma_as, value); 52eab71394SAndrew Baumann bufsize = ldl_le_phys(&s->dma_as, value + 4); 5304f1ab15SAndrew Baumann /* @(value + 8) : Request/response indicator */ 5404f1ab15SAndrew Baumann resplen = 0; 5504f1ab15SAndrew Baumann switch (tag) { 5625191826SSergey Kambalin case RPI_FWREQ_PROPERTY_END: 5704f1ab15SAndrew Baumann break; 5825191826SSergey Kambalin case RPI_FWREQ_GET_FIRMWARE_REVISION: 59eab71394SAndrew Baumann stl_le_phys(&s->dma_as, value + 12, 346337); 6004f1ab15SAndrew Baumann resplen = 4; 6104f1ab15SAndrew Baumann break; 6225191826SSergey Kambalin case RPI_FWREQ_GET_BOARD_MODEL: 6304f1ab15SAndrew Baumann qemu_log_mask(LOG_UNIMP, 64e1ecf8c8SPhilippe Mathieu-Daudé "bcm2835_property: 0x%08x get board model NYI\n", 65e1ecf8c8SPhilippe Mathieu-Daudé tag); 6604f1ab15SAndrew Baumann resplen = 4; 6704f1ab15SAndrew Baumann break; 6825191826SSergey Kambalin case RPI_FWREQ_GET_BOARD_REVISION: 69eab71394SAndrew Baumann stl_le_phys(&s->dma_as, value + 12, s->board_rev); 7004f1ab15SAndrew Baumann resplen = 4; 7104f1ab15SAndrew Baumann break; 7225191826SSergey Kambalin case RPI_FWREQ_GET_BOARD_MAC_ADDRESS: 7304f1ab15SAndrew Baumann resplen = sizeof(s->macaddr.a); 74ba06fe8aSPhilippe Mathieu-Daudé dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen, 75ba06fe8aSPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED); 7604f1ab15SAndrew Baumann break; 7725191826SSergey Kambalin case RPI_FWREQ_GET_BOARD_SERIAL: 7804f1ab15SAndrew Baumann qemu_log_mask(LOG_UNIMP, 79e1ecf8c8SPhilippe Mathieu-Daudé "bcm2835_property: 0x%08x get board serial NYI\n", 80e1ecf8c8SPhilippe Mathieu-Daudé tag); 8104f1ab15SAndrew Baumann resplen = 8; 8204f1ab15SAndrew Baumann break; 8325191826SSergey Kambalin case RPI_FWREQ_GET_ARM_MEMORY: 8404f1ab15SAndrew Baumann /* base */ 85eab71394SAndrew Baumann stl_le_phys(&s->dma_as, value + 12, 0); 8604f1ab15SAndrew Baumann /* size */ 87355a8cccSGrégory ESTRADE stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_base); 88355a8cccSGrégory ESTRADE resplen = 8; 89355a8cccSGrégory ESTRADE break; 9025191826SSergey Kambalin case RPI_FWREQ_GET_VC_MEMORY: 91355a8cccSGrégory ESTRADE /* base */ 92355a8cccSGrégory ESTRADE stl_le_phys(&s->dma_as, value + 12, s->fbdev->vcram_base); 93355a8cccSGrégory ESTRADE /* size */ 94355a8cccSGrégory ESTRADE stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size); 9504f1ab15SAndrew Baumann resplen = 8; 9604f1ab15SAndrew Baumann break; 9725191826SSergey Kambalin case RPI_FWREQ_SET_POWER_STATE: 9804f1ab15SAndrew Baumann /* Assume that whatever device they asked for exists, 9904f1ab15SAndrew Baumann * and we'll just claim we set it to the desired state 10004f1ab15SAndrew Baumann */ 101eab71394SAndrew Baumann tmp = ldl_le_phys(&s->dma_as, value + 16); 102eab71394SAndrew Baumann stl_le_phys(&s->dma_as, value + 16, (tmp & 1)); 10304f1ab15SAndrew Baumann resplen = 8; 10404f1ab15SAndrew Baumann break; 10504f1ab15SAndrew Baumann 10604f1ab15SAndrew Baumann /* Clocks */ 10704f1ab15SAndrew Baumann 10825191826SSergey Kambalin case RPI_FWREQ_GET_CLOCK_STATE: 109eab71394SAndrew Baumann stl_le_phys(&s->dma_as, value + 16, 0x1); 11004f1ab15SAndrew Baumann resplen = 8; 11104f1ab15SAndrew Baumann break; 11204f1ab15SAndrew Baumann 11325191826SSergey Kambalin case RPI_FWREQ_SET_CLOCK_STATE: 11404f1ab15SAndrew Baumann qemu_log_mask(LOG_UNIMP, 115e1ecf8c8SPhilippe Mathieu-Daudé "bcm2835_property: 0x%08x set clock state NYI\n", 116e1ecf8c8SPhilippe Mathieu-Daudé tag); 11704f1ab15SAndrew Baumann resplen = 8; 11804f1ab15SAndrew Baumann break; 11904f1ab15SAndrew Baumann 12025191826SSergey Kambalin case RPI_FWREQ_GET_CLOCK_RATE: 12125191826SSergey Kambalin case RPI_FWREQ_GET_MAX_CLOCK_RATE: 12225191826SSergey Kambalin case RPI_FWREQ_GET_MIN_CLOCK_RATE: 123eab71394SAndrew Baumann switch (ldl_le_phys(&s->dma_as, value + 12)) { 12425191826SSergey Kambalin case RPI_FIRMWARE_EMMC_CLK_ID: 1255dc49636SSergey Kambalin stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_EMMC_CLK_RATE); 12604f1ab15SAndrew Baumann break; 12725191826SSergey Kambalin case RPI_FIRMWARE_UART_CLK_ID: 1285dc49636SSergey Kambalin stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_UART_CLK_RATE); 12904f1ab15SAndrew Baumann break; 130074259c0SSergey Kambalin case RPI_FIRMWARE_CORE_CLK_ID: 131074259c0SSergey Kambalin stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_CORE_CLK_RATE); 132074259c0SSergey Kambalin break; 13304f1ab15SAndrew Baumann default: 1345dc49636SSergey Kambalin stl_le_phys(&s->dma_as, value + 16, 1355dc49636SSergey Kambalin RPI_FIRMWARE_DEFAULT_CLK_RATE); 13604f1ab15SAndrew Baumann break; 13704f1ab15SAndrew Baumann } 13804f1ab15SAndrew Baumann resplen = 8; 13904f1ab15SAndrew Baumann break; 14004f1ab15SAndrew Baumann 14125191826SSergey Kambalin case RPI_FWREQ_SET_CLOCK_RATE: 14225191826SSergey Kambalin case RPI_FWREQ_SET_MAX_CLOCK_RATE: 14325191826SSergey Kambalin case RPI_FWREQ_SET_MIN_CLOCK_RATE: 14404f1ab15SAndrew Baumann qemu_log_mask(LOG_UNIMP, 145e1ecf8c8SPhilippe Mathieu-Daudé "bcm2835_property: 0x%08x set clock rate NYI\n", 146e1ecf8c8SPhilippe Mathieu-Daudé tag); 14704f1ab15SAndrew Baumann resplen = 8; 14804f1ab15SAndrew Baumann break; 14904f1ab15SAndrew Baumann 15004f1ab15SAndrew Baumann /* Temperature */ 15104f1ab15SAndrew Baumann 15225191826SSergey Kambalin case RPI_FWREQ_GET_TEMPERATURE: 153eab71394SAndrew Baumann stl_le_phys(&s->dma_as, value + 16, 25000); 15404f1ab15SAndrew Baumann resplen = 8; 15504f1ab15SAndrew Baumann break; 15604f1ab15SAndrew Baumann 15725191826SSergey Kambalin case RPI_FWREQ_GET_MAX_TEMPERATURE: 158eab71394SAndrew Baumann stl_le_phys(&s->dma_as, value + 16, 99000); 15904f1ab15SAndrew Baumann resplen = 8; 16004f1ab15SAndrew Baumann break; 16104f1ab15SAndrew Baumann 162355a8cccSGrégory ESTRADE /* Frame buffer */ 163355a8cccSGrégory ESTRADE 16425191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_ALLOCATE: 165193100b5SPeter Maydell stl_le_phys(&s->dma_as, value + 12, fbconfig.base); 16627a5dc7bSSylvain Garrigues stl_le_phys(&s->dma_as, value + 16, 1679a1f03f4SPeter Maydell bcm2835_fb_get_size(&fbconfig)); 168355a8cccSGrégory ESTRADE resplen = 8; 169355a8cccSGrégory ESTRADE break; 17025191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_RELEASE: 171355a8cccSGrégory ESTRADE resplen = 0; 172355a8cccSGrégory ESTRADE break; 17325191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_BLANK: 174355a8cccSGrégory ESTRADE resplen = 4; 175355a8cccSGrégory ESTRADE break; 17625191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT: 17725191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT: 17801f18af9SPeter Maydell resplen = 8; 17901f18af9SPeter Maydell break; 18025191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT: 181193100b5SPeter Maydell fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12); 182193100b5SPeter Maydell fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16); 183f8add62cSPeter Maydell bcm2835_fb_validate_config(&fbconfig); 184193100b5SPeter Maydell fbconfig_updated = true; 185f8add62cSPeter Maydell /* fall through */ 18625191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT: 187f8add62cSPeter Maydell stl_le_phys(&s->dma_as, value + 12, fbconfig.xres); 188f8add62cSPeter Maydell stl_le_phys(&s->dma_as, value + 16, fbconfig.yres); 189355a8cccSGrégory ESTRADE resplen = 8; 190355a8cccSGrégory ESTRADE break; 19125191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT: 19201f18af9SPeter Maydell fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12); 19301f18af9SPeter Maydell fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16); 194f8add62cSPeter Maydell bcm2835_fb_validate_config(&fbconfig); 19501f18af9SPeter Maydell fbconfig_updated = true; 196f8add62cSPeter Maydell /* fall through */ 19725191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT: 198f8add62cSPeter Maydell stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual); 199f8add62cSPeter Maydell stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual); 20001f18af9SPeter Maydell resplen = 8; 20101f18af9SPeter Maydell break; 20225191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_TEST_DEPTH: 203355a8cccSGrégory ESTRADE resplen = 4; 204355a8cccSGrégory ESTRADE break; 20525191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_SET_DEPTH: 206193100b5SPeter Maydell fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12); 207f8add62cSPeter Maydell bcm2835_fb_validate_config(&fbconfig); 208193100b5SPeter Maydell fbconfig_updated = true; 209f8add62cSPeter Maydell /* fall through */ 21025191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_GET_DEPTH: 211f8add62cSPeter Maydell stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp); 212355a8cccSGrégory ESTRADE resplen = 4; 213355a8cccSGrégory ESTRADE break; 21425191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_TEST_PIXEL_ORDER: 215355a8cccSGrégory ESTRADE resplen = 4; 216355a8cccSGrégory ESTRADE break; 21725191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_SET_PIXEL_ORDER: 218193100b5SPeter Maydell fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12); 219f8add62cSPeter Maydell bcm2835_fb_validate_config(&fbconfig); 220193100b5SPeter Maydell fbconfig_updated = true; 221f8add62cSPeter Maydell /* fall through */ 22225191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_GET_PIXEL_ORDER: 223f8add62cSPeter Maydell stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo); 224355a8cccSGrégory ESTRADE resplen = 4; 225355a8cccSGrégory ESTRADE break; 22625191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_TEST_ALPHA_MODE: 227355a8cccSGrégory ESTRADE resplen = 4; 228355a8cccSGrégory ESTRADE break; 22925191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_SET_ALPHA_MODE: 230193100b5SPeter Maydell fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12); 231f8add62cSPeter Maydell bcm2835_fb_validate_config(&fbconfig); 232193100b5SPeter Maydell fbconfig_updated = true; 233f8add62cSPeter Maydell /* fall through */ 23425191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_GET_ALPHA_MODE: 235f8add62cSPeter Maydell stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha); 236355a8cccSGrégory ESTRADE resplen = 4; 237355a8cccSGrégory ESTRADE break; 23825191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_GET_PITCH: 239193100b5SPeter Maydell stl_le_phys(&s->dma_as, value + 12, 2409a1f03f4SPeter Maydell bcm2835_fb_get_pitch(&fbconfig)); 241355a8cccSGrégory ESTRADE resplen = 4; 242355a8cccSGrégory ESTRADE break; 24325191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_OFFSET: 244355a8cccSGrégory ESTRADE resplen = 8; 245355a8cccSGrégory ESTRADE break; 24625191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_OFFSET: 247193100b5SPeter Maydell fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12); 248193100b5SPeter Maydell fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16); 249f8add62cSPeter Maydell bcm2835_fb_validate_config(&fbconfig); 250193100b5SPeter Maydell fbconfig_updated = true; 251f8add62cSPeter Maydell /* fall through */ 25225191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_OFFSET: 253f8add62cSPeter Maydell stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset); 254f8add62cSPeter Maydell stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset); 255355a8cccSGrégory ESTRADE resplen = 8; 256355a8cccSGrégory ESTRADE break; 25725191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_GET_OVERSCAN: 25825191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_TEST_OVERSCAN: 25925191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_SET_OVERSCAN: 260355a8cccSGrégory ESTRADE stl_le_phys(&s->dma_as, value + 12, 0); 261355a8cccSGrégory ESTRADE stl_le_phys(&s->dma_as, value + 16, 0); 262355a8cccSGrégory ESTRADE stl_le_phys(&s->dma_as, value + 20, 0); 263355a8cccSGrégory ESTRADE stl_le_phys(&s->dma_as, value + 24, 0); 264355a8cccSGrégory ESTRADE resplen = 16; 265355a8cccSGrégory ESTRADE break; 26625191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_SET_PALETTE: 267355a8cccSGrégory ESTRADE offset = ldl_le_phys(&s->dma_as, value + 12); 268355a8cccSGrégory ESTRADE length = ldl_le_phys(&s->dma_as, value + 16); 269355a8cccSGrégory ESTRADE n = 0; 270355a8cccSGrégory ESTRADE while (n < length - offset) { 271355a8cccSGrégory ESTRADE color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2)); 272355a8cccSGrégory ESTRADE stl_le_phys(&s->dma_as, 273355a8cccSGrégory ESTRADE s->fbdev->vcram_base + ((offset + n) << 2), color); 274355a8cccSGrégory ESTRADE n++; 275355a8cccSGrégory ESTRADE } 276355a8cccSGrégory ESTRADE stl_le_phys(&s->dma_as, value + 12, 0); 277355a8cccSGrégory ESTRADE resplen = 4; 278355a8cccSGrégory ESTRADE break; 27925191826SSergey Kambalin case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS: 2803b9a030eSEnrik Berkhan stl_le_phys(&s->dma_as, value + 12, 1); 2813b9a030eSEnrik Berkhan resplen = 4; 2823b9a030eSEnrik Berkhan break; 28304f1ab15SAndrew Baumann 28425191826SSergey Kambalin case RPI_FWREQ_GET_DMA_CHANNELS: 28504f1ab15SAndrew Baumann /* channels 2-5 */ 286eab71394SAndrew Baumann stl_le_phys(&s->dma_as, value + 12, 0x003C); 28704f1ab15SAndrew Baumann resplen = 4; 28804f1ab15SAndrew Baumann break; 28904f1ab15SAndrew Baumann 29025191826SSergey Kambalin case RPI_FWREQ_GET_COMMAND_LINE: 291f802ff1eSDaniel Bertalan /* 292f802ff1eSDaniel Bertalan * We follow the firmware behaviour: no NUL terminator is 293f802ff1eSDaniel Bertalan * written to the buffer, and if the buffer is too short 294f802ff1eSDaniel Bertalan * we report the required length in the response header 295f802ff1eSDaniel Bertalan * and copy nothing to the buffer. 296f802ff1eSDaniel Bertalan */ 297f802ff1eSDaniel Bertalan resplen = strlen(s->command_line); 298f802ff1eSDaniel Bertalan if (bufsize >= resplen) 299f802ff1eSDaniel Bertalan address_space_write(&s->dma_as, value + 12, 300f802ff1eSDaniel Bertalan MEMTXATTRS_UNSPECIFIED, s->command_line, 301f802ff1eSDaniel Bertalan resplen); 30204f1ab15SAndrew Baumann break; 30304f1ab15SAndrew Baumann 30404f1ab15SAndrew Baumann default: 305e1ecf8c8SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, 306e1ecf8c8SPhilippe Mathieu-Daudé "bcm2835_property: unhandled tag 0x%08x\n", tag); 30704f1ab15SAndrew Baumann break; 30804f1ab15SAndrew Baumann } 30904f1ab15SAndrew Baumann 31019845504SPhilippe Mathieu-Daudé trace_bcm2835_mbox_property(tag, bufsize, resplen); 31104f1ab15SAndrew Baumann if (tag == 0) { 31204f1ab15SAndrew Baumann break; 31304f1ab15SAndrew Baumann } 31404f1ab15SAndrew Baumann 315eab71394SAndrew Baumann stl_le_phys(&s->dma_as, value + 8, (1 << 31) | resplen); 31604f1ab15SAndrew Baumann value += bufsize + 12; 31704f1ab15SAndrew Baumann } 31804f1ab15SAndrew Baumann 319355a8cccSGrégory ESTRADE /* Reconfigure framebuffer if required */ 320193100b5SPeter Maydell if (fbconfig_updated) { 321193100b5SPeter Maydell bcm2835_fb_reconfigure(s->fbdev, &fbconfig); 322355a8cccSGrégory ESTRADE } 323355a8cccSGrégory ESTRADE 32404f1ab15SAndrew Baumann /* Buffer response code */ 325eab71394SAndrew Baumann stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31)); 32604f1ab15SAndrew Baumann } 32704f1ab15SAndrew Baumann 32804f1ab15SAndrew Baumann static uint64_t bcm2835_property_read(void *opaque, hwaddr offset, 32904f1ab15SAndrew Baumann unsigned size) 33004f1ab15SAndrew Baumann { 33104f1ab15SAndrew Baumann BCM2835PropertyState *s = opaque; 33204f1ab15SAndrew Baumann uint32_t res = 0; 33304f1ab15SAndrew Baumann 33404f1ab15SAndrew Baumann switch (offset) { 33504f1ab15SAndrew Baumann case MBOX_AS_DATA: 33604f1ab15SAndrew Baumann res = MBOX_CHAN_PROPERTY | s->addr; 33704f1ab15SAndrew Baumann s->pending = false; 33804f1ab15SAndrew Baumann qemu_set_irq(s->mbox_irq, 0); 33904f1ab15SAndrew Baumann break; 34004f1ab15SAndrew Baumann 34104f1ab15SAndrew Baumann case MBOX_AS_PENDING: 34204f1ab15SAndrew Baumann res = s->pending; 34304f1ab15SAndrew Baumann break; 34404f1ab15SAndrew Baumann 34504f1ab15SAndrew Baumann default: 34604f1ab15SAndrew Baumann qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 34704f1ab15SAndrew Baumann __func__, offset); 34804f1ab15SAndrew Baumann return 0; 34904f1ab15SAndrew Baumann } 35004f1ab15SAndrew Baumann 35104f1ab15SAndrew Baumann return res; 35204f1ab15SAndrew Baumann } 35304f1ab15SAndrew Baumann 35404f1ab15SAndrew Baumann static void bcm2835_property_write(void *opaque, hwaddr offset, 35504f1ab15SAndrew Baumann uint64_t value, unsigned size) 35604f1ab15SAndrew Baumann { 35704f1ab15SAndrew Baumann BCM2835PropertyState *s = opaque; 35804f1ab15SAndrew Baumann 35904f1ab15SAndrew Baumann switch (offset) { 36004f1ab15SAndrew Baumann case MBOX_AS_DATA: 36104f1ab15SAndrew Baumann /* bcm2835_mbox should check our pending status before pushing */ 36204f1ab15SAndrew Baumann assert(!s->pending); 36304f1ab15SAndrew Baumann s->pending = true; 36404f1ab15SAndrew Baumann bcm2835_property_mbox_push(s, value); 36504f1ab15SAndrew Baumann qemu_set_irq(s->mbox_irq, 1); 36604f1ab15SAndrew Baumann break; 36704f1ab15SAndrew Baumann 36804f1ab15SAndrew Baumann default: 36904f1ab15SAndrew Baumann qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 37004f1ab15SAndrew Baumann __func__, offset); 37104f1ab15SAndrew Baumann return; 37204f1ab15SAndrew Baumann } 37304f1ab15SAndrew Baumann } 37404f1ab15SAndrew Baumann 37504f1ab15SAndrew Baumann static const MemoryRegionOps bcm2835_property_ops = { 37604f1ab15SAndrew Baumann .read = bcm2835_property_read, 37704f1ab15SAndrew Baumann .write = bcm2835_property_write, 37804f1ab15SAndrew Baumann .endianness = DEVICE_NATIVE_ENDIAN, 37904f1ab15SAndrew Baumann .valid.min_access_size = 4, 38004f1ab15SAndrew Baumann .valid.max_access_size = 4, 38104f1ab15SAndrew Baumann }; 38204f1ab15SAndrew Baumann 38304f1ab15SAndrew Baumann static const VMStateDescription vmstate_bcm2835_property = { 38404f1ab15SAndrew Baumann .name = TYPE_BCM2835_PROPERTY, 38504f1ab15SAndrew Baumann .version_id = 1, 38604f1ab15SAndrew Baumann .minimum_version_id = 1, 387*e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 38804f1ab15SAndrew Baumann VMSTATE_MACADDR(macaddr, BCM2835PropertyState), 38904f1ab15SAndrew Baumann VMSTATE_UINT32(addr, BCM2835PropertyState), 39004f1ab15SAndrew Baumann VMSTATE_BOOL(pending, BCM2835PropertyState), 39104f1ab15SAndrew Baumann VMSTATE_END_OF_LIST() 39204f1ab15SAndrew Baumann } 39304f1ab15SAndrew Baumann }; 39404f1ab15SAndrew Baumann 39504f1ab15SAndrew Baumann static void bcm2835_property_init(Object *obj) 39604f1ab15SAndrew Baumann { 39704f1ab15SAndrew Baumann BCM2835PropertyState *s = BCM2835_PROPERTY(obj); 39804f1ab15SAndrew Baumann 39904f1ab15SAndrew Baumann memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s, 40004f1ab15SAndrew Baumann TYPE_BCM2835_PROPERTY, 0x10); 401985c4a4eSAlexander Bulekov 402985c4a4eSAlexander Bulekov /* 403985c4a4eSAlexander Bulekov * bcm2835_property_ops call into bcm2835_mbox, which in-turn reads from 404985c4a4eSAlexander Bulekov * iomem. As such, mark iomem as re-entracy safe. 405985c4a4eSAlexander Bulekov */ 406985c4a4eSAlexander Bulekov s->iomem.disable_reentrancy_guard = true; 407985c4a4eSAlexander Bulekov 40804f1ab15SAndrew Baumann sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 40904f1ab15SAndrew Baumann sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq); 41004f1ab15SAndrew Baumann } 41104f1ab15SAndrew Baumann 41204f1ab15SAndrew Baumann static void bcm2835_property_reset(DeviceState *dev) 41304f1ab15SAndrew Baumann { 41404f1ab15SAndrew Baumann BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 41504f1ab15SAndrew Baumann 41604f1ab15SAndrew Baumann s->pending = false; 41704f1ab15SAndrew Baumann } 41804f1ab15SAndrew Baumann 41904f1ab15SAndrew Baumann static void bcm2835_property_realize(DeviceState *dev, Error **errp) 42004f1ab15SAndrew Baumann { 42104f1ab15SAndrew Baumann BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 42204f1ab15SAndrew Baumann Object *obj; 42304f1ab15SAndrew Baumann 4244d21fcd5SMarkus Armbruster obj = object_property_get_link(OBJECT(dev), "fb", &error_abort); 425355a8cccSGrégory ESTRADE s->fbdev = BCM2835_FB(obj); 426355a8cccSGrégory ESTRADE 4274d21fcd5SMarkus Armbruster obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort); 42804f1ab15SAndrew Baumann s->dma_mr = MEMORY_REGION(obj); 429e55a8b37SPhilippe Mathieu-Daudé address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_PROPERTY "-memory"); 43004f1ab15SAndrew Baumann 43104f1ab15SAndrew Baumann /* TODO: connect to MAC address of USB NIC device, once we emulate it */ 43204f1ab15SAndrew Baumann qemu_macaddr_default_if_unset(&s->macaddr); 43304f1ab15SAndrew Baumann 43404f1ab15SAndrew Baumann bcm2835_property_reset(dev); 43504f1ab15SAndrew Baumann } 43604f1ab15SAndrew Baumann 43704f1ab15SAndrew Baumann static Property bcm2835_property_props[] = { 438f0afa731SStephen Warren DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0), 439f802ff1eSDaniel Bertalan DEFINE_PROP_STRING("command-line", BCM2835PropertyState, command_line), 44004f1ab15SAndrew Baumann DEFINE_PROP_END_OF_LIST() 44104f1ab15SAndrew Baumann }; 44204f1ab15SAndrew Baumann 44304f1ab15SAndrew Baumann static void bcm2835_property_class_init(ObjectClass *klass, void *data) 44404f1ab15SAndrew Baumann { 44504f1ab15SAndrew Baumann DeviceClass *dc = DEVICE_CLASS(klass); 44604f1ab15SAndrew Baumann 4474f67d30bSMarc-André Lureau device_class_set_props(dc, bcm2835_property_props); 44804f1ab15SAndrew Baumann dc->realize = bcm2835_property_realize; 44904f1ab15SAndrew Baumann dc->vmsd = &vmstate_bcm2835_property; 45004f1ab15SAndrew Baumann } 45104f1ab15SAndrew Baumann 4525e78c98bSBernhard Beschow static const TypeInfo bcm2835_property_info = { 45304f1ab15SAndrew Baumann .name = TYPE_BCM2835_PROPERTY, 45404f1ab15SAndrew Baumann .parent = TYPE_SYS_BUS_DEVICE, 45504f1ab15SAndrew Baumann .instance_size = sizeof(BCM2835PropertyState), 45604f1ab15SAndrew Baumann .class_init = bcm2835_property_class_init, 45704f1ab15SAndrew Baumann .instance_init = bcm2835_property_init, 45804f1ab15SAndrew Baumann }; 45904f1ab15SAndrew Baumann 46004f1ab15SAndrew Baumann static void bcm2835_property_register_types(void) 46104f1ab15SAndrew Baumann { 46204f1ab15SAndrew Baumann type_register_static(&bcm2835_property_info); 46304f1ab15SAndrew Baumann } 46404f1ab15SAndrew Baumann 46504f1ab15SAndrew Baumann type_init(bcm2835_property_register_types) 466