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/misc/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 default: 131 stl_le_phys(&s->dma_as, value + 16, 132 RPI_FIRMWARE_DEFAULT_CLK_RATE); 133 break; 134 } 135 resplen = 8; 136 break; 137 138 case RPI_FWREQ_SET_CLOCK_RATE: 139 case RPI_FWREQ_SET_MAX_CLOCK_RATE: 140 case RPI_FWREQ_SET_MIN_CLOCK_RATE: 141 qemu_log_mask(LOG_UNIMP, 142 "bcm2835_property: 0x%08x set clock rate NYI\n", 143 tag); 144 resplen = 8; 145 break; 146 147 /* Temperature */ 148 149 case RPI_FWREQ_GET_TEMPERATURE: 150 stl_le_phys(&s->dma_as, value + 16, 25000); 151 resplen = 8; 152 break; 153 154 case RPI_FWREQ_GET_MAX_TEMPERATURE: 155 stl_le_phys(&s->dma_as, value + 16, 99000); 156 resplen = 8; 157 break; 158 159 /* Frame buffer */ 160 161 case RPI_FWREQ_FRAMEBUFFER_ALLOCATE: 162 stl_le_phys(&s->dma_as, value + 12, fbconfig.base); 163 stl_le_phys(&s->dma_as, value + 16, 164 bcm2835_fb_get_size(&fbconfig)); 165 resplen = 8; 166 break; 167 case RPI_FWREQ_FRAMEBUFFER_RELEASE: 168 resplen = 0; 169 break; 170 case RPI_FWREQ_FRAMEBUFFER_BLANK: 171 resplen = 4; 172 break; 173 case RPI_FWREQ_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT: 174 case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT: 175 resplen = 8; 176 break; 177 case RPI_FWREQ_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT: 178 fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12); 179 fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16); 180 bcm2835_fb_validate_config(&fbconfig); 181 fbconfig_updated = true; 182 /* fall through */ 183 case RPI_FWREQ_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT: 184 stl_le_phys(&s->dma_as, value + 12, fbconfig.xres); 185 stl_le_phys(&s->dma_as, value + 16, fbconfig.yres); 186 resplen = 8; 187 break; 188 case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT: 189 fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12); 190 fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16); 191 bcm2835_fb_validate_config(&fbconfig); 192 fbconfig_updated = true; 193 /* fall through */ 194 case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT: 195 stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual); 196 stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual); 197 resplen = 8; 198 break; 199 case RPI_FWREQ_FRAMEBUFFER_TEST_DEPTH: 200 resplen = 4; 201 break; 202 case RPI_FWREQ_FRAMEBUFFER_SET_DEPTH: 203 fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12); 204 bcm2835_fb_validate_config(&fbconfig); 205 fbconfig_updated = true; 206 /* fall through */ 207 case RPI_FWREQ_FRAMEBUFFER_GET_DEPTH: 208 stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp); 209 resplen = 4; 210 break; 211 case RPI_FWREQ_FRAMEBUFFER_TEST_PIXEL_ORDER: 212 resplen = 4; 213 break; 214 case RPI_FWREQ_FRAMEBUFFER_SET_PIXEL_ORDER: 215 fbconfig.pixo = 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_PIXEL_ORDER: 220 stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo); 221 resplen = 4; 222 break; 223 case RPI_FWREQ_FRAMEBUFFER_TEST_ALPHA_MODE: 224 resplen = 4; 225 break; 226 case RPI_FWREQ_FRAMEBUFFER_SET_ALPHA_MODE: 227 fbconfig.alpha = 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_ALPHA_MODE: 232 stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha); 233 resplen = 4; 234 break; 235 case RPI_FWREQ_FRAMEBUFFER_GET_PITCH: 236 stl_le_phys(&s->dma_as, value + 12, 237 bcm2835_fb_get_pitch(&fbconfig)); 238 resplen = 4; 239 break; 240 case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_OFFSET: 241 resplen = 8; 242 break; 243 case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_OFFSET: 244 fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12); 245 fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16); 246 bcm2835_fb_validate_config(&fbconfig); 247 fbconfig_updated = true; 248 /* fall through */ 249 case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_OFFSET: 250 stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset); 251 stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset); 252 resplen = 8; 253 break; 254 case RPI_FWREQ_FRAMEBUFFER_GET_OVERSCAN: 255 case RPI_FWREQ_FRAMEBUFFER_TEST_OVERSCAN: 256 case RPI_FWREQ_FRAMEBUFFER_SET_OVERSCAN: 257 stl_le_phys(&s->dma_as, value + 12, 0); 258 stl_le_phys(&s->dma_as, value + 16, 0); 259 stl_le_phys(&s->dma_as, value + 20, 0); 260 stl_le_phys(&s->dma_as, value + 24, 0); 261 resplen = 16; 262 break; 263 case RPI_FWREQ_FRAMEBUFFER_SET_PALETTE: 264 offset = ldl_le_phys(&s->dma_as, value + 12); 265 length = ldl_le_phys(&s->dma_as, value + 16); 266 n = 0; 267 while (n < length - offset) { 268 color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2)); 269 stl_le_phys(&s->dma_as, 270 s->fbdev->vcram_base + ((offset + n) << 2), color); 271 n++; 272 } 273 stl_le_phys(&s->dma_as, value + 12, 0); 274 resplen = 4; 275 break; 276 case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS: 277 stl_le_phys(&s->dma_as, value + 12, 1); 278 resplen = 4; 279 break; 280 281 case RPI_FWREQ_GET_DMA_CHANNELS: 282 /* channels 2-5 */ 283 stl_le_phys(&s->dma_as, value + 12, 0x003C); 284 resplen = 4; 285 break; 286 287 case RPI_FWREQ_GET_COMMAND_LINE: 288 /* 289 * We follow the firmware behaviour: no NUL terminator is 290 * written to the buffer, and if the buffer is too short 291 * we report the required length in the response header 292 * and copy nothing to the buffer. 293 */ 294 resplen = strlen(s->command_line); 295 if (bufsize >= resplen) 296 address_space_write(&s->dma_as, value + 12, 297 MEMTXATTRS_UNSPECIFIED, s->command_line, 298 resplen); 299 break; 300 301 default: 302 qemu_log_mask(LOG_UNIMP, 303 "bcm2835_property: unhandled tag 0x%08x\n", tag); 304 break; 305 } 306 307 trace_bcm2835_mbox_property(tag, bufsize, resplen); 308 if (tag == 0) { 309 break; 310 } 311 312 stl_le_phys(&s->dma_as, value + 8, (1 << 31) | resplen); 313 value += bufsize + 12; 314 } 315 316 /* Reconfigure framebuffer if required */ 317 if (fbconfig_updated) { 318 bcm2835_fb_reconfigure(s->fbdev, &fbconfig); 319 } 320 321 /* Buffer response code */ 322 stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31)); 323 } 324 325 static uint64_t bcm2835_property_read(void *opaque, hwaddr offset, 326 unsigned size) 327 { 328 BCM2835PropertyState *s = opaque; 329 uint32_t res = 0; 330 331 switch (offset) { 332 case MBOX_AS_DATA: 333 res = MBOX_CHAN_PROPERTY | s->addr; 334 s->pending = false; 335 qemu_set_irq(s->mbox_irq, 0); 336 break; 337 338 case MBOX_AS_PENDING: 339 res = s->pending; 340 break; 341 342 default: 343 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 344 __func__, offset); 345 return 0; 346 } 347 348 return res; 349 } 350 351 static void bcm2835_property_write(void *opaque, hwaddr offset, 352 uint64_t value, unsigned size) 353 { 354 BCM2835PropertyState *s = opaque; 355 356 switch (offset) { 357 case MBOX_AS_DATA: 358 /* bcm2835_mbox should check our pending status before pushing */ 359 assert(!s->pending); 360 s->pending = true; 361 bcm2835_property_mbox_push(s, value); 362 qemu_set_irq(s->mbox_irq, 1); 363 break; 364 365 default: 366 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 367 __func__, offset); 368 return; 369 } 370 } 371 372 static const MemoryRegionOps bcm2835_property_ops = { 373 .read = bcm2835_property_read, 374 .write = bcm2835_property_write, 375 .endianness = DEVICE_NATIVE_ENDIAN, 376 .valid.min_access_size = 4, 377 .valid.max_access_size = 4, 378 }; 379 380 static const VMStateDescription vmstate_bcm2835_property = { 381 .name = TYPE_BCM2835_PROPERTY, 382 .version_id = 1, 383 .minimum_version_id = 1, 384 .fields = (VMStateField[]) { 385 VMSTATE_MACADDR(macaddr, BCM2835PropertyState), 386 VMSTATE_UINT32(addr, BCM2835PropertyState), 387 VMSTATE_BOOL(pending, BCM2835PropertyState), 388 VMSTATE_END_OF_LIST() 389 } 390 }; 391 392 static void bcm2835_property_init(Object *obj) 393 { 394 BCM2835PropertyState *s = BCM2835_PROPERTY(obj); 395 396 memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s, 397 TYPE_BCM2835_PROPERTY, 0x10); 398 399 /* 400 * bcm2835_property_ops call into bcm2835_mbox, which in-turn reads from 401 * iomem. As such, mark iomem as re-entracy safe. 402 */ 403 s->iomem.disable_reentrancy_guard = true; 404 405 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 406 sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq); 407 } 408 409 static void bcm2835_property_reset(DeviceState *dev) 410 { 411 BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 412 413 s->pending = false; 414 } 415 416 static void bcm2835_property_realize(DeviceState *dev, Error **errp) 417 { 418 BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 419 Object *obj; 420 421 obj = object_property_get_link(OBJECT(dev), "fb", &error_abort); 422 s->fbdev = BCM2835_FB(obj); 423 424 obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort); 425 s->dma_mr = MEMORY_REGION(obj); 426 address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_PROPERTY "-memory"); 427 428 /* TODO: connect to MAC address of USB NIC device, once we emulate it */ 429 qemu_macaddr_default_if_unset(&s->macaddr); 430 431 bcm2835_property_reset(dev); 432 } 433 434 static Property bcm2835_property_props[] = { 435 DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0), 436 DEFINE_PROP_STRING("command-line", BCM2835PropertyState, command_line), 437 DEFINE_PROP_END_OF_LIST() 438 }; 439 440 static void bcm2835_property_class_init(ObjectClass *klass, void *data) 441 { 442 DeviceClass *dc = DEVICE_CLASS(klass); 443 444 device_class_set_props(dc, bcm2835_property_props); 445 dc->realize = bcm2835_property_realize; 446 dc->vmsd = &vmstate_bcm2835_property; 447 } 448 449 static const TypeInfo bcm2835_property_info = { 450 .name = TYPE_BCM2835_PROPERTY, 451 .parent = TYPE_SYS_BUS_DEVICE, 452 .instance_size = sizeof(BCM2835PropertyState), 453 .class_init = bcm2835_property_class_init, 454 .instance_init = bcm2835_property_init, 455 }; 456 457 static void bcm2835_property_register_types(void) 458 { 459 type_register_static(&bcm2835_property_info); 460 } 461 462 type_init(bcm2835_property_register_types) 463