|
|
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.