1e3355a0cSThomas Huth /*
2e3355a0cSThomas Huth * NeXT Cube/Station Framebuffer Emulation
3e3355a0cSThomas Huth *
4e3355a0cSThomas Huth * Copyright (c) 2011 Bryce Lanham
5e3355a0cSThomas Huth *
6e3355a0cSThomas Huth * Permission is hereby granted, free of charge, to any person obtaining a copy
7e3355a0cSThomas Huth * of this software and associated documentation files (the "Software"), to deal
8e3355a0cSThomas Huth * in the Software without restriction, including without limitation the rights
9e3355a0cSThomas Huth * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10e3355a0cSThomas Huth * copies of the Software, and to permit persons to whom the Software is
11e3355a0cSThomas Huth * furnished to do so, subject to the following conditions:
12e3355a0cSThomas Huth *
13e3355a0cSThomas Huth * The above copyright notice and this permission notice shall be included in
14e3355a0cSThomas Huth * all copies or substantial portions of the Software.
15e3355a0cSThomas Huth *
16e3355a0cSThomas Huth * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e3355a0cSThomas Huth * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e3355a0cSThomas Huth * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19e3355a0cSThomas Huth * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20e3355a0cSThomas Huth * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21e3355a0cSThomas Huth * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22e3355a0cSThomas Huth * THE SOFTWARE.
23e3355a0cSThomas Huth */
24e3355a0cSThomas Huth #include "qemu/osdep.h"
25e3355a0cSThomas Huth #include "qapi/error.h"
26e3355a0cSThomas Huth #include "ui/console.h"
27e3355a0cSThomas Huth #include "hw/loader.h"
2863dc3465SPhilippe Mathieu-Daudé #include "framebuffer.h"
29e3355a0cSThomas Huth #include "ui/pixel_ops.h"
30e3355a0cSThomas Huth #include "hw/m68k/next-cube.h"
31db1015e9SEduardo Habkost #include "qom/object.h"
32e3355a0cSThomas Huth
338063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(NeXTFbState, NEXTFB)
34e3355a0cSThomas Huth
35e3355a0cSThomas Huth struct NeXTFbState {
36e3355a0cSThomas Huth SysBusDevice parent_obj;
37e3355a0cSThomas Huth
38e3355a0cSThomas Huth MemoryRegion fb_mr;
39e3355a0cSThomas Huth MemoryRegionSection fbsection;
40e3355a0cSThomas Huth QemuConsole *con;
41e3355a0cSThomas Huth
42e3355a0cSThomas Huth uint32_t cols;
43e3355a0cSThomas Huth uint32_t rows;
44e3355a0cSThomas Huth int invalidate;
45e3355a0cSThomas Huth };
46e3355a0cSThomas Huth
nextfb_draw_line(void * opaque,uint8_t * d,const uint8_t * s,int width,int pitch)47e3355a0cSThomas Huth static void nextfb_draw_line(void *opaque, uint8_t *d, const uint8_t *s,
48e3355a0cSThomas Huth int width, int pitch)
49e3355a0cSThomas Huth {
50e3355a0cSThomas Huth NeXTFbState *nfbstate = NEXTFB(opaque);
51e3355a0cSThomas Huth static const uint32_t pal[4] = {
52e3355a0cSThomas Huth 0xFFFFFFFF, 0xFFAAAAAA, 0xFF555555, 0xFF000000
53e3355a0cSThomas Huth };
54e3355a0cSThomas Huth uint32_t *buf = (uint32_t *)d;
55e3355a0cSThomas Huth int i = 0;
56e3355a0cSThomas Huth
57e3355a0cSThomas Huth for (i = 0; i < nfbstate->cols / 4; i++) {
58e3355a0cSThomas Huth int j = i * 4;
59e3355a0cSThomas Huth uint8_t src = s[i];
60e3355a0cSThomas Huth buf[j + 3] = pal[src & 0x3];
61e3355a0cSThomas Huth src >>= 2;
62e3355a0cSThomas Huth buf[j + 2] = pal[src & 0x3];
63e3355a0cSThomas Huth src >>= 2;
64e3355a0cSThomas Huth buf[j + 1] = pal[src & 0x3];
65e3355a0cSThomas Huth src >>= 2;
66e3355a0cSThomas Huth buf[j + 0] = pal[src & 0x3];
67e3355a0cSThomas Huth }
68e3355a0cSThomas Huth }
69e3355a0cSThomas Huth
nextfb_update(void * opaque)70e3355a0cSThomas Huth static void nextfb_update(void *opaque)
71e3355a0cSThomas Huth {
72e3355a0cSThomas Huth NeXTFbState *s = NEXTFB(opaque);
73e3355a0cSThomas Huth int dest_width = 4;
74e3355a0cSThomas Huth int src_width;
75e3355a0cSThomas Huth int first = 0;
76e3355a0cSThomas Huth int last = 0;
77e3355a0cSThomas Huth DisplaySurface *surface = qemu_console_surface(s->con);
78e3355a0cSThomas Huth
79e3355a0cSThomas Huth src_width = s->cols / 4 + 8;
80e3355a0cSThomas Huth dest_width = s->cols * 4;
81e3355a0cSThomas Huth
82e3355a0cSThomas Huth if (s->invalidate) {
83e3355a0cSThomas Huth framebuffer_update_memory_section(&s->fbsection, &s->fb_mr, 0,
84e3355a0cSThomas Huth s->cols, src_width);
85e3355a0cSThomas Huth s->invalidate = 0;
86e3355a0cSThomas Huth }
87e3355a0cSThomas Huth
88e3355a0cSThomas Huth framebuffer_update_display(surface, &s->fbsection, s->cols, s->rows,
89e3355a0cSThomas Huth src_width, dest_width, 0, 1, nextfb_draw_line,
90e3355a0cSThomas Huth s, &first, &last);
91e3355a0cSThomas Huth
92e3355a0cSThomas Huth dpy_gfx_update(s->con, 0, 0, s->cols, s->rows);
93e3355a0cSThomas Huth }
94e3355a0cSThomas Huth
nextfb_invalidate(void * opaque)95e3355a0cSThomas Huth static void nextfb_invalidate(void *opaque)
96e3355a0cSThomas Huth {
97e3355a0cSThomas Huth NeXTFbState *s = NEXTFB(opaque);
98e3355a0cSThomas Huth s->invalidate = 1;
99e3355a0cSThomas Huth }
100e3355a0cSThomas Huth
101e3355a0cSThomas Huth static const GraphicHwOps nextfb_ops = {
102e3355a0cSThomas Huth .invalidate = nextfb_invalidate,
103e3355a0cSThomas Huth .gfx_update = nextfb_update,
104e3355a0cSThomas Huth };
105e3355a0cSThomas Huth
nextfb_realize(DeviceState * dev,Error ** errp)106e3355a0cSThomas Huth static void nextfb_realize(DeviceState *dev, Error **errp)
107e3355a0cSThomas Huth {
108e3355a0cSThomas Huth NeXTFbState *s = NEXTFB(dev);
109e3355a0cSThomas Huth
110e3355a0cSThomas Huth memory_region_init_ram(&s->fb_mr, OBJECT(dev), "next-video", 0x1CB100,
111e3355a0cSThomas Huth &error_fatal);
112e3355a0cSThomas Huth sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->fb_mr);
113e3355a0cSThomas Huth
114e3355a0cSThomas Huth s->invalidate = 1;
115e3355a0cSThomas Huth s->cols = 1120;
116e3355a0cSThomas Huth s->rows = 832;
117e3355a0cSThomas Huth
118e3355a0cSThomas Huth s->con = graphic_console_init(dev, 0, &nextfb_ops, s);
119e3355a0cSThomas Huth qemu_console_resize(s->con, s->cols, s->rows);
120e3355a0cSThomas Huth }
121e3355a0cSThomas Huth
nextfb_class_init(ObjectClass * oc,void * data)122e3355a0cSThomas Huth static void nextfb_class_init(ObjectClass *oc, void *data)
123e3355a0cSThomas Huth {
124e3355a0cSThomas Huth DeviceClass *dc = DEVICE_CLASS(oc);
125e3355a0cSThomas Huth
126e3355a0cSThomas Huth set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
127e3355a0cSThomas Huth dc->realize = nextfb_realize;
128e3355a0cSThomas Huth
129*c1966f51SEvgeny Ermakov /* Note: This device does not have any state that we have to reset or migrate */
130e3355a0cSThomas Huth }
131e3355a0cSThomas Huth
132e3355a0cSThomas Huth static const TypeInfo nextfb_info = {
133e3355a0cSThomas Huth .name = TYPE_NEXTFB,
134e3355a0cSThomas Huth .parent = TYPE_SYS_BUS_DEVICE,
135e3355a0cSThomas Huth .instance_size = sizeof(NeXTFbState),
136e3355a0cSThomas Huth .class_init = nextfb_class_init,
137e3355a0cSThomas Huth };
138e3355a0cSThomas Huth
nextfb_register_types(void)139e3355a0cSThomas Huth static void nextfb_register_types(void)
140e3355a0cSThomas Huth {
141e3355a0cSThomas Huth type_register_static(&nextfb_info);
142e3355a0cSThomas Huth }
143e3355a0cSThomas Huth
144e3355a0cSThomas Huth type_init(nextfb_register_types)
145