2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
3 * This code is licensed under the GNU GPLv2 and later.
6 /* Heavily based on milkymist-vgafb.c, copyright terms below. */
9 * QEMU model of the Milkymist VGA framebuffer.
11 * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
28 #include "hw/display/bcm2835_fb.h"
29 #include "hw/display/framebuffer.h"
30 #include "ui/pixel_ops.h"
31 #include "hw/arm/bcm2835_mbox.h"
33 #define DEFAULT_VCRAM_SIZE 0x4000000
34 #define BCM2835_FB_OFFSET 0x00100000
37 static void fb_invalidate_display(void *opaque
)
39 Bcm2835FbState
*s
= BCM2835_FB(opaque
);
43 static void draw_line_src16(void *opaque
, uint8_t *dst
, const uint8_t *src
,
44 int width
, int deststep
)
46 Bcm2835FbState
*s
= (Bcm2835FbState
*)opaque
;
50 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
51 int bpp
= surface_bits_per_pixel(surface
);
56 rgb888
= ldl_phys(&s
->dma_as
, s
->vcram_base
+ (*src
<< 2));
57 r
= (rgb888
>> 0) & 0xff;
58 g
= (rgb888
>> 8) & 0xff;
59 b
= (rgb888
>> 16) & 0xff;
64 r
= ((rgb565
>> 11) & 0x1f) << 3;
65 g
= ((rgb565
>> 5) & 0x3f) << 2;
66 b
= ((rgb565
>> 0) & 0x1f) << 3;
71 r
= (rgb888
>> 0) & 0xff;
72 g
= (rgb888
>> 8) & 0xff;
73 b
= (rgb888
>> 16) & 0xff;
78 r
= (rgb888
>> 0) & 0xff;
79 g
= (rgb888
>> 8) & 0xff;
80 b
= (rgb888
>> 16) & 0xff;
91 /* swap to BGR pixel format */
99 *dst
++ = rgb_to_pixel8(r
, g
, b
);
102 *(uint16_t *)dst
= rgb_to_pixel15(r
, g
, b
);
106 *(uint16_t *)dst
= rgb_to_pixel16(r
, g
, b
);
110 rgb888
= rgb_to_pixel24(r
, g
, b
);
111 *dst
++ = rgb888
& 0xff;
112 *dst
++ = (rgb888
>> 8) & 0xff;
113 *dst
++ = (rgb888
>> 16) & 0xff;
116 *(uint32_t *)dst
= rgb_to_pixel32(r
, g
, b
);
125 static void fb_update_display(void *opaque
)
127 Bcm2835FbState
*s
= (Bcm2835FbState
*)opaque
;
131 DisplaySurface
*surface
= qemu_console_surface(s
->con
);
136 static uint32_t frame
; /* 0 */
138 if (++frame
< FRAMESKIP
) {
152 src_width
= s
->xres
* (s
->bpp
>> 3);
154 dest_width
= s
->xres
;
155 switch (surface_bits_per_pixel(surface
)) {
173 hw_error("bcm2835_fb: bad color depth\n");
179 fn
= draw_line_src16
;
182 framebuffer_update_memory_section(&s
->fbsection
,
189 framebuffer_update_display(surface
, &s
->fbsection
,
201 dpy_gfx_update(s
->con
, 0, first
,
202 s
->xres
, last
- first
+ 1);
205 s
->invalidate
= false;
208 static void bcm2835_fb_mbox_push(Bcm2835FbState
*s
, uint32_t value
)
214 s
->xres
= ldl_phys(&s
->dma_as
, value
);
215 s
->yres
= ldl_phys(&s
->dma_as
, value
+ 4);
216 s
->xres_virtual
= ldl_phys(&s
->dma_as
, value
+ 8);
217 s
->yres_virtual
= ldl_phys(&s
->dma_as
, value
+ 12);
219 s
->bpp
= ldl_phys(&s
->dma_as
, value
+ 20);
220 s
->xoffset
= ldl_phys(&s
->dma_as
, value
+ 24);
221 s
->yoffset
= ldl_phys(&s
->dma_as
, value
+ 28);
223 s
->base
= s
->vcram_base
| (value
& 0xc0000000);
224 s
->base
+= BCM2835_FB_OFFSET
;
226 /* TODO - Manage properly virtual resolution */
228 s
->pitch
= s
->xres
* (s
->bpp
>> 3);
229 s
->size
= s
->yres
* s
->pitch
;
231 stl_phys(&s
->dma_as
, value
+ 16, s
->pitch
);
232 stl_phys(&s
->dma_as
, value
+ 32, s
->base
);
233 stl_phys(&s
->dma_as
, value
+ 36, s
->size
);
235 s
->invalidate
= true;
236 qemu_console_resize(s
->con
, s
->xres
, s
->yres
);
240 void bcm2835_fb_reconfigure(Bcm2835FbState
*s
, uint32_t *xres
, uint32_t *yres
,
241 uint32_t *xoffset
, uint32_t *yoffset
, uint32_t *bpp
,
242 uint32_t *pixo
, uint32_t *alpha
)
246 /* TODO: input validation! */
254 s
->xoffset
= *xoffset
;
257 s
->yoffset
= *yoffset
;
269 /* TODO - Manage properly virtual resolution */
271 s
->pitch
= s
->xres
* (s
->bpp
>> 3);
272 s
->size
= s
->yres
* s
->pitch
;
274 s
->invalidate
= true;
275 qemu_console_resize(s
->con
, s
->xres
, s
->yres
);
279 static uint64_t bcm2835_fb_read(void *opaque
, hwaddr offset
,
282 Bcm2835FbState
*s
= (Bcm2835FbState
*)opaque
;
289 qemu_set_irq(s
->mbox_irq
, 0);
295 qemu_log_mask(LOG_GUEST_ERROR
,
296 "bcm2835_fb_read: Bad offset %x\n", (int)offset
);
302 static void bcm2835_fb_write(void *opaque
, hwaddr offset
,
303 uint64_t value
, unsigned size
)
305 Bcm2835FbState
*s
= (Bcm2835FbState
*)opaque
;
310 bcm2835_fb_mbox_push(s
, value
);
311 qemu_set_irq(s
->mbox_irq
, 1);
315 qemu_log_mask(LOG_GUEST_ERROR
,
316 "bcm2835_fb_write: Bad offset %x\n", (int)offset
);
321 static const MemoryRegionOps bcm2835_fb_ops
= {
322 .read
= bcm2835_fb_read
,
323 .write
= bcm2835_fb_write
,
324 .endianness
= DEVICE_NATIVE_ENDIAN
,
327 static const VMStateDescription vmstate_bcm2835_fb
= {
328 .name
= TYPE_BCM2835_FB
,
330 .minimum_version_id
= 1,
331 .minimum_version_id_old
= 1,
332 .fields
= (VMStateField
[]) {
333 VMSTATE_END_OF_LIST()
336 static const GraphicHwOps vgafb_ops
= {
337 .invalidate
= fb_invalidate_display
,
338 .gfx_update
= fb_update_display
,
341 static void bcm2835_fb_init(Object
*obj
)
343 Bcm2835FbState
*s
= BCM2835_FB(obj
);
344 memory_region_init_io(&s
->iomem
, obj
, &bcm2835_fb_ops
, s
, TYPE_BCM2835_FB
,
346 sysbus_init_mmio(SYS_BUS_DEVICE(s
), &s
->iomem
);
347 sysbus_init_irq(SYS_BUS_DEVICE(s
), &s
->mbox_irq
);
350 static void bcm2835_fb_realize(DeviceState
*dev
, Error
**errp
)
352 Bcm2835FbState
*s
= BCM2835_FB(dev
);
356 if (s
->vcram_base
== 0) {
357 error_setg(errp
, "bcm2835_fb: required vcram-base property not found");
361 obj
= object_property_get_link(OBJECT(dev
), "dma_mr", &err
);
362 if (err
|| obj
== NULL
) {
363 error_setg(errp
, "bcm2835_fb: required dma_mr property not found");
367 s
->dma_mr
= MEMORY_REGION(obj
);
368 address_space_init(&s
->dma_as
, s
->dma_mr
, NULL
);
372 s
->xres_virtual
= s
->xres
;
373 s
->yres_virtual
= s
->yres
;
377 s
->base
= s
->vcram_base
+ BCM2835_FB_OFFSET
;
379 s
->pitch
= s
->xres
* (s
->bpp
>> 3);
380 s
->size
= s
->yres
* s
->pitch
;
382 s
->invalidate
= true;
385 s
->con
= graphic_console_init(dev
, 0, &vgafb_ops
, s
);
386 qemu_console_resize(s
->con
, s
->xres
, s
->yres
);
389 static Property bcm2835_fb_props
[] = {
390 DEFINE_PROP_UINT32("vcram-base", Bcm2835FbState
, vcram_base
, 0),/*required*/
391 DEFINE_PROP_UINT32("vcram-size", Bcm2835FbState
, vcram_size
,
393 DEFINE_PROP_UINT32("xres", Bcm2835FbState
, xres
, 640),
394 DEFINE_PROP_UINT32("yres", Bcm2835FbState
, yres
, 480),
395 DEFINE_PROP_UINT32("bpp", Bcm2835FbState
, bpp
, 16),
396 DEFINE_PROP_UINT32("pixo", Bcm2835FbState
, pixo
, 1), /* 1=RGB, 0=BGR */
397 DEFINE_PROP_UINT32("alpha", Bcm2835FbState
, alpha
, 2), /* alpha ignored */
398 DEFINE_PROP_END_OF_LIST()
401 static void bcm2835_fb_class_init(ObjectClass
*klass
, void *data
)
403 DeviceClass
*dc
= DEVICE_CLASS(klass
);
405 dc
->props
= bcm2835_fb_props
;
406 dc
->realize
= bcm2835_fb_realize
;
407 dc
->vmsd
= &vmstate_bcm2835_fb
;
410 static TypeInfo bcm2835_fb_info
= {
411 .name
= TYPE_BCM2835_FB
,
412 .parent
= TYPE_SYS_BUS_DEVICE
,
413 .instance_size
= sizeof(Bcm2835FbState
),
414 .class_init
= bcm2835_fb_class_init
,
415 .instance_init
= bcm2835_fb_init
,
418 static void bcm2835_fb_register_types(void)
420 type_register_static(&bcm2835_fb_info
);
423 type_init(bcm2835_fb_register_types
)