minor style cleanups
[qemu/ar7.git] / hw / misc / bcm2835_property.c
blob5d7f3bad212a7763413a9a68ea60d988e6c14a5a
1 /*
2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
3 * This code is licensed under the GNU GPLv2 and later.
4 */
6 #include "hw/display/framebuffer.h"
7 #include "hw/sysbus.h"
8 #include "ui/console.h"
9 #include "ui/pixel_ops.h"
10 #include "exec/address-spaces.h"
11 #include "hw/arm/bcm2835_mbox.h"
12 #include "hw/display/bcm2835_fb.h"
14 #define TYPE_BCM2835_PROPERTY "bcm2835_property"
15 #define BCM2835_PROPERTY(obj) \
16 OBJECT_CHECK(Bcm2835PropertyState, (obj), TYPE_BCM2835_PROPERTY)
18 typedef struct {
19 SysBusDevice busdev;
20 MemoryRegion *dma_mr;
21 AddressSpace dma_as;
22 Bcm2835FbState *fbdev;
23 MemoryRegion iomem;
24 uint32_t addr;
25 int pending;
26 qemu_irq mbox_irq;
27 } Bcm2835PropertyState;
29 /* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */
31 static void bcm2835_property_mbox_push(Bcm2835PropertyState *s, uint32_t value)
33 uint32_t tag;
34 uint32_t bufsize;
35 uint32_t tot_len;
36 int n;
37 size_t resplen;
38 uint32_t offset, length, color;
39 uint32_t tmp;
40 uint32_t xres, yres, xoffset, yoffset, bpp, pixo, alpha;
41 uint32_t *newxres = NULL, *newyres = NULL, *newxoffset = NULL,
42 *newyoffset = NULL, *newbpp = NULL, *newpixo = NULL, *newalpha = NULL;
44 value &= ~0xf;
46 s->addr = value;
48 tot_len = ldl_phys(&s->dma_as, value);
50 /* @(addr + 4) : Buffer response code */
51 value = s->addr + 8;
52 while (value + 8 <= s->addr + tot_len) {
53 tag = ldl_phys(&s->dma_as, value);
54 bufsize = ldl_phys(&s->dma_as, value + 4);
55 /* @(value + 8) : Request/response indicator */
56 resplen = 0;
57 switch (tag) {
58 case 0x00000000: /* End tag */
59 break;
60 case 0x00000001: /* Get firmware revision */
61 stl_phys(&s->dma_as, value + 12, 346337);
62 resplen = 4;
63 break;
65 case 0x00010001: /* Get board model */
66 resplen = 4;
67 break;
68 case 0x00010002: /* Get board revision */
69 resplen = 4;
70 break;
71 case 0x00010003: /* Get board MAC address */
72 /* write the first four bytes of the 6-byte MAC */
73 stl_phys(&s->dma_as, value + 12, 0xB827EBD0);
74 /* write the last two bytes, avoid any write past the buffer end */
75 stb_phys(&s->dma_as, value + 16, 0xEE);
76 stb_phys(&s->dma_as, value + 17, 0xDF);
77 resplen = 6;
78 break;
79 case 0x00010004: /* Get board serial */
80 resplen = 8;
81 break;
82 case 0x00010005: /* Get ARM memory */
83 /* base */
84 stl_phys(&s->dma_as, value + 12, 0);
85 /* size */
86 stl_phys(&s->dma_as, value + 16, s->fbdev->vcram_base);
87 resplen = 8;
88 break;
89 case 0x00010006: /* Get VC memory */
90 /* base */
91 stl_phys(&s->dma_as, value + 12, s->fbdev->vcram_base);
92 /* size */
93 stl_phys(&s->dma_as, value + 16, s->fbdev->vcram_size);
94 resplen = 8;
95 break;
96 case 0x00028001: /* Set power state */
97 /* Assume that whatever device they asked for exists,
98 * and we'll just claim we set it to the desired state */
99 tmp = ldl_phys(&s->dma_as, value + 16);
100 stl_phys(&s->dma_as, value + 16, (tmp & 1));
101 resplen = 8;
102 break;
104 /* Clocks */
106 case 0x00030001: /* Get clock state */
107 stl_phys(&s->dma_as, value + 16, 0x1);
108 resplen = 8;
109 break;
111 case 0x00038001: /* Set clock state */
112 resplen = 8;
113 break;
115 case 0x00030002: /* Get clock rate */
116 case 0x00030004: /* Get max clock rate */
117 case 0x00030007: /* Get min clock rate */
118 switch (ldl_phys(&s->dma_as, value + 12)) {
119 case 1: /* EMMC */
120 stl_phys(&s->dma_as, value + 16, 50000000);
121 break;
122 case 2: /* UART */
123 stl_phys(&s->dma_as, value + 16, 3000000);
124 break;
125 default:
126 stl_phys(&s->dma_as, value + 16, 700000000);
127 break;
129 resplen = 8;
130 break;
132 case 0x00038002: /* Set clock rate */
133 case 0x00038004: /* Set max clock rate */
134 case 0x00038007: /* Set min clock rate */
135 resplen = 8;
136 break;
138 /* Temperature */
140 case 0x00030006: /* Get temperature */
141 stl_phys(&s->dma_as, value + 16, 25000);
142 resplen = 8;
143 break;
145 case 0x0003000A: /* Get max temperature */
146 stl_phys(&s->dma_as, value + 16, 99000);
147 resplen = 8;
148 break;
151 /* Frame buffer */
153 case 0x00040001: /* Allocate buffer */
154 stl_phys(&s->dma_as, value + 12, s->fbdev->base);
155 stl_phys(&s->dma_as, value + 16, s->fbdev->size);
156 resplen = 8;
157 break;
158 case 0x00048001: /* Release buffer */
159 resplen = 0;
160 break;
161 case 0x00040002: /* Blank screen */
162 resplen = 4;
163 break;
164 case 0x00040003: /* Get display width/height */
165 case 0x00040004:
166 stl_phys(&s->dma_as, value + 12, s->fbdev->xres);
167 stl_phys(&s->dma_as, value + 16, s->fbdev->yres);
168 resplen = 8;
169 break;
170 case 0x00044003: /* Test display width/height */
171 case 0x00044004:
172 resplen = 8;
173 break;
174 case 0x00048003: /* Set display width/height */
175 case 0x00048004:
176 xres = ldl_phys(&s->dma_as, value + 12);
177 newxres = &xres;
178 yres = ldl_phys(&s->dma_as, value + 16);
179 newyres = &yres;
180 resplen = 8;
181 break;
182 case 0x00040005: /* Get depth */
183 stl_phys(&s->dma_as, value + 12, s->fbdev->bpp);
184 resplen = 4;
185 break;
186 case 0x00044005: /* Test depth */
187 resplen = 4;
188 break;
189 case 0x00048005: /* Set depth */
190 bpp = ldl_phys(&s->dma_as, value + 12);
191 newbpp = &bpp;
192 resplen = 4;
193 break;
194 case 0x00040006: /* Get pixel order */
195 stl_phys(&s->dma_as, value + 12, s->fbdev->pixo);
196 resplen = 4;
197 break;
198 case 0x00044006: /* Test pixel order */
199 resplen = 4;
200 break;
201 case 0x00048006: /* Set pixel order */
202 pixo = ldl_phys(&s->dma_as, value + 12);
203 newpixo = &pixo;
204 resplen = 4;
205 break;
206 case 0x00040007: /* Get alpha */
207 stl_phys(&s->dma_as, value + 12, s->fbdev->alpha);
208 resplen = 4;
209 break;
210 case 0x00044007: /* Test pixel alpha */
211 resplen = 4;
212 break;
213 case 0x00048007: /* Set alpha */
214 alpha = ldl_phys(&s->dma_as, value + 12);
215 newalpha = &alpha;
216 resplen = 4;
217 break;
218 case 0x00040008: /* Get pitch */
219 stl_phys(&s->dma_as, value + 12, s->fbdev->pitch);
220 resplen = 4;
221 break;
222 case 0x00040009: /* Get virtual offset */
223 stl_phys(&s->dma_as, value + 12, s->fbdev->xoffset);
224 stl_phys(&s->dma_as, value + 16, s->fbdev->yoffset);
225 resplen = 8;
226 break;
227 case 0x00044009: /* Test virtual offset */
228 resplen = 8;
229 break;
230 case 0x00048009: /* Set virtual offset */
231 xoffset = ldl_phys(&s->dma_as, value + 12);
232 newxoffset = &xoffset;
233 yoffset = ldl_phys(&s->dma_as, value + 16);
234 newyoffset = &yoffset;
236 stl_phys(&s->dma_as, value + 12, bcm2835_fb.xres);
237 stl_phys(&s->dma_as, value + 16, bcm2835_fb.yres);
239 resplen = 8;
240 break;
241 case 0x0004000a: /* Get/Test/Set overscan */
242 case 0x0004400a:
243 case 0x0004800a:
244 stl_phys(&s->dma_as, value + 12, 0);
245 stl_phys(&s->dma_as, value + 16, 0);
246 stl_phys(&s->dma_as, value + 20, 0);
247 stl_phys(&s->dma_as, value + 24, 0);
248 resplen = 16;
249 break;
251 case 0x0004800b: /* Set palette */
252 offset = ldl_phys(&s->dma_as, value + 12);
253 length = ldl_phys(&s->dma_as, value + 16);
254 n = 0;
255 while (n < length - offset) {
256 color = ldl_phys(&s->dma_as, value + 20 + (n << 2));
257 stl_phys(&s->dma_as,
258 s->fbdev->vcram_base + ((offset + n) << 2), color);
259 n++;
261 stl_phys(&s->dma_as, value + 12, 0);
262 resplen = 4;
263 break;
265 case 0x00060001: /* Get DMA channels */
266 /* channels 2-5 */
267 stl_phys(&s->dma_as, value + 12, 0x003C);
268 resplen = 4;
269 break;
271 case 0x00050001: /* Get command line */
272 resplen = 0;
273 break;
275 default:
276 qemu_log_mask(LOG_GUEST_ERROR,
277 "bcm2835_property: unhandled tag %08x\n", tag);
278 break;
281 if (tag == 0) {
282 break;
285 stl_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
286 value += bufsize + 12;
289 if (newxres || newyres || newxoffset || newyoffset || newbpp || newpixo
290 || newalpha) {
291 bcm2835_fb_reconfigure(s->fbdev, newxres, newyres, newxoffset,
292 newyoffset, newbpp, newpixo, newalpha);
295 /* Buffer response code */
296 stl_phys(&s->dma_as, s->addr + 4, (1 << 31));
299 static uint64_t bcm2835_property_read(void *opaque, hwaddr offset,
300 unsigned size)
302 Bcm2835PropertyState *s = (Bcm2835PropertyState *)opaque;
303 uint32_t res = 0;
305 switch (offset) {
306 case 0:
307 res = MBOX_CHAN_PROPERTY | s->addr;
308 s->pending = 0;
309 qemu_set_irq(s->mbox_irq, 0);
310 break;
311 case 4:
312 res = s->pending;
313 break;
314 default:
315 qemu_log_mask(LOG_GUEST_ERROR,
316 "bcm2835_property_read: Bad offset %x\n", (int)offset);
317 return 0;
319 return res;
322 static void bcm2835_property_write(void *opaque, hwaddr offset,
323 uint64_t value, unsigned size)
325 Bcm2835PropertyState *s = (Bcm2835PropertyState *)opaque;
326 switch (offset) {
327 case 0:
328 if (!s->pending) {
329 s->pending = 1;
330 bcm2835_property_mbox_push(s, value);
331 qemu_set_irq(s->mbox_irq, 1);
333 break;
334 default:
335 qemu_log_mask(LOG_GUEST_ERROR,
336 "bcm2835_property_write: Bad offset %x\n", (int)offset);
337 return;
343 static const MemoryRegionOps bcm2835_property_ops = {
344 .read = bcm2835_property_read,
345 .write = bcm2835_property_write,
346 .endianness = DEVICE_NATIVE_ENDIAN,
350 static const VMStateDescription vmstate_bcm2835_property = {
351 .name = TYPE_BCM2835_PROPERTY,
352 .version_id = 1,
353 .minimum_version_id = 1,
354 .minimum_version_id_old = 1,
355 .fields = (VMStateField[]) {
356 VMSTATE_END_OF_LIST()
360 static void bcm2835_property_init(Object *obj)
362 Bcm2835PropertyState *s = BCM2835_PROPERTY(obj);
363 memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s,
364 TYPE_BCM2835_PROPERTY, 0x10);
367 static void bcm2835_property_realize(DeviceState *dev, Error **errp)
369 Bcm2835PropertyState *s = BCM2835_PROPERTY(dev);
370 Object *obj;
371 Error *err = NULL;
373 obj = object_property_get_link(OBJECT(dev), "bcm2835_fb", &err);
374 if (err || obj == NULL) {
375 error_setg(errp, "bcm2835_property: required bcm2835_fb link missing");
376 return;
379 s->fbdev = BCM2835_FB(obj);
381 obj = object_property_get_link(OBJECT(dev), "dma_mr", &err);
382 if (err || obj == NULL) {
383 error_setg(errp, "bcm2835_property: required dma_mr link not found");
384 return;
387 s->dma_mr = MEMORY_REGION(obj);
388 address_space_init(&s->dma_as, s->dma_mr, NULL);
390 s->pending = 0;
392 sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->mbox_irq);
393 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
396 static void bcm2835_property_class_init(ObjectClass *klass, void *data)
398 DeviceClass *dc = DEVICE_CLASS(klass);
400 dc->realize = bcm2835_property_realize;
401 dc->vmsd = &vmstate_bcm2835_property;
404 static TypeInfo bcm2835_property_info = {
405 .name = TYPE_BCM2835_PROPERTY,
406 .parent = TYPE_SYS_BUS_DEVICE,
407 .instance_size = sizeof(Bcm2835PropertyState),
408 .class_init = bcm2835_property_class_init,
409 .instance_init = bcm2835_property_init,
412 static void bcm2835_property_register_types(void)
414 type_register_static(&bcm2835_property_info);
417 type_init(bcm2835_property_register_types)