]> Git Repo - qemu.git/blob - hw/pl110.c
Fix some SLIRP warnings
[qemu.git] / hw / pl110.c
1 /*
2  * Arm PrimeCell PL110 Color LCD Controller
3  *
4  * Copyright (c) 2005-2006 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licenced under the GNU LGPL
8  */
9
10 #include "hw.h"
11 #include "primecell.h"
12 #include "console.h"
13
14 #define PL110_CR_EN   0x001
15 #define PL110_CR_BGR  0x100
16 #define PL110_CR_BEBO 0x200
17 #define PL110_CR_BEPO 0x400
18 #define PL110_CR_PWR  0x800
19
20 enum pl110_bppmode
21 {
22     BPP_1,
23     BPP_2,
24     BPP_4,
25     BPP_8,
26     BPP_16,
27     BPP_32
28 };
29
30 typedef struct {
31     DisplayState *ds;
32     QEMUConsole *console;
33
34     /* The Versatile/PB uses a slightly modified PL110 controller.  */
35     int versatile;
36     uint32_t timing[4];
37     uint32_t cr;
38     uint32_t upbase;
39     uint32_t lpbase;
40     uint32_t int_status;
41     uint32_t int_mask;
42     int cols;
43     int rows;
44     enum pl110_bppmode bpp;
45     int invalidate;
46     uint32_t pallette[256];
47     uint32_t raw_pallette[128];
48     qemu_irq irq;
49 } pl110_state;
50
51 static const unsigned char pl110_id[] =
52 { 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
53
54 /* The Arm documentation (DDI0224C) says the CLDC on the Versatile board
55    has a different ID.  However Linux only looks for the normal ID.  */
56 #if 0
57 static const unsigned char pl110_versatile_id[] =
58 { 0x93, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
59 #else
60 #define pl110_versatile_id pl110_id
61 #endif
62
63 static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
64 {
65     return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
66 }
67
68 static inline uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
69 {
70     return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
71 }
72
73 static inline uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
74 {
75     return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
76 }
77
78 static inline uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b)
79 {
80     return (r << 16) | (g << 8) | b;
81 }
82
83 static inline uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
84 {
85     return (r << 16) | (g << 8) | b;
86 }
87
88 typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int);
89
90 #define BITS 8
91 #include "pl110_template.h"
92 #define BITS 15
93 #include "pl110_template.h"
94 #define BITS 16
95 #include "pl110_template.h"
96 #define BITS 24
97 #include "pl110_template.h"
98 #define BITS 32
99 #include "pl110_template.h"
100
101 static int pl110_enabled(pl110_state *s)
102 {
103   return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR);
104 }
105
106 static void pl110_update_display(void *opaque)
107 {
108     pl110_state *s = (pl110_state *)opaque;
109     drawfn* fntable;
110     drawfn fn;
111     uint32_t *pallette;
112     uint32_t addr;
113     uint32_t base;
114     int dest_width;
115     int src_width;
116     uint8_t *dest;
117     uint8_t *src;
118     int first, last = 0;
119     int dirty, new_dirty;
120     int i;
121     int bpp_offset;
122
123     if (!pl110_enabled(s))
124         return;
125
126     switch (ds_get_bits_per_pixel(s->ds)) {
127     case 0:
128         return;
129     case 8:
130         fntable = pl110_draw_fn_8;
131         dest_width = 1;
132         break;
133     case 15:
134         fntable = pl110_draw_fn_15;
135         dest_width = 2;
136         break;
137     case 16:
138         fntable = pl110_draw_fn_16;
139         dest_width = 2;
140         break;
141     case 24:
142         fntable = pl110_draw_fn_24;
143         dest_width = 3;
144         break;
145     case 32:
146         fntable = pl110_draw_fn_32;
147         dest_width = 4;
148         break;
149     default:
150         fprintf(stderr, "pl110: Bad color depth\n");
151         exit(1);
152     }
153     if (s->cr & PL110_CR_BGR)
154         bpp_offset = 0;
155     else
156         bpp_offset = 18;
157
158     if (s->cr & PL110_CR_BEBO)
159         fn = fntable[s->bpp + 6 + bpp_offset];
160     else if (s->cr & PL110_CR_BEPO)
161         fn = fntable[s->bpp + 12 + bpp_offset];
162     else
163         fn = fntable[s->bpp + bpp_offset];
164
165     src_width = s->cols;
166     switch (s->bpp) {
167     case BPP_1:
168         src_width >>= 3;
169         break;
170     case BPP_2:
171         src_width >>= 2;
172         break;
173     case BPP_4:
174         src_width >>= 1;
175         break;
176     case BPP_8:
177         break;
178     case BPP_16:
179         src_width <<= 1;
180         break;
181     case BPP_32:
182         src_width <<= 2;
183         break;
184     }
185     dest_width *= s->cols;
186     pallette = s->pallette;
187     base = s->upbase;
188     /* HACK: Arm aliases physical memory at 0x80000000.  */
189     if (base > 0x80000000)
190         base -= 0x80000000;
191     src = phys_ram_base + base;
192     dest = ds_get_data(s->ds);
193     first = -1;
194     addr = base;
195
196     dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
197     new_dirty = dirty;
198     for (i = 0; i < s->rows; i++) {
199         if ((addr & ~TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) {
200             uint32_t tmp;
201             new_dirty = 0;
202             for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) {
203                 new_dirty |= cpu_physical_memory_get_dirty(addr + tmp,
204                                                            VGA_DIRTY_FLAG);
205             }
206         }
207
208         if (dirty || new_dirty || s->invalidate) {
209             fn(pallette, dest, src, s->cols);
210             if (first == -1)
211                 first = i;
212             last = i;
213         }
214         dirty = new_dirty;
215         addr += src_width;
216         dest += dest_width;
217         src += src_width;
218     }
219     if (first < 0)
220       return;
221
222     s->invalidate = 0;
223     cpu_physical_memory_reset_dirty(base + first * src_width,
224                                     base + (last + 1) * src_width,
225                                     VGA_DIRTY_FLAG);
226     dpy_update(s->ds, 0, first, s->cols, last - first + 1);
227 }
228
229 static void pl110_invalidate_display(void * opaque)
230 {
231     pl110_state *s = (pl110_state *)opaque;
232     s->invalidate = 1;
233 }
234
235 static void pl110_update_pallette(pl110_state *s, int n)
236 {
237     int i;
238     uint32_t raw;
239     unsigned int r, g, b;
240
241     raw = s->raw_pallette[n];
242     n <<= 1;
243     for (i = 0; i < 2; i++) {
244         r = (raw & 0x1f) << 3;
245         raw >>= 5;
246         g = (raw & 0x1f) << 3;
247         raw >>= 5;
248         b = (raw & 0x1f) << 3;
249         /* The I bit is ignored.  */
250         raw >>= 6;
251         switch (ds_get_bits_per_pixel(s->ds)) {
252         case 8:
253             s->pallette[n] = rgb_to_pixel8(r, g, b);
254             break;
255         case 15:
256             s->pallette[n] = rgb_to_pixel15(r, g, b);
257             break;
258         case 16:
259             s->pallette[n] = rgb_to_pixel16(r, g, b);
260             break;
261         case 24:
262         case 32:
263             s->pallette[n] = rgb_to_pixel32(r, g, b);
264             break;
265         }
266         n++;
267     }
268 }
269
270 static void pl110_resize(pl110_state *s, int width, int height)
271 {
272     if (width != s->cols || height != s->rows) {
273         if (pl110_enabled(s)) {
274             qemu_console_resize(s->console, width, height);
275         }
276     }
277     s->cols = width;
278     s->rows = height;
279 }
280
281 /* Update interrupts.  */
282 static void pl110_update(pl110_state *s)
283 {
284   /* TODO: Implement interrupts.  */
285 }
286
287 static uint32_t pl110_read(void *opaque, target_phys_addr_t offset)
288 {
289     pl110_state *s = (pl110_state *)opaque;
290
291     if (offset >= 0xfe0 && offset < 0x1000) {
292         if (s->versatile)
293             return pl110_versatile_id[(offset - 0xfe0) >> 2];
294         else
295             return pl110_id[(offset - 0xfe0) >> 2];
296     }
297     if (offset >= 0x200 && offset < 0x400) {
298         return s->raw_pallette[(offset - 0x200) >> 2];
299     }
300     switch (offset >> 2) {
301     case 0: /* LCDTiming0 */
302         return s->timing[0];
303     case 1: /* LCDTiming1 */
304         return s->timing[1];
305     case 2: /* LCDTiming2 */
306         return s->timing[2];
307     case 3: /* LCDTiming3 */
308         return s->timing[3];
309     case 4: /* LCDUPBASE */
310         return s->upbase;
311     case 5: /* LCDLPBASE */
312         return s->lpbase;
313     case 6: /* LCDIMSC */
314         if (s->versatile)
315           return s->cr;
316         return s->int_mask;
317     case 7: /* LCDControl */
318         if (s->versatile)
319           return s->int_mask;
320         return s->cr;
321     case 8: /* LCDRIS */
322         return s->int_status;
323     case 9: /* LCDMIS */
324         return s->int_status & s->int_mask;
325     case 11: /* LCDUPCURR */
326         /* TODO: Implement vertical refresh.  */
327         return s->upbase;
328     case 12: /* LCDLPCURR */
329         return s->lpbase;
330     default:
331         cpu_abort (cpu_single_env, "pl110_read: Bad offset %x\n", (int)offset);
332         return 0;
333     }
334 }
335
336 static void pl110_write(void *opaque, target_phys_addr_t offset,
337                         uint32_t val)
338 {
339     pl110_state *s = (pl110_state *)opaque;
340     int n;
341
342     /* For simplicity invalidate the display whenever a control register
343        is writen to.  */
344     s->invalidate = 1;
345     if (offset >= 0x200 && offset < 0x400) {
346         /* Pallette.  */
347         n = (offset - 0x200) >> 2;
348         s->raw_pallette[(offset - 0x200) >> 2] = val;
349         pl110_update_pallette(s, n);
350         return;
351     }
352     switch (offset >> 2) {
353     case 0: /* LCDTiming0 */
354         s->timing[0] = val;
355         n = ((val & 0xfc) + 4) * 4;
356         pl110_resize(s, n, s->rows);
357         break;
358     case 1: /* LCDTiming1 */
359         s->timing[1] = val;
360         n = (val & 0x3ff) + 1;
361         pl110_resize(s, s->cols, n);
362         break;
363     case 2: /* LCDTiming2 */
364         s->timing[2] = val;
365         break;
366     case 3: /* LCDTiming3 */
367         s->timing[3] = val;
368         break;
369     case 4: /* LCDUPBASE */
370         s->upbase = val;
371         break;
372     case 5: /* LCDLPBASE */
373         s->lpbase = val;
374         break;
375     case 6: /* LCDIMSC */
376         if (s->versatile)
377             goto control;
378     imsc:
379         s->int_mask = val;
380         pl110_update(s);
381         break;
382     case 7: /* LCDControl */
383         if (s->versatile)
384             goto imsc;
385     control:
386         s->cr = val;
387         s->bpp = (val >> 1) & 7;
388         if (pl110_enabled(s)) {
389             qemu_console_resize(s->console, s->cols, s->rows);
390         }
391         break;
392     case 10: /* LCDICR */
393         s->int_status &= ~val;
394         pl110_update(s);
395         break;
396     default:
397         cpu_abort (cpu_single_env, "pl110_write: Bad offset %x\n", (int)offset);
398     }
399 }
400
401 static CPUReadMemoryFunc *pl110_readfn[] = {
402    pl110_read,
403    pl110_read,
404    pl110_read
405 };
406
407 static CPUWriteMemoryFunc *pl110_writefn[] = {
408    pl110_write,
409    pl110_write,
410    pl110_write
411 };
412
413 void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq,
414                  int versatile)
415 {
416     pl110_state *s;
417     int iomemtype;
418
419     s = (pl110_state *)qemu_mallocz(sizeof(pl110_state));
420     iomemtype = cpu_register_io_memory(0, pl110_readfn,
421                                        pl110_writefn, s);
422     cpu_register_physical_memory(base, 0x00001000, iomemtype);
423     s->ds = ds;
424     s->versatile = versatile;
425     s->irq = irq;
426     s->console = graphic_console_init(ds, pl110_update_display,
427                                       pl110_invalidate_display,
428                                       NULL, NULL, s);
429     /* ??? Save/restore.  */
430     return s;
431 }
This page took 0.048135 seconds and 4 git commands to generate.