Statistics
| Branch: | Revision:

root / hw / g364fb.c @ 0200db65

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