tcg: fix size of local variables in tcg_gen_bswap64_i64
[qemu] / hw / syborg_fb.c
1 /*
2  * Syborg Framebuffer
3  *
4  * Copyright (c) 2009 CodeSourcery
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include "sysbus.h"
26 #include "console.h"
27 #include "syborg.h"
28 #include "framebuffer.h"
29
30 //#define DEBUG_SYBORG_FB
31
32 #ifdef DEBUG_SYBORG_FB
33 #define DPRINTF(fmt, ...) \
34 do { printf("syborg_fb: " fmt , ## __VA_ARGS__); } while (0)
35 #define BADF(fmt, ...) \
36 do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__); \
37     exit(1);} while (0)
38 #else
39 #define DPRINTF(fmt, ...) do {} while(0)
40 #define BADF(fmt, ...) \
41 do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__);} while (0)
42 #endif
43
44 enum {
45     FB_ID               = 0,
46     FB_BASE             = 1,
47     FB_HEIGHT           = 2,
48     FB_WIDTH            = 3,
49     FB_ORIENTATION      = 4,
50     FB_BLANK            = 5,
51     FB_INT_MASK         = 6,
52     FB_INTERRUPT_CAUSE  = 7,
53     FB_BPP              = 8,
54     FB_COLOR_ORDER      = 9,
55     FB_BYTE_ORDER       = 10,
56     FB_PIXEL_ORDER      = 11,
57     FB_ROW_PITCH        = 12,
58     FB_ENABLED          = 13,
59     FB_PALETTE_START    = 0x400 >> 2,
60     FB_PALETTE_END   = FB_PALETTE_START+256-1,
61 };
62
63 #define FB_INT_VSYNC            (1U << 0)
64 #define FB_INT_BASE_UPDATE_DONE (1U << 1)
65
66 typedef struct {
67     SysBusDevice busdev;
68     DisplayState *ds;
69     /*QEMUConsole *console;*/
70     uint32_t need_update : 1;
71     uint32_t need_int : 1;
72     uint32_t enabled : 1;
73     uint32_t int_status;
74     uint32_t int_enable;
75     qemu_irq irq;
76
77     uint32_t base;
78     uint32_t pitch;
79     uint32_t rows;
80     uint32_t cols;
81     int blank;
82     int bpp;
83     int rgb; /* 0 = BGR, 1 = RGB */
84     int endian; /* 0 = Little, 1 = Big */
85     uint32_t raw_palette[256];
86     uint32_t palette[256];
87 } SyborgFBState;
88
89 enum {
90     BPP_SRC_1,
91     BPP_SRC_2,
92     BPP_SRC_4,
93     BPP_SRC_8,
94     BPP_SRC_16,
95     BPP_SRC_32,
96     /* TODO: Implement these.  */
97     BPP_SRC_15 = -1,
98     BPP_SRC_24 = -2
99 };
100
101 #include "pixel_ops.h"
102
103 #define BITS 8
104 #include "pl110_template.h"
105 #define BITS 15
106 #include "pl110_template.h"
107 #define BITS 16
108 #include "pl110_template.h"
109 #define BITS 24
110 #include "pl110_template.h"
111 #define BITS 32
112 #include "pl110_template.h"
113
114 /* Update interrupts.  */
115 static void syborg_fb_update(SyborgFBState *s)
116 {
117     if ((s->int_status & s->int_enable) != 0) {
118         DPRINTF("Raise IRQ\n");
119         qemu_irq_raise(s->irq);
120     } else {
121         DPRINTF("Lower IRQ\n");
122         qemu_irq_lower(s->irq);
123     }
124 }
125
126 static int syborg_fb_enabled(const SyborgFBState *s)
127 {
128     return s->enabled;
129 }
130
131 static void syborg_fb_update_palette(SyborgFBState *s)
132 {
133     int n, i;
134     uint32_t raw;
135     unsigned int r, g, b;
136
137     switch (s->bpp) {
138     case BPP_SRC_1: n = 2; break;
139     case BPP_SRC_2: n = 4; break;
140     case BPP_SRC_4: n = 16; break;
141     case BPP_SRC_8: n = 256; break;
142     default: return;
143     }
144
145     for (i = 0; i < n; i++) {
146         raw = s->raw_palette[i];
147         r = (raw >> 16) & 0xff;
148         g = (raw >> 8) & 0xff;
149         b = raw & 0xff;
150         switch (ds_get_bits_per_pixel(s->ds)) {
151         case 8:
152             s->palette[i] = rgb_to_pixel8(r, g, b);
153             break;
154         case 15:
155             s->palette[i] = rgb_to_pixel15(r, g, b);
156             break;
157         case 16:
158             s->palette[i] = rgb_to_pixel16(r, g, b);
159             break;
160         case 24:
161         case 32:
162             s->palette[i] = rgb_to_pixel32(r, g, b);
163             break;
164         default:
165             abort();
166         }
167     }
168
169 }
170
171 static void syborg_fb_update_display(void *opaque)
172 {
173     SyborgFBState *s = (SyborgFBState *)opaque;
174     drawfn* fntable;
175     drawfn fn;
176     int dest_width;
177     int src_width;
178     int bpp_offset;
179     int first;
180     int last;
181
182     if (!syborg_fb_enabled(s))
183         return;
184
185     switch (ds_get_bits_per_pixel(s->ds)) {
186     case 0:
187         return;
188     case 8:
189         fntable = pl110_draw_fn_8;
190         dest_width = 1;
191         break;
192     case 15:
193         fntable = pl110_draw_fn_15;
194         dest_width = 2;
195         break;
196     case 16:
197         fntable = pl110_draw_fn_16;
198         dest_width = 2;
199         break;
200     case 24:
201         fntable = pl110_draw_fn_24;
202         dest_width = 3;
203         break;
204     case 32:
205         fntable = pl110_draw_fn_32;
206         dest_width = 4;
207         break;
208     default:
209         fprintf(stderr, "syborg_fb: Bad color depth\n");
210         exit(1);
211     }
212
213     if (s->need_int) {
214         s->int_status |= FB_INT_BASE_UPDATE_DONE;
215         syborg_fb_update(s);
216         s->need_int = 0;
217     }
218
219     if (s->rgb) {
220         bpp_offset = 18;
221     } else {
222         bpp_offset = 0;
223     }
224     if (s->endian) {
225         bpp_offset += 6;
226     }
227
228     fn = fntable[s->bpp + bpp_offset];
229
230     if (s->pitch) {
231         src_width = s->pitch;
232     } else {
233         src_width = s->cols;
234         switch (s->bpp) {
235         case BPP_SRC_1:
236             src_width >>= 3;
237             break;
238         case BPP_SRC_2:
239             src_width >>= 2;
240             break;
241         case BPP_SRC_4:
242             src_width >>= 1;
243             break;
244         case BPP_SRC_8:
245             break;
246         case BPP_SRC_15:
247         case BPP_SRC_16:
248             src_width <<= 1;
249             break;
250         case BPP_SRC_24:
251             src_width *= 3;
252             break;
253         case BPP_SRC_32:
254             src_width <<= 2;
255             break;
256         }
257     }
258     dest_width *= s->cols;
259     first = 0;
260     /* TODO: Implement blanking.  */
261     if (!s->blank) {
262         if (s->need_update && s->bpp <= BPP_SRC_8) {
263             syborg_fb_update_palette(s);
264         }
265         framebuffer_update_display(s->ds,
266                                    s->base, s->cols, s->rows,
267                                    src_width, dest_width, 0,
268                                    s->need_update,
269                                    fn, s->palette,
270                                    &first, &last);
271         if (first >= 0) {
272             dpy_update(s->ds, 0, first, s->cols, last - first + 1);
273         }
274
275         s->int_status |= FB_INT_VSYNC;
276         syborg_fb_update(s);
277     }
278
279     s->need_update = 0;
280 }
281
282 static void syborg_fb_invalidate_display(void * opaque)
283 {
284     SyborgFBState *s = (SyborgFBState *)opaque;
285     s->need_update = 1;
286 }
287
288 static uint32_t syborg_fb_read(void *opaque, target_phys_addr_t offset)
289 {
290     SyborgFBState *s = opaque;
291
292     DPRINTF("read reg %d\n", (int)offset);
293     offset &= 0xfff;
294     switch (offset >> 2) {
295     case FB_ID:
296         return SYBORG_ID_FRAMEBUFFER;
297
298     case FB_BASE:
299         return s->base;
300
301     case FB_HEIGHT:
302         return s->rows;
303
304     case FB_WIDTH:
305         return s->cols;
306
307     case FB_ORIENTATION:
308         return 0;
309
310     case FB_BLANK:
311         return s->blank;
312
313     case FB_INT_MASK:
314         return s->int_enable;
315
316     case FB_INTERRUPT_CAUSE:
317         return s->int_status;
318
319     case FB_BPP:
320         switch (s->bpp) {
321         case BPP_SRC_1: return 1;
322         case BPP_SRC_2: return 2;
323         case BPP_SRC_4: return 4;
324         case BPP_SRC_8: return 8;
325         case BPP_SRC_15: return 15;
326         case BPP_SRC_16: return 16;
327         case BPP_SRC_24: return 24;
328         case BPP_SRC_32: return 32;
329         default: return 0;
330         }
331
332     case FB_COLOR_ORDER:
333         return s->rgb;
334
335     case FB_BYTE_ORDER:
336         return s->endian;
337
338     case FB_PIXEL_ORDER:
339         return 0;
340
341     case FB_ROW_PITCH:
342         return s->pitch;
343
344     case FB_ENABLED:
345         return s->enabled;
346
347     default:
348         if ((offset >> 2) >= FB_PALETTE_START
349             && (offset >> 2) <= FB_PALETTE_END) {
350             return s->raw_palette[(offset >> 2) - FB_PALETTE_START];
351         } else {
352             cpu_abort (cpu_single_env, "syborg_fb_read: Bad offset %x\n",
353                          (int)offset);
354         }
355         return 0;
356     }
357 }
358
359 static void syborg_fb_write(void *opaque, target_phys_addr_t offset,
360                             uint32_t val)
361 {
362     SyborgFBState *s = opaque;
363
364     DPRINTF("write reg %d = %d\n", (int)offset, val);
365     s->need_update = 1;
366     offset &= 0xfff;
367     switch (offset >> 2) {
368     case FB_BASE:
369         s->base = val;
370         s->need_int = 1;
371         s->need_update = 1;
372         syborg_fb_update(s);
373         break;
374
375     case FB_HEIGHT:
376         s->rows = val;
377         break;
378
379     case FB_WIDTH:
380         s->cols = val;
381         break;
382
383     case FB_ORIENTATION:
384         /* TODO: Implement rotation.  */
385         break;
386
387     case FB_BLANK:
388         s->blank = val & 1;
389         break;
390
391     case FB_INT_MASK:
392         s->int_enable = val;
393         syborg_fb_update(s);
394         break;
395
396     case FB_INTERRUPT_CAUSE:
397         s->int_status &= ~val;
398         syborg_fb_update(s);
399         break;
400
401     case FB_BPP:
402         switch (val) {
403         case 1: val = BPP_SRC_1; break;
404         case 2: val = BPP_SRC_2; break;
405         case 4: val = BPP_SRC_4; break;
406         case 8: val = BPP_SRC_8; break;
407         /* case 15: val = BPP_SRC_15; break; */
408         case 16: val = BPP_SRC_16; break;
409         /* case 24: val = BPP_SRC_24; break; */
410         case 32: val = BPP_SRC_32; break;
411         default: val = s->bpp; break;
412         }
413         s->bpp = val;
414         break;
415
416     case FB_COLOR_ORDER:
417         s->rgb = (val != 0);
418         break;
419
420     case FB_BYTE_ORDER:
421         s->endian = (val != 0);
422         break;
423
424     case FB_PIXEL_ORDER:
425         /* TODO: Implement this.  */
426         break;
427
428     case FB_ROW_PITCH:
429         s->pitch = val;
430         break;
431
432     case FB_ENABLED:
433         s->enabled = val;
434         break;
435
436     default:
437         if ((offset >> 2) >= FB_PALETTE_START
438             && (offset >> 2) <= FB_PALETTE_END) {
439             s->raw_palette[(offset >> 2) - FB_PALETTE_START] = val;
440         } else {
441             cpu_abort (cpu_single_env, "syborg_fb_write: Bad offset %x\n",
442                       (int)offset);
443         }
444         break;
445     }
446 }
447
448 static CPUReadMemoryFunc * const syborg_fb_readfn[] = {
449     syborg_fb_read,
450     syborg_fb_read,
451     syborg_fb_read
452 };
453
454 static CPUWriteMemoryFunc * const syborg_fb_writefn[] = {
455     syborg_fb_write,
456     syborg_fb_write,
457     syborg_fb_write
458 };
459
460 static void syborg_fb_save(QEMUFile *f, void *opaque)
461 {
462     SyborgFBState *s = opaque;
463     int i;
464
465     qemu_put_be32(f, s->need_int);
466     qemu_put_be32(f, s->int_status);
467     qemu_put_be32(f, s->int_enable);
468     qemu_put_be32(f, s->enabled);
469     qemu_put_be32(f, s->base);
470     qemu_put_be32(f, s->pitch);
471     qemu_put_be32(f, s->rows);
472     qemu_put_be32(f, s->cols);
473     qemu_put_be32(f, s->bpp);
474     qemu_put_be32(f, s->rgb);
475     for (i = 0; i < 256; i++) {
476         qemu_put_be32(f, s->raw_palette[i]);
477     }
478 }
479
480 static int syborg_fb_load(QEMUFile *f, void *opaque, int version_id)
481 {
482     SyborgFBState *s = opaque;
483     int i;
484
485     if (version_id != 1)
486         return -EINVAL;
487
488     s->need_int = qemu_get_be32(f);
489     s->int_status = qemu_get_be32(f);
490     s->int_enable = qemu_get_be32(f);
491     s->enabled = qemu_get_be32(f);
492     s->base = qemu_get_be32(f);
493     s->pitch = qemu_get_be32(f);
494     s->rows = qemu_get_be32(f);
495     s->cols = qemu_get_be32(f);
496     s->bpp = qemu_get_be32(f);
497     s->rgb = qemu_get_be32(f);
498     for (i = 0; i < 256; i++) {
499         s->raw_palette[i] = qemu_get_be32(f);
500     }
501     s->need_update = 1;
502
503     return 0;
504 }
505
506 static int syborg_fb_init(SysBusDevice *dev)
507 {
508     SyborgFBState *s = FROM_SYSBUS(SyborgFBState, dev);
509     int iomemtype;
510
511     sysbus_init_irq(dev, &s->irq);
512     iomemtype = cpu_register_io_memory(syborg_fb_readfn,
513                                        syborg_fb_writefn, s);
514     sysbus_init_mmio(dev, 0x1000, iomemtype);
515
516     s->ds = graphic_console_init(syborg_fb_update_display,
517                                  syborg_fb_invalidate_display,
518                                  NULL, NULL, s);
519
520     if (s->cols != 0 && s->rows != 0) {
521         qemu_console_resize(s->ds, s->cols, s->rows);
522     }
523
524     if (!s->cols)
525         s->cols = ds_get_width(s->ds);
526     if (!s->rows)
527         s->rows = ds_get_height(s->ds);
528
529     register_savevm("syborg_framebuffer", -1, 1,
530                     syborg_fb_save, syborg_fb_load, s);
531     return 0;
532 }
533
534 static SysBusDeviceInfo syborg_fb_info = {
535     .init = syborg_fb_init,
536     .qdev.name  = "syborg,framebuffer",
537     .qdev.size  = sizeof(SyborgFBState),
538     .qdev.props = (Property[]) {
539         DEFINE_PROP_UINT32("width",  SyborgFBState, cols, 0),
540         DEFINE_PROP_UINT32("height", SyborgFBState, rows, 0),
541         DEFINE_PROP_END_OF_LIST(),
542     }
543 };
544
545 static void syborg_fb_register_devices(void)
546 {
547     sysbus_register_withprop(&syborg_fb_info);
548 }
549
550 device_init(syborg_fb_register_devices)