1 /* 2 * Raspberry Pi emulation (c) 2012 Gregory Estrade 3 * This code is licensed under the GNU GPLv2 and later. 4 */ 5 6 #include "qemu/osdep.h" 7 #include "qapi/error.h" 8 #include "hw/misc/bcm2835_property.h" 9 #include "hw/misc/bcm2835_mbox_defs.h" 10 #include "sysemu/dma.h" 11 12 /* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ 13 14 static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) 15 { 16 uint32_t tag; 17 uint32_t bufsize; 18 uint32_t tot_len; 19 size_t resplen; 20 uint32_t tmp; 21 int n; 22 uint32_t offset, length, color; 23 uint32_t xres, yres, xoffset, yoffset, bpp, pixo, alpha; 24 uint32_t *newxres = NULL, *newyres = NULL, *newxoffset = NULL, 25 *newyoffset = NULL, *newbpp = NULL, *newpixo = NULL, *newalpha = NULL; 26 27 value &= ~0xf; 28 29 s->addr = value; 30 31 tot_len = ldl_le_phys(&s->dma_as, value); 32 33 /* @(addr + 4) : Buffer response code */ 34 value = s->addr + 8; 35 while (value + 8 <= s->addr + tot_len) { 36 tag = ldl_le_phys(&s->dma_as, value); 37 bufsize = ldl_le_phys(&s->dma_as, value + 4); 38 /* @(value + 8) : Request/response indicator */ 39 resplen = 0; 40 switch (tag) { 41 case 0x00000000: /* End tag */ 42 break; 43 case 0x00000001: /* Get firmware revision */ 44 stl_le_phys(&s->dma_as, value + 12, 346337); 45 resplen = 4; 46 break; 47 case 0x00010001: /* Get board model */ 48 qemu_log_mask(LOG_UNIMP, 49 "bcm2835_property: %x get board model NYI\n", tag); 50 resplen = 4; 51 break; 52 case 0x00010002: /* Get board revision */ 53 stl_le_phys(&s->dma_as, value + 12, s->board_rev); 54 resplen = 4; 55 break; 56 case 0x00010003: /* Get board MAC address */ 57 resplen = sizeof(s->macaddr.a); 58 dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen); 59 break; 60 case 0x00010004: /* Get board serial */ 61 qemu_log_mask(LOG_UNIMP, 62 "bcm2835_property: %x get board serial NYI\n", tag); 63 resplen = 8; 64 break; 65 case 0x00010005: /* Get ARM memory */ 66 /* base */ 67 stl_le_phys(&s->dma_as, value + 12, 0); 68 /* size */ 69 stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_base); 70 resplen = 8; 71 break; 72 case 0x00010006: /* Get VC memory */ 73 /* base */ 74 stl_le_phys(&s->dma_as, value + 12, s->fbdev->vcram_base); 75 /* size */ 76 stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size); 77 resplen = 8; 78 break; 79 case 0x00028001: /* Set power state */ 80 /* Assume that whatever device they asked for exists, 81 * and we'll just claim we set it to the desired state 82 */ 83 tmp = ldl_le_phys(&s->dma_as, value + 16); 84 stl_le_phys(&s->dma_as, value + 16, (tmp & 1)); 85 resplen = 8; 86 break; 87 88 /* Clocks */ 89 90 case 0x00030001: /* Get clock state */ 91 stl_le_phys(&s->dma_as, value + 16, 0x1); 92 resplen = 8; 93 break; 94 95 case 0x00038001: /* Set clock state */ 96 qemu_log_mask(LOG_UNIMP, 97 "bcm2835_property: %x set clock state NYI\n", tag); 98 resplen = 8; 99 break; 100 101 case 0x00030002: /* Get clock rate */ 102 case 0x00030004: /* Get max clock rate */ 103 case 0x00030007: /* Get min clock rate */ 104 switch (ldl_le_phys(&s->dma_as, value + 12)) { 105 case 1: /* EMMC */ 106 stl_le_phys(&s->dma_as, value + 16, 50000000); 107 break; 108 case 2: /* UART */ 109 stl_le_phys(&s->dma_as, value + 16, 3000000); 110 break; 111 default: 112 stl_le_phys(&s->dma_as, value + 16, 700000000); 113 break; 114 } 115 resplen = 8; 116 break; 117 118 case 0x00038002: /* Set clock rate */ 119 case 0x00038004: /* Set max clock rate */ 120 case 0x00038007: /* Set min clock rate */ 121 qemu_log_mask(LOG_UNIMP, 122 "bcm2835_property: %x set clock rates NYI\n", tag); 123 resplen = 8; 124 break; 125 126 /* Temperature */ 127 128 case 0x00030006: /* Get temperature */ 129 stl_le_phys(&s->dma_as, value + 16, 25000); 130 resplen = 8; 131 break; 132 133 case 0x0003000A: /* Get max temperature */ 134 stl_le_phys(&s->dma_as, value + 16, 99000); 135 resplen = 8; 136 break; 137 138 /* Frame buffer */ 139 140 case 0x00040001: /* Allocate buffer */ 141 stl_le_phys(&s->dma_as, value + 12, s->fbdev->base); 142 stl_le_phys(&s->dma_as, value + 16, s->fbdev->size); 143 resplen = 8; 144 break; 145 case 0x00048001: /* Release buffer */ 146 resplen = 0; 147 break; 148 case 0x00040002: /* Blank screen */ 149 resplen = 4; 150 break; 151 case 0x00040003: /* Get display width/height */ 152 case 0x00040004: 153 stl_le_phys(&s->dma_as, value + 12, s->fbdev->xres); 154 stl_le_phys(&s->dma_as, value + 16, s->fbdev->yres); 155 resplen = 8; 156 break; 157 case 0x00044003: /* Test display width/height */ 158 case 0x00044004: 159 resplen = 8; 160 break; 161 case 0x00048003: /* Set display width/height */ 162 case 0x00048004: 163 xres = ldl_le_phys(&s->dma_as, value + 12); 164 newxres = &xres; 165 yres = ldl_le_phys(&s->dma_as, value + 16); 166 newyres = &yres; 167 resplen = 8; 168 break; 169 case 0x00040005: /* Get depth */ 170 stl_le_phys(&s->dma_as, value + 12, s->fbdev->bpp); 171 resplen = 4; 172 break; 173 case 0x00044005: /* Test depth */ 174 resplen = 4; 175 break; 176 case 0x00048005: /* Set depth */ 177 bpp = ldl_le_phys(&s->dma_as, value + 12); 178 newbpp = &bpp; 179 resplen = 4; 180 break; 181 case 0x00040006: /* Get pixel order */ 182 stl_le_phys(&s->dma_as, value + 12, s->fbdev->pixo); 183 resplen = 4; 184 break; 185 case 0x00044006: /* Test pixel order */ 186 resplen = 4; 187 break; 188 case 0x00048006: /* Set pixel order */ 189 pixo = ldl_le_phys(&s->dma_as, value + 12); 190 newpixo = &pixo; 191 resplen = 4; 192 break; 193 case 0x00040007: /* Get alpha */ 194 stl_le_phys(&s->dma_as, value + 12, s->fbdev->alpha); 195 resplen = 4; 196 break; 197 case 0x00044007: /* Test pixel alpha */ 198 resplen = 4; 199 break; 200 case 0x00048007: /* Set alpha */ 201 alpha = ldl_le_phys(&s->dma_as, value + 12); 202 newalpha = α 203 resplen = 4; 204 break; 205 case 0x00040008: /* Get pitch */ 206 stl_le_phys(&s->dma_as, value + 12, s->fbdev->pitch); 207 resplen = 4; 208 break; 209 case 0x00040009: /* Get virtual offset */ 210 stl_le_phys(&s->dma_as, value + 12, s->fbdev->xoffset); 211 stl_le_phys(&s->dma_as, value + 16, s->fbdev->yoffset); 212 resplen = 8; 213 break; 214 case 0x00044009: /* Test virtual offset */ 215 resplen = 8; 216 break; 217 case 0x00048009: /* Set virtual offset */ 218 xoffset = ldl_le_phys(&s->dma_as, value + 12); 219 newxoffset = &xoffset; 220 yoffset = ldl_le_phys(&s->dma_as, value + 16); 221 newyoffset = &yoffset; 222 resplen = 8; 223 break; 224 case 0x0004000a: /* Get/Test/Set overscan */ 225 case 0x0004400a: 226 case 0x0004800a: 227 stl_le_phys(&s->dma_as, value + 12, 0); 228 stl_le_phys(&s->dma_as, value + 16, 0); 229 stl_le_phys(&s->dma_as, value + 20, 0); 230 stl_le_phys(&s->dma_as, value + 24, 0); 231 resplen = 16; 232 break; 233 case 0x0004800b: /* Set palette */ 234 offset = ldl_le_phys(&s->dma_as, value + 12); 235 length = ldl_le_phys(&s->dma_as, value + 16); 236 n = 0; 237 while (n < length - offset) { 238 color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2)); 239 stl_le_phys(&s->dma_as, 240 s->fbdev->vcram_base + ((offset + n) << 2), color); 241 n++; 242 } 243 stl_le_phys(&s->dma_as, value + 12, 0); 244 resplen = 4; 245 break; 246 247 case 0x00060001: /* Get DMA channels */ 248 /* channels 2-5 */ 249 stl_le_phys(&s->dma_as, value + 12, 0x003C); 250 resplen = 4; 251 break; 252 253 case 0x00050001: /* Get command line */ 254 resplen = 0; 255 break; 256 257 default: 258 qemu_log_mask(LOG_GUEST_ERROR, 259 "bcm2835_property: unhandled tag %08x\n", tag); 260 break; 261 } 262 263 if (tag == 0) { 264 break; 265 } 266 267 stl_le_phys(&s->dma_as, value + 8, (1 << 31) | resplen); 268 value += bufsize + 12; 269 } 270 271 /* Reconfigure framebuffer if required */ 272 if (newxres || newyres || newxoffset || newyoffset || newbpp || newpixo 273 || newalpha) { 274 bcm2835_fb_reconfigure(s->fbdev, newxres, newyres, newxoffset, 275 newyoffset, newbpp, newpixo, newalpha); 276 } 277 278 /* Buffer response code */ 279 stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31)); 280 } 281 282 static uint64_t bcm2835_property_read(void *opaque, hwaddr offset, 283 unsigned size) 284 { 285 BCM2835PropertyState *s = opaque; 286 uint32_t res = 0; 287 288 switch (offset) { 289 case MBOX_AS_DATA: 290 res = MBOX_CHAN_PROPERTY | s->addr; 291 s->pending = false; 292 qemu_set_irq(s->mbox_irq, 0); 293 break; 294 295 case MBOX_AS_PENDING: 296 res = s->pending; 297 break; 298 299 default: 300 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 301 __func__, offset); 302 return 0; 303 } 304 305 return res; 306 } 307 308 static void bcm2835_property_write(void *opaque, hwaddr offset, 309 uint64_t value, unsigned size) 310 { 311 BCM2835PropertyState *s = opaque; 312 313 switch (offset) { 314 case MBOX_AS_DATA: 315 /* bcm2835_mbox should check our pending status before pushing */ 316 assert(!s->pending); 317 s->pending = true; 318 bcm2835_property_mbox_push(s, value); 319 qemu_set_irq(s->mbox_irq, 1); 320 break; 321 322 default: 323 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 324 __func__, offset); 325 return; 326 } 327 } 328 329 static const MemoryRegionOps bcm2835_property_ops = { 330 .read = bcm2835_property_read, 331 .write = bcm2835_property_write, 332 .endianness = DEVICE_NATIVE_ENDIAN, 333 .valid.min_access_size = 4, 334 .valid.max_access_size = 4, 335 }; 336 337 static const VMStateDescription vmstate_bcm2835_property = { 338 .name = TYPE_BCM2835_PROPERTY, 339 .version_id = 1, 340 .minimum_version_id = 1, 341 .fields = (VMStateField[]) { 342 VMSTATE_MACADDR(macaddr, BCM2835PropertyState), 343 VMSTATE_UINT32(addr, BCM2835PropertyState), 344 VMSTATE_BOOL(pending, BCM2835PropertyState), 345 VMSTATE_END_OF_LIST() 346 } 347 }; 348 349 static void bcm2835_property_init(Object *obj) 350 { 351 BCM2835PropertyState *s = BCM2835_PROPERTY(obj); 352 353 memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s, 354 TYPE_BCM2835_PROPERTY, 0x10); 355 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 356 sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq); 357 } 358 359 static void bcm2835_property_reset(DeviceState *dev) 360 { 361 BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 362 363 s->pending = false; 364 } 365 366 static void bcm2835_property_realize(DeviceState *dev, Error **errp) 367 { 368 BCM2835PropertyState *s = BCM2835_PROPERTY(dev); 369 Object *obj; 370 Error *err = NULL; 371 372 obj = object_property_get_link(OBJECT(dev), "fb", &err); 373 if (obj == NULL) { 374 error_setg(errp, "%s: required fb link not found: %s", 375 __func__, error_get_pretty(err)); 376 return; 377 } 378 379 s->fbdev = BCM2835_FB(obj); 380 381 obj = object_property_get_link(OBJECT(dev), "dma-mr", &err); 382 if (obj == NULL) { 383 error_setg(errp, "%s: required dma-mr link not found: %s", 384 __func__, error_get_pretty(err)); 385 return; 386 } 387 388 s->dma_mr = MEMORY_REGION(obj); 389 address_space_init(&s->dma_as, s->dma_mr, NULL); 390 391 /* TODO: connect to MAC address of USB NIC device, once we emulate it */ 392 qemu_macaddr_default_if_unset(&s->macaddr); 393 394 bcm2835_property_reset(dev); 395 } 396 397 static Property bcm2835_property_props[] = { 398 DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0), 399 DEFINE_PROP_END_OF_LIST() 400 }; 401 402 static void bcm2835_property_class_init(ObjectClass *klass, void *data) 403 { 404 DeviceClass *dc = DEVICE_CLASS(klass); 405 406 dc->props = bcm2835_property_props; 407 dc->realize = bcm2835_property_realize; 408 dc->vmsd = &vmstate_bcm2835_property; 409 } 410 411 static TypeInfo bcm2835_property_info = { 412 .name = TYPE_BCM2835_PROPERTY, 413 .parent = TYPE_SYS_BUS_DEVICE, 414 .instance_size = sizeof(BCM2835PropertyState), 415 .class_init = bcm2835_property_class_init, 416 .instance_init = bcm2835_property_init, 417 }; 418 419 static void bcm2835_property_register_types(void) 420 { 421 type_register_static(&bcm2835_property_info); 422 } 423 424 type_init(bcm2835_property_register_types) 425