1 /* 2 * Raspberry Pi emulation (c) 2012 Gregory Estrade 3 * 4 * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 * See the COPYING file in the top-level directory. 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qapi/error.h" 10 #include "hw/misc/bcm2835_property.h" 11 #include "hw/qdev-properties.h" 12 #include "migration/vmstate.h" 13 #include "hw/irq.h" 14 #include "hw/misc/bcm2835_mbox_defs.h" 15 #include "hw/arm/raspberrypi-fw-defs.h" 16 #include "sysemu/dma.h" 17 #include "qemu/log.h" 18 #include "qemu/module.h" 19 #include "trace.h" 20 #include "hw/arm/raspi_platform.h" 21 22 #define VCHI_BUSADDR_SIZE sizeof(uint32_t) 23 24 /* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ 25 26 static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) 27 { 28 uint32_t tag; 29 uint32_t bufsize; 30 uint32_t tot_len; 31 size_t resplen; 32 uint32_t tmp; 33 int n; 34 uint32_t offset, length, color; 35 36 /* 37 * Copy the current state of the framebuffer config; we will update 38 * this copy as we process tags and then ask the framebuffer to use 39 * it at the end. 40 */ 41 BCM2835FBConfig fbconfig = s->fbdev->config; 42 bool fbconfig_updated = false; 43 44 value &= ~0xf; 45 46 s->addr = value; 47 48 tot_len = ldl_le_phys(&s->dma_as, value); 49 50 /* @(addr + 4) : Buffer response code */ 51 value = s->addr + 8; 52 while (value + 8 <= s->addr + tot_len) { 53 tag = ldl_le_phys(&s->dma_as, value); 54 bufsize = ldl_le_phys(&s->dma_as, value + 4); 55 /* @(value + 8) : Request/response indicator */ 56 resplen = 0; 57 switch (tag) { 58 case RPI_FWREQ_PROPERTY_END: 59 break; 60 case RPI_FWREQ_GET_FIRMWARE_REVISION: 61 stl_le_phys(&s->dma_as, value + 12, 346337); 62 resplen = 4; 63 break; 64 case RPI_FWREQ_GET_BOARD_MODEL: 65 qemu_log_mask(LOG_UNIMP, 66 "bcm2835_property: 0x%08x get board model NYI\n", 67 tag); 68 resplen = 4; 69 break; 70 case RPI_FWREQ_GET_BOARD_REVISION: 71 stl_le_phys(&s->dma_as, value + 12, s->board_rev); 72 resplen = 4; 73 break; 74 case RPI_FWREQ_GET_BOARD_MAC_ADDRESS: 75 resplen = sizeof(s->macaddr.a); 76 dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen, 77 MEMTXATTRS_UNSPECIFIED); 78 break; 79 case RPI_FWREQ_GET_BOARD_SERIAL: 80 qemu_log_mask(LOG_UNIMP, 81 "bcm2835_property: 0x%08x get board serial NYI\n", 82 tag); 83 resplen = 8; 84 break; 85 case RPI_FWREQ_GET_ARM_MEMORY: 86 /* base */ 87 stl_le_phys(&s->dma_as, value + 12, 0); 88 /* size */ 89 stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_base); 90 resplen = 8; 91 break; 92 case RPI_FWREQ_GET_VC_MEMORY: 93 /* base */ 94 stl_le_phys(&s->dma_as, value + 12, s->fbdev->vcram_base); 95 /* size */ 96 stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size); 97 resplen = 8; 98 break; 99 case RPI_FWREQ_SET_POWER_STATE: 100 /* Assume that whatever device they asked for exists, 101 * and we'll just claim we set it to the desired state 102 */ 103 tmp = ldl_le_phys(&s->dma_as, value + 16); 104 stl_le_phys(&s->dma_as, value + 16, (tmp & 1)); 105 resplen = 8; 106 break; 107 108 /* Clocks */ 109 110 case RPI_FWREQ_GET_CLOCK_STATE: 111 stl_le_phys(&s->dma_as, value + 16, 0x1); 112 resplen = 8; 113 break; 114 115 case RPI_FWREQ_SET_CLOCK_STATE: 116 qemu_log_mask(LOG_UNIMP, 117 "bcm2835_property: 0x%08x set clock state NYI\n", 118 tag); 119 resplen = 8; 120 break; 121 122 case RPI_FWREQ_GET_CLOCK_RATE: 123 case RPI_FWREQ_GET_MAX_CLOCK_RATE: 124 case RPI_FWREQ_GET_MIN_CLOCK_RATE: 125 switch (ldl_le_phys(&s->dma_as, value + 12)) { 126 case RPI_FIRMWARE_EMMC_CLK_ID: 127 stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_EMMC_CLK_RATE); 128 break; 129 case RPI_FIRMWARE_UART_CLK_ID: 130 stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_UART_CLK_RATE); 131 break; 132 case RPI_FIRMWARE_CORE_CLK_ID: 133 stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_CORE_CLK_RATE); 134 break; 135 default: 136 stl_le_phys(&s->dma_as, value + 16, 137 RPI_FIRMWARE_DEFAULT_CLK_RATE); 138 break; 139 } 140 resplen = 8; 141 break; 142 143 case RPI_FWREQ_GET_CLOCKS: 144 /* TODO: add more clock IDs if needed */ 145 stl_le_phys(&s->dma_as, value + 12, 0); 146 stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_ARM_CLK_ID); 147 resplen = 8; 148 break; 149 150 case RPI_FWREQ_SET_CLOCK_RATE: 151 case RPI_FWREQ_SET_MAX_CLOCK_RATE: 152 case RPI_FWREQ_SET_MIN_CLOCK_RATE: 153 qemu_log_mask(LOG_UNIMP, 154 "bcm2835_property: 0x%08x set clock rate NYI\n", 155 tag); 156 resplen = 8; 157 break; 158 159 /* Temperature */ 160 161 case RPI_FWREQ_GET_TEMPERATURE: 162 stl_le_phys(&s->dma_as, value + 16, 25000); 163 resplen = 8; 164 break; 165 166 case RPI_FWREQ_GET_MAX_TEMPERATURE: 167 stl_le_phys(&s->dma_as, value + 16, 99000); 168 resplen = 8; 169 break; 170 171 /* Frame buffer */ 172 173 case RPI_FWREQ_FRAMEBUFFER_ALLOCATE: 174 stl_le_phys(&s->dma_as, value + 12, fbconfig.base); 175 stl_le_phys(&s->dma_as, value + 16, 176 bcm2835_fb_get_size(&fbconfig)); 177 resplen = 8; 178 break; 179 case RPI_FWREQ_FRAMEBUFFER_RELEASE: 180 resplen = 0; 181 break; 182 case RPI_FWREQ_FRAMEBUFFER_BLANK: 183 resplen = 4; 184 break; 185 case RPI_FWREQ_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT: 186 case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT: 187 resplen = 8; 188 break; 189 case RPI_FWREQ_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT: 190 fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12); 191 fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16); 192 bcm2835_fb_validate_config(&fbconfig); 193 fbconfig_updated = true; 194 /* fall through */ 195 case RPI_FWREQ_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT: 196 stl_le_phys(&s->dma_as, value + 12, fbconfig.xres); 197 stl_le_phys(&s->dma_as, value + 16, fbconfig.yres); 198 resplen = 8; 199 break; 200 case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT: 201 fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12); 202 fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16); 203 bcm2835_fb_validate_config(&fbconfig); 204 fbconfig_updated = true; 205 /* fall through */ 206 case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT: 207 stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual); 208 stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual); 209 resplen = 8; 210 break; 211 case RPI_FWREQ_FRAMEBUFFER_TEST_DEPTH: 212 resplen = 4; 213 break; 214 case RPI_FWREQ_FRAMEBUFFER_SET_DEPTH: 215 fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12); 216 bcm2835_fb_validate_config(&fbconfig); 217 fbconfig_updated = true; 218 /* fall through */ 219 case RPI_FWREQ_FRAMEBUFFER_GET_DEPTH: 220 stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp); 221 resplen = 4; 222 break; 223 case RPI_FWREQ_FRAMEBUFFER_TEST_PIXEL_ORDER: 224 resplen = 4; 225 break; 226 case RPI_FWREQ_FRAMEBUFFER_SET_PIXEL_ORDER: 227 fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12); 228 bcm2835_fb_validate_config(&fbconfig); 229 fbconfig_updated = true; 230 /* fall through */ 231 case RPI_FWREQ_FRAMEBUFFER_GET_PIXEL_ORDER: 232 stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo); 233 resplen = 4; 234 break; 235 case RPI_FWREQ_FRAMEBUFFER_TEST_ALPHA_MODE: 236 resplen = 4; 237 break; 238 case RPI_FWREQ_FRAMEBUFFER_SET_ALPHA_MODE: 239 fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12); 240 bcm2835_fb_validate_config(&fbconfig); 241 fbconfig_updated = true; 242 /* fall through */ 243 case RPI_FWREQ_FRAMEBUFFER_GET_ALPHA_MODE: 244 stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha); 245 resplen = 4; 246 break; 247 case RPI_FWREQ_FRAMEBUFFER_GET_PITCH: 248 stl_le_phys(&s->dma_as, value + 12, 249 bcm2835_fb_get_pitch(&fbconfig)); 250 resplen = 4; 251 break; 252 case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_OFFSET: 253 resplen = 8; 254 break; 255 case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_OFFSET: 256 fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12); 257 fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16); 258 bcm2835_fb_validate_config(&fbconfig); 259 fbconfig_updated = true; 260 /* fall through */ 261 case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_OFFSET: 262 stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset); 263 stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset); 264 resplen = 8; 265 break; 266 case RPI_FWREQ_FRAMEBUFFER_GET_OVERSCAN: 267 case RPI_FWREQ_FRAMEBUFFER_TEST_OVERSCAN: 268 case RPI_FWREQ_FRAMEBUFFER_SET_OVERSCAN: 269 stl_le_phys(&s->dma_as, value + 12, 0); 270 stl_le_phys(&s->dma_as, value + 16, 0); 271 stl_le_phys(&s->dma_as, value + 20, 0); 272 stl_le_phys(&s->dma_as, value + 24, 0); 273 resplen = 16; 274 break; 275 case RPI_FWREQ_FRAMEBUFFER_SET_PALETTE: 276 offset = ldl_le_phys(&s->dma_as, value + 12); 277 length = ldl_le_phys(&s->dma_as, value + 16); 278 n = 0; 279 while (n < length - offset) { 280 color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2)); 281 stl_le_phys(&s->dma_as, 282 s->fbdev->vcram_base + ((offset + n) << 2), color); 283 n++; 284 } 285 stl_le_phys(&s->dma_as, value + 12, 0); 286 resplen = 4; 287 break; 288 289 case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS: 290 stl_le_phys(&s->dma_as, value + 12, 1); 291 resplen = 4; 292 break; 293 294 case RPI_FWREQ_GET_DMA_CHANNELS: 295 /* channels 2-5 */ 296 stl_le_phys(&s->dma_as, value + 12, 0x003C); 297 resplen = 4; 298 break; 299 300 case RPI_FWREQ_GET_COMMAND_LINE: 301 /* 302 * We follow the firmware behaviour: no NUL terminator is 303 * written to the buffer, and if the buffer is too short 304 * we report the required length in the response header 305 * and copy nothing to the buffer. 306 */ 307 resplen = strlen(s->command_line); 308 if (bufsize >= resplen) 309 address_space_write(&s->dma_as, value + 12, 310 MEMTXATTRS_UNSPECIFIED, s->command_line, 311 resplen); 312 break; 313 314 case RPI_FWREQ_GET_THROTTLED: 315 stl_le_phys(&s->dma_as, value + 12, 0); 316 resplen = 4; 317 break; 318 319 case RPI_FWREQ_VCHIQ_INIT: 320 stl_le_phys(&s->dma_as, 321 value + offsetof(rpi_firmware_prop_request_t, payload), 322 0); 323 resplen = VCHI_BUSADDR_SIZE; 324 break; 325 default: 326 qemu_log_mask(LOG_UNIMP, 327 "bcm2835_property: unhandled tag 0x%08x\n", tag); 328 break; 329 } 330 331 trace_bcm2835_mbox_property(tag, bufsize, resplen); 332 if (tag == 0) { 333 break; 334 } 335 336 stl_le_phys(&s->dma_as, value + 8, (1 << 31) | resplen); 337 value += bufsize + 12; 338 } 339 340 /* Reconfigure framebuffer if required */ 341 if (fbconfig_updated) { 342 bcm2835_fb_reconfigure(s->fbdev, &fbconfig); 343 } 344 345 /* Buffer response code */ 346 stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31)); 347 } 348 349 static uint64_t bcm2835_property_read(void *opaque, hwaddr offset, 350 unsigned size) 351 { 352 BCM2835PropertyState *s = opaque; 353 uint32_t res = 0; 354 355 switch (offset) { 356 case MBOX_AS_DATA: 357 res = MBOX_CHAN_PROPERTY | s->addr; 358 s->pending = false; 359 qemu_set_irq(s->mbox_irq, 0); 360 break; 361 362 case MBOX_AS_PENDING: 363 res = s->pending; 364 break; 365 366 default: 367 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 368 __func__, offset); 369 return 0; 370 } 371 372 return res; 373 } 374 375 static void bcm2835_property_write(void *opaque, hwaddr offset, 376 uint64_t value, unsigned size) 377 { 378 BCM2835PropertyState *s = opaque; 379 380 switch (offset) { 381 case MBOX_AS_DATA: 382 /* bcm2835_mbox should check our pending status before pushing */ 383 assert(!s->pending); 384 s->pending = true; 385 bcm2835_property_mbox_push(s, value); 386 qemu_set_irq(s->mbox_irq, 1); 387 break; 388 389 default: 390 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 391 __func__, offset); 392 return; 393 } 394 } 395 396 static const MemoryRegionOps bcm2835_property_ops = { 397 .read = bcm2835_property_read, 398 .write = bcm2835_property_write, 399 .endianness = DEVICE_NATIVE_ENDIAN, 400 .valid.min_access_size = 4, 401 .valid.max_access_size = 4, 402 }; 403 404 static const VMStateDescription vmstate_bcm2835_property = { 405 .name = TYPE_BCM2835_PROPERTY, 406 .version_id = 1, 407 .minimum_version_id = 1, 408 .fields = (const VMStateField[]) { 409 VMSTATE_MACADDR(macaddr, BCM2835PropertyState), 410 VMSTATE_UINT32(addr, BCM2835PropertyState), 411 VMSTATE_BOOL(pending, BCM2835PropertyState), 412 VMSTATE_END_OF_LIST() 413 } 414 }; 415 416 static void bcm2835_property_init(Object *obj) 417 { 418 BCM2835PropertyState *s = BCM2835_PROPERTY(obj); 419 420 memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s, 421 TYPE_BCM2835_PROPERTY, 0x10); 422 423 /* 424 * bcm2835_property_ops call into bcm2835_mbox, which in-turn reads from 425 * iomem. As such, mark iomem as re-entracy safe. 426 */ 427 s->iomem.disable_reentrancy_guard = true; 428 429 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 430 sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq); 431 } 432 433 static void bcm2835_property_reset(DeviceState *dev) 434 { 435 BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 436 437 s->pending = false; 438 } 439 440 static void bcm2835_property_realize(DeviceState *dev, Error **errp) 441 { 442 BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 443 Object *obj; 444 445 obj = object_property_get_link(OBJECT(dev), "fb", &error_abort); 446 s->fbdev = BCM2835_FB(obj); 447 448 obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort); 449 s->dma_mr = MEMORY_REGION(obj); 450 address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_PROPERTY "-memory"); 451 452 /* TODO: connect to MAC address of USB NIC device, once we emulate it */ 453 qemu_macaddr_default_if_unset(&s->macaddr); 454 455 bcm2835_property_reset(dev); 456 } 457 458 static Property bcm2835_property_props[] = { 459 DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0), 460 DEFINE_PROP_STRING("command-line", BCM2835PropertyState, command_line), 461 DEFINE_PROP_END_OF_LIST() 462 }; 463 464 static void bcm2835_property_class_init(ObjectClass *klass, void *data) 465 { 466 DeviceClass *dc = DEVICE_CLASS(klass); 467 468 device_class_set_props(dc, bcm2835_property_props); 469 dc->realize = bcm2835_property_realize; 470 dc->vmsd = &vmstate_bcm2835_property; 471 } 472 473 static const TypeInfo bcm2835_property_info = { 474 .name = TYPE_BCM2835_PROPERTY, 475 .parent = TYPE_SYS_BUS_DEVICE, 476 .instance_size = sizeof(BCM2835PropertyState), 477 .class_init = bcm2835_property_class_init, 478 .instance_init = bcm2835_property_init, 479 }; 480 481 static void bcm2835_property_register_types(void) 482 { 483 type_register_static(&bcm2835_property_info); 484 } 485 486 type_init(bcm2835_property_register_types) 487