Statistics
| Branch: | Revision:

root / hw / g364fb.c @ cd7a45c9

History | View | Annotate | Download (17 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 1fc3d392 aurel32
#include "hw.h"
21 1fc3d392 aurel32
#include "console.h"
22 1fc3d392 aurel32
#include "pixel_ops.h"
23 b213b370 Hervé Poussineau
#include "trace.h"
24 97a3f6ff Hervé Poussineau
#include "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 1fc3d392 aurel32
    DisplayState *ds;
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 0add30cf aurel32
    int i, w;
81 0add30cf aurel32
    uint8_t *vram;
82 0add30cf aurel32
    uint8_t *data_display, *dd;
83 c227f099 Anthony Liguori
    ram_addr_t page, page_min, page_max;
84 0add30cf aurel32
    int x, y;
85 0add30cf aurel32
    int xmin, xmax;
86 0add30cf aurel32
    int ymin, ymax;
87 0add30cf aurel32
    int xcursor, ycursor;
88 0add30cf aurel32
    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
89 0add30cf aurel32
90 0e1f5a0c aliguori
    switch (ds_get_bits_per_pixel(s->ds)) {
91 1fc3d392 aurel32
        case 8:
92 0add30cf aurel32
            rgb_to_pixel = rgb_to_pixel8;
93 0add30cf aurel32
            w = 1;
94 1fc3d392 aurel32
            break;
95 1fc3d392 aurel32
        case 15:
96 0add30cf aurel32
            rgb_to_pixel = rgb_to_pixel15;
97 0add30cf aurel32
            w = 2;
98 1fc3d392 aurel32
            break;
99 1fc3d392 aurel32
        case 16:
100 0add30cf aurel32
            rgb_to_pixel = rgb_to_pixel16;
101 0add30cf aurel32
            w = 2;
102 1fc3d392 aurel32
            break;
103 1fc3d392 aurel32
        case 32:
104 0add30cf aurel32
            rgb_to_pixel = rgb_to_pixel32;
105 0add30cf aurel32
            w = 4;
106 1fc3d392 aurel32
            break;
107 1fc3d392 aurel32
        default:
108 b213b370 Hervé Poussineau
            hw_error("g364: unknown host depth %d",
109 b213b370 Hervé Poussineau
                     ds_get_bits_per_pixel(s->ds));
110 1fc3d392 aurel32
            return;
111 1fc3d392 aurel32
    }
112 1fc3d392 aurel32
113 97a3f6ff Hervé Poussineau
    page = 0;
114 c227f099 Anthony Liguori
    page_min = (ram_addr_t)-1;
115 0add30cf aurel32
    page_max = 0;
116 0add30cf aurel32
117 0add30cf aurel32
    x = y = 0;
118 0add30cf aurel32
    xmin = s->width;
119 0add30cf aurel32
    xmax = 0;
120 0add30cf aurel32
    ymin = s->height;
121 0add30cf aurel32
    ymax = 0;
122 0add30cf aurel32
123 0add30cf aurel32
    if (!(s->ctla & CTLA_NO_CURSOR)) {
124 0add30cf aurel32
        xcursor = s->cursor_position >> 12;
125 0add30cf aurel32
        ycursor = s->cursor_position & 0xfff;
126 0add30cf aurel32
    } else {
127 0add30cf aurel32
        xcursor = ycursor = -65;
128 0add30cf aurel32
    }
129 0add30cf aurel32
130 0add30cf aurel32
    vram = s->vram + s->top_of_screen;
131 0add30cf aurel32
    /* XXX: out of range in vram? */
132 0add30cf aurel32
    data_display = dd = ds_get_data(s->ds);
133 0add30cf aurel32
    while (y < s->height) {
134 97a3f6ff Hervé Poussineau
        if (check_dirty(s, page)) {
135 0add30cf aurel32
            if (y < ymin)
136 0add30cf aurel32
                ymin = ymax = y;
137 c227f099 Anthony Liguori
            if (page_min == (ram_addr_t)-1)
138 0add30cf aurel32
                page_min = page;
139 0add30cf aurel32
            page_max = page;
140 0add30cf aurel32
            if (x < xmin)
141 0add30cf aurel32
                xmin = x;
142 1213406b Blue Swirl
            for (i = 0; i < G364_PAGE_SIZE; i++) {
143 0add30cf aurel32
                uint8_t index;
144 0add30cf aurel32
                unsigned int color;
145 0add30cf aurel32
                if (unlikely((y >= ycursor && y < ycursor + 64) &&
146 0add30cf aurel32
                    (x >= xcursor && x < xcursor + 64))) {
147 0add30cf aurel32
                    /* pointer area */
148 0add30cf aurel32
                    int xdiff = x - xcursor;
149 0add30cf aurel32
                    uint16_t curs = s->cursor[(y - ycursor) * 8 + xdiff / 8];
150 0add30cf aurel32
                    int op = (curs >> ((xdiff & 7) * 2)) & 3;
151 0add30cf aurel32
                    if (likely(op == 0)) {
152 0add30cf aurel32
                        /* transparent */
153 0add30cf aurel32
                        index = *vram;
154 0add30cf aurel32
                        color = (*rgb_to_pixel)(
155 0add30cf aurel32
                            s->color_palette[index][0],
156 0add30cf aurel32
                            s->color_palette[index][1],
157 0add30cf aurel32
                            s->color_palette[index][2]);
158 0add30cf aurel32
                    } else {
159 0add30cf aurel32
                        /* get cursor color */
160 0add30cf aurel32
                        index = op - 1;
161 0add30cf aurel32
                        color = (*rgb_to_pixel)(
162 0add30cf aurel32
                            s->cursor_palette[index][0],
163 0add30cf aurel32
                            s->cursor_palette[index][1],
164 0add30cf aurel32
                            s->cursor_palette[index][2]);
165 0add30cf aurel32
                    }
166 0add30cf aurel32
                } else {
167 0add30cf aurel32
                    /* normal area */
168 0add30cf aurel32
                    index = *vram;
169 0add30cf aurel32
                    color = (*rgb_to_pixel)(
170 0add30cf aurel32
                        s->color_palette[index][0],
171 0add30cf aurel32
                        s->color_palette[index][1],
172 0add30cf aurel32
                        s->color_palette[index][2]);
173 0add30cf aurel32
                }
174 0add30cf aurel32
                memcpy(dd, &color, w);
175 0add30cf aurel32
                dd += w;
176 0add30cf aurel32
                x++;
177 0add30cf aurel32
                vram++;
178 0add30cf aurel32
                if (x == s->width) {
179 0add30cf aurel32
                    xmax = s->width - 1;
180 0add30cf aurel32
                    y++;
181 0add30cf aurel32
                    if (y == s->height) {
182 0add30cf aurel32
                        ymax = s->height - 1;
183 0add30cf aurel32
                        goto done;
184 0add30cf aurel32
                    }
185 0add30cf aurel32
                    data_display = dd = data_display + ds_get_linesize(s->ds);
186 0add30cf aurel32
                    xmin = 0;
187 0add30cf aurel32
                    x = 0;
188 0add30cf aurel32
                }
189 0add30cf aurel32
            }
190 0add30cf aurel32
            if (x > xmax)
191 0add30cf aurel32
                xmax = x;
192 0add30cf aurel32
            if (y > ymax)
193 0add30cf aurel32
                ymax = y;
194 0add30cf aurel32
        } else {
195 0add30cf aurel32
            int dy;
196 c227f099 Anthony Liguori
            if (page_min != (ram_addr_t)-1) {
197 0add30cf aurel32
                reset_dirty(s, page_min, page_max);
198 c227f099 Anthony Liguori
                page_min = (ram_addr_t)-1;
199 0add30cf aurel32
                page_max = 0;
200 0add30cf aurel32
                dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
201 0add30cf aurel32
                xmin = s->width;
202 0add30cf aurel32
                xmax = 0;
203 0add30cf aurel32
                ymin = s->height;
204 0add30cf aurel32
                ymax = 0;
205 0add30cf aurel32
            }
206 1213406b Blue Swirl
            x += G364_PAGE_SIZE;
207 0add30cf aurel32
            dy = x / s->width;
208 0add30cf aurel32
            x = x % s->width;
209 0add30cf aurel32
            y += dy;
210 1213406b Blue Swirl
            vram += G364_PAGE_SIZE;
211 0add30cf aurel32
            data_display += dy * ds_get_linesize(s->ds);
212 0add30cf aurel32
            dd = data_display + x * w;
213 0add30cf aurel32
        }
214 1213406b Blue Swirl
        page += G364_PAGE_SIZE;
215 0add30cf aurel32
    }
216 0add30cf aurel32
217 0add30cf aurel32
done:
218 c227f099 Anthony Liguori
    if (page_min != (ram_addr_t)-1) {
219 0add30cf aurel32
        dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
220 0add30cf aurel32
        reset_dirty(s, page_min, page_max);
221 0add30cf aurel32
    }
222 1fc3d392 aurel32
}
223 1fc3d392 aurel32
224 0add30cf aurel32
static void g364fb_draw_blank(G364State *s)
225 1fc3d392 aurel32
{
226 1fc3d392 aurel32
    int i, w;
227 1fc3d392 aurel32
    uint8_t *d;
228 1fc3d392 aurel32
229 0add30cf aurel32
    if (s->blanked) {
230 0add30cf aurel32
        /* Screen is already blank. No need to redraw it */
231 1fc3d392 aurel32
        return;
232 0add30cf aurel32
    }
233 1fc3d392 aurel32
234 0add30cf aurel32
    w = s->width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
235 0e1f5a0c aliguori
    d = ds_get_data(s->ds);
236 0add30cf aurel32
    for (i = 0; i < s->height; i++) {
237 1fc3d392 aurel32
        memset(d, 0, w);
238 0e1f5a0c aliguori
        d += ds_get_linesize(s->ds);
239 1fc3d392 aurel32
    }
240 221bb2d5 aurel32
241 0add30cf aurel32
    dpy_update(s->ds, 0, 0, s->width, s->height);
242 0add30cf aurel32
    s->blanked = 1;
243 1fc3d392 aurel32
}
244 1fc3d392 aurel32
245 1fc3d392 aurel32
static void g364fb_update_display(void *opaque)
246 1fc3d392 aurel32
{
247 1fc3d392 aurel32
    G364State *s = opaque;
248 1fc3d392 aurel32
249 e9a07334 Jan Kiszka
    qemu_flush_coalesced_mmio_buffer();
250 e9a07334 Jan Kiszka
251 0add30cf aurel32
    if (s->width == 0 || s->height == 0)
252 221bb2d5 aurel32
        return;
253 221bb2d5 aurel32
254 0add30cf aurel32
    if (s->width != ds_get_width(s->ds) || s->height != ds_get_height(s->ds)) {
255 0add30cf aurel32
        qemu_console_resize(s->ds, s->width, s->height);
256 221bb2d5 aurel32
    }
257 0add30cf aurel32
258 0add30cf aurel32
    if (s->ctla & CTLA_FORCE_BLANK) {
259 0add30cf aurel32
        g364fb_draw_blank(s);
260 0add30cf aurel32
    } else if (s->depth == 8) {
261 0add30cf aurel32
        g364fb_draw_graphic8(s);
262 0add30cf aurel32
    } else {
263 b213b370 Hervé Poussineau
        error_report("g364: unknown guest depth %d", s->depth);
264 1fc3d392 aurel32
    }
265 0add30cf aurel32
266 0add30cf aurel32
    qemu_irq_raise(s->irq);
267 1fc3d392 aurel32
}
268 1fc3d392 aurel32
269 86178a57 Juan Quintela
static inline void g364fb_invalidate_display(void *opaque)
270 1fc3d392 aurel32
{
271 1fc3d392 aurel32
    G364State *s = opaque;
272 0add30cf aurel32
273 0add30cf aurel32
    s->blanked = 0;
274 fd4aa979 Blue Swirl
    memory_region_set_dirty(&s->mem_vram, 0, s->vram_size);
275 1fc3d392 aurel32
}
276 1fc3d392 aurel32
277 97a3f6ff Hervé Poussineau
static void g364fb_reset(G364State *s)
278 1fc3d392 aurel32
{
279 0add30cf aurel32
    qemu_irq_lower(s->irq);
280 0add30cf aurel32
281 0add30cf aurel32
    memset(s->color_palette, 0, sizeof(s->color_palette));
282 0add30cf aurel32
    memset(s->cursor_palette, 0, sizeof(s->cursor_palette));
283 0add30cf aurel32
    memset(s->cursor, 0, sizeof(s->cursor));
284 0add30cf aurel32
    s->cursor_position = 0;
285 0add30cf aurel32
    s->ctla = 0;
286 0add30cf aurel32
    s->top_of_screen = 0;
287 0add30cf aurel32
    s->width = s->height = 0;
288 0add30cf aurel32
    memset(s->vram, 0, s->vram_size);
289 97a3f6ff Hervé Poussineau
    g364fb_invalidate_display(s);
290 1fc3d392 aurel32
}
291 1fc3d392 aurel32
292 1fc3d392 aurel32
static void g364fb_screen_dump(void *opaque, const char *filename)
293 1fc3d392 aurel32
{
294 1fc3d392 aurel32
    G364State *s = opaque;
295 1fc3d392 aurel32
    int y, x;
296 1fc3d392 aurel32
    uint8_t index;
297 1fc3d392 aurel32
    uint8_t *data_buffer;
298 1fc3d392 aurel32
    FILE *f;
299 1fc3d392 aurel32
300 e9a07334 Jan Kiszka
    qemu_flush_coalesced_mmio_buffer();
301 e9a07334 Jan Kiszka
302 0add30cf aurel32
    if (s->depth != 8) {
303 b213b370 Hervé Poussineau
        error_report("g364: unknown guest depth %d", s->depth);
304 0add30cf aurel32
        return;
305 0add30cf aurel32
    }
306 0add30cf aurel32
307 1fc3d392 aurel32
    f = fopen(filename, "wb");
308 1fc3d392 aurel32
    if (!f)
309 1fc3d392 aurel32
        return;
310 1fc3d392 aurel32
311 0add30cf aurel32
    if (s->ctla & CTLA_FORCE_BLANK) {
312 0add30cf aurel32
        /* blank screen */
313 0add30cf aurel32
        fprintf(f, "P4\n%d %d\n",
314 0add30cf aurel32
            s->width, s->height);
315 0add30cf aurel32
        for (y = 0; y < s->height; y++)
316 0add30cf aurel32
            for (x = 0; x < s->width; x++)
317 0add30cf aurel32
                fputc(0, f);
318 0add30cf aurel32
    } else {
319 0add30cf aurel32
        data_buffer = s->vram + s->top_of_screen;
320 0add30cf aurel32
        fprintf(f, "P6\n%d %d\n%d\n",
321 0add30cf aurel32
            s->width, s->height, 255);
322 0add30cf aurel32
        for (y = 0; y < s->height; y++)
323 0add30cf aurel32
            for (x = 0; x < s->width; x++, data_buffer++) {
324 0add30cf aurel32
                index = *data_buffer;
325 0add30cf aurel32
                fputc(s->color_palette[index][0], f);
326 0add30cf aurel32
                fputc(s->color_palette[index][1], f);
327 0add30cf aurel32
                fputc(s->color_palette[index][2], f);
328 1fc3d392 aurel32
        }
329 0add30cf aurel32
    }
330 0add30cf aurel32
331 1fc3d392 aurel32
    fclose(f);
332 1fc3d392 aurel32
}
333 1fc3d392 aurel32
334 1fc3d392 aurel32
/* called for accesses to io ports */
335 97a3f6ff Hervé Poussineau
static uint64_t g364fb_ctrl_read(void *opaque,
336 97a3f6ff Hervé Poussineau
                                 target_phys_addr_t addr,
337 97a3f6ff Hervé Poussineau
                                 unsigned int size)
338 1fc3d392 aurel32
{
339 0add30cf aurel32
    G364State *s = opaque;
340 1fc3d392 aurel32
    uint32_t val;
341 1fc3d392 aurel32
342 0add30cf aurel32
    if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
343 0add30cf aurel32
        /* cursor pattern */
344 0add30cf aurel32
        int idx = (addr - REG_CURS_PAT) >> 3;
345 0add30cf aurel32
        val = s->cursor[idx];
346 0add30cf aurel32
    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
347 0add30cf aurel32
        /* cursor palette */
348 0add30cf aurel32
        int idx = (addr - REG_CURS_PAL) >> 3;
349 0add30cf aurel32
        val = ((uint32_t)s->cursor_palette[idx][0] << 16);
350 0add30cf aurel32
        val |= ((uint32_t)s->cursor_palette[idx][1] << 8);
351 0add30cf aurel32
        val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
352 0add30cf aurel32
    } else {
353 0add30cf aurel32
        switch (addr) {
354 0add30cf aurel32
            case REG_DISPLAY:
355 0add30cf aurel32
                val = s->width / 4;
356 0add30cf aurel32
                break;
357 0add30cf aurel32
            case REG_VDISPLAY:
358 0add30cf aurel32
                val = s->height * 2;
359 0add30cf aurel32
                break;
360 0add30cf aurel32
            case REG_CTLA:
361 0add30cf aurel32
                val = s->ctla;
362 0add30cf aurel32
                break;
363 0add30cf aurel32
            default:
364 0add30cf aurel32
            {
365 b213b370 Hervé Poussineau
                error_report("g364: invalid read at [" TARGET_FMT_plx "]",
366 b213b370 Hervé Poussineau
                             addr);
367 0add30cf aurel32
                val = 0;
368 0add30cf aurel32
                break;
369 0add30cf aurel32
            }
370 0add30cf aurel32
        }
371 1fc3d392 aurel32
    }
372 1fc3d392 aurel32
373 b213b370 Hervé Poussineau
    trace_g364fb_read(addr, val);
374 1fc3d392 aurel32
375 1fc3d392 aurel32
    return val;
376 1fc3d392 aurel32
}
377 1fc3d392 aurel32
378 0add30cf aurel32
static void g364fb_update_depth(G364State *s)
379 1fc3d392 aurel32
{
380 38972938 Juan Quintela
    static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
381 0add30cf aurel32
    s->depth = depths[(s->ctla & 0x00700000) >> 20];
382 0add30cf aurel32
}
383 1fc3d392 aurel32
384 0add30cf aurel32
static void g364_invalidate_cursor_position(G364State *s)
385 0add30cf aurel32
{
386 fd4aa979 Blue Swirl
    int ymin, ymax, start, end;
387 1fc3d392 aurel32
388 0add30cf aurel32
    /* invalidate only near the cursor */
389 0add30cf aurel32
    ymin = s->cursor_position & 0xfff;
390 0add30cf aurel32
    ymax = MIN(s->height, ymin + 64);
391 0add30cf aurel32
    start = ymin * ds_get_linesize(s->ds);
392 0add30cf aurel32
    end = (ymax + 1) * ds_get_linesize(s->ds);
393 1fc3d392 aurel32
394 fd4aa979 Blue Swirl
    memory_region_set_dirty(&s->mem_vram, start, end - start);
395 0add30cf aurel32
}
396 0add30cf aurel32
397 97a3f6ff Hervé Poussineau
static void g364fb_ctrl_write(void *opaque,
398 97a3f6ff Hervé Poussineau
                              target_phys_addr_t addr,
399 97a3f6ff Hervé Poussineau
                              uint64_t val,
400 97a3f6ff Hervé Poussineau
                              unsigned int size)
401 0add30cf aurel32
{
402 0add30cf aurel32
    G364State *s = opaque;
403 0add30cf aurel32
404 b213b370 Hervé Poussineau
    trace_g364fb_write(addr, val);
405 0add30cf aurel32
406 0add30cf aurel32
    if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
407 1fc3d392 aurel32
        /* color palette */
408 0add30cf aurel32
        int idx = (addr - REG_CLR_PAL) >> 3;
409 0add30cf aurel32
        s->color_palette[idx][0] = (val >> 16) & 0xff;
410 0add30cf aurel32
        s->color_palette[idx][1] = (val >> 8) & 0xff;
411 0add30cf aurel32
        s->color_palette[idx][2] = val & 0xff;
412 0add30cf aurel32
        g364fb_invalidate_display(s);
413 0add30cf aurel32
    } else if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
414 0add30cf aurel32
        /* cursor pattern */
415 0add30cf aurel32
        int idx = (addr - REG_CURS_PAT) >> 3;
416 0add30cf aurel32
        s->cursor[idx] = val;
417 0add30cf aurel32
        g364fb_invalidate_display(s);
418 0add30cf aurel32
    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
419 0add30cf aurel32
        /* cursor palette */
420 0add30cf aurel32
        int idx = (addr - REG_CURS_PAL) >> 3;
421 0add30cf aurel32
        s->cursor_palette[idx][0] = (val >> 16) & 0xff;
422 0add30cf aurel32
        s->cursor_palette[idx][1] = (val >> 8) & 0xff;
423 0add30cf aurel32
        s->cursor_palette[idx][2] = val & 0xff;
424 0add30cf aurel32
        g364fb_invalidate_display(s);
425 1fc3d392 aurel32
    } else {
426 1fc3d392 aurel32
        switch (addr) {
427 97a3f6ff Hervé Poussineau
        case REG_BOOT: /* Boot timing */
428 97a3f6ff Hervé Poussineau
        case 0x00108: /* Line timing: half sync */
429 97a3f6ff Hervé Poussineau
        case 0x00110: /* Line timing: back porch */
430 97a3f6ff Hervé Poussineau
        case 0x00120: /* Line timing: short display */
431 97a3f6ff Hervé Poussineau
        case 0x00128: /* Frame timing: broad pulse */
432 97a3f6ff Hervé Poussineau
        case 0x00130: /* Frame timing: v sync */
433 97a3f6ff Hervé Poussineau
        case 0x00138: /* Frame timing: v preequalise */
434 97a3f6ff Hervé Poussineau
        case 0x00140: /* Frame timing: v postequalise */
435 97a3f6ff Hervé Poussineau
        case 0x00148: /* Frame timing: v blank */
436 97a3f6ff Hervé Poussineau
        case 0x00158: /* Line timing: line time */
437 97a3f6ff Hervé Poussineau
        case 0x00160: /* Frame store: line start */
438 97a3f6ff Hervé Poussineau
        case 0x00168: /* vram cycle: mem init */
439 97a3f6ff Hervé Poussineau
        case 0x00170: /* vram cycle: transfer delay */
440 97a3f6ff Hervé Poussineau
        case 0x00200: /* vram cycle: mask register */
441 97a3f6ff Hervé Poussineau
            /* ignore */
442 97a3f6ff Hervé Poussineau
            break;
443 97a3f6ff Hervé Poussineau
        case REG_TOP:
444 97a3f6ff Hervé Poussineau
            s->top_of_screen = val;
445 97a3f6ff Hervé Poussineau
            g364fb_invalidate_display(s);
446 97a3f6ff Hervé Poussineau
            break;
447 97a3f6ff Hervé Poussineau
        case REG_DISPLAY:
448 97a3f6ff Hervé Poussineau
            s->width = val * 4;
449 97a3f6ff Hervé Poussineau
            break;
450 97a3f6ff Hervé Poussineau
        case REG_VDISPLAY:
451 97a3f6ff Hervé Poussineau
            s->height = val / 2;
452 97a3f6ff Hervé Poussineau
            break;
453 97a3f6ff Hervé Poussineau
        case REG_CTLA:
454 97a3f6ff Hervé Poussineau
            s->ctla = val;
455 97a3f6ff Hervé Poussineau
            g364fb_update_depth(s);
456 97a3f6ff Hervé Poussineau
            g364fb_invalidate_display(s);
457 97a3f6ff Hervé Poussineau
            break;
458 97a3f6ff Hervé Poussineau
        case REG_CURS_POS:
459 97a3f6ff Hervé Poussineau
            g364_invalidate_cursor_position(s);
460 97a3f6ff Hervé Poussineau
            s->cursor_position = val;
461 97a3f6ff Hervé Poussineau
            g364_invalidate_cursor_position(s);
462 97a3f6ff Hervé Poussineau
            break;
463 97a3f6ff Hervé Poussineau
        case REG_RESET:
464 97a3f6ff Hervé Poussineau
            g364fb_reset(s);
465 97a3f6ff Hervé Poussineau
            break;
466 97a3f6ff Hervé Poussineau
        default:
467 97a3f6ff Hervé Poussineau
            error_report("g364: invalid write of 0x%" PRIx64
468 97a3f6ff Hervé Poussineau
                         " at [" TARGET_FMT_plx "]", val, addr);
469 97a3f6ff Hervé Poussineau
            break;
470 1fc3d392 aurel32
        }
471 1fc3d392 aurel32
    }
472 0add30cf aurel32
    qemu_irq_lower(s->irq);
473 1fc3d392 aurel32
}
474 1fc3d392 aurel32
475 97a3f6ff Hervé Poussineau
static const MemoryRegionOps g364fb_ctrl_ops = {
476 97a3f6ff Hervé Poussineau
    .read = g364fb_ctrl_read,
477 97a3f6ff Hervé Poussineau
    .write = g364fb_ctrl_write,
478 97a3f6ff Hervé Poussineau
    .endianness = DEVICE_LITTLE_ENDIAN,
479 97a3f6ff Hervé Poussineau
    .impl.min_access_size = 4,
480 97a3f6ff Hervé Poussineau
    .impl.max_access_size = 4,
481 1fc3d392 aurel32
};
482 1fc3d392 aurel32
483 97a3f6ff Hervé Poussineau
static int g364fb_post_load(void *opaque, int version_id)
484 1fc3d392 aurel32
{
485 1fc3d392 aurel32
    G364State *s = opaque;
486 0add30cf aurel32
487 0add30cf aurel32
    /* force refresh */
488 0add30cf aurel32
    g364fb_update_depth(s);
489 0add30cf aurel32
    g364fb_invalidate_display(s);
490 1fc3d392 aurel32
491 0add30cf aurel32
    return 0;
492 1fc3d392 aurel32
}
493 1fc3d392 aurel32
494 97a3f6ff Hervé Poussineau
static const VMStateDescription vmstate_g364fb = {
495 97a3f6ff Hervé Poussineau
    .name = "g364fb",
496 97a3f6ff Hervé Poussineau
    .version_id = 1,
497 97a3f6ff Hervé Poussineau
    .minimum_version_id = 1,
498 97a3f6ff Hervé Poussineau
    .minimum_version_id_old = 1,
499 97a3f6ff Hervé Poussineau
    .post_load = g364fb_post_load,
500 97a3f6ff Hervé Poussineau
    .fields = (VMStateField[]) {
501 97a3f6ff Hervé Poussineau
        VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
502 97a3f6ff Hervé Poussineau
        VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
503 97a3f6ff Hervé Poussineau
        VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
504 97a3f6ff Hervé Poussineau
        VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
505 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(cursor_position, G364State),
506 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(ctla, G364State),
507 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(top_of_screen, G364State),
508 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(width, G364State),
509 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(height, G364State),
510 97a3f6ff Hervé Poussineau
        VMSTATE_END_OF_LIST()
511 97a3f6ff Hervé Poussineau
    }
512 97a3f6ff Hervé Poussineau
};
513 1fc3d392 aurel32
514 97a3f6ff Hervé Poussineau
static void g364fb_init(DeviceState *dev, G364State *s)
515 1fc3d392 aurel32
{
516 97a3f6ff Hervé Poussineau
    s->vram = g_malloc0(s->vram_size);
517 1fc3d392 aurel32
518 3023f332 aliguori
    s->ds = graphic_console_init(g364fb_update_display,
519 3023f332 aliguori
                                 g364fb_invalidate_display,
520 3023f332 aliguori
                                 g364fb_screen_dump, NULL, s);
521 1fc3d392 aurel32
522 97a3f6ff Hervé Poussineau
    memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
523 c5705a77 Avi Kivity
    memory_region_init_ram_ptr(&s->mem_vram, "vram",
524 97a3f6ff Hervé Poussineau
                               s->vram_size, s->vram);
525 c5705a77 Avi Kivity
    vmstate_register_ram(&s->mem_vram, dev);
526 97a3f6ff Hervé Poussineau
    memory_region_set_coalescing(&s->mem_vram);
527 97a3f6ff Hervé Poussineau
}
528 97a3f6ff Hervé Poussineau
529 97a3f6ff Hervé Poussineau
typedef struct {
530 97a3f6ff Hervé Poussineau
    SysBusDevice busdev;
531 97a3f6ff Hervé Poussineau
    G364State g364;
532 97a3f6ff Hervé Poussineau
} G364SysBusState;
533 1fc3d392 aurel32
534 97a3f6ff Hervé Poussineau
static int g364fb_sysbus_init(SysBusDevice *dev)
535 97a3f6ff Hervé Poussineau
{
536 97a3f6ff Hervé Poussineau
    G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364;
537 97a3f6ff Hervé Poussineau
538 97a3f6ff Hervé Poussineau
    g364fb_init(&dev->qdev, s);
539 97a3f6ff Hervé Poussineau
    sysbus_init_irq(dev, &s->irq);
540 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->mem_ctrl);
541 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->mem_vram);
542 1fc3d392 aurel32
543 1fc3d392 aurel32
    return 0;
544 1fc3d392 aurel32
}
545 97a3f6ff Hervé Poussineau
546 97a3f6ff Hervé Poussineau
static void g364fb_sysbus_reset(DeviceState *d)
547 97a3f6ff Hervé Poussineau
{
548 97a3f6ff Hervé Poussineau
    G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d);
549 97a3f6ff Hervé Poussineau
    g364fb_reset(&s->g364);
550 97a3f6ff Hervé Poussineau
}
551 97a3f6ff Hervé Poussineau
552 999e12bb Anthony Liguori
static Property g364fb_sysbus_properties[] = {
553 999e12bb Anthony Liguori
    DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
554 999e12bb Anthony Liguori
    8 * 1024 * 1024),
555 999e12bb Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
556 999e12bb Anthony Liguori
};
557 999e12bb Anthony Liguori
558 999e12bb Anthony Liguori
static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
559 999e12bb Anthony Liguori
{
560 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
561 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
562 999e12bb Anthony Liguori
563 999e12bb Anthony Liguori
    k->init = g364fb_sysbus_init;
564 39bffca2 Anthony Liguori
    dc->desc = "G364 framebuffer";
565 39bffca2 Anthony Liguori
    dc->reset = g364fb_sysbus_reset;
566 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_g364fb;
567 39bffca2 Anthony Liguori
    dc->props = g364fb_sysbus_properties;
568 999e12bb Anthony Liguori
}
569 999e12bb Anthony Liguori
570 39bffca2 Anthony Liguori
static TypeInfo g364fb_sysbus_info = {
571 39bffca2 Anthony Liguori
    .name          = "sysbus-g364",
572 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
573 39bffca2 Anthony Liguori
    .instance_size = sizeof(G364SysBusState),
574 39bffca2 Anthony Liguori
    .class_init    = g364fb_sysbus_class_init,
575 97a3f6ff Hervé Poussineau
};
576 97a3f6ff Hervé Poussineau
577 97a3f6ff Hervé Poussineau
static void g364fb_register(void)
578 97a3f6ff Hervé Poussineau
{
579 39bffca2 Anthony Liguori
    type_register_static(&g364fb_sysbus_info);
580 97a3f6ff Hervé Poussineau
}
581 97a3f6ff Hervé Poussineau
582 97a3f6ff Hervé Poussineau
device_init(g364fb_register);