These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / hw / misc / bcm2835_property.c
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 = &alpha;
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)