Statistics
| Branch: | Revision:

root / hw / g364fb.c @ ab902981

History | View | Annotate | Download (17.8 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 d7098135 Luiz Capitulino
static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch,
293 d7098135 Luiz Capitulino
                               Error **errp)
294 1fc3d392 aurel32
{
295 1fc3d392 aurel32
    G364State *s = opaque;
296 61a3f955 Luiz Capitulino
    int ret, y, x;
297 1fc3d392 aurel32
    uint8_t index;
298 1fc3d392 aurel32
    uint8_t *data_buffer;
299 1fc3d392 aurel32
    FILE *f;
300 1fc3d392 aurel32
301 e9a07334 Jan Kiszka
    qemu_flush_coalesced_mmio_buffer();
302 e9a07334 Jan Kiszka
303 0add30cf aurel32
    if (s->depth != 8) {
304 61a3f955 Luiz Capitulino
        error_setg(errp, "g364: unknown guest depth %d", s->depth);
305 0add30cf aurel32
        return;
306 0add30cf aurel32
    }
307 0add30cf aurel32
308 1fc3d392 aurel32
    f = fopen(filename, "wb");
309 61a3f955 Luiz Capitulino
    if (!f) {
310 61a3f955 Luiz Capitulino
        error_setg(errp, "failed to open file '%s': %s", filename,
311 61a3f955 Luiz Capitulino
                   strerror(errno));
312 1fc3d392 aurel32
        return;
313 61a3f955 Luiz Capitulino
    }
314 1fc3d392 aurel32
315 0add30cf aurel32
    if (s->ctla & CTLA_FORCE_BLANK) {
316 0add30cf aurel32
        /* blank screen */
317 61a3f955 Luiz Capitulino
        ret = fprintf(f, "P4\n%d %d\n", s->width, s->height);
318 61a3f955 Luiz Capitulino
        if (ret < 0) {
319 61a3f955 Luiz Capitulino
            goto write_err;
320 61a3f955 Luiz Capitulino
        }
321 0add30cf aurel32
        for (y = 0; y < s->height; y++)
322 61a3f955 Luiz Capitulino
            for (x = 0; x < s->width; x++) {
323 61a3f955 Luiz Capitulino
                ret = fputc(0, f);
324 61a3f955 Luiz Capitulino
                if (ret == EOF) {
325 61a3f955 Luiz Capitulino
                    goto write_err;
326 61a3f955 Luiz Capitulino
                }
327 61a3f955 Luiz Capitulino
            }
328 0add30cf aurel32
    } else {
329 0add30cf aurel32
        data_buffer = s->vram + s->top_of_screen;
330 61a3f955 Luiz Capitulino
        ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
331 61a3f955 Luiz Capitulino
        if (ret < 0) {
332 61a3f955 Luiz Capitulino
            goto write_err;
333 61a3f955 Luiz Capitulino
        }
334 0add30cf aurel32
        for (y = 0; y < s->height; y++)
335 0add30cf aurel32
            for (x = 0; x < s->width; x++, data_buffer++) {
336 0add30cf aurel32
                index = *data_buffer;
337 61a3f955 Luiz Capitulino
                ret = fputc(s->color_palette[index][0], f);
338 61a3f955 Luiz Capitulino
                if (ret == EOF) {
339 61a3f955 Luiz Capitulino
                    goto write_err;
340 61a3f955 Luiz Capitulino
                }
341 61a3f955 Luiz Capitulino
                ret = fputc(s->color_palette[index][1], f);
342 61a3f955 Luiz Capitulino
                if (ret == EOF) {
343 61a3f955 Luiz Capitulino
                    goto write_err;
344 61a3f955 Luiz Capitulino
                }
345 61a3f955 Luiz Capitulino
                ret = fputc(s->color_palette[index][2], f);
346 61a3f955 Luiz Capitulino
                if (ret == EOF) {
347 61a3f955 Luiz Capitulino
                    goto write_err;
348 61a3f955 Luiz Capitulino
                }
349 1fc3d392 aurel32
        }
350 0add30cf aurel32
    }
351 0add30cf aurel32
352 61a3f955 Luiz Capitulino
out:
353 1fc3d392 aurel32
    fclose(f);
354 61a3f955 Luiz Capitulino
    return;
355 61a3f955 Luiz Capitulino
356 61a3f955 Luiz Capitulino
write_err:
357 61a3f955 Luiz Capitulino
    error_setg(errp, "failed to write to file '%s': %s", filename,
358 61a3f955 Luiz Capitulino
               strerror(errno));
359 61a3f955 Luiz Capitulino
    unlink(filename);
360 61a3f955 Luiz Capitulino
    goto out;
361 1fc3d392 aurel32
}
362 1fc3d392 aurel32
363 1fc3d392 aurel32
/* called for accesses to io ports */
364 97a3f6ff Hervé Poussineau
static uint64_t g364fb_ctrl_read(void *opaque,
365 97a3f6ff Hervé Poussineau
                                 target_phys_addr_t addr,
366 97a3f6ff Hervé Poussineau
                                 unsigned int size)
367 1fc3d392 aurel32
{
368 0add30cf aurel32
    G364State *s = opaque;
369 1fc3d392 aurel32
    uint32_t val;
370 1fc3d392 aurel32
371 0add30cf aurel32
    if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
372 0add30cf aurel32
        /* cursor pattern */
373 0add30cf aurel32
        int idx = (addr - REG_CURS_PAT) >> 3;
374 0add30cf aurel32
        val = s->cursor[idx];
375 0add30cf aurel32
    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
376 0add30cf aurel32
        /* cursor palette */
377 0add30cf aurel32
        int idx = (addr - REG_CURS_PAL) >> 3;
378 0add30cf aurel32
        val = ((uint32_t)s->cursor_palette[idx][0] << 16);
379 0add30cf aurel32
        val |= ((uint32_t)s->cursor_palette[idx][1] << 8);
380 0add30cf aurel32
        val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
381 0add30cf aurel32
    } else {
382 0add30cf aurel32
        switch (addr) {
383 0add30cf aurel32
            case REG_DISPLAY:
384 0add30cf aurel32
                val = s->width / 4;
385 0add30cf aurel32
                break;
386 0add30cf aurel32
            case REG_VDISPLAY:
387 0add30cf aurel32
                val = s->height * 2;
388 0add30cf aurel32
                break;
389 0add30cf aurel32
            case REG_CTLA:
390 0add30cf aurel32
                val = s->ctla;
391 0add30cf aurel32
                break;
392 0add30cf aurel32
            default:
393 0add30cf aurel32
            {
394 b213b370 Hervé Poussineau
                error_report("g364: invalid read at [" TARGET_FMT_plx "]",
395 b213b370 Hervé Poussineau
                             addr);
396 0add30cf aurel32
                val = 0;
397 0add30cf aurel32
                break;
398 0add30cf aurel32
            }
399 0add30cf aurel32
        }
400 1fc3d392 aurel32
    }
401 1fc3d392 aurel32
402 b213b370 Hervé Poussineau
    trace_g364fb_read(addr, val);
403 1fc3d392 aurel32
404 1fc3d392 aurel32
    return val;
405 1fc3d392 aurel32
}
406 1fc3d392 aurel32
407 0add30cf aurel32
static void g364fb_update_depth(G364State *s)
408 1fc3d392 aurel32
{
409 38972938 Juan Quintela
    static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
410 0add30cf aurel32
    s->depth = depths[(s->ctla & 0x00700000) >> 20];
411 0add30cf aurel32
}
412 1fc3d392 aurel32
413 0add30cf aurel32
static void g364_invalidate_cursor_position(G364State *s)
414 0add30cf aurel32
{
415 fd4aa979 Blue Swirl
    int ymin, ymax, start, end;
416 1fc3d392 aurel32
417 0add30cf aurel32
    /* invalidate only near the cursor */
418 0add30cf aurel32
    ymin = s->cursor_position & 0xfff;
419 0add30cf aurel32
    ymax = MIN(s->height, ymin + 64);
420 0add30cf aurel32
    start = ymin * ds_get_linesize(s->ds);
421 0add30cf aurel32
    end = (ymax + 1) * ds_get_linesize(s->ds);
422 1fc3d392 aurel32
423 fd4aa979 Blue Swirl
    memory_region_set_dirty(&s->mem_vram, start, end - start);
424 0add30cf aurel32
}
425 0add30cf aurel32
426 97a3f6ff Hervé Poussineau
static void g364fb_ctrl_write(void *opaque,
427 97a3f6ff Hervé Poussineau
                              target_phys_addr_t addr,
428 97a3f6ff Hervé Poussineau
                              uint64_t val,
429 97a3f6ff Hervé Poussineau
                              unsigned int size)
430 0add30cf aurel32
{
431 0add30cf aurel32
    G364State *s = opaque;
432 0add30cf aurel32
433 b213b370 Hervé Poussineau
    trace_g364fb_write(addr, val);
434 0add30cf aurel32
435 0add30cf aurel32
    if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
436 1fc3d392 aurel32
        /* color palette */
437 0add30cf aurel32
        int idx = (addr - REG_CLR_PAL) >> 3;
438 0add30cf aurel32
        s->color_palette[idx][0] = (val >> 16) & 0xff;
439 0add30cf aurel32
        s->color_palette[idx][1] = (val >> 8) & 0xff;
440 0add30cf aurel32
        s->color_palette[idx][2] = val & 0xff;
441 0add30cf aurel32
        g364fb_invalidate_display(s);
442 0add30cf aurel32
    } else if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
443 0add30cf aurel32
        /* cursor pattern */
444 0add30cf aurel32
        int idx = (addr - REG_CURS_PAT) >> 3;
445 0add30cf aurel32
        s->cursor[idx] = val;
446 0add30cf aurel32
        g364fb_invalidate_display(s);
447 0add30cf aurel32
    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
448 0add30cf aurel32
        /* cursor palette */
449 0add30cf aurel32
        int idx = (addr - REG_CURS_PAL) >> 3;
450 0add30cf aurel32
        s->cursor_palette[idx][0] = (val >> 16) & 0xff;
451 0add30cf aurel32
        s->cursor_palette[idx][1] = (val >> 8) & 0xff;
452 0add30cf aurel32
        s->cursor_palette[idx][2] = val & 0xff;
453 0add30cf aurel32
        g364fb_invalidate_display(s);
454 1fc3d392 aurel32
    } else {
455 1fc3d392 aurel32
        switch (addr) {
456 97a3f6ff Hervé Poussineau
        case REG_BOOT: /* Boot timing */
457 97a3f6ff Hervé Poussineau
        case 0x00108: /* Line timing: half sync */
458 97a3f6ff Hervé Poussineau
        case 0x00110: /* Line timing: back porch */
459 97a3f6ff Hervé Poussineau
        case 0x00120: /* Line timing: short display */
460 97a3f6ff Hervé Poussineau
        case 0x00128: /* Frame timing: broad pulse */
461 97a3f6ff Hervé Poussineau
        case 0x00130: /* Frame timing: v sync */
462 97a3f6ff Hervé Poussineau
        case 0x00138: /* Frame timing: v preequalise */
463 97a3f6ff Hervé Poussineau
        case 0x00140: /* Frame timing: v postequalise */
464 97a3f6ff Hervé Poussineau
        case 0x00148: /* Frame timing: v blank */
465 97a3f6ff Hervé Poussineau
        case 0x00158: /* Line timing: line time */
466 97a3f6ff Hervé Poussineau
        case 0x00160: /* Frame store: line start */
467 97a3f6ff Hervé Poussineau
        case 0x00168: /* vram cycle: mem init */
468 97a3f6ff Hervé Poussineau
        case 0x00170: /* vram cycle: transfer delay */
469 97a3f6ff Hervé Poussineau
        case 0x00200: /* vram cycle: mask register */
470 97a3f6ff Hervé Poussineau
            /* ignore */
471 97a3f6ff Hervé Poussineau
            break;
472 97a3f6ff Hervé Poussineau
        case REG_TOP:
473 97a3f6ff Hervé Poussineau
            s->top_of_screen = val;
474 97a3f6ff Hervé Poussineau
            g364fb_invalidate_display(s);
475 97a3f6ff Hervé Poussineau
            break;
476 97a3f6ff Hervé Poussineau
        case REG_DISPLAY:
477 97a3f6ff Hervé Poussineau
            s->width = val * 4;
478 97a3f6ff Hervé Poussineau
            break;
479 97a3f6ff Hervé Poussineau
        case REG_VDISPLAY:
480 97a3f6ff Hervé Poussineau
            s->height = val / 2;
481 97a3f6ff Hervé Poussineau
            break;
482 97a3f6ff Hervé Poussineau
        case REG_CTLA:
483 97a3f6ff Hervé Poussineau
            s->ctla = val;
484 97a3f6ff Hervé Poussineau
            g364fb_update_depth(s);
485 97a3f6ff Hervé Poussineau
            g364fb_invalidate_display(s);
486 97a3f6ff Hervé Poussineau
            break;
487 97a3f6ff Hervé Poussineau
        case REG_CURS_POS:
488 97a3f6ff Hervé Poussineau
            g364_invalidate_cursor_position(s);
489 97a3f6ff Hervé Poussineau
            s->cursor_position = val;
490 97a3f6ff Hervé Poussineau
            g364_invalidate_cursor_position(s);
491 97a3f6ff Hervé Poussineau
            break;
492 97a3f6ff Hervé Poussineau
        case REG_RESET:
493 97a3f6ff Hervé Poussineau
            g364fb_reset(s);
494 97a3f6ff Hervé Poussineau
            break;
495 97a3f6ff Hervé Poussineau
        default:
496 97a3f6ff Hervé Poussineau
            error_report("g364: invalid write of 0x%" PRIx64
497 97a3f6ff Hervé Poussineau
                         " at [" TARGET_FMT_plx "]", val, addr);
498 97a3f6ff Hervé Poussineau
            break;
499 1fc3d392 aurel32
        }
500 1fc3d392 aurel32
    }
501 0add30cf aurel32
    qemu_irq_lower(s->irq);
502 1fc3d392 aurel32
}
503 1fc3d392 aurel32
504 97a3f6ff Hervé Poussineau
static const MemoryRegionOps g364fb_ctrl_ops = {
505 97a3f6ff Hervé Poussineau
    .read = g364fb_ctrl_read,
506 97a3f6ff Hervé Poussineau
    .write = g364fb_ctrl_write,
507 97a3f6ff Hervé Poussineau
    .endianness = DEVICE_LITTLE_ENDIAN,
508 97a3f6ff Hervé Poussineau
    .impl.min_access_size = 4,
509 97a3f6ff Hervé Poussineau
    .impl.max_access_size = 4,
510 1fc3d392 aurel32
};
511 1fc3d392 aurel32
512 97a3f6ff Hervé Poussineau
static int g364fb_post_load(void *opaque, int version_id)
513 1fc3d392 aurel32
{
514 1fc3d392 aurel32
    G364State *s = opaque;
515 0add30cf aurel32
516 0add30cf aurel32
    /* force refresh */
517 0add30cf aurel32
    g364fb_update_depth(s);
518 0add30cf aurel32
    g364fb_invalidate_display(s);
519 1fc3d392 aurel32
520 0add30cf aurel32
    return 0;
521 1fc3d392 aurel32
}
522 1fc3d392 aurel32
523 97a3f6ff Hervé Poussineau
static const VMStateDescription vmstate_g364fb = {
524 97a3f6ff Hervé Poussineau
    .name = "g364fb",
525 97a3f6ff Hervé Poussineau
    .version_id = 1,
526 97a3f6ff Hervé Poussineau
    .minimum_version_id = 1,
527 97a3f6ff Hervé Poussineau
    .minimum_version_id_old = 1,
528 97a3f6ff Hervé Poussineau
    .post_load = g364fb_post_load,
529 97a3f6ff Hervé Poussineau
    .fields = (VMStateField[]) {
530 97a3f6ff Hervé Poussineau
        VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
531 97a3f6ff Hervé Poussineau
        VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
532 97a3f6ff Hervé Poussineau
        VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
533 97a3f6ff Hervé Poussineau
        VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
534 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(cursor_position, G364State),
535 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(ctla, G364State),
536 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(top_of_screen, G364State),
537 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(width, G364State),
538 97a3f6ff Hervé Poussineau
        VMSTATE_UINT32(height, G364State),
539 97a3f6ff Hervé Poussineau
        VMSTATE_END_OF_LIST()
540 97a3f6ff Hervé Poussineau
    }
541 97a3f6ff Hervé Poussineau
};
542 1fc3d392 aurel32
543 97a3f6ff Hervé Poussineau
static void g364fb_init(DeviceState *dev, G364State *s)
544 1fc3d392 aurel32
{
545 97a3f6ff Hervé Poussineau
    s->vram = g_malloc0(s->vram_size);
546 1fc3d392 aurel32
547 3023f332 aliguori
    s->ds = graphic_console_init(g364fb_update_display,
548 3023f332 aliguori
                                 g364fb_invalidate_display,
549 3023f332 aliguori
                                 g364fb_screen_dump, NULL, s);
550 1fc3d392 aurel32
551 97a3f6ff Hervé Poussineau
    memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
552 c5705a77 Avi Kivity
    memory_region_init_ram_ptr(&s->mem_vram, "vram",
553 97a3f6ff Hervé Poussineau
                               s->vram_size, s->vram);
554 c5705a77 Avi Kivity
    vmstate_register_ram(&s->mem_vram, dev);
555 97a3f6ff Hervé Poussineau
    memory_region_set_coalescing(&s->mem_vram);
556 97a3f6ff Hervé Poussineau
}
557 97a3f6ff Hervé Poussineau
558 97a3f6ff Hervé Poussineau
typedef struct {
559 97a3f6ff Hervé Poussineau
    SysBusDevice busdev;
560 97a3f6ff Hervé Poussineau
    G364State g364;
561 97a3f6ff Hervé Poussineau
} G364SysBusState;
562 1fc3d392 aurel32
563 97a3f6ff Hervé Poussineau
static int g364fb_sysbus_init(SysBusDevice *dev)
564 97a3f6ff Hervé Poussineau
{
565 97a3f6ff Hervé Poussineau
    G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364;
566 97a3f6ff Hervé Poussineau
567 97a3f6ff Hervé Poussineau
    g364fb_init(&dev->qdev, s);
568 97a3f6ff Hervé Poussineau
    sysbus_init_irq(dev, &s->irq);
569 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->mem_ctrl);
570 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->mem_vram);
571 1fc3d392 aurel32
572 1fc3d392 aurel32
    return 0;
573 1fc3d392 aurel32
}
574 97a3f6ff Hervé Poussineau
575 97a3f6ff Hervé Poussineau
static void g364fb_sysbus_reset(DeviceState *d)
576 97a3f6ff Hervé Poussineau
{
577 97a3f6ff Hervé Poussineau
    G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d);
578 97a3f6ff Hervé Poussineau
    g364fb_reset(&s->g364);
579 97a3f6ff Hervé Poussineau
}
580 97a3f6ff Hervé Poussineau
581 999e12bb Anthony Liguori
static Property g364fb_sysbus_properties[] = {
582 999e12bb Anthony Liguori
    DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
583 999e12bb Anthony Liguori
    8 * 1024 * 1024),
584 999e12bb Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
585 999e12bb Anthony Liguori
};
586 999e12bb Anthony Liguori
587 999e12bb Anthony Liguori
static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
588 999e12bb Anthony Liguori
{
589 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
590 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
591 999e12bb Anthony Liguori
592 999e12bb Anthony Liguori
    k->init = g364fb_sysbus_init;
593 39bffca2 Anthony Liguori
    dc->desc = "G364 framebuffer";
594 39bffca2 Anthony Liguori
    dc->reset = g364fb_sysbus_reset;
595 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_g364fb;
596 39bffca2 Anthony Liguori
    dc->props = g364fb_sysbus_properties;
597 999e12bb Anthony Liguori
}
598 999e12bb Anthony Liguori
599 39bffca2 Anthony Liguori
static TypeInfo g364fb_sysbus_info = {
600 39bffca2 Anthony Liguori
    .name          = "sysbus-g364",
601 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
602 39bffca2 Anthony Liguori
    .instance_size = sizeof(G364SysBusState),
603 39bffca2 Anthony Liguori
    .class_init    = g364fb_sysbus_class_init,
604 97a3f6ff Hervé Poussineau
};
605 97a3f6ff Hervé Poussineau
606 83f7d43a Andreas Färber
static void g364fb_register_types(void)
607 97a3f6ff Hervé Poussineau
{
608 39bffca2 Anthony Liguori
    type_register_static(&g364fb_sysbus_info);
609 97a3f6ff Hervé Poussineau
}
610 97a3f6ff Hervé Poussineau
611 83f7d43a Andreas Färber
type_init(g364fb_register_types)