2
* Raspberry Pi emulation (c) 2012 Gregory Estrade
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.
10
#include "hw/misc/bcm2835_property.h"
11
#include "hw/qdev-properties.h"
12
#include "migration/vmstate.h"
14
#include "hw/misc/bcm2835_mbox_defs.h"
15
#include "hw/arm/raspberrypi-fw-defs.h"
16
#include "sysemu/dma.h"
18
#include "qemu/module.h"
20
#include "hw/arm/raspi_platform.h"
22
#define VCHI_BUSADDR_SIZE sizeof(uint32_t)
24
/* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */
26
static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
31
* Copy the current state of the framebuffer config; we will update
32
* this copy as we process tags and then ask the framebuffer to use
35
BCM2835FBConfig fbconfig = s->fbdev->config;
36
bool fbconfig_updated = false;
42
tot_len = ldl_le_phys(&s->dma_as, value);
44
/* @(addr + 4) : Buffer response code */
46
while (value + 8 <= s->addr + tot_len) {
47
uint32_t tag = ldl_le_phys(&s->dma_as, value);
48
uint32_t bufsize = ldl_le_phys(&s->dma_as, value + 4);
49
/* @(value + 8) : Request/response indicator */
52
case RPI_FWREQ_PROPERTY_END:
54
case RPI_FWREQ_GET_FIRMWARE_REVISION:
55
stl_le_phys(&s->dma_as, value + 12, 346337);
58
case RPI_FWREQ_GET_BOARD_MODEL:
59
qemu_log_mask(LOG_UNIMP,
60
"bcm2835_property: 0x%08x get board model NYI\n",
64
case RPI_FWREQ_GET_BOARD_REVISION:
65
stl_le_phys(&s->dma_as, value + 12, s->board_rev);
68
case RPI_FWREQ_GET_BOARD_MAC_ADDRESS:
69
resplen = sizeof(s->macaddr.a);
70
dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen,
71
MEMTXATTRS_UNSPECIFIED);
73
case RPI_FWREQ_GET_BOARD_SERIAL:
74
qemu_log_mask(LOG_UNIMP,
75
"bcm2835_property: 0x%08x get board serial NYI\n",
79
case RPI_FWREQ_GET_ARM_MEMORY:
81
stl_le_phys(&s->dma_as, value + 12, 0);
83
stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_base);
86
case RPI_FWREQ_GET_VC_MEMORY:
88
stl_le_phys(&s->dma_as, value + 12, s->fbdev->vcram_base);
90
stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size);
93
case RPI_FWREQ_SET_POWER_STATE:
96
* Assume that whatever device they asked for exists,
97
* and we'll just claim we set it to the desired state.
99
uint32_t state = ldl_le_phys(&s->dma_as, value + 16);
100
stl_le_phys(&s->dma_as, value + 16, (state & 1));
107
case RPI_FWREQ_GET_CLOCK_STATE:
108
stl_le_phys(&s->dma_as, value + 16, 0x1);
112
case RPI_FWREQ_SET_CLOCK_STATE:
113
qemu_log_mask(LOG_UNIMP,
114
"bcm2835_property: 0x%08x set clock state NYI\n",
119
case RPI_FWREQ_GET_CLOCK_RATE:
120
case RPI_FWREQ_GET_MAX_CLOCK_RATE:
121
case RPI_FWREQ_GET_MIN_CLOCK_RATE:
122
switch (ldl_le_phys(&s->dma_as, value + 12)) {
123
case RPI_FIRMWARE_EMMC_CLK_ID:
124
stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_EMMC_CLK_RATE);
126
case RPI_FIRMWARE_UART_CLK_ID:
127
stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_UART_CLK_RATE);
129
case RPI_FIRMWARE_CORE_CLK_ID:
130
stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_CORE_CLK_RATE);
133
stl_le_phys(&s->dma_as, value + 16,
134
RPI_FIRMWARE_DEFAULT_CLK_RATE);
140
case RPI_FWREQ_GET_CLOCKS:
141
/* TODO: add more clock IDs if needed */
142
stl_le_phys(&s->dma_as, value + 12, 0);
143
stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_ARM_CLK_ID);
147
case RPI_FWREQ_SET_CLOCK_RATE:
148
case RPI_FWREQ_SET_MAX_CLOCK_RATE:
149
case RPI_FWREQ_SET_MIN_CLOCK_RATE:
150
qemu_log_mask(LOG_UNIMP,
151
"bcm2835_property: 0x%08x set clock rate NYI\n",
158
case RPI_FWREQ_GET_TEMPERATURE:
159
stl_le_phys(&s->dma_as, value + 16, 25000);
163
case RPI_FWREQ_GET_MAX_TEMPERATURE:
164
stl_le_phys(&s->dma_as, value + 16, 99000);
170
case RPI_FWREQ_FRAMEBUFFER_ALLOCATE:
171
stl_le_phys(&s->dma_as, value + 12, fbconfig.base);
172
stl_le_phys(&s->dma_as, value + 16,
173
bcm2835_fb_get_size(&fbconfig));
176
case RPI_FWREQ_FRAMEBUFFER_RELEASE:
179
case RPI_FWREQ_FRAMEBUFFER_BLANK:
182
case RPI_FWREQ_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT:
183
case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT:
186
case RPI_FWREQ_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT:
187
fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12);
188
fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16);
189
bcm2835_fb_validate_config(&fbconfig);
190
fbconfig_updated = true;
192
case RPI_FWREQ_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT:
193
stl_le_phys(&s->dma_as, value + 12, fbconfig.xres);
194
stl_le_phys(&s->dma_as, value + 16, fbconfig.yres);
197
case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT:
198
fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12);
199
fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16);
200
bcm2835_fb_validate_config(&fbconfig);
201
fbconfig_updated = true;
203
case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT:
204
stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual);
205
stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual);
208
case RPI_FWREQ_FRAMEBUFFER_TEST_DEPTH:
211
case RPI_FWREQ_FRAMEBUFFER_SET_DEPTH:
212
fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12);
213
bcm2835_fb_validate_config(&fbconfig);
214
fbconfig_updated = true;
216
case RPI_FWREQ_FRAMEBUFFER_GET_DEPTH:
217
stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp);
220
case RPI_FWREQ_FRAMEBUFFER_TEST_PIXEL_ORDER:
223
case RPI_FWREQ_FRAMEBUFFER_SET_PIXEL_ORDER:
224
fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12);
225
bcm2835_fb_validate_config(&fbconfig);
226
fbconfig_updated = true;
228
case RPI_FWREQ_FRAMEBUFFER_GET_PIXEL_ORDER:
229
stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo);
232
case RPI_FWREQ_FRAMEBUFFER_TEST_ALPHA_MODE:
235
case RPI_FWREQ_FRAMEBUFFER_SET_ALPHA_MODE:
236
fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12);
237
bcm2835_fb_validate_config(&fbconfig);
238
fbconfig_updated = true;
240
case RPI_FWREQ_FRAMEBUFFER_GET_ALPHA_MODE:
241
stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha);
244
case RPI_FWREQ_FRAMEBUFFER_GET_PITCH:
245
stl_le_phys(&s->dma_as, value + 12,
246
bcm2835_fb_get_pitch(&fbconfig));
249
case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_OFFSET:
252
case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_OFFSET:
253
fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12);
254
fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16);
255
bcm2835_fb_validate_config(&fbconfig);
256
fbconfig_updated = true;
258
case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_OFFSET:
259
stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset);
260
stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset);
263
case RPI_FWREQ_FRAMEBUFFER_GET_OVERSCAN:
264
case RPI_FWREQ_FRAMEBUFFER_TEST_OVERSCAN:
265
case RPI_FWREQ_FRAMEBUFFER_SET_OVERSCAN:
266
stl_le_phys(&s->dma_as, value + 12, 0);
267
stl_le_phys(&s->dma_as, value + 16, 0);
268
stl_le_phys(&s->dma_as, value + 20, 0);
269
stl_le_phys(&s->dma_as, value + 24, 0);
272
case RPI_FWREQ_FRAMEBUFFER_SET_PALETTE:
274
uint32_t offset = ldl_le_phys(&s->dma_as, value + 12);
275
uint32_t length = ldl_le_phys(&s->dma_as, value + 16);
278
if (offset > 255 || length < 1 || length > 256) {
279
resp = 1; /* invalid request */
281
for (uint32_t e = 0; e < length; e++) {
282
uint32_t color = ldl_le_phys(&s->dma_as, value + 20 + (e << 2));
283
stl_le_phys(&s->dma_as,
284
s->fbdev->vcram_base + ((offset + e) << 2), color);
288
stl_le_phys(&s->dma_as, value + 12, resp);
292
case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS:
293
stl_le_phys(&s->dma_as, value + 12, 1);
297
case RPI_FWREQ_GET_DMA_CHANNELS:
299
stl_le_phys(&s->dma_as, value + 12, 0x003C);
303
case RPI_FWREQ_GET_COMMAND_LINE:
305
* We follow the firmware behaviour: no NUL terminator is
306
* written to the buffer, and if the buffer is too short
307
* we report the required length in the response header
308
* and copy nothing to the buffer.
310
resplen = strlen(s->command_line);
311
if (bufsize >= resplen)
312
address_space_write(&s->dma_as, value + 12,
313
MEMTXATTRS_UNSPECIFIED, s->command_line,
317
case RPI_FWREQ_GET_THROTTLED:
318
stl_le_phys(&s->dma_as, value + 12, 0);
322
case RPI_FWREQ_VCHIQ_INIT:
323
stl_le_phys(&s->dma_as,
324
value + offsetof(rpi_firmware_prop_request_t, payload),
326
resplen = VCHI_BUSADDR_SIZE;
331
case RPI_FWREQ_GET_CUSTOMER_OTP:
333
uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
334
uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
336
resplen = 8 + 4 * number;
338
for (uint32_t n = start_num; n < start_num + number &&
339
n < BCM2835_OTP_CUSTOMER_OTP_LEN; n++) {
340
uint32_t otp_row = bcm2835_otp_get_row(s->otp,
341
BCM2835_OTP_CUSTOMER_OTP + n);
342
stl_le_phys(&s->dma_as,
343
value + 20 + ((n - start_num) << 2), otp_row);
347
case RPI_FWREQ_SET_CUSTOMER_OTP:
349
uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
350
uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
354
/* Magic numbers to permanently lock customer OTP */
355
if (start_num == BCM2835_OTP_LOCK_NUM1 &&
356
number == BCM2835_OTP_LOCK_NUM2) {
357
bcm2835_otp_set_row(s->otp,
359
BCM2835_OTP_ROW_32_LOCK);
363
/* If row 32 has the lock bit, don't allow further writes */
364
if (bcm2835_otp_get_row(s->otp, BCM2835_OTP_ROW_32) &
365
BCM2835_OTP_ROW_32_LOCK) {
369
for (uint32_t n = start_num; n < start_num + number &&
370
n < BCM2835_OTP_CUSTOMER_OTP_LEN; n++) {
371
uint32_t otp_row = ldl_le_phys(&s->dma_as,
372
value + 20 + ((n - start_num) << 2));
373
bcm2835_otp_set_row(s->otp,
374
BCM2835_OTP_CUSTOMER_OTP + n, otp_row);
379
/* Device-specific private key */
380
case RPI_FWREQ_GET_PRIVATE_KEY:
382
uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
383
uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
385
resplen = 8 + 4 * number;
387
for (uint32_t n = start_num; n < start_num + number &&
388
n < BCM2835_OTP_PRIVATE_KEY_LEN; n++) {
389
uint32_t otp_row = bcm2835_otp_get_row(s->otp,
390
BCM2835_OTP_PRIVATE_KEY + n);
391
stl_le_phys(&s->dma_as,
392
value + 20 + ((n - start_num) << 2), otp_row);
396
case RPI_FWREQ_SET_PRIVATE_KEY:
398
uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
399
uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
403
/* If row 32 has the lock bit, don't allow further writes */
404
if (bcm2835_otp_get_row(s->otp, BCM2835_OTP_ROW_32) &
405
BCM2835_OTP_ROW_32_LOCK) {
409
for (uint32_t n = start_num; n < start_num + number &&
410
n < BCM2835_OTP_PRIVATE_KEY_LEN; n++) {
411
uint32_t otp_row = ldl_le_phys(&s->dma_as,
412
value + 20 + ((n - start_num) << 2));
413
bcm2835_otp_set_row(s->otp,
414
BCM2835_OTP_PRIVATE_KEY + n, otp_row);
419
qemu_log_mask(LOG_UNIMP,
420
"bcm2835_property: unhandled tag 0x%08x\n", tag);
424
trace_bcm2835_mbox_property(tag, bufsize, resplen);
429
stl_le_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
430
value += bufsize + 12;
433
/* Reconfigure framebuffer if required */
434
if (fbconfig_updated) {
435
bcm2835_fb_reconfigure(s->fbdev, &fbconfig);
438
/* Buffer response code */
439
stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31));
442
static uint64_t bcm2835_property_read(void *opaque, hwaddr offset,
445
BCM2835PropertyState *s = opaque;
450
res = MBOX_CHAN_PROPERTY | s->addr;
452
qemu_set_irq(s->mbox_irq, 0);
455
case MBOX_AS_PENDING:
460
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
468
static void bcm2835_property_write(void *opaque, hwaddr offset,
469
uint64_t value, unsigned size)
471
BCM2835PropertyState *s = opaque;
475
/* bcm2835_mbox should check our pending status before pushing */
478
bcm2835_property_mbox_push(s, value);
479
qemu_set_irq(s->mbox_irq, 1);
483
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
489
static const MemoryRegionOps bcm2835_property_ops = {
490
.read = bcm2835_property_read,
491
.write = bcm2835_property_write,
492
.endianness = DEVICE_NATIVE_ENDIAN,
493
.valid.min_access_size = 4,
494
.valid.max_access_size = 4,
497
static const VMStateDescription vmstate_bcm2835_property = {
498
.name = TYPE_BCM2835_PROPERTY,
500
.minimum_version_id = 1,
501
.fields = (const VMStateField[]) {
502
VMSTATE_MACADDR(macaddr, BCM2835PropertyState),
503
VMSTATE_UINT32(addr, BCM2835PropertyState),
504
VMSTATE_BOOL(pending, BCM2835PropertyState),
505
VMSTATE_END_OF_LIST()
509
static void bcm2835_property_init(Object *obj)
511
BCM2835PropertyState *s = BCM2835_PROPERTY(obj);
513
memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s,
514
TYPE_BCM2835_PROPERTY, 0x10);
517
* bcm2835_property_ops call into bcm2835_mbox, which in-turn reads from
518
* iomem. As such, mark iomem as re-entracy safe.
520
s->iomem.disable_reentrancy_guard = true;
522
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
523
sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq);
526
static void bcm2835_property_reset(DeviceState *dev)
528
BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
533
static void bcm2835_property_realize(DeviceState *dev, Error **errp)
535
BCM2835PropertyState *s = BCM2835_PROPERTY(dev);
538
obj = object_property_get_link(OBJECT(dev), "fb", &error_abort);
539
s->fbdev = BCM2835_FB(obj);
541
obj = object_property_get_link(OBJECT(dev), "dma-mr", &error_abort);
542
s->dma_mr = MEMORY_REGION(obj);
543
address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_PROPERTY "-memory");
545
obj = object_property_get_link(OBJECT(dev), "otp", &error_abort);
546
s->otp = BCM2835_OTP(obj);
548
/* TODO: connect to MAC address of USB NIC device, once we emulate it */
549
qemu_macaddr_default_if_unset(&s->macaddr);
551
bcm2835_property_reset(dev);
554
static Property bcm2835_property_props[] = {
555
DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0),
556
DEFINE_PROP_STRING("command-line", BCM2835PropertyState, command_line),
557
DEFINE_PROP_END_OF_LIST()
560
static void bcm2835_property_class_init(ObjectClass *klass, void *data)
562
DeviceClass *dc = DEVICE_CLASS(klass);
564
device_class_set_props(dc, bcm2835_property_props);
565
dc->realize = bcm2835_property_realize;
566
dc->vmsd = &vmstate_bcm2835_property;
569
static const TypeInfo bcm2835_property_info = {
570
.name = TYPE_BCM2835_PROPERTY,
571
.parent = TYPE_SYS_BUS_DEVICE,
572
.instance_size = sizeof(BCM2835PropertyState),
573
.class_init = bcm2835_property_class_init,
574
.instance_init = bcm2835_property_init,
577
static void bcm2835_property_register_types(void)
579
type_register_static(&bcm2835_property_info);
582
type_init(bcm2835_property_register_types)