]> Git Repo - qemu.git/blob - hw/syborg_fb.c
usb: claim port at device initialization time.
[qemu.git] / 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 = 24;
221     } else {
222         bpp_offset = 0;
223     }
224     if (s->endian) {
225         bpp_offset += 8;
226     }
227     /* Our bpp constants mostly match the PL110/PL111 but
228      * not for the 16 bit case
229      */
230     switch (s->bpp) {
231     case BPP_SRC_16:
232         bpp_offset += 6;
233         break;
234     default:
235         bpp_offset += s->bpp;
236     }
237     fn = fntable[bpp_offset];
238
239     if (s->pitch) {
240         src_width = s->pitch;
241     } else {
242         src_width = s->cols;
243         switch (s->bpp) {
244         case BPP_SRC_1:
245             src_width >>= 3;
246             break;
247         case BPP_SRC_2:
248             src_width >>= 2;
249             break;
250         case BPP_SRC_4:
251             src_width >>= 1;
252             break;
253         case BPP_SRC_8:
254             break;
255         case BPP_SRC_15:
256         case BPP_SRC_16:
257             src_width <<= 1;
258             break;
259         case BPP_SRC_24:
260             src_width *= 3;
261             break;
262         case BPP_SRC_32:
263             src_width <<= 2;
264             break;
265         }
266     }
267     dest_width *= s->cols;
268     first = 0;
269     /* TODO: Implement blanking.  */
270     if (!s->blank) {
271         if (s->need_update && s->bpp <= BPP_SRC_8) {
272             syborg_fb_update_palette(s);
273         }
274         framebuffer_update_display(s->ds,
275                                    s->base, s->cols, s->rows,
276                                    src_width, dest_width, 0,
277                                    s->need_update,
278                                    fn, s->palette,
279                                    &first, &last);
280         if (first >= 0) {
281             dpy_update(s->ds, 0, first, s->cols, last - first + 1);
282         }
283
284         s->int_status |= FB_INT_VSYNC;
285         syborg_fb_update(s);
286     }
287
288     s->need_update = 0;
289 }
290
291 static void syborg_fb_invalidate_display(void * opaque)
292 {
293     SyborgFBState *s = (SyborgFBState *)opaque;
294     s->need_update = 1;
295 }
296
297 static uint32_t syborg_fb_read(void *opaque, target_phys_addr_t offset)
298 {
299     SyborgFBState *s = opaque;
300
301     DPRINTF("read reg %d\n", (int)offset);
302     offset &= 0xfff;
303     switch (offset >> 2) {
304     case FB_ID:
305         return SYBORG_ID_FRAMEBUFFER;
306
307     case FB_BASE:
308         return s->base;
309
310     case FB_HEIGHT:
311         return s->rows;
312
313     case FB_WIDTH:
314         return s->cols;
315
316     case FB_ORIENTATION:
317         return 0;
318
319     case FB_BLANK:
320         return s->blank;
321
322     case FB_INT_MASK:
323         return s->int_enable;
324
325     case FB_INTERRUPT_CAUSE:
326         return s->int_status;
327
328     case FB_BPP:
329         switch (s->bpp) {
330         case BPP_SRC_1: return 1;
331         case BPP_SRC_2: return 2;
332         case BPP_SRC_4: return 4;
333         case BPP_SRC_8: return 8;
334         case BPP_SRC_15: return 15;
335         case BPP_SRC_16: return 16;
336         case BPP_SRC_24: return 24;
337         case BPP_SRC_32: return 32;
338         default: return 0;
339         }
340
341     case FB_COLOR_ORDER:
342         return s->rgb;
343
344     case FB_BYTE_ORDER:
345         return s->endian;
346
347     case FB_PIXEL_ORDER:
348         return 0;
349
350     case FB_ROW_PITCH:
351         return s->pitch;
352
353     case FB_ENABLED:
354         return s->enabled;
355
356     default:
357         if ((offset >> 2) >= FB_PALETTE_START
358             && (offset >> 2) <= FB_PALETTE_END) {
359             return s->raw_palette[(offset >> 2) - FB_PALETTE_START];
360         } else {
361             cpu_abort (cpu_single_env, "syborg_fb_read: Bad offset %x\n",
362                          (int)offset);
363         }
364         return 0;
365     }
366 }
367
368 static void syborg_fb_write(void *opaque, target_phys_addr_t offset,
369                             uint32_t val)
370 {
371     SyborgFBState *s = opaque;
372
373     DPRINTF("write reg %d = %d\n", (int)offset, val);
374     s->need_update = 1;
375     offset &= 0xfff;
376     switch (offset >> 2) {
377     case FB_BASE:
378         s->base = val;
379         s->need_int = 1;
380         s->need_update = 1;
381         syborg_fb_update(s);
382         break;
383
384     case FB_HEIGHT:
385         s->rows = val;
386         break;
387
388     case FB_WIDTH:
389         s->cols = val;
390         break;
391
392     case FB_ORIENTATION:
393         /* TODO: Implement rotation.  */
394         break;
395
396     case FB_BLANK:
397         s->blank = val & 1;
398         break;
399
400     case FB_INT_MASK:
401         s->int_enable = val;
402         syborg_fb_update(s);
403         break;
404
405     case FB_INTERRUPT_CAUSE:
406         s->int_status &= ~val;
407         syborg_fb_update(s);
408         break;
409
410     case FB_BPP:
411         switch (val) {
412         case 1: val = BPP_SRC_1; break;
413         case 2: val = BPP_SRC_2; break;
414         case 4: val = BPP_SRC_4; break;
415         case 8: val = BPP_SRC_8; break;
416         /* case 15: val = BPP_SRC_15; break; */
417         case 16: val = BPP_SRC_16; break;
418         /* case 24: val = BPP_SRC_24; break; */
419         case 32: val = BPP_SRC_32; break;
420         default: val = s->bpp; break;
421         }
422         s->bpp = val;
423         break;
424
425     case FB_COLOR_ORDER:
426         s->rgb = (val != 0);
427         break;
428
429     case FB_BYTE_ORDER:
430         s->endian = (val != 0);
431         break;
432
433     case FB_PIXEL_ORDER:
434         /* TODO: Implement this.  */
435         break;
436
437     case FB_ROW_PITCH:
438         s->pitch = val;
439         break;
440
441     case FB_ENABLED:
442         s->enabled = val;
443         break;
444
445     default:
446         if ((offset >> 2) >= FB_PALETTE_START
447             && (offset >> 2) <= FB_PALETTE_END) {
448             s->raw_palette[(offset >> 2) - FB_PALETTE_START] = val;
449         } else {
450             cpu_abort (cpu_single_env, "syborg_fb_write: Bad offset %x\n",
451                       (int)offset);
452         }
453         break;
454     }
455 }
456
457 static CPUReadMemoryFunc * const syborg_fb_readfn[] = {
458     syborg_fb_read,
459     syborg_fb_read,
460     syborg_fb_read
461 };
462
463 static CPUWriteMemoryFunc * const syborg_fb_writefn[] = {
464     syborg_fb_write,
465     syborg_fb_write,
466     syborg_fb_write
467 };
468
469 static void syborg_fb_save(QEMUFile *f, void *opaque)
470 {
471     SyborgFBState *s = opaque;
472     int i;
473
474     qemu_put_be32(f, s->need_int);
475     qemu_put_be32(f, s->int_status);
476     qemu_put_be32(f, s->int_enable);
477     qemu_put_be32(f, s->enabled);
478     qemu_put_be32(f, s->base);
479     qemu_put_be32(f, s->pitch);
480     qemu_put_be32(f, s->rows);
481     qemu_put_be32(f, s->cols);
482     qemu_put_be32(f, s->bpp);
483     qemu_put_be32(f, s->rgb);
484     for (i = 0; i < 256; i++) {
485         qemu_put_be32(f, s->raw_palette[i]);
486     }
487 }
488
489 static int syborg_fb_load(QEMUFile *f, void *opaque, int version_id)
490 {
491     SyborgFBState *s = opaque;
492     int i;
493
494     if (version_id != 1)
495         return -EINVAL;
496
497     s->need_int = qemu_get_be32(f);
498     s->int_status = qemu_get_be32(f);
499     s->int_enable = qemu_get_be32(f);
500     s->enabled = qemu_get_be32(f);
501     s->base = qemu_get_be32(f);
502     s->pitch = qemu_get_be32(f);
503     s->rows = qemu_get_be32(f);
504     s->cols = qemu_get_be32(f);
505     s->bpp = qemu_get_be32(f);
506     s->rgb = qemu_get_be32(f);
507     for (i = 0; i < 256; i++) {
508         s->raw_palette[i] = qemu_get_be32(f);
509     }
510     s->need_update = 1;
511
512     return 0;
513 }
514
515 static int syborg_fb_init(SysBusDevice *dev)
516 {
517     SyborgFBState *s = FROM_SYSBUS(SyborgFBState, dev);
518     int iomemtype;
519
520     sysbus_init_irq(dev, &s->irq);
521     iomemtype = cpu_register_io_memory(syborg_fb_readfn,
522                                        syborg_fb_writefn, s,
523                                        DEVICE_NATIVE_ENDIAN);
524     sysbus_init_mmio(dev, 0x1000, iomemtype);
525
526     s->ds = graphic_console_init(syborg_fb_update_display,
527                                  syborg_fb_invalidate_display,
528                                  NULL, NULL, s);
529
530     if (s->cols != 0 && s->rows != 0) {
531         qemu_console_resize(s->ds, s->cols, s->rows);
532     }
533
534     if (!s->cols)
535         s->cols = ds_get_width(s->ds);
536     if (!s->rows)
537         s->rows = ds_get_height(s->ds);
538
539     register_savevm(&dev->qdev, "syborg_framebuffer", -1, 1,
540                     syborg_fb_save, syborg_fb_load, s);
541     return 0;
542 }
543
544 static SysBusDeviceInfo syborg_fb_info = {
545     .init = syborg_fb_init,
546     .qdev.name  = "syborg,framebuffer",
547     .qdev.size  = sizeof(SyborgFBState),
548     .qdev.props = (Property[]) {
549         DEFINE_PROP_UINT32("width",  SyborgFBState, cols, 0),
550         DEFINE_PROP_UINT32("height", SyborgFBState, rows, 0),
551         DEFINE_PROP_END_OF_LIST(),
552     }
553 };
554
555 static void syborg_fb_register_devices(void)
556 {
557     sysbus_register_withprop(&syborg_fb_info);
558 }
559
560 device_init(syborg_fb_register_devices)
This page took 0.053362 seconds and 4 git commands to generate.