Statistics
| Branch: | Revision:

root / hw / display / g364fb.c @ 2c9b15ca

History | View | Annotate | Download (16.2 kB)

1 1fc3d392 aurel32
/*
2 1fc3d392 aurel32
 * QEMU G364 framebuffer Emulator.
3 1fc3d392 aurel32
 *
4 97a3f6ff Hervé Poussineau
 * Copyright (c) 2007-2011 Herve Poussineau
5 1fc3d392 aurel32
 *
6 1fc3d392 aurel32
 * This program is free software; you can redistribute it and/or
7 1fc3d392 aurel32
 * modify it under the terms of the GNU General Public License as
8 1fc3d392 aurel32
 * published by the Free Software Foundation; either version 2 of
9 1fc3d392 aurel32
 * the License, or (at your option) any later version.
10 1fc3d392 aurel32
 *
11 1fc3d392 aurel32
 * This program is distributed in the hope that it will be useful,
12 1fc3d392 aurel32
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1fc3d392 aurel32
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 1fc3d392 aurel32
 * GNU General Public License for more details.
15 1fc3d392 aurel32
 *
16 fad6cb1a aurel32
 * You should have received a copy of the GNU General Public License along
17 8167ee88 Blue Swirl
 * with this program; if not, see <http://www.gnu.org/licenses/>.
18 1fc3d392 aurel32
 */
19 1fc3d392 aurel32
20 83c9f4ca Paolo Bonzini
#include "hw/hw.h"
21 28ecbaee Paolo Bonzini
#include "ui/console.h"
22 28ecbaee Paolo Bonzini
#include "ui/pixel_ops.h"
23 b213b370 Hervé Poussineau
#include "trace.h"
24 83c9f4ca Paolo Bonzini
#include "hw/sysbus.h"
25 0add30cf aurel32
26 1fc3d392 aurel32
typedef struct G364State {
27 0add30cf aurel32
    /* hardware */
28 0add30cf aurel32
    uint8_t *vram;
29 97a3f6ff Hervé Poussineau
    uint32_t vram_size;
30 0add30cf aurel32
    qemu_irq irq;
31 97a3f6ff Hervé Poussineau
    MemoryRegion mem_vram;
32 97a3f6ff Hervé Poussineau
    MemoryRegion mem_ctrl;
33 0add30cf aurel32
    /* registers */
34 0add30cf aurel32
    uint8_t color_palette[256][3];
35 0add30cf aurel32
    uint8_t cursor_palette[3][3];
36 0add30cf aurel32
    uint16_t cursor[512];
37 0add30cf aurel32
    uint32_t cursor_position;
38 1fc3d392 aurel32
    uint32_t ctla;
39 0add30cf aurel32
    uint32_t top_of_screen;
40 0add30cf aurel32
    uint32_t width, height; /* in pixels */
41 1fc3d392 aurel32
    /* display refresh support */
42 c78f7137 Gerd Hoffmann
    QemuConsole *con;
43 0add30cf aurel32
    int depth;
44 0add30cf aurel32
    int blanked;
45 1fc3d392 aurel32
} G364State;
46 1fc3d392 aurel32
47 97a3f6ff Hervé Poussineau
#define REG_BOOT     0x000000
48 97a3f6ff Hervé Poussineau
#define REG_DISPLAY  0x000118
49 97a3f6ff Hervé Poussineau
#define REG_VDISPLAY 0x000150
50 97a3f6ff Hervé Poussineau
#define REG_CTLA     0x000300
51 97a3f6ff Hervé Poussineau
#define REG_TOP      0x000400
52 97a3f6ff Hervé Poussineau
#define REG_CURS_PAL 0x000508
53 97a3f6ff Hervé Poussineau
#define REG_CURS_POS 0x000638
54 97a3f6ff Hervé Poussineau
#define REG_CLR_PAL  0x000800
55 97a3f6ff Hervé Poussineau
#define REG_CURS_PAT 0x001000
56 97a3f6ff Hervé Poussineau
#define REG_RESET    0x100000
57 0add30cf aurel32
58 0add30cf aurel32
#define CTLA_FORCE_BLANK 0x00000400
59 0add30cf aurel32
#define CTLA_NO_CURSOR   0x00800000
60 0add30cf aurel32
61 1213406b Blue Swirl
#define G364_PAGE_SIZE 4096
62 1213406b Blue Swirl
63 97a3f6ff Hervé Poussineau
static inline int check_dirty(G364State *s, ram_addr_t page)
64 0add30cf aurel32
{
65 cd7a45c9 Blue Swirl
    return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
66 cd7a45c9 Blue Swirl
                                   DIRTY_MEMORY_VGA);
67 0add30cf aurel32
}
68 0add30cf aurel32
69 0add30cf aurel32
static inline void reset_dirty(G364State *s,
70 c227f099 Anthony Liguori
                               ram_addr_t page_min, ram_addr_t page_max)
71 0add30cf aurel32
{
72 97a3f6ff Hervé Poussineau
    memory_region_reset_dirty(&s->mem_vram,
73 97a3f6ff Hervé Poussineau
                              page_min,
74 1213406b Blue Swirl
                              page_max + G364_PAGE_SIZE - page_min - 1,
75 97a3f6ff Hervé Poussineau
                              DIRTY_MEMORY_VGA);
76 0add30cf aurel32
}
77 0add30cf aurel32
78 0add30cf aurel32
static void g364fb_draw_graphic8(G364State *s)
79 1fc3d392 aurel32
{
80 c78f7137 Gerd Hoffmann
    DisplaySurface *surface = qemu_console_surface(s->con);
81 0add30cf aurel32
    int i, w;
82 0add30cf aurel32
    uint8_t *vram;
83 0add30cf aurel32
    uint8_t *data_display, *dd;
84 c227f099 Anthony Liguori
    ram_addr_t page, page_min, page_max;
85 0add30cf aurel32
    int x, y;
86 0add30cf aurel32
    int xmin, xmax;
87 0add30cf aurel32
    int ymin, ymax;
88 0add30cf aurel32
    int xcursor, ycursor;
89 0add30cf aurel32
    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
90 0add30cf aurel32
91 c78f7137 Gerd Hoffmann
    switch (surface_bits_per_pixel(surface)) {
92 1fc3d392 aurel32
        case 8:
93 0add30cf aurel32
            rgb_to_pixel = rgb_to_pixel8;
94 0add30cf aurel32
            w = 1;
95 1fc3d392 aurel32
            break;
96 1fc3d392 aurel32
        case 15:
97 0add30cf aurel32
            rgb_to_pixel = rgb_to_pixel15;
98 0add30cf aurel32
            w = 2;
99 1fc3d392 aurel32
            break;
100 1fc3d392 aurel32
        case 16:
101 0add30cf aurel32
            rgb_to_pixel = rgb_to_pixel16;
102 0add30cf aurel32
            w = 2;
103 1fc3d392 aurel32
            break;
104 1fc3d392 aurel32
        case 32:
105 0add30cf aurel32
            rgb_to_pixel = rgb_to_pixel32;
106 0add30cf aurel32
            w = 4;
107 1fc3d392 aurel32
            break;
108 1fc3d392 aurel32
        default:
109 b213b370 Hervé Poussineau
            hw_error("g364: unknown host depth %d",
110 c78f7137 Gerd Hoffmann
                     surface_bits_per_pixel(surface));
111 1fc3d392 aurel32
            return;
112 1fc3d392 aurel32
    }
113 1fc3d392 aurel32
114 97a3f6ff Hervé Poussineau
    page = 0;
115 c227f099 Anthony Liguori
    page_min = (ram_addr_t)-1;
116 0add30cf aurel32
    page_max = 0;
117 0add30cf aurel32
118 0add30cf aurel32
    x = y = 0;
119 0add30cf aurel32
    xmin = s->width;
120 0add30cf aurel32
    xmax = 0;
121 0add30cf aurel32
    ymin = s->height;
122 0add30cf aurel32
    ymax = 0;
123 0add30cf aurel32
124 0add30cf aurel32
    if (!(s->ctla & CTLA_NO_CURSOR)) {
125 0add30cf aurel32
        xcursor = s->cursor_position >> 12;
126 0add30cf aurel32
        ycursor = s->cursor_position & 0xfff;
127 0add30cf aurel32
    } else {
128 0add30cf aurel32
        xcursor = ycursor = -65;
129 0add30cf aurel32
    }
130 0add30cf aurel32
131 0add30cf aurel32
    vram = s->vram + s->top_of_screen;
132 0add30cf aurel32
    /* XXX: out of range in vram? */
133 c78f7137 Gerd Hoffmann
    data_display = dd = surface_data(surface);
134 0add30cf aurel32
    while (y < s->height) {
135 97a3f6ff Hervé Poussineau
        if (check_dirty(s, page)) {
136 0add30cf aurel32
            if (y < ymin)
137 0add30cf aurel32
                ymin = ymax = y;
138 c227f099 Anthony Liguori
            if (page_min == (ram_addr_t)-1)
139 0add30cf aurel32
                page_min = page;
140 0add30cf aurel32
            page_max = page;
141 0add30cf aurel32
            if (x < xmin)
142 0add30cf aurel32
                xmin = x;
143 1213406b Blue Swirl
            for (i = 0; i < G364_PAGE_SIZE; i++) {
144 0add30cf aurel32
                uint8_t index;
145 0add30cf aurel32
                unsigned int color;
146 0add30cf aurel32
                if (unlikely((y >= ycursor && y < ycursor + 64) &&
147 0add30cf aurel32
                    (x >= xcursor && x < xcursor + 64))) {
148 0add30cf aurel32
                    /* pointer area */
149 0add30cf aurel32
                    int xdiff = x - xcursor;
150 0add30cf aurel32
                    uint16_t curs = s->cursor[(y - ycursor) * 8 + xdiff / 8];
151 0add30cf aurel32
                    int op = (curs >> ((xdiff & 7) * 2)) & 3;
152 0add30cf aurel32
                    if (likely(op == 0)) {
153 0add30cf aurel32
                        /* transparent */
154 0add30cf aurel32
                        index = *vram;
155 0add30cf aurel32
                        color = (*rgb_to_pixel)(
156 0add30cf aurel32
                            s->color_palette[index][0],
157 0add30cf aurel32
                            s->color_palette[index][1],
158 0add30cf aurel32
                            s->color_palette[index][2]);
159 0add30cf aurel32
                    } else {
160 0add30cf aurel32
                        /* get cursor color */
161 0add30cf aurel32
                        index = op - 1;
162 0add30cf aurel32
                        color = (*rgb_to_pixel)(
163 0add30cf aurel32
                            s->cursor_palette[index][0],
164 0add30cf aurel32
                            s->cursor_palette[index][1],
165 0add30cf aurel32
                            s->cursor_palette[index][2]);
166 0add30cf aurel32
                    }
167 0add30cf aurel32
                } else {
168 0add30cf aurel32
                    /* normal area */
169 0add30cf aurel32
                    index = *vram;
170 0add30cf aurel32
                    color = (*rgb_to_pixel)(
171 0add30cf aurel32
                        s->color_palette[index][0],
172 0add30cf aurel32
                        s->color_palette[index][1],
173 0add30cf aurel32
                        s->color_palette[index][2]);
174 0add30cf aurel32
                }
175 0add30cf aurel32
                memcpy(dd, &color, w);
176 0add30cf aurel32
                dd += w;
177 0add30cf aurel32
                x++;
178 0add30cf aurel32
                vram++;
179 0add30cf aurel32
                if (x == s->width) {
180 0add30cf aurel32
                    xmax = s->width - 1;
181 0add30cf aurel32
                    y++;
182 0add30cf aurel32
                    if (y == s->height) {
183 0add30cf aurel32
                        ymax = s->height - 1;
184 0add30cf aurel32
                        goto done;
185 0add30cf aurel32
                    }
186 c78f7137 Gerd Hoffmann
                    data_display = dd = data_display + surface_stride(surface);
187 0add30cf aurel32
                    xmin = 0;
188 0add30cf aurel32
                    x = 0;
189 0add30cf aurel32
                }
190 0add30cf aurel32
            }
191 0add30cf aurel32
            if (x > xmax)
192 0add30cf aurel32
                xmax = x;
193 0add30cf aurel32
            if (y > ymax)
194 0add30cf aurel32
                ymax = y;
195 0add30cf aurel32
        } else {
196 0add30cf aurel32
            int dy;
197 c227f099 Anthony Liguori
            if (page_min != (ram_addr_t)-1) {
198 0add30cf aurel32
                reset_dirty(s, page_min, page_max);
199 c227f099 Anthony Liguori
                page_min = (ram_addr_t)-1;
200 0add30cf aurel32
                page_max = 0;
201 c78f7137 Gerd Hoffmann
                dpy_gfx_update(s->con, xmin, ymin,
202 a93a4a22 Gerd Hoffmann
                               xmax - xmin + 1, ymax - ymin + 1);
203 0add30cf aurel32
                xmin = s->width;
204 0add30cf aurel32
                xmax = 0;
205 0add30cf aurel32
                ymin = s->height;
206 0add30cf aurel32
                ymax = 0;
207 0add30cf aurel32
            }
208 1213406b Blue Swirl
            x += G364_PAGE_SIZE;
209 0add30cf aurel32
            dy = x / s->width;
210 0add30cf aurel32
            x = x % s->width;
211 0add30cf aurel32
            y += dy;
212 1213406b Blue Swirl
            vram += G364_PAGE_SIZE;
213 c78f7137 Gerd Hoffmann
            data_display += dy * surface_stride(surface);
214 0add30cf aurel32
            dd = data_display + x * w;
215 0add30cf aurel32
        }
216 1213406b Blue Swirl
        page += G364_PAGE_SIZE;
217 0add30cf aurel32
    }
218 0add30cf aurel32
219 0add30cf aurel32
done:
220 c227f099 Anthony Liguori
    if (page_min != (ram_addr_t)-1) {
221 c78f7137 Gerd Hoffmann
        dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
222 0add30cf aurel32
        reset_dirty(s, page_min, page_max);
223 0add30cf aurel32
    }
224 1fc3d392 aurel32
}
225 1fc3d392 aurel32
226 0add30cf aurel32
static void g364fb_draw_blank(G364State *s)
227 1fc3d392 aurel32
{
228 c78f7137 Gerd Hoffmann
    DisplaySurface *surface = qemu_console_surface(s->con);
229 1fc3d392 aurel32
    int i, w;
230 1fc3d392 aurel32
    uint8_t *d;
231 1fc3d392 aurel32
232 0add30cf aurel32
    if (s->blanked) {
233 0add30cf aurel32
        /* Screen is already blank. No need to redraw it */
234 1fc3d392 aurel32
        return;
235 0add30cf aurel32
    }
236 1fc3d392 aurel32
237 c78f7137 Gerd Hoffmann
    w = s->width * surface_bytes_per_pixel(surface);
238 c78f7137 Gerd Hoffmann
    d = surface_data(surface);
239 0add30cf aurel32
    for (i = 0; i < s->height; i++) {
240 1fc3d392 aurel32
        memset(d, 0, w);
241 c78f7137 Gerd Hoffmann
        d += surface_stride(surface);
242 1fc3d392 aurel32
    }
243 221bb2d5 aurel32
244 c78f7137 Gerd Hoffmann
    dpy_gfx_update(s->con, 0, 0, s->width, s->height);
245 0add30cf aurel32
    s->blanked = 1;
246 1fc3d392 aurel32
}
247 1fc3d392 aurel32
248 1fc3d392 aurel32
static void g364fb_update_display(void *opaque)
249 1fc3d392 aurel32
{
250 1fc3d392 aurel32
    G364State *s = opaque;
251 c78f7137 Gerd Hoffmann
    DisplaySurface *surface = qemu_console_surface(s->con);
252 1fc3d392 aurel32
253 e9a07334 Jan Kiszka
    qemu_flush_coalesced_mmio_buffer();
254 e9a07334 Jan Kiszka
255 0add30cf aurel32
    if (s->width == 0 || s->height == 0)
256 221bb2d5 aurel32
        return;
257 221bb2d5 aurel32
258 c78f7137 Gerd Hoffmann
    if (s->width != surface_width(surface) ||
259 c78f7137 Gerd Hoffmann
        s->height != surface_height(surface)) {
260 c78f7137 Gerd Hoffmann
        qemu_console_resize(s->con, s->width, s->height);
261 221bb2d5 aurel32
    }
262 0add30cf aurel32
263 0add30cf aurel32
    if (s->ctla & CTLA_FORCE_BLANK) {
264 0add30cf aurel32
        g364fb_draw_blank(s);
265 0add30cf aurel32
    } else if (s->depth == 8) {
266 0add30cf aurel32
        g364fb_draw_graphic8(s);
267 0add30cf aurel32
    } else {
268 b213b370 Hervé Poussineau
        error_report("g364: unknown guest depth %d", s->depth);
269 1fc3d392 aurel32
    }
270 0add30cf aurel32
271 0add30cf aurel32
    qemu_irq_raise(s->irq);
272 1fc3d392 aurel32
}
273 1fc3d392 aurel32
274 86178a57 Juan Quintela
static inline void g364fb_invalidate_display(void *opaque)
275 1fc3d392 aurel32
{
276 1fc3d392 aurel32
    G364State *s = opaque;
277 0add30cf aurel32
278 0add30cf aurel32
    s->blanked = 0;
279 fd4aa979 Blue Swirl
    memory_region_set_dirty(&s->mem_vram, 0, s->vram_size);
280 1fc3d392 aurel32
}
281 1fc3d392 aurel32
282 97a3f6ff Hervé Poussineau
static void g364fb_reset(G364State *s)
283 1fc3d392 aurel32
{
284 0add30cf aurel32
    qemu_irq_lower(s->irq);
285 0add30cf aurel32
286 0add30cf aurel32
    memset(s->color_palette, 0, sizeof(s->color_palette));
287 0add30cf aurel32
    memset(s->cursor_palette, 0, sizeof(s->cursor_palette));
288 0add30cf aurel32
    memset(s->cursor, 0, sizeof(s->cursor));
289 0add30cf aurel32
    s->cursor_position = 0;
290 0add30cf aurel32
    s->ctla = 0;
291 0add30cf aurel32
    s->top_of_screen = 0;
292 0add30cf aurel32
    s->width = s->height = 0;
293 0add30cf aurel32
    memset(s->vram, 0, s->vram_size);
294 97a3f6ff Hervé Poussineau
    g364fb_invalidate_display(s);
295 1fc3d392 aurel32
}
296 1fc3d392 aurel32
297 1fc3d392 aurel32
/* called for accesses to io ports */
298 97a3f6ff Hervé Poussineau
static uint64_t g364fb_ctrl_read(void *opaque,
299 a8170e5e Avi Kivity
                                 hwaddr addr,
300 97a3f6ff Hervé Poussineau
                                 unsigned int size)
301 1fc3d392 aurel32
{
302 0add30cf aurel32
    G364State *s = opaque;
303 1fc3d392 aurel32
    uint32_t val;
304 1fc3d392 aurel32
305 0add30cf aurel32
    if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
306 0add30cf aurel32
        /* cursor pattern */
307 0add30cf aurel32
        int idx = (addr - REG_CURS_PAT) >> 3;
308 0add30cf aurel32
        val = s->cursor[idx];
309 0add30cf aurel32
    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
310 0add30cf aurel32
        /* cursor palette */
311 0add30cf aurel32
        int idx = (addr - REG_CURS_PAL) >> 3;
312 0add30cf aurel32
        val = ((uint32_t)s->cursor_palette[idx][0] << 16);
313 0add30cf aurel32
        val |= ((uint32_t)s->cursor_palette[idx][1] << 8);
314 0add30cf aurel32
        val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
315 0add30cf aurel32
    } else {
316 0add30cf aurel32
        switch (addr) {
317 0add30cf aurel32
            case REG_DISPLAY:
318 0add30cf aurel32
                val = s->width / 4;
319 0add30cf aurel32
                break;
320 0add30cf aurel32
            case REG_VDISPLAY:
321 0add30cf aurel32
                val = s->height * 2;
322 0add30cf aurel32
                break;
323 0add30cf aurel32
            case REG_CTLA:
324 0add30cf aurel32
                val = s->ctla;
325 0add30cf aurel32
                break;
326 0add30cf aurel32
            default:
327 0add30cf aurel32
            {
328 b213b370 Hervé Poussineau
                error_report("g364: invalid read at [" TARGET_FMT_plx "]",
329 b213b370 Hervé Poussineau
                             addr);
330 0add30cf aurel32
                val = 0;
331 0add30cf aurel32
                break;
332 0add30cf aurel32
            }
333 0add30cf aurel32
        }
334 1fc3d392 aurel32
    }
335 1fc3d392 aurel32
336 b213b370 Hervé Poussineau
    trace_g364fb_read(addr, val);
337 1fc3d392 aurel32
338 1fc3d392 aurel32
    return val;
339 1fc3d392 aurel32
}
340 1fc3d392 aurel32
341 0add30cf aurel32
static void g364fb_update_depth(G364State *s)
342 1fc3d392 aurel32
{
343 38972938 Juan Quintela
    static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
344 0add30cf aurel32
    s->depth = depths[(s->ctla & 0x00700000) >> 20];
345 0add30cf aurel32
}
346 1fc3d392 aurel32
347 0add30cf aurel32
static void g364_invalidate_cursor_position(G364State *s)
348 0add30cf aurel32
{
349 c78f7137 Gerd Hoffmann
    DisplaySurface *surface = qemu_console_surface(s->con);
350 fd4aa979 Blue Swirl
    int ymin, ymax, start, end;
351 1fc3d392 aurel32
352 0add30cf aurel32
    /* invalidate only near the cursor */
353 0add30cf aurel32
    ymin = s->cursor_position & 0xfff;
354 0add30cf aurel32
    ymax = MIN(s->height, ymin + 64);
355 c78f7137 Gerd Hoffmann
    start = ymin * surface_stride(surface);
356 c78f7137 Gerd Hoffmann
    end = (ymax + 1) * surface_stride(surface);
357 1fc3d392 aurel32
358 fd4aa979 Blue Swirl
    memory_region_set_dirty(&s->mem_vram, start, end - start);
359 0add30cf aurel32
}
360 0add30cf aurel32
361 97a3f6ff Hervé Poussineau
static void g364fb_ctrl_write(void *opaque,
362 a8170e5e Avi Kivity
                              hwaddr addr,
363 97a3f6ff Hervé Poussineau
                              uint64_t val,
364 97a3f6ff Hervé Poussineau
                              unsigned int size)
365 0add30cf aurel32
{
366 0add30cf aurel32
    G364State *s = opaque;
367 0add30cf aurel32
368 b213b370 Hervé Poussineau
    trace_g364fb_write(addr, val);
369 0add30cf aurel32
370 0add30cf aurel32
    if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
371 1fc3d392 aurel32
        /* color palette */
372 0add30cf aurel32
        int idx = (addr - REG_CLR_PAL) >> 3;
373 0add30cf aurel32
        s->color_palette[idx][0] = (val >> 16) & 0xff;
374 0add30cf aurel32
        s->color_palette[idx][1] = (val >> 8) & 0xff;
375 0add30cf aurel32
        s->color_palette[idx][2] = val & 0xff;
376 0add30cf aurel32
        g364fb_invalidate_display(s);
377 0add30cf aurel32
    } else if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
378 0add30cf aurel32
        /* cursor pattern */
379 0add30cf aurel32
        int idx = (addr - REG_CURS_PAT) >> 3;
380 0add30cf aurel32
        s->cursor[idx] = val;
381 0add30cf aurel32
        g364fb_invalidate_display(s);
382 0add30cf aurel32
    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
383 0add30cf aurel32
        /* cursor palette */
384 0add30cf aurel32
        int idx = (addr - REG_CURS_PAL) >> 3;
385 0add30cf aurel32
        s->cursor_palette[idx][0] = (val >> 16) & 0xff;
386 0add30cf aurel32
        s->cursor_palette[idx][1] = (val >> 8) & 0xff;
387 0add30cf aurel32
        s->cursor_palette[idx][2] = val & 0xff;
388 0add30cf aurel32
        g364fb_invalidate_display(s);
389 1fc3d392 aurel32
    } else {
390 1fc3d392 aurel32
        switch (addr) {
391 97a3f6ff Hervé Poussineau
        case REG_BOOT: /* Boot timing */
392 97a3f6ff Hervé Poussineau
        case 0x00108: /* Line timing: half sync */
393 97a3f6ff Hervé Poussineau
        case 0x00110: /* Line timing: back porch */
394 97a3f6ff Hervé Poussineau
        case 0x00120: /* Line timing: short display */
395 97a3f6ff Hervé Poussineau
        case 0x00128: /* Frame timing: broad pulse */
396 97a3f6ff Hervé Poussineau
        case 0x00130: /* Frame timing: v sync */
397 97a3f6ff Hervé Poussineau
        case 0x00138: /* Frame timing: v preequalise */
398 97a3f6ff Hervé Poussineau
        case 0x00140: /* Frame timing: v postequalise */
399 97a3f6ff Hervé Poussineau
        case 0x00148: /* Frame timing: v blank */
400 97a3f6ff Hervé Poussineau
        case 0x00158: /* Line timing: line time */
401 97a3f6ff Hervé Poussineau
        case 0x00160: /* Frame store: line start */
402 97a3f6ff Hervé Poussineau
        case 0x00168: /* vram cycle: mem init */
403 97a3f6ff Hervé Poussineau
        case 0x00170: /* vram cycle: transfer delay */
404 97a3f6ff Hervé Poussineau
        case 0x00200: /* vram cycle: mask register */
405 97a3f6ff Hervé Poussineau
            /* ignore */
406 97a3f6ff Hervé Poussineau
            break;
407 97a3f6ff Hervé Poussineau
        case REG_TOP:
408 97a3f6ff Hervé Poussineau
            s->top_of_screen = val;
409 97a3f6ff Hervé Poussineau
            g364fb_invalidate_display(s);
410 97a3f6ff Hervé Poussineau
            break;
411 97a3f6ff Hervé Poussineau
        case REG_DISPLAY:
412 97a3f6ff Hervé Poussineau
            s->width = val * 4;
413 97a3f6ff Hervé Poussineau
            break;
414 97a3f6ff Hervé Poussineau
        case REG_VDISPLAY:
415 97a3f6ff Hervé Poussineau
            s->height = val / 2;
416 97a3f6ff Hervé Poussineau
            break;
417 97a3f6ff Hervé Poussineau
        case REG_CTLA:
418 97a3f6ff Hervé Poussineau
            s->ctla = val;
419 97a3f6ff Hervé Poussineau
            g364fb_update_depth(s);
420 97a3f6ff Hervé Poussineau
            g364fb_invalidate_display(s);
421 97a3f6ff Hervé Poussineau
            break;
422 97a3f6ff Hervé Poussineau
        case REG_CURS_POS:
423 97a3f6ff Hervé Poussineau
            g364_invalidate_cursor_position(s);
424 97a3f6ff Hervé Poussineau
            s->cursor_position = val;
425 97a3f6ff Hervé Poussineau
            g364_invalidate_cursor_position(s);
426 97a3f6ff Hervé Poussineau
            break;
427 97a3f6ff Hervé Poussineau
        case REG_RESET:
428 97a3f6ff Hervé Poussineau
            g364fb_reset(s);
429 97a3f6ff Hervé Poussineau
            break;
430 97a3f6ff Hervé Poussineau
        default:
431 97a3f6ff Hervé Poussineau
            error_report("g364: invalid write of 0x%" PRIx64
432 97a3f6ff Hervé Poussineau
                         " at [" TARGET_FMT_plx "]", val, addr);
433 97a3f6ff Hervé Poussineau
            break;
434 1fc3d392 aurel32
        }
435 1fc3d392 aurel32
    }
436 0add30cf aurel32
    qemu_irq_lower(s->irq);
437 1fc3d392 aurel32
}
438 1fc3d392 aurel32
439 97a3f6ff Hervé Poussineau
static const MemoryRegionOps g364fb_ctrl_ops = {
440 97a3f6ff Hervé Poussineau
    .read = g364fb_ctrl_read,
441 97a3f6ff Hervé Poussineau
    .write = g364fb_ctrl_write,
442 97a3f6ff Hervé Poussineau
    .endianness = DEVICE_LITTLE_ENDIAN,
443 97a3f6ff Hervé Poussineau
    .impl.min_access_size = 4,
444 97a3f6ff Hervé Poussineau
    .impl.max_access_size = 4,
445 1fc3d392 aurel32
};
446 1fc3d392 aurel32
447 97a3f6ff Hervé Poussineau
static int g364fb_post_load(void *opaque, int version_id)
448 1fc3d392 aurel32
{
449 1fc3d392 aurel32
    G364State *s = opaque;
450 0add30cf aurel32
451 0add30cf aurel32
    /* force refresh */
452 0add30cf aurel32
    g364fb_update_depth(s);
453 0add30cf aurel32
    g364fb_invalidate_display(s);
454 1fc3d392 aurel32
455 0add30cf aurel32
    return 0;
456 1fc3d392 aurel32
}
457 1fc3d392 aurel32
458 97a3f6ff Hervé Poussineau
static const VMStateDescription vmstate_g364fb = {
459 97a3f6ff Hervé Poussineau
    .name = "g364fb",
460 97a3f6ff Hervé Poussineau
    .version_id = 1,
461 97a3f6ff Hervé Poussineau
    .minimum_version_id = 1,
462 97a3f6ff Hervé Poussineau
    .minimum_version_id_old = 1,
463 97a3f6ff Hervé Poussineau
    .post_load = g364fb_post_load,
464 97a3f6ff Hervé Poussineau
    .fields = (VMStateField[]) {
465 97a3f6ff Hervé Poussineau
        VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
466 97a3f6ff Hervé Poussineau
        VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
467 97a3f6ff Hervé Poussineau
        VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
468 97a3f6ff Hervé Poussineau
        VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
469 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(cursor_position, G364State),
470 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(ctla, G364State),
471 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(top_of_screen, G364State),
472 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(width, G364State),
473 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(height, G364State),
474 97a3f6ff Hervé Poussineau
        VMSTATE_END_OF_LIST()
475 97a3f6ff Hervé Poussineau
    }
476 97a3f6ff Hervé Poussineau
};
477 1fc3d392 aurel32
478 380cd056 Gerd Hoffmann
static const GraphicHwOps g364fb_ops = {
479 380cd056 Gerd Hoffmann
    .invalidate  = g364fb_invalidate_display,
480 380cd056 Gerd Hoffmann
    .gfx_update  = g364fb_update_display,
481 380cd056 Gerd Hoffmann
};
482 380cd056 Gerd Hoffmann
483 97a3f6ff Hervé Poussineau
static void g364fb_init(DeviceState *dev, G364State *s)
484 1fc3d392 aurel32
{
485 97a3f6ff Hervé Poussineau
    s->vram = g_malloc0(s->vram_size);
486 1fc3d392 aurel32
487 aa2beaa1 Gerd Hoffmann
    s->con = graphic_console_init(dev, &g364fb_ops, s);
488 1fc3d392 aurel32
489 2c9b15ca Paolo Bonzini
    memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
490 2c9b15ca Paolo Bonzini
    memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
491 97a3f6ff Hervé Poussineau
                               s->vram_size, s->vram);
492 c5705a77 Avi Kivity
    vmstate_register_ram(&s->mem_vram, dev);
493 97a3f6ff Hervé Poussineau
    memory_region_set_coalescing(&s->mem_vram);
494 97a3f6ff Hervé Poussineau
}
495 97a3f6ff Hervé Poussineau
496 97a3f6ff Hervé Poussineau
typedef struct {
497 97a3f6ff Hervé Poussineau
    SysBusDevice busdev;
498 97a3f6ff Hervé Poussineau
    G364State g364;
499 97a3f6ff Hervé Poussineau
} G364SysBusState;
500 1fc3d392 aurel32
501 97a3f6ff Hervé Poussineau
static int g364fb_sysbus_init(SysBusDevice *dev)
502 97a3f6ff Hervé Poussineau
{
503 97a3f6ff Hervé Poussineau
    G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364;
504 97a3f6ff Hervé Poussineau
505 97a3f6ff Hervé Poussineau
    g364fb_init(&dev->qdev, s);
506 97a3f6ff Hervé Poussineau
    sysbus_init_irq(dev, &s->irq);
507 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->mem_ctrl);
508 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->mem_vram);
509 1fc3d392 aurel32
510 1fc3d392 aurel32
    return 0;
511 1fc3d392 aurel32
}
512 97a3f6ff Hervé Poussineau
513 97a3f6ff Hervé Poussineau
static void g364fb_sysbus_reset(DeviceState *d)
514 97a3f6ff Hervé Poussineau
{
515 97a3f6ff Hervé Poussineau
    G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d);
516 97a3f6ff Hervé Poussineau
    g364fb_reset(&s->g364);
517 97a3f6ff Hervé Poussineau
}
518 97a3f6ff Hervé Poussineau
519 999e12bb Anthony Liguori
static Property g364fb_sysbus_properties[] = {
520 999e12bb Anthony Liguori
    DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
521 999e12bb Anthony Liguori
    8 * 1024 * 1024),
522 999e12bb Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
523 999e12bb Anthony Liguori
};
524 999e12bb Anthony Liguori
525 999e12bb Anthony Liguori
static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
526 999e12bb Anthony Liguori
{
527 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
528 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
529 999e12bb Anthony Liguori
530 999e12bb Anthony Liguori
    k->init = g364fb_sysbus_init;
531 39bffca2 Anthony Liguori
    dc->desc = "G364 framebuffer";
532 39bffca2 Anthony Liguori
    dc->reset = g364fb_sysbus_reset;
533 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_g364fb;
534 39bffca2 Anthony Liguori
    dc->props = g364fb_sysbus_properties;
535 999e12bb Anthony Liguori
}
536 999e12bb Anthony Liguori
537 8c43a6f0 Andreas Färber
static const TypeInfo g364fb_sysbus_info = {
538 39bffca2 Anthony Liguori
    .name          = "sysbus-g364",
539 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
540 39bffca2 Anthony Liguori
    .instance_size = sizeof(G364SysBusState),
541 39bffca2 Anthony Liguori
    .class_init    = g364fb_sysbus_class_init,
542 97a3f6ff Hervé Poussineau
};
543 97a3f6ff Hervé Poussineau
544 83f7d43a Andreas Färber
static void g364fb_register_types(void)
545 97a3f6ff Hervé Poussineau
{
546 39bffca2 Anthony Liguori
    type_register_static(&g364fb_sysbus_info);
547 97a3f6ff Hervé Poussineau
}
548 97a3f6ff Hervé Poussineau
549 83f7d43a Andreas Färber
type_init(g364fb_register_types)