3 * QEMU model of the Milkymist VGA framebuffer.
5 * Copyright (c) 2010 Michael Walle <michael@walle.cc>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 * Specification available at:
22 * http://www.milkymist.org/socdoc/vgafb.pdf
29 #include "framebuffer.h"
30 #include "pixel_ops.h"
31 #include "qemu-error.h"
34 #include "milkymist-vgafb_template.h"
36 #include "milkymist-vgafb_template.h"
38 #include "milkymist-vgafb_template.h"
40 #include "milkymist-vgafb_template.h"
42 #include "milkymist-vgafb_template.h"
65 struct MilkymistVgafbState
{
75 typedef struct MilkymistVgafbState MilkymistVgafbState
;
77 static int vgafb_enabled(MilkymistVgafbState
*s
)
79 return !(s
->regs
[R_CTRL
] & CTRL_RESET
);
82 static void vgafb_update_display(void *opaque
)
84 MilkymistVgafbState
*s
= opaque
;
89 if (!vgafb_enabled(s
)) {
93 int dest_width
= s
->regs
[R_HRES
];
95 switch (ds_get_bits_per_pixel(s
->ds
)) {
118 hw_error("milkymist_vgafb: bad color depth\n");
122 framebuffer_update_display(s
->ds
,
123 s
->regs
[R_BASEADDRESS
] + s
->fb_offset
,
135 dpy_update(s
->ds
, 0, first
, s
->regs
[R_HRES
], last
- first
+ 1);
140 static void vgafb_invalidate_display(void *opaque
)
142 MilkymistVgafbState
*s
= opaque
;
146 static void vgafb_resize(MilkymistVgafbState
*s
)
148 if (!vgafb_enabled(s
)) {
152 qemu_console_resize(s
->ds
, s
->regs
[R_HRES
], s
->regs
[R_VRES
]);
156 static uint32_t vgafb_read(void *opaque
, target_phys_addr_t addr
)
158 MilkymistVgafbState
*s
= opaque
;
177 case R_BASEADDRESS_ACT
:
178 r
= s
->regs
[R_BASEADDRESS
];
182 error_report("milkymist_vgafb: read access to unknown register 0x"
183 TARGET_FMT_plx
, addr
<< 2);
187 trace_milkymist_vgafb_memory_read(addr
<< 2, r
);
193 vgafb_write(void *opaque
, target_phys_addr_t addr
, uint32_t value
)
195 MilkymistVgafbState
*s
= opaque
;
197 trace_milkymist_vgafb_memory_write(addr
, value
);
202 s
->regs
[addr
] = value
;
213 s
->regs
[addr
] = value
;
217 error_report("milkymist_vgafb: framebuffer base address have to "
218 "be 32 byte aligned");
221 s
->regs
[addr
] = value
& s
->fb_mask
;
226 s
->regs
[addr
] = value
;
229 case R_BASEADDRESS_ACT
:
230 error_report("milkymist_vgafb: write to read-only register 0x"
231 TARGET_FMT_plx
, addr
<< 2);
235 error_report("milkymist_vgafb: write access to unknown register 0x"
236 TARGET_FMT_plx
, addr
<< 2);
241 static CPUReadMemoryFunc
* const vgafb_read_fn
[] = {
247 static CPUWriteMemoryFunc
* const vgafb_write_fn
[] = {
253 static void milkymist_vgafb_reset(DeviceState
*d
)
255 MilkymistVgafbState
*s
= container_of(d
, MilkymistVgafbState
, busdev
.qdev
);
258 for (i
= 0; i
< R_MAX
; i
++) {
263 s
->regs
[R_CTRL
] = CTRL_RESET
;
264 s
->regs
[R_HRES
] = 640;
265 s
->regs
[R_VRES
] = 480;
266 s
->regs
[R_BASEADDRESS
] = 0;
269 static int milkymist_vgafb_init(SysBusDevice
*dev
)
271 MilkymistVgafbState
*s
= FROM_SYSBUS(typeof(*s
), dev
);
274 vgafb_regs
= cpu_register_io_memory(vgafb_read_fn
, vgafb_write_fn
, s
,
275 DEVICE_NATIVE_ENDIAN
);
276 sysbus_init_mmio(dev
, R_MAX
* 4, vgafb_regs
);
278 s
->ds
= graphic_console_init(vgafb_update_display
,
279 vgafb_invalidate_display
,
285 static int vgafb_post_load(void *opaque
, int version_id
)
287 vgafb_invalidate_display(opaque
);
291 static const VMStateDescription vmstate_milkymist_vgafb
= {
292 .name
= "milkymist-vgafb",
294 .minimum_version_id
= 1,
295 .minimum_version_id_old
= 1,
296 .post_load
= vgafb_post_load
,
297 .fields
= (VMStateField
[]) {
298 VMSTATE_UINT32_ARRAY(regs
, MilkymistVgafbState
, R_MAX
),
299 VMSTATE_END_OF_LIST()
303 static SysBusDeviceInfo milkymist_vgafb_info
= {
304 .init
= milkymist_vgafb_init
,
305 .qdev
.name
= "milkymist-vgafb",
306 .qdev
.size
= sizeof(MilkymistVgafbState
),
307 .qdev
.vmsd
= &vmstate_milkymist_vgafb
,
308 .qdev
.reset
= milkymist_vgafb_reset
,
309 .qdev
.props
= (Property
[]) {
310 DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState
, fb_offset
, 0x0),
311 DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState
, fb_mask
, 0xffffffff),
312 DEFINE_PROP_END_OF_LIST(),
316 static void milkymist_vgafb_register(void)
318 sysbus_register_withprop(&milkymist_vgafb_info
);
321 device_init(milkymist_vgafb_register
)