|
|
1.1 root 1:
2: /*
3: * QEMU model of the Milkymist VGA framebuffer.
4: *
5: * Copyright (c) 2010 Michael Walle <[email protected]>
6: *
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.
11: *
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.
16: *
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/>.
19: *
20: *
21: * Specification available at:
22: * http://www.milkymist.org/socdoc/vgafb.pdf
23: */
24:
25: #include "hw.h"
26: #include "sysbus.h"
27: #include "trace.h"
28: #include "console.h"
29: #include "framebuffer.h"
30: #include "pixel_ops.h"
31: #include "qemu-error.h"
32:
33: #define BITS 8
34: #include "milkymist-vgafb_template.h"
35: #define BITS 15
36: #include "milkymist-vgafb_template.h"
37: #define BITS 16
38: #include "milkymist-vgafb_template.h"
39: #define BITS 24
40: #include "milkymist-vgafb_template.h"
41: #define BITS 32
42: #include "milkymist-vgafb_template.h"
43:
44: enum {
45: R_CTRL = 0,
46: R_HRES,
47: R_HSYNC_START,
48: R_HSYNC_END,
49: R_HSCAN,
50: R_VRES,
51: R_VSYNC_START,
52: R_VSYNC_END,
53: R_VSCAN,
54: R_BASEADDRESS,
55: R_BASEADDRESS_ACT,
56: R_BURST_COUNT,
57: R_SOURCE_CLOCK,
58: R_MAX
59: };
60:
61: enum {
62: CTRL_RESET = (1<<0),
63: };
64:
65: struct MilkymistVgafbState {
66: SysBusDevice busdev;
67: DisplayState *ds;
68:
69: int invalidate;
70: uint32_t fb_offset;
71: uint32_t fb_mask;
72:
73: uint32_t regs[R_MAX];
74: };
75: typedef struct MilkymistVgafbState MilkymistVgafbState;
76:
77: static int vgafb_enabled(MilkymistVgafbState *s)
78: {
79: return !(s->regs[R_CTRL] & CTRL_RESET);
80: }
81:
82: static void vgafb_update_display(void *opaque)
83: {
84: MilkymistVgafbState *s = opaque;
85: int first = 0;
86: int last = 0;
87: drawfn fn;
88:
89: if (!vgafb_enabled(s)) {
90: return;
91: }
92:
93: int dest_width = s->regs[R_HRES];
94:
95: switch (ds_get_bits_per_pixel(s->ds)) {
96: case 0:
97: return;
98: case 8:
99: fn = draw_line_8;
100: break;
101: case 15:
102: fn = draw_line_15;
103: dest_width *= 2;
104: break;
105: case 16:
106: fn = draw_line_16;
107: dest_width *= 2;
108: break;
109: case 24:
110: fn = draw_line_24;
111: dest_width *= 3;
112: break;
113: case 32:
114: fn = draw_line_32;
115: dest_width *= 4;
116: break;
117: default:
118: hw_error("milkymist_vgafb: bad color depth\n");
119: break;
120: }
121:
122: framebuffer_update_display(s->ds,
123: s->regs[R_BASEADDRESS] + s->fb_offset,
124: s->regs[R_HRES],
125: s->regs[R_VRES],
126: s->regs[R_HRES] * 2,
127: dest_width,
128: 0,
129: s->invalidate,
130: fn,
131: NULL,
132: &first, &last);
133:
134: if (first >= 0) {
135: dpy_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1);
136: }
137: s->invalidate = 0;
138: }
139:
140: static void vgafb_invalidate_display(void *opaque)
141: {
142: MilkymistVgafbState *s = opaque;
143: s->invalidate = 1;
144: }
145:
146: static void vgafb_resize(MilkymistVgafbState *s)
147: {
148: if (!vgafb_enabled(s)) {
149: return;
150: }
151:
152: qemu_console_resize(s->ds, s->regs[R_HRES], s->regs[R_VRES]);
153: s->invalidate = 1;
154: }
155:
156: static uint32_t vgafb_read(void *opaque, target_phys_addr_t addr)
157: {
158: MilkymistVgafbState *s = opaque;
159: uint32_t r = 0;
160:
161: addr >>= 2;
162: switch (addr) {
163: case R_CTRL:
164: case R_HRES:
165: case R_HSYNC_START:
166: case R_HSYNC_END:
167: case R_HSCAN:
168: case R_VRES:
169: case R_VSYNC_START:
170: case R_VSYNC_END:
171: case R_VSCAN:
172: case R_BASEADDRESS:
173: case R_BURST_COUNT:
174: case R_SOURCE_CLOCK:
175: r = s->regs[addr];
176: break;
177: case R_BASEADDRESS_ACT:
178: r = s->regs[R_BASEADDRESS];
179: break;
180:
181: default:
182: error_report("milkymist_vgafb: read access to unknown register 0x"
183: TARGET_FMT_plx, addr << 2);
184: break;
185: }
186:
187: trace_milkymist_vgafb_memory_read(addr << 2, r);
188:
189: return r;
190: }
191:
192: static void
193: vgafb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
194: {
195: MilkymistVgafbState *s = opaque;
196:
197: trace_milkymist_vgafb_memory_write(addr, value);
198:
199: addr >>= 2;
200: switch (addr) {
201: case R_CTRL:
202: s->regs[addr] = value;
203: vgafb_resize(s);
204: break;
205: case R_HSYNC_START:
206: case R_HSYNC_END:
207: case R_HSCAN:
208: case R_VSYNC_START:
209: case R_VSYNC_END:
210: case R_VSCAN:
211: case R_BURST_COUNT:
212: case R_SOURCE_CLOCK:
213: s->regs[addr] = value;
214: break;
215: case R_BASEADDRESS:
216: if (value & 0x1f) {
217: error_report("milkymist_vgafb: framebuffer base address have to "
218: "be 32 byte aligned");
219: break;
220: }
221: s->regs[addr] = value & s->fb_mask;
222: s->invalidate = 1;
223: break;
224: case R_HRES:
225: case R_VRES:
226: s->regs[addr] = value;
227: vgafb_resize(s);
228: break;
229: case R_BASEADDRESS_ACT:
230: error_report("milkymist_vgafb: write to read-only register 0x"
231: TARGET_FMT_plx, addr << 2);
232: break;
233:
234: default:
235: error_report("milkymist_vgafb: write access to unknown register 0x"
236: TARGET_FMT_plx, addr << 2);
237: break;
238: }
239: }
240:
241: static CPUReadMemoryFunc * const vgafb_read_fn[] = {
242: NULL,
243: NULL,
244: &vgafb_read
245: };
246:
247: static CPUWriteMemoryFunc * const vgafb_write_fn[] = {
248: NULL,
249: NULL,
250: &vgafb_write
251: };
252:
253: static void milkymist_vgafb_reset(DeviceState *d)
254: {
255: MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev);
256: int i;
257:
258: for (i = 0; i < R_MAX; i++) {
259: s->regs[i] = 0;
260: }
261:
262: /* defaults */
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;
267: }
268:
269: static int milkymist_vgafb_init(SysBusDevice *dev)
270: {
271: MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
272: int vgafb_regs;
273:
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);
277:
278: s->ds = graphic_console_init(vgafb_update_display,
279: vgafb_invalidate_display,
280: NULL, NULL, s);
281:
282: return 0;
283: }
284:
285: static int vgafb_post_load(void *opaque, int version_id)
286: {
287: vgafb_invalidate_display(opaque);
288: return 0;
289: }
290:
291: static const VMStateDescription vmstate_milkymist_vgafb = {
292: .name = "milkymist-vgafb",
293: .version_id = 1,
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()
300: }
301: };
302:
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(),
313: }
314: };
315:
316: static void milkymist_vgafb_register(void)
317: {
318: sysbus_register_withprop(&milkymist_vgafb_info);
319: }
320:
321: device_init(milkymist_vgafb_register)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.