|
|
1.1 root 1:
2: /*
3: * QEMU model of the Milkymist VGA framebuffer.
4: *
1.1.1.3 ! root 5: * Copyright (c) 2010-2012 Michael Walle <[email protected]>
1.1 root 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,
1.1.1.3 ! root 57: R_DDC,
1.1 root 58: R_SOURCE_CLOCK,
59: R_MAX
60: };
61:
62: enum {
63: CTRL_RESET = (1<<0),
64: };
65:
66: struct MilkymistVgafbState {
67: SysBusDevice busdev;
1.1.1.2 root 68: MemoryRegion regs_region;
1.1 root 69: DisplayState *ds;
70:
71: int invalidate;
72: uint32_t fb_offset;
73: uint32_t fb_mask;
74:
75: uint32_t regs[R_MAX];
76: };
77: typedef struct MilkymistVgafbState MilkymistVgafbState;
78:
79: static int vgafb_enabled(MilkymistVgafbState *s)
80: {
81: return !(s->regs[R_CTRL] & CTRL_RESET);
82: }
83:
84: static void vgafb_update_display(void *opaque)
85: {
86: MilkymistVgafbState *s = opaque;
87: int first = 0;
88: int last = 0;
89: drawfn fn;
90:
91: if (!vgafb_enabled(s)) {
92: return;
93: }
94:
95: int dest_width = s->regs[R_HRES];
96:
97: switch (ds_get_bits_per_pixel(s->ds)) {
98: case 0:
99: return;
100: case 8:
101: fn = draw_line_8;
102: break;
103: case 15:
104: fn = draw_line_15;
105: dest_width *= 2;
106: break;
107: case 16:
108: fn = draw_line_16;
109: dest_width *= 2;
110: break;
111: case 24:
112: fn = draw_line_24;
113: dest_width *= 3;
114: break;
115: case 32:
116: fn = draw_line_32;
117: dest_width *= 4;
118: break;
119: default:
120: hw_error("milkymist_vgafb: bad color depth\n");
121: break;
122: }
123:
1.1.1.3 ! root 124: framebuffer_update_display(s->ds, sysbus_address_space(&s->busdev),
1.1 root 125: s->regs[R_BASEADDRESS] + s->fb_offset,
126: s->regs[R_HRES],
127: s->regs[R_VRES],
128: s->regs[R_HRES] * 2,
129: dest_width,
130: 0,
131: s->invalidate,
132: fn,
133: NULL,
134: &first, &last);
135:
136: if (first >= 0) {
137: dpy_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1);
138: }
139: s->invalidate = 0;
140: }
141:
142: static void vgafb_invalidate_display(void *opaque)
143: {
144: MilkymistVgafbState *s = opaque;
145: s->invalidate = 1;
146: }
147:
148: static void vgafb_resize(MilkymistVgafbState *s)
149: {
150: if (!vgafb_enabled(s)) {
151: return;
152: }
153:
154: qemu_console_resize(s->ds, s->regs[R_HRES], s->regs[R_VRES]);
155: s->invalidate = 1;
156: }
157:
1.1.1.2 root 158: static uint64_t vgafb_read(void *opaque, target_phys_addr_t addr,
159: unsigned size)
1.1 root 160: {
161: MilkymistVgafbState *s = opaque;
162: uint32_t r = 0;
163:
164: addr >>= 2;
165: switch (addr) {
166: case R_CTRL:
167: case R_HRES:
168: case R_HSYNC_START:
169: case R_HSYNC_END:
170: case R_HSCAN:
171: case R_VRES:
172: case R_VSYNC_START:
173: case R_VSYNC_END:
174: case R_VSCAN:
175: case R_BASEADDRESS:
176: case R_BURST_COUNT:
1.1.1.3 ! root 177: case R_DDC:
1.1 root 178: case R_SOURCE_CLOCK:
179: r = s->regs[addr];
180: break;
181: case R_BASEADDRESS_ACT:
182: r = s->regs[R_BASEADDRESS];
183: break;
184:
185: default:
186: error_report("milkymist_vgafb: read access to unknown register 0x"
187: TARGET_FMT_plx, addr << 2);
188: break;
189: }
190:
191: trace_milkymist_vgafb_memory_read(addr << 2, r);
192:
193: return r;
194: }
195:
1.1.1.2 root 196: static void vgafb_write(void *opaque, target_phys_addr_t addr, uint64_t value,
197: unsigned size)
1.1 root 198: {
199: MilkymistVgafbState *s = opaque;
200:
201: trace_milkymist_vgafb_memory_write(addr, value);
202:
203: addr >>= 2;
204: switch (addr) {
205: case R_CTRL:
206: s->regs[addr] = value;
207: vgafb_resize(s);
208: break;
209: case R_HSYNC_START:
210: case R_HSYNC_END:
211: case R_HSCAN:
212: case R_VSYNC_START:
213: case R_VSYNC_END:
214: case R_VSCAN:
215: case R_BURST_COUNT:
1.1.1.3 ! root 216: case R_DDC:
1.1 root 217: case R_SOURCE_CLOCK:
218: s->regs[addr] = value;
219: break;
220: case R_BASEADDRESS:
221: if (value & 0x1f) {
222: error_report("milkymist_vgafb: framebuffer base address have to "
223: "be 32 byte aligned");
224: break;
225: }
226: s->regs[addr] = value & s->fb_mask;
227: s->invalidate = 1;
228: break;
229: case R_HRES:
230: case R_VRES:
231: s->regs[addr] = value;
232: vgafb_resize(s);
233: break;
234: case R_BASEADDRESS_ACT:
235: error_report("milkymist_vgafb: write to read-only register 0x"
236: TARGET_FMT_plx, addr << 2);
237: break;
238:
239: default:
240: error_report("milkymist_vgafb: write access to unknown register 0x"
241: TARGET_FMT_plx, addr << 2);
242: break;
243: }
244: }
245:
1.1.1.2 root 246: static const MemoryRegionOps vgafb_mmio_ops = {
247: .read = vgafb_read,
248: .write = vgafb_write,
249: .valid = {
250: .min_access_size = 4,
251: .max_access_size = 4,
252: },
253: .endianness = DEVICE_NATIVE_ENDIAN,
1.1 root 254: };
255:
256: static void milkymist_vgafb_reset(DeviceState *d)
257: {
258: MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev);
259: int i;
260:
261: for (i = 0; i < R_MAX; i++) {
262: s->regs[i] = 0;
263: }
264:
265: /* defaults */
266: s->regs[R_CTRL] = CTRL_RESET;
267: s->regs[R_HRES] = 640;
268: s->regs[R_VRES] = 480;
269: s->regs[R_BASEADDRESS] = 0;
270: }
271:
272: static int milkymist_vgafb_init(SysBusDevice *dev)
273: {
274: MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
275:
1.1.1.2 root 276: memory_region_init_io(&s->regs_region, &vgafb_mmio_ops, s,
277: "milkymist-vgafb", R_MAX * 4);
1.1.1.3 ! root 278: sysbus_init_mmio(dev, &s->regs_region);
1.1 root 279:
280: s->ds = graphic_console_init(vgafb_update_display,
281: vgafb_invalidate_display,
282: NULL, NULL, s);
283:
284: return 0;
285: }
286:
287: static int vgafb_post_load(void *opaque, int version_id)
288: {
289: vgafb_invalidate_display(opaque);
290: return 0;
291: }
292:
293: static const VMStateDescription vmstate_milkymist_vgafb = {
294: .name = "milkymist-vgafb",
295: .version_id = 1,
296: .minimum_version_id = 1,
297: .minimum_version_id_old = 1,
298: .post_load = vgafb_post_load,
299: .fields = (VMStateField[]) {
300: VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
301: VMSTATE_END_OF_LIST()
302: }
303: };
304:
1.1.1.3 ! root 305: static Property milkymist_vgafb_properties[] = {
! 306: DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
! 307: DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
! 308: DEFINE_PROP_END_OF_LIST(),
! 309: };
! 310:
! 311: static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
! 312: {
! 313: DeviceClass *dc = DEVICE_CLASS(klass);
! 314: SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
! 315:
! 316: k->init = milkymist_vgafb_init;
! 317: dc->reset = milkymist_vgafb_reset;
! 318: dc->vmsd = &vmstate_milkymist_vgafb;
! 319: dc->props = milkymist_vgafb_properties;
! 320: }
! 321:
! 322: static TypeInfo milkymist_vgafb_info = {
! 323: .name = "milkymist-vgafb",
! 324: .parent = TYPE_SYS_BUS_DEVICE,
! 325: .instance_size = sizeof(MilkymistVgafbState),
! 326: .class_init = milkymist_vgafb_class_init,
1.1 root 327: };
328:
1.1.1.3 ! root 329: static void milkymist_vgafb_register_types(void)
1.1 root 330: {
1.1.1.3 ! root 331: type_register_static(&milkymist_vgafb_info);
1.1 root 332: }
333:
1.1.1.3 ! root 334: type_init(milkymist_vgafb_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.