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