g364fb.c 17.0 KB
Newer Older
A
aurel32 已提交
1 2 3
/*
 * QEMU G364 framebuffer Emulator.
 *
H
Hervé Poussineau 已提交
4
 * Copyright (c) 2007-2011 Herve Poussineau
A
aurel32 已提交
5 6 7 8 9 10 11 12 13 14 15
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
16
 * You should have received a copy of the GNU General Public License along
17
 * with this program; if not, see <http://www.gnu.org/licenses/>.
A
aurel32 已提交
18 19 20 21 22
 */

#include "hw.h"
#include "console.h"
#include "pixel_ops.h"
H
Hervé Poussineau 已提交
23
#include "trace.h"
H
Hervé Poussineau 已提交
24
#include "sysbus.h"
A
aurel32 已提交
25

A
aurel32 已提交
26
typedef struct G364State {
A
aurel32 已提交
27 28
    /* hardware */
    uint8_t *vram;
H
Hervé Poussineau 已提交
29
    uint32_t vram_size;
A
aurel32 已提交
30
    qemu_irq irq;
H
Hervé Poussineau 已提交
31 32
    MemoryRegion mem_vram;
    MemoryRegion mem_ctrl;
A
aurel32 已提交
33 34 35 36 37
    /* registers */
    uint8_t color_palette[256][3];
    uint8_t cursor_palette[3][3];
    uint16_t cursor[512];
    uint32_t cursor_position;
A
aurel32 已提交
38
    uint32_t ctla;
A
aurel32 已提交
39 40
    uint32_t top_of_screen;
    uint32_t width, height; /* in pixels */
A
aurel32 已提交
41 42
    /* display refresh support */
    DisplayState *ds;
A
aurel32 已提交
43 44
    int depth;
    int blanked;
A
aurel32 已提交
45 46
} G364State;

H
Hervé Poussineau 已提交
47 48 49 50 51 52 53 54 55 56
#define REG_BOOT     0x000000
#define REG_DISPLAY  0x000118
#define REG_VDISPLAY 0x000150
#define REG_CTLA     0x000300
#define REG_TOP      0x000400
#define REG_CURS_PAL 0x000508
#define REG_CURS_POS 0x000638
#define REG_CLR_PAL  0x000800
#define REG_CURS_PAT 0x001000
#define REG_RESET    0x100000
A
aurel32 已提交
57 58 59 60

#define CTLA_FORCE_BLANK 0x00000400
#define CTLA_NO_CURSOR   0x00800000

B
Blue Swirl 已提交
61 62
#define G364_PAGE_SIZE 4096

H
Hervé Poussineau 已提交
63
static inline int check_dirty(G364State *s, ram_addr_t page)
A
aurel32 已提交
64
{
65 66
    return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
                                   DIRTY_MEMORY_VGA);
A
aurel32 已提交
67 68 69
}

static inline void reset_dirty(G364State *s,
A
Anthony Liguori 已提交
70
                               ram_addr_t page_min, ram_addr_t page_max)
A
aurel32 已提交
71
{
H
Hervé Poussineau 已提交
72 73
    memory_region_reset_dirty(&s->mem_vram,
                              page_min,
B
Blue Swirl 已提交
74
                              page_max + G364_PAGE_SIZE - page_min - 1,
H
Hervé Poussineau 已提交
75
                              DIRTY_MEMORY_VGA);
A
aurel32 已提交
76 77 78
}

static void g364fb_draw_graphic8(G364State *s)
A
aurel32 已提交
79
{
A
aurel32 已提交
80 81 82
    int i, w;
    uint8_t *vram;
    uint8_t *data_display, *dd;
A
Anthony Liguori 已提交
83
    ram_addr_t page, page_min, page_max;
A
aurel32 已提交
84 85 86 87 88 89
    int x, y;
    int xmin, xmax;
    int ymin, ymax;
    int xcursor, ycursor;
    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);

90
    switch (ds_get_bits_per_pixel(s->ds)) {
A
aurel32 已提交
91
        case 8:
A
aurel32 已提交
92 93
            rgb_to_pixel = rgb_to_pixel8;
            w = 1;
A
aurel32 已提交
94 95
            break;
        case 15:
A
aurel32 已提交
96 97
            rgb_to_pixel = rgb_to_pixel15;
            w = 2;
A
aurel32 已提交
98 99
            break;
        case 16:
A
aurel32 已提交
100 101
            rgb_to_pixel = rgb_to_pixel16;
            w = 2;
A
aurel32 已提交
102 103
            break;
        case 32:
A
aurel32 已提交
104 105
            rgb_to_pixel = rgb_to_pixel32;
            w = 4;
A
aurel32 已提交
106 107
            break;
        default:
H
Hervé Poussineau 已提交
108 109
            hw_error("g364: unknown host depth %d",
                     ds_get_bits_per_pixel(s->ds));
A
aurel32 已提交
110 111 112
            return;
    }

H
Hervé Poussineau 已提交
113
    page = 0;
A
Anthony Liguori 已提交
114
    page_min = (ram_addr_t)-1;
A
aurel32 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    page_max = 0;

    x = y = 0;
    xmin = s->width;
    xmax = 0;
    ymin = s->height;
    ymax = 0;

    if (!(s->ctla & CTLA_NO_CURSOR)) {
        xcursor = s->cursor_position >> 12;
        ycursor = s->cursor_position & 0xfff;
    } else {
        xcursor = ycursor = -65;
    }

    vram = s->vram + s->top_of_screen;
    /* XXX: out of range in vram? */
    data_display = dd = ds_get_data(s->ds);
    while (y < s->height) {
H
Hervé Poussineau 已提交
134
        if (check_dirty(s, page)) {
A
aurel32 已提交
135 136
            if (y < ymin)
                ymin = ymax = y;
A
Anthony Liguori 已提交
137
            if (page_min == (ram_addr_t)-1)
A
aurel32 已提交
138 139 140 141
                page_min = page;
            page_max = page;
            if (x < xmin)
                xmin = x;
B
Blue Swirl 已提交
142
            for (i = 0; i < G364_PAGE_SIZE; i++) {
A
aurel32 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
                uint8_t index;
                unsigned int color;
                if (unlikely((y >= ycursor && y < ycursor + 64) &&
                    (x >= xcursor && x < xcursor + 64))) {
                    /* pointer area */
                    int xdiff = x - xcursor;
                    uint16_t curs = s->cursor[(y - ycursor) * 8 + xdiff / 8];
                    int op = (curs >> ((xdiff & 7) * 2)) & 3;
                    if (likely(op == 0)) {
                        /* transparent */
                        index = *vram;
                        color = (*rgb_to_pixel)(
                            s->color_palette[index][0],
                            s->color_palette[index][1],
                            s->color_palette[index][2]);
                    } else {
                        /* get cursor color */
                        index = op - 1;
                        color = (*rgb_to_pixel)(
                            s->cursor_palette[index][0],
                            s->cursor_palette[index][1],
                            s->cursor_palette[index][2]);
                    }
                } else {
                    /* normal area */
                    index = *vram;
                    color = (*rgb_to_pixel)(
                        s->color_palette[index][0],
                        s->color_palette[index][1],
                        s->color_palette[index][2]);
                }
                memcpy(dd, &color, w);
                dd += w;
                x++;
                vram++;
                if (x == s->width) {
                    xmax = s->width - 1;
                    y++;
                    if (y == s->height) {
                        ymax = s->height - 1;
                        goto done;
                    }
                    data_display = dd = data_display + ds_get_linesize(s->ds);
                    xmin = 0;
                    x = 0;
                }
            }
            if (x > xmax)
                xmax = x;
            if (y > ymax)
                ymax = y;
        } else {
            int dy;
A
Anthony Liguori 已提交
196
            if (page_min != (ram_addr_t)-1) {
A
aurel32 已提交
197
                reset_dirty(s, page_min, page_max);
A
Anthony Liguori 已提交
198
                page_min = (ram_addr_t)-1;
A
aurel32 已提交
199 200 201 202 203 204 205
                page_max = 0;
                dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
                xmin = s->width;
                xmax = 0;
                ymin = s->height;
                ymax = 0;
            }
B
Blue Swirl 已提交
206
            x += G364_PAGE_SIZE;
A
aurel32 已提交
207 208 209
            dy = x / s->width;
            x = x % s->width;
            y += dy;
B
Blue Swirl 已提交
210
            vram += G364_PAGE_SIZE;
A
aurel32 已提交
211 212 213
            data_display += dy * ds_get_linesize(s->ds);
            dd = data_display + x * w;
        }
B
Blue Swirl 已提交
214
        page += G364_PAGE_SIZE;
A
aurel32 已提交
215 216 217
    }

done:
A
Anthony Liguori 已提交
218
    if (page_min != (ram_addr_t)-1) {
A
aurel32 已提交
219 220 221
        dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
        reset_dirty(s, page_min, page_max);
    }
A
aurel32 已提交
222 223
}

A
aurel32 已提交
224
static void g364fb_draw_blank(G364State *s)
A
aurel32 已提交
225 226 227 228
{
    int i, w;
    uint8_t *d;

A
aurel32 已提交
229 230
    if (s->blanked) {
        /* Screen is already blank. No need to redraw it */
A
aurel32 已提交
231
        return;
A
aurel32 已提交
232
    }
A
aurel32 已提交
233

A
aurel32 已提交
234
    w = s->width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
235
    d = ds_get_data(s->ds);
A
aurel32 已提交
236
    for (i = 0; i < s->height; i++) {
A
aurel32 已提交
237
        memset(d, 0, w);
238
        d += ds_get_linesize(s->ds);
A
aurel32 已提交
239
    }
A
aurel32 已提交
240

A
aurel32 已提交
241 242
    dpy_update(s->ds, 0, 0, s->width, s->height);
    s->blanked = 1;
A
aurel32 已提交
243 244 245 246 247 248
}

static void g364fb_update_display(void *opaque)
{
    G364State *s = opaque;

249 250
    qemu_flush_coalesced_mmio_buffer();

A
aurel32 已提交
251
    if (s->width == 0 || s->height == 0)
A
aurel32 已提交
252 253
        return;

A
aurel32 已提交
254 255
    if (s->width != ds_get_width(s->ds) || s->height != ds_get_height(s->ds)) {
        qemu_console_resize(s->ds, s->width, s->height);
A
aurel32 已提交
256
    }
A
aurel32 已提交
257 258 259 260 261 262

    if (s->ctla & CTLA_FORCE_BLANK) {
        g364fb_draw_blank(s);
    } else if (s->depth == 8) {
        g364fb_draw_graphic8(s);
    } else {
H
Hervé Poussineau 已提交
263
        error_report("g364: unknown guest depth %d", s->depth);
A
aurel32 已提交
264
    }
A
aurel32 已提交
265 266

    qemu_irq_raise(s->irq);
A
aurel32 已提交
267 268
}

269
static inline void g364fb_invalidate_display(void *opaque)
A
aurel32 已提交
270 271
{
    G364State *s = opaque;
A
aurel32 已提交
272 273

    s->blanked = 0;
274
    memory_region_set_dirty(&s->mem_vram, 0, s->vram_size);
A
aurel32 已提交
275 276
}

H
Hervé Poussineau 已提交
277
static void g364fb_reset(G364State *s)
A
aurel32 已提交
278
{
A
aurel32 已提交
279 280 281 282 283 284 285 286 287 288
    qemu_irq_lower(s->irq);

    memset(s->color_palette, 0, sizeof(s->color_palette));
    memset(s->cursor_palette, 0, sizeof(s->cursor_palette));
    memset(s->cursor, 0, sizeof(s->cursor));
    s->cursor_position = 0;
    s->ctla = 0;
    s->top_of_screen = 0;
    s->width = s->height = 0;
    memset(s->vram, 0, s->vram_size);
H
Hervé Poussineau 已提交
289
    g364fb_invalidate_display(s);
A
aurel32 已提交
290 291 292 293 294 295 296 297 298 299
}

static void g364fb_screen_dump(void *opaque, const char *filename)
{
    G364State *s = opaque;
    int y, x;
    uint8_t index;
    uint8_t *data_buffer;
    FILE *f;

300 301
    qemu_flush_coalesced_mmio_buffer();

A
aurel32 已提交
302
    if (s->depth != 8) {
H
Hervé Poussineau 已提交
303
        error_report("g364: unknown guest depth %d", s->depth);
A
aurel32 已提交
304 305 306
        return;
    }

A
aurel32 已提交
307 308 309 310
    f = fopen(filename, "wb");
    if (!f)
        return;

A
aurel32 已提交
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    if (s->ctla & CTLA_FORCE_BLANK) {
        /* blank screen */
        fprintf(f, "P4\n%d %d\n",
            s->width, s->height);
        for (y = 0; y < s->height; y++)
            for (x = 0; x < s->width; x++)
                fputc(0, f);
    } else {
        data_buffer = s->vram + s->top_of_screen;
        fprintf(f, "P6\n%d %d\n%d\n",
            s->width, s->height, 255);
        for (y = 0; y < s->height; y++)
            for (x = 0; x < s->width; x++, data_buffer++) {
                index = *data_buffer;
                fputc(s->color_palette[index][0], f);
                fputc(s->color_palette[index][1], f);
                fputc(s->color_palette[index][2], f);
A
aurel32 已提交
328
        }
A
aurel32 已提交
329 330
    }

A
aurel32 已提交
331 332 333 334
    fclose(f);
}

/* called for accesses to io ports */
H
Hervé Poussineau 已提交
335 336 337
static uint64_t g364fb_ctrl_read(void *opaque,
                                 target_phys_addr_t addr,
                                 unsigned int size)
A
aurel32 已提交
338
{
A
aurel32 已提交
339
    G364State *s = opaque;
A
aurel32 已提交
340 341
    uint32_t val;

A
aurel32 已提交
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
    if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
        /* cursor pattern */
        int idx = (addr - REG_CURS_PAT) >> 3;
        val = s->cursor[idx];
    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
        /* cursor palette */
        int idx = (addr - REG_CURS_PAL) >> 3;
        val = ((uint32_t)s->cursor_palette[idx][0] << 16);
        val |= ((uint32_t)s->cursor_palette[idx][1] << 8);
        val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
    } else {
        switch (addr) {
            case REG_DISPLAY:
                val = s->width / 4;
                break;
            case REG_VDISPLAY:
                val = s->height * 2;
                break;
            case REG_CTLA:
                val = s->ctla;
                break;
            default:
            {
H
Hervé Poussineau 已提交
365 366
                error_report("g364: invalid read at [" TARGET_FMT_plx "]",
                             addr);
A
aurel32 已提交
367 368 369 370
                val = 0;
                break;
            }
        }
A
aurel32 已提交
371 372
    }

H
Hervé Poussineau 已提交
373
    trace_g364fb_read(addr, val);
A
aurel32 已提交
374 375 376 377

    return val;
}

A
aurel32 已提交
378
static void g364fb_update_depth(G364State *s)
A
aurel32 已提交
379
{
380
    static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
A
aurel32 已提交
381 382
    s->depth = depths[(s->ctla & 0x00700000) >> 20];
}
A
aurel32 已提交
383

A
aurel32 已提交
384 385
static void g364_invalidate_cursor_position(G364State *s)
{
386
    int ymin, ymax, start, end;
A
aurel32 已提交
387

A
aurel32 已提交
388 389 390 391 392
    /* invalidate only near the cursor */
    ymin = s->cursor_position & 0xfff;
    ymax = MIN(s->height, ymin + 64);
    start = ymin * ds_get_linesize(s->ds);
    end = (ymax + 1) * ds_get_linesize(s->ds);
A
aurel32 已提交
393

394
    memory_region_set_dirty(&s->mem_vram, start, end - start);
A
aurel32 已提交
395 396
}

H
Hervé Poussineau 已提交
397 398 399 400
static void g364fb_ctrl_write(void *opaque,
                              target_phys_addr_t addr,
                              uint64_t val,
                              unsigned int size)
A
aurel32 已提交
401 402 403
{
    G364State *s = opaque;

H
Hervé Poussineau 已提交
404
    trace_g364fb_write(addr, val);
A
aurel32 已提交
405 406

    if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
A
aurel32 已提交
407
        /* color palette */
A
aurel32 已提交
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
        int idx = (addr - REG_CLR_PAL) >> 3;
        s->color_palette[idx][0] = (val >> 16) & 0xff;
        s->color_palette[idx][1] = (val >> 8) & 0xff;
        s->color_palette[idx][2] = val & 0xff;
        g364fb_invalidate_display(s);
    } else if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
        /* cursor pattern */
        int idx = (addr - REG_CURS_PAT) >> 3;
        s->cursor[idx] = val;
        g364fb_invalidate_display(s);
    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
        /* cursor palette */
        int idx = (addr - REG_CURS_PAL) >> 3;
        s->cursor_palette[idx][0] = (val >> 16) & 0xff;
        s->cursor_palette[idx][1] = (val >> 8) & 0xff;
        s->cursor_palette[idx][2] = val & 0xff;
        g364fb_invalidate_display(s);
A
aurel32 已提交
425 426
    } else {
        switch (addr) {
H
Hervé Poussineau 已提交
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
        case REG_BOOT: /* Boot timing */
        case 0x00108: /* Line timing: half sync */
        case 0x00110: /* Line timing: back porch */
        case 0x00120: /* Line timing: short display */
        case 0x00128: /* Frame timing: broad pulse */
        case 0x00130: /* Frame timing: v sync */
        case 0x00138: /* Frame timing: v preequalise */
        case 0x00140: /* Frame timing: v postequalise */
        case 0x00148: /* Frame timing: v blank */
        case 0x00158: /* Line timing: line time */
        case 0x00160: /* Frame store: line start */
        case 0x00168: /* vram cycle: mem init */
        case 0x00170: /* vram cycle: transfer delay */
        case 0x00200: /* vram cycle: mask register */
            /* ignore */
            break;
        case REG_TOP:
            s->top_of_screen = val;
            g364fb_invalidate_display(s);
            break;
        case REG_DISPLAY:
            s->width = val * 4;
            break;
        case REG_VDISPLAY:
            s->height = val / 2;
            break;
        case REG_CTLA:
            s->ctla = val;
            g364fb_update_depth(s);
            g364fb_invalidate_display(s);
            break;
        case REG_CURS_POS:
            g364_invalidate_cursor_position(s);
            s->cursor_position = val;
            g364_invalidate_cursor_position(s);
            break;
        case REG_RESET:
            g364fb_reset(s);
            break;
        default:
            error_report("g364: invalid write of 0x%" PRIx64
                         " at [" TARGET_FMT_plx "]", val, addr);
            break;
A
aurel32 已提交
470 471
        }
    }
A
aurel32 已提交
472
    qemu_irq_lower(s->irq);
A
aurel32 已提交
473 474
}

H
Hervé Poussineau 已提交
475 476 477 478 479 480
static const MemoryRegionOps g364fb_ctrl_ops = {
    .read = g364fb_ctrl_read,
    .write = g364fb_ctrl_write,
    .endianness = DEVICE_LITTLE_ENDIAN,
    .impl.min_access_size = 4,
    .impl.max_access_size = 4,
A
aurel32 已提交
481 482
};

H
Hervé Poussineau 已提交
483
static int g364fb_post_load(void *opaque, int version_id)
A
aurel32 已提交
484 485
{
    G364State *s = opaque;
A
aurel32 已提交
486 487 488 489

    /* force refresh */
    g364fb_update_depth(s);
    g364fb_invalidate_display(s);
A
aurel32 已提交
490

A
aurel32 已提交
491
    return 0;
A
aurel32 已提交
492 493
}

H
Hervé Poussineau 已提交
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
static const VMStateDescription vmstate_g364fb = {
    .name = "g364fb",
    .version_id = 1,
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
    .post_load = g364fb_post_load,
    .fields = (VMStateField[]) {
        VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
        VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
        VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
        VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
        VMSTATE_UINT32(cursor_position, G364State),
        VMSTATE_UINT32(ctla, G364State),
        VMSTATE_UINT32(top_of_screen, G364State),
        VMSTATE_UINT32(width, G364State),
        VMSTATE_UINT32(height, G364State),
        VMSTATE_END_OF_LIST()
    }
};
A
aurel32 已提交
513

H
Hervé Poussineau 已提交
514
static void g364fb_init(DeviceState *dev, G364State *s)
A
aurel32 已提交
515
{
H
Hervé Poussineau 已提交
516
    s->vram = g_malloc0(s->vram_size);
A
aurel32 已提交
517

518 519 520
    s->ds = graphic_console_init(g364fb_update_display,
                                 g364fb_invalidate_display,
                                 g364fb_screen_dump, NULL, s);
A
aurel32 已提交
521

H
Hervé Poussineau 已提交
522
    memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
523
    memory_region_init_ram_ptr(&s->mem_vram, "vram",
H
Hervé Poussineau 已提交
524
                               s->vram_size, s->vram);
525
    vmstate_register_ram(&s->mem_vram, dev);
H
Hervé Poussineau 已提交
526 527 528 529 530 531 532
    memory_region_set_coalescing(&s->mem_vram);
}

typedef struct {
    SysBusDevice busdev;
    G364State g364;
} G364SysBusState;
A
aurel32 已提交
533

H
Hervé Poussineau 已提交
534 535 536 537 538 539
static int g364fb_sysbus_init(SysBusDevice *dev)
{
    G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364;

    g364fb_init(&dev->qdev, s);
    sysbus_init_irq(dev, &s->irq);
540 541
    sysbus_init_mmio(dev, &s->mem_ctrl);
    sysbus_init_mmio(dev, &s->mem_vram);
A
aurel32 已提交
542 543 544

    return 0;
}
H
Hervé Poussineau 已提交
545 546 547 548 549 550 551

static void g364fb_sysbus_reset(DeviceState *d)
{
    G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d);
    g364fb_reset(&s->g364);
}

552 553 554 555 556 557 558 559
static Property g364fb_sysbus_properties[] = {
    DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
    8 * 1024 * 1024),
    DEFINE_PROP_END_OF_LIST(),
};

static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
{
560
    DeviceClass *dc = DEVICE_CLASS(klass);
561 562 563
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);

    k->init = g364fb_sysbus_init;
564 565 566 567
    dc->desc = "G364 framebuffer";
    dc->reset = g364fb_sysbus_reset;
    dc->vmsd = &vmstate_g364fb;
    dc->props = g364fb_sysbus_properties;
568 569
}

570 571 572 573 574
static TypeInfo g364fb_sysbus_info = {
    .name          = "sysbus-g364",
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(G364SysBusState),
    .class_init    = g364fb_sysbus_class_init,
H
Hervé Poussineau 已提交
575 576 577 578
};

static void g364fb_register(void)
{
579
    type_register_static(&g364fb_sysbus_info);
H
Hervé Poussineau 已提交
580 581 582
}

device_init(g364fb_register);