8250: Customized base baudrate
[qemu] / hw / omap_dss.c
1 /*
2  * OMAP2 Display Subsystem.
3  *
4  * Copyright (C) 2008 Nokia Corporation
5  * Written by Andrzej Zaborowski <andrew@openedhand.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 or
10  * (at your option) version 3 of the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22 #include "hw.h"
23 #include "console.h"
24 #include "omap.h"
25
26 struct omap_dss_s {
27     target_phys_addr_t diss_base;
28     target_phys_addr_t disc_base;
29     target_phys_addr_t rfbi_base;
30     target_phys_addr_t venc_base;
31     target_phys_addr_t im3_base;
32     qemu_irq irq;
33     qemu_irq drq;
34     DisplayState *state;
35
36     int autoidle;
37     int control;
38     int enable;
39
40     struct omap_dss_panel_s {
41         int enable;
42         int nx;
43         int ny;
44
45         int x;
46         int y;
47     } dig, lcd;
48
49     struct {
50         uint32_t idlemode;
51         uint32_t irqst;
52         uint32_t irqen;
53         uint32_t control;
54         uint32_t config;
55         uint32_t capable;
56         uint32_t timing[3];
57         int line;
58         uint32_t bg[2];
59         uint32_t trans[2];
60
61         struct omap_dss_plane_s {
62             int enable;
63             int bpp;
64             int posx;
65             int posy;
66             int nx;
67             int ny;
68
69             target_phys_addr_t addr[3];
70
71             uint32_t attr;
72             uint32_t tresh;
73             int rowinc;
74             int colinc;
75             int wininc;
76         } l[3];
77
78         int invalidate;
79         uint16_t palette[256];
80     } dispc;
81
82     struct {
83         int idlemode;
84         uint32_t control;
85         int enable;
86         int pixels;
87         int busy;
88         int skiplines;
89         uint16_t rxbuf;
90         uint32_t config[2];
91         uint32_t time[4];
92         uint32_t data[6];
93         uint16_t vsync;
94         uint16_t hsync;
95         struct rfbi_chip_s *chip[2];
96     } rfbi;
97 };
98
99 static void omap_dispc_interrupt_update(struct omap_dss_s *s)
100 {
101     qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
102 }
103
104 static void omap_rfbi_reset(struct omap_dss_s *s)
105 {
106     s->rfbi.idlemode = 0;
107     s->rfbi.control = 2;
108     s->rfbi.enable = 0;
109     s->rfbi.pixels = 0;
110     s->rfbi.skiplines = 0;
111     s->rfbi.busy = 0;
112     s->rfbi.config[0] = 0x00310000;
113     s->rfbi.config[1] = 0x00310000;
114     s->rfbi.time[0] = 0;
115     s->rfbi.time[1] = 0;
116     s->rfbi.time[2] = 0;
117     s->rfbi.time[3] = 0;
118     s->rfbi.data[0] = 0;
119     s->rfbi.data[1] = 0;
120     s->rfbi.data[2] = 0;
121     s->rfbi.data[3] = 0;
122     s->rfbi.data[4] = 0;
123     s->rfbi.data[5] = 0;
124     s->rfbi.vsync = 0;
125     s->rfbi.hsync = 0;
126 }
127
128 void omap_dss_reset(struct omap_dss_s *s)
129 {
130     s->autoidle = 0;
131     s->control = 0;
132     s->enable = 0;
133
134     s->dig.enable = 0;
135     s->dig.nx = 1;
136     s->dig.ny = 1;
137
138     s->lcd.enable = 0;
139     s->lcd.nx = 1;
140     s->lcd.ny = 1;
141
142     s->dispc.idlemode = 0;
143     s->dispc.irqst = 0;
144     s->dispc.irqen = 0;
145     s->dispc.control = 0;
146     s->dispc.config = 0;
147     s->dispc.capable = 0x161;
148     s->dispc.timing[0] = 0;
149     s->dispc.timing[1] = 0;
150     s->dispc.timing[2] = 0;
151     s->dispc.line = 0;
152     s->dispc.bg[0] = 0;
153     s->dispc.bg[1] = 0;
154     s->dispc.trans[0] = 0;
155     s->dispc.trans[1] = 0;
156
157     s->dispc.l[0].enable = 0;
158     s->dispc.l[0].bpp = 0;
159     s->dispc.l[0].addr[0] = 0;
160     s->dispc.l[0].addr[1] = 0;
161     s->dispc.l[0].addr[2] = 0;
162     s->dispc.l[0].posx = 0;
163     s->dispc.l[0].posy = 0;
164     s->dispc.l[0].nx = 1;
165     s->dispc.l[0].ny = 1;
166     s->dispc.l[0].attr = 0;
167     s->dispc.l[0].tresh = 0;
168     s->dispc.l[0].rowinc = 1;
169     s->dispc.l[0].colinc = 1;
170     s->dispc.l[0].wininc = 0;
171
172     omap_rfbi_reset(s);
173     omap_dispc_interrupt_update(s);
174 }
175
176 static uint32_t omap_diss_read(void *opaque, target_phys_addr_t addr)
177 {
178     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
179     int offset = addr - s->diss_base;
180
181     switch (offset) {
182     case 0x00:  /* DSS_REVISIONNUMBER */
183         return 0x20;
184
185     case 0x10:  /* DSS_SYSCONFIG */
186         return s->autoidle;
187
188     case 0x14:  /* DSS_SYSSTATUS */
189         return 1;                                               /* RESETDONE */
190
191     case 0x40:  /* DSS_CONTROL */
192         return s->control;
193
194     case 0x50:  /* DSS_PSA_LCD_REG_1 */
195     case 0x54:  /* DSS_PSA_LCD_REG_2 */
196     case 0x58:  /* DSS_PSA_VIDEO_REG */
197         /* TODO: fake some values when appropriate s->control bits are set */
198         return 0;
199
200     case 0x5c:  /* DSS_STATUS */
201         return 1 + (s->control & 1);
202
203     default:
204         break;
205     }
206     OMAP_BAD_REG(addr);
207     return 0;
208 }
209
210 static void omap_diss_write(void *opaque, target_phys_addr_t addr,
211                 uint32_t value)
212 {
213     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
214     int offset = addr - s->diss_base;
215
216     switch (offset) {
217     case 0x00:  /* DSS_REVISIONNUMBER */
218     case 0x14:  /* DSS_SYSSTATUS */
219     case 0x50:  /* DSS_PSA_LCD_REG_1 */
220     case 0x54:  /* DSS_PSA_LCD_REG_2 */
221     case 0x58:  /* DSS_PSA_VIDEO_REG */
222     case 0x5c:  /* DSS_STATUS */
223         OMAP_RO_REG(addr);
224         break;
225
226     case 0x10:  /* DSS_SYSCONFIG */
227         if (value & 2)                                          /* SOFTRESET */
228             omap_dss_reset(s);
229         s->autoidle = value & 1;
230         break;
231
232     case 0x40:  /* DSS_CONTROL */
233         s->control = value & 0x3dd;
234         break;
235
236     default:
237         OMAP_BAD_REG(addr);
238     }
239 }
240
241 static CPUReadMemoryFunc *omap_diss1_readfn[] = {
242     omap_badwidth_read32,
243     omap_badwidth_read32,
244     omap_diss_read,
245 };
246
247 static CPUWriteMemoryFunc *omap_diss1_writefn[] = {
248     omap_badwidth_write32,
249     omap_badwidth_write32,
250     omap_diss_write,
251 };
252
253 static uint32_t omap_disc_read(void *opaque, target_phys_addr_t addr)
254 {
255     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
256     int offset = addr - s->disc_base;
257
258     switch (offset) {
259     case 0x000: /* DISPC_REVISION */
260         return 0x20;
261
262     case 0x010: /* DISPC_SYSCONFIG */
263         return s->dispc.idlemode;
264
265     case 0x014: /* DISPC_SYSSTATUS */
266         return 1;                                               /* RESETDONE */
267
268     case 0x018: /* DISPC_IRQSTATUS */
269         return s->dispc.irqst;
270
271     case 0x01c: /* DISPC_IRQENABLE */
272         return s->dispc.irqen;
273
274     case 0x040: /* DISPC_CONTROL */
275         return s->dispc.control;
276
277     case 0x044: /* DISPC_CONFIG */
278         return s->dispc.config;
279
280     case 0x048: /* DISPC_CAPABLE */
281         return s->dispc.capable;
282
283     case 0x04c: /* DISPC_DEFAULT_COLOR0 */
284         return s->dispc.bg[0];
285     case 0x050: /* DISPC_DEFAULT_COLOR1 */
286         return s->dispc.bg[1];
287     case 0x054: /* DISPC_TRANS_COLOR0 */
288         return s->dispc.trans[0];
289     case 0x058: /* DISPC_TRANS_COLOR1 */
290         return s->dispc.trans[1];
291
292     case 0x05c: /* DISPC_LINE_STATUS */
293         return 0x7ff;
294     case 0x060: /* DISPC_LINE_NUMBER */
295         return s->dispc.line;
296
297     case 0x064: /* DISPC_TIMING_H */
298         return s->dispc.timing[0];
299     case 0x068: /* DISPC_TIMING_V */
300         return s->dispc.timing[1];
301     case 0x06c: /* DISPC_POL_FREQ */
302         return s->dispc.timing[2];
303     case 0x070: /* DISPC_DIVISOR */
304         return s->dispc.timing[3];
305
306     case 0x078: /* DISPC_SIZE_DIG */
307         return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
308     case 0x07c: /* DISPC_SIZE_LCD */
309         return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
310
311     case 0x080: /* DISPC_GFX_BA0 */
312         return s->dispc.l[0].addr[0];
313     case 0x084: /* DISPC_GFX_BA1 */
314         return s->dispc.l[0].addr[1];
315     case 0x088: /* DISPC_GFX_POSITION */
316         return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
317     case 0x08c: /* DISPC_GFX_SIZE */
318         return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
319     case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
320         return s->dispc.l[0].attr;
321     case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
322         return s->dispc.l[0].tresh;
323     case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */
324         return 256;
325     case 0x0ac: /* DISPC_GFX_ROW_INC */
326         return s->dispc.l[0].rowinc;
327     case 0x0b0: /* DISPC_GFX_PIXEL_INC */
328         return s->dispc.l[0].colinc;
329     case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
330         return s->dispc.l[0].wininc;
331     case 0x0b8: /* DISPC_GFX_TABLE_BA */
332         return s->dispc.l[0].addr[2];
333
334     case 0x0bc: /* DISPC_VID1_BA0 */
335     case 0x0c0: /* DISPC_VID1_BA1 */
336     case 0x0c4: /* DISPC_VID1_POSITION */
337     case 0x0c8: /* DISPC_VID1_SIZE */
338     case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
339     case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
340     case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */
341     case 0x0d8: /* DISPC_VID1_ROW_INC */
342     case 0x0dc: /* DISPC_VID1_PIXEL_INC */
343     case 0x0e0: /* DISPC_VID1_FIR */
344     case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
345     case 0x0e8: /* DISPC_VID1_ACCU0 */
346     case 0x0ec: /* DISPC_VID1_ACCU1 */
347     case 0x0f0 ... 0x140:       /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
348     case 0x14c: /* DISPC_VID2_BA0 */
349     case 0x150: /* DISPC_VID2_BA1 */
350     case 0x154: /* DISPC_VID2_POSITION */
351     case 0x158: /* DISPC_VID2_SIZE */
352     case 0x15c: /* DISPC_VID2_ATTRIBUTES */
353     case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
354     case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */
355     case 0x168: /* DISPC_VID2_ROW_INC */
356     case 0x16c: /* DISPC_VID2_PIXEL_INC */
357     case 0x170: /* DISPC_VID2_FIR */
358     case 0x174: /* DISPC_VID2_PICTURE_SIZE */
359     case 0x178: /* DISPC_VID2_ACCU0 */
360     case 0x17c: /* DISPC_VID2_ACCU1 */
361     case 0x180 ... 0x1d0:       /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
362     case 0x1d4: /* DISPC_DATA_CYCLE1 */
363     case 0x1d8: /* DISPC_DATA_CYCLE2 */
364     case 0x1dc: /* DISPC_DATA_CYCLE3 */
365         return 0;
366
367     default:
368         break;
369     }
370     OMAP_BAD_REG(addr);
371     return 0;
372 }
373
374 static void omap_disc_write(void *opaque, target_phys_addr_t addr,
375                 uint32_t value)
376 {
377     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
378     int offset = addr - s->disc_base;
379
380     switch (offset) {
381     case 0x010: /* DISPC_SYSCONFIG */
382         if (value & 2)                                          /* SOFTRESET */
383             omap_dss_reset(s);
384         s->dispc.idlemode = value & 0x301b;
385         break;
386
387     case 0x018: /* DISPC_IRQSTATUS */
388         s->dispc.irqst &= ~value;
389         omap_dispc_interrupt_update(s);
390         break;
391
392     case 0x01c: /* DISPC_IRQENABLE */
393         s->dispc.irqen = value & 0xffff;
394         omap_dispc_interrupt_update(s);
395         break;
396
397     case 0x040: /* DISPC_CONTROL */
398         s->dispc.control = value & 0x07ff9fff;
399         s->dig.enable = (value >> 1) & 1;
400         s->lcd.enable = (value >> 0) & 1;
401         if (value & (1 << 12))                  /* OVERLAY_OPTIMIZATION */
402             if (~((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1))
403                  fprintf(stderr, "%s: Overlay Optimization when no overlay "
404                                  "region effectively exists leads to "
405                                  "unpredictable behaviour!\n", __FUNCTION__);
406         if (value & (1 << 6)) {                         /* GODIGITAL */
407             /* XXX: Shadowed fields are:
408              * s->dispc.config
409              * s->dispc.capable
410              * s->dispc.bg[0]
411              * s->dispc.bg[1]
412              * s->dispc.trans[0]
413              * s->dispc.trans[1]
414              * s->dispc.line
415              * s->dispc.timing[0]
416              * s->dispc.timing[1]
417              * s->dispc.timing[2]
418              * s->dispc.timing[3]
419              * s->lcd.nx
420              * s->lcd.ny
421              * s->dig.nx
422              * s->dig.ny
423              * s->dispc.l[0].addr[0]
424              * s->dispc.l[0].addr[1]
425              * s->dispc.l[0].addr[2]
426              * s->dispc.l[0].posx
427              * s->dispc.l[0].posy
428              * s->dispc.l[0].nx
429              * s->dispc.l[0].ny
430              * s->dispc.l[0].tresh
431              * s->dispc.l[0].rowinc
432              * s->dispc.l[0].colinc
433              * s->dispc.l[0].wininc
434              * All they need to be loaded here from their shadow registers.
435              */
436         }
437         if (value & (1 << 5)) {                         /* GOLCD */
438              /* XXX: Likewise for LCD here.  */
439         }
440         s->dispc.invalidate = 1;
441         break;
442
443     case 0x044: /* DISPC_CONFIG */
444         s->dispc.config = value & 0x3fff;
445         /* XXX:
446          * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
447          * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
448          */
449         s->dispc.invalidate = 1;
450         break;
451
452     case 0x048: /* DISPC_CAPABLE */
453         s->dispc.capable = value & 0x3ff;
454         break;
455
456     case 0x04c: /* DISPC_DEFAULT_COLOR0 */
457         s->dispc.bg[0] = value & 0xffffff;
458         s->dispc.invalidate = 1;
459         break;
460     case 0x050: /* DISPC_DEFAULT_COLOR1 */
461         s->dispc.bg[1] = value & 0xffffff;
462         s->dispc.invalidate = 1;
463         break;
464     case 0x054: /* DISPC_TRANS_COLOR0 */
465         s->dispc.trans[0] = value & 0xffffff;
466         s->dispc.invalidate = 1;
467         break;
468     case 0x058: /* DISPC_TRANS_COLOR1 */
469         s->dispc.trans[1] = value & 0xffffff;
470         s->dispc.invalidate = 1;
471         break;
472
473     case 0x060: /* DISPC_LINE_NUMBER */
474         s->dispc.line = value & 0x7ff;
475         break;
476
477     case 0x064: /* DISPC_TIMING_H */
478         s->dispc.timing[0] = value & 0x0ff0ff3f;
479         break;
480     case 0x068: /* DISPC_TIMING_V */
481         s->dispc.timing[1] = value & 0x0ff0ff3f;
482         break;
483     case 0x06c: /* DISPC_POL_FREQ */
484         s->dispc.timing[2] = value & 0x0003ffff;
485         break;
486     case 0x070: /* DISPC_DIVISOR */
487         s->dispc.timing[3] = value & 0x00ff00ff;
488         break;
489
490     case 0x078: /* DISPC_SIZE_DIG */
491         s->dig.nx = ((value >>  0) & 0x7ff) + 1;                /* PPL */
492         s->dig.ny = ((value >> 16) & 0x7ff) + 1;                /* LPP */
493         s->dispc.invalidate = 1;
494         break;
495     case 0x07c: /* DISPC_SIZE_LCD */
496         s->lcd.nx = ((value >>  0) & 0x7ff) + 1;                /* PPL */
497         s->lcd.ny = ((value >> 16) & 0x7ff) + 1;                /* LPP */
498         s->dispc.invalidate = 1;
499         break;
500     case 0x080: /* DISPC_GFX_BA0 */
501         s->dispc.l[0].addr[0] = (target_phys_addr_t) value;
502         s->dispc.invalidate = 1;
503         break;
504     case 0x084: /* DISPC_GFX_BA1 */
505         s->dispc.l[0].addr[1] = (target_phys_addr_t) value;
506         s->dispc.invalidate = 1;
507         break;
508     case 0x088: /* DISPC_GFX_POSITION */
509         s->dispc.l[0].posx = ((value >>  0) & 0x7ff);           /* GFXPOSX */
510         s->dispc.l[0].posy = ((value >> 16) & 0x7ff);           /* GFXPOSY */
511         s->dispc.invalidate = 1;
512         break;
513     case 0x08c: /* DISPC_GFX_SIZE */
514         s->dispc.l[0].nx = ((value >>  0) & 0x7ff) + 1;         /* GFXSIZEX */
515         s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1;         /* GFXSIZEY */
516         s->dispc.invalidate = 1;
517         break;
518     case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
519         s->dispc.l[0].attr = value & 0x7ff;
520         if (value & (3 << 9))
521             fprintf(stderr, "%s: Big-endian pixel format not supported\n",
522                             __FUNCTION__);
523         s->dispc.l[0].enable = value & 1;
524         s->dispc.l[0].bpp = (value >> 1) & 0xf;
525         s->dispc.invalidate = 1;
526         break;
527     case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
528         s->dispc.l[0].tresh = value & 0x01ff01ff;
529         break;
530     case 0x0ac: /* DISPC_GFX_ROW_INC */
531         s->dispc.l[0].rowinc = value;
532         s->dispc.invalidate = 1;
533         break;
534     case 0x0b0: /* DISPC_GFX_PIXEL_INC */
535         s->dispc.l[0].colinc = value;
536         s->dispc.invalidate = 1;
537         break;
538     case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
539         s->dispc.l[0].wininc = value;
540         break;
541     case 0x0b8: /* DISPC_GFX_TABLE_BA */
542         s->dispc.l[0].addr[2] = (target_phys_addr_t) value;
543         s->dispc.invalidate = 1;
544         break;
545
546     case 0x0bc: /* DISPC_VID1_BA0 */
547     case 0x0c0: /* DISPC_VID1_BA1 */
548     case 0x0c4: /* DISPC_VID1_POSITION */
549     case 0x0c8: /* DISPC_VID1_SIZE */
550     case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
551     case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
552     case 0x0d8: /* DISPC_VID1_ROW_INC */
553     case 0x0dc: /* DISPC_VID1_PIXEL_INC */
554     case 0x0e0: /* DISPC_VID1_FIR */
555     case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
556     case 0x0e8: /* DISPC_VID1_ACCU0 */
557     case 0x0ec: /* DISPC_VID1_ACCU1 */
558     case 0x0f0 ... 0x140:       /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
559     case 0x14c: /* DISPC_VID2_BA0 */
560     case 0x150: /* DISPC_VID2_BA1 */
561     case 0x154: /* DISPC_VID2_POSITION */
562     case 0x158: /* DISPC_VID2_SIZE */
563     case 0x15c: /* DISPC_VID2_ATTRIBUTES */
564     case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
565     case 0x168: /* DISPC_VID2_ROW_INC */
566     case 0x16c: /* DISPC_VID2_PIXEL_INC */
567     case 0x170: /* DISPC_VID2_FIR */
568     case 0x174: /* DISPC_VID2_PICTURE_SIZE */
569     case 0x178: /* DISPC_VID2_ACCU0 */
570     case 0x17c: /* DISPC_VID2_ACCU1 */
571     case 0x180 ... 0x1d0:       /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
572     case 0x1d4: /* DISPC_DATA_CYCLE1 */
573     case 0x1d8: /* DISPC_DATA_CYCLE2 */
574     case 0x1dc: /* DISPC_DATA_CYCLE3 */
575         break;
576
577     default:
578         OMAP_BAD_REG(addr);
579     }
580 }
581
582 static CPUReadMemoryFunc *omap_disc1_readfn[] = {
583     omap_badwidth_read32,
584     omap_badwidth_read32,
585     omap_disc_read,
586 };
587
588 static CPUWriteMemoryFunc *omap_disc1_writefn[] = {
589     omap_badwidth_write32,
590     omap_badwidth_write32,
591     omap_disc_write,
592 };
593
594 static void *omap_rfbi_get_buffer(struct omap_dss_s *s)
595 {
596     target_phys_addr_t fb;
597     uint32_t pd;
598
599     /* TODO */
600     fb = s->dispc.l[0].addr[0];
601
602     pd = cpu_get_physical_page_desc(fb);
603     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
604         /* TODO */
605         cpu_abort(cpu_single_env, "%s: framebuffer outside RAM!\n",
606                         __FUNCTION__);
607     else
608         return phys_ram_base +
609                 (pd & TARGET_PAGE_MASK) +
610                 (fb & ~TARGET_PAGE_MASK);
611 }
612
613 static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
614 {
615     if (!s->rfbi.busy)
616         return;
617
618     /* TODO: in non-Bypass mode we probably need to just deassert the DRQ.  */
619
620     s->rfbi.busy = 0;
621 }
622
623 static void omap_rfbi_transfer_start(struct omap_dss_s *s)
624 {
625     void *data;
626     size_t len;
627     int pitch;
628
629     if (!s->rfbi.enable || s->rfbi.busy)
630         return;
631
632     if (s->rfbi.control & (1 << 1)) {                           /* BYPASS */
633         /* TODO: in non-Bypass mode we probably need to just assert the
634          * DRQ and wait for DMA to write the pixels.  */
635         fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
636         return;
637     }
638
639     if (!(s->dispc.control & (1 << 11)))                        /* RFBIMODE */
640         return;
641     /* TODO: check that LCD output is enabled in DISPC.  */
642
643     s->rfbi.busy = 1;
644
645     data = omap_rfbi_get_buffer(s);
646
647     /* TODO bpp */
648     len = s->rfbi.pixels * 2;
649     s->rfbi.pixels = 0;
650
651     /* TODO: negative values */
652     pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
653
654     if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
655         s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
656     if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
657         s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
658
659     omap_rfbi_transfer_stop(s);
660
661     /* TODO */
662     s->dispc.irqst |= 1;                                        /* FRAMEDONE */
663     omap_dispc_interrupt_update(s);
664 }
665
666 static uint32_t omap_rfbi_read(void *opaque, target_phys_addr_t addr)
667 {
668     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
669     int offset = addr - s->rfbi_base;
670
671     switch (offset) {
672     case 0x00:  /* RFBI_REVISION */
673         return 0x10;
674
675     case 0x10:  /* RFBI_SYSCONFIG */
676         return s->rfbi.idlemode;
677
678     case 0x14:  /* RFBI_SYSSTATUS */
679         return 1 | (s->rfbi.busy << 8);                         /* RESETDONE */
680
681     case 0x40:  /* RFBI_CONTROL */
682         return s->rfbi.control;
683
684     case 0x44:  /* RFBI_PIXELCNT */
685         return s->rfbi.pixels;
686
687     case 0x48:  /* RFBI_LINE_NUMBER */
688         return s->rfbi.skiplines;
689
690     case 0x58:  /* RFBI_READ */
691     case 0x5c:  /* RFBI_STATUS */
692         return s->rfbi.rxbuf;
693
694     case 0x60:  /* RFBI_CONFIG0 */
695         return s->rfbi.config[0];
696     case 0x64:  /* RFBI_ONOFF_TIME0 */
697         return s->rfbi.time[0];
698     case 0x68:  /* RFBI_CYCLE_TIME0 */
699         return s->rfbi.time[1];
700     case 0x6c:  /* RFBI_DATA_CYCLE1_0 */
701         return s->rfbi.data[0];
702     case 0x70:  /* RFBI_DATA_CYCLE2_0 */
703         return s->rfbi.data[1];
704     case 0x74:  /* RFBI_DATA_CYCLE3_0 */
705         return s->rfbi.data[2];
706
707     case 0x78:  /* RFBI_CONFIG1 */
708         return s->rfbi.config[1];
709     case 0x7c:  /* RFBI_ONOFF_TIME1 */
710         return s->rfbi.time[2];
711     case 0x80:  /* RFBI_CYCLE_TIME1 */
712         return s->rfbi.time[3];
713     case 0x84:  /* RFBI_DATA_CYCLE1_1 */
714         return s->rfbi.data[3];
715     case 0x88:  /* RFBI_DATA_CYCLE2_1 */
716         return s->rfbi.data[4];
717     case 0x8c:  /* RFBI_DATA_CYCLE3_1 */
718         return s->rfbi.data[5];
719
720     case 0x90:  /* RFBI_VSYNC_WIDTH */
721         return s->rfbi.vsync;
722     case 0x94:  /* RFBI_HSYNC_WIDTH */
723         return s->rfbi.hsync;
724     }
725     OMAP_BAD_REG(addr);
726     return 0;
727 }
728
729 static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
730                 uint32_t value)
731 {
732     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
733     int offset = addr - s->rfbi_base;
734
735     switch (offset) {
736     case 0x10:  /* RFBI_SYSCONFIG */
737         if (value & 2)                                          /* SOFTRESET */
738             omap_rfbi_reset(s);
739         s->rfbi.idlemode = value & 0x19;
740         break;
741
742     case 0x40:  /* RFBI_CONTROL */
743         s->rfbi.control = value & 0xf;
744         s->rfbi.enable = value & 1;
745         if (value & (1 << 4) &&                                 /* ITE */
746                         !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
747             omap_rfbi_transfer_start(s);
748         break;
749
750     case 0x44:  /* RFBI_PIXELCNT */
751         s->rfbi.pixels = value;
752         break;
753
754     case 0x48:  /* RFBI_LINE_NUMBER */
755         s->rfbi.skiplines = value & 0x7ff;
756         break;
757
758     case 0x4c:  /* RFBI_CMD */
759         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
760             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
761         if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
762             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
763         break;
764     case 0x50:  /* RFBI_PARAM */
765         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
766             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
767         if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
768             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
769         break;
770     case 0x54:  /* RFBI_DATA */
771         /* TODO: take into account the format set up in s->rfbi.config[?] and
772          * s->rfbi.data[?], but special-case the most usual scenario so that
773          * speed doesn't suffer.  */
774         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
775             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
776             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
777         }
778         if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
779             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
780             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
781         }
782         if (!-- s->rfbi.pixels)
783             omap_rfbi_transfer_stop(s);
784         break;
785     case 0x58:  /* RFBI_READ */
786         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
787             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
788         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
789             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
790         if (!-- s->rfbi.pixels)
791             omap_rfbi_transfer_stop(s);
792         break;
793
794     case 0x5c:  /* RFBI_STATUS */
795         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
796             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
797         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
798             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
799         if (!-- s->rfbi.pixels)
800             omap_rfbi_transfer_stop(s);
801         break;
802
803     case 0x60:  /* RFBI_CONFIG0 */
804         s->rfbi.config[0] = value & 0x003f1fff;
805         break;
806
807     case 0x64:  /* RFBI_ONOFF_TIME0 */
808         s->rfbi.time[0] = value & 0x3fffffff;
809         break;
810     case 0x68:  /* RFBI_CYCLE_TIME0 */
811         s->rfbi.time[1] = value & 0x0fffffff;
812         break;
813     case 0x6c:  /* RFBI_DATA_CYCLE1_0 */
814         s->rfbi.data[0] = value & 0x0f1f0f1f;
815         break;
816     case 0x70:  /* RFBI_DATA_CYCLE2_0 */
817         s->rfbi.data[1] = value & 0x0f1f0f1f;
818         break;
819     case 0x74:  /* RFBI_DATA_CYCLE3_0 */
820         s->rfbi.data[2] = value & 0x0f1f0f1f;
821         break;
822     case 0x78:  /* RFBI_CONFIG1 */
823         s->rfbi.config[1] = value & 0x003f1fff;
824         break;
825
826     case 0x7c:  /* RFBI_ONOFF_TIME1 */
827         s->rfbi.time[2] = value & 0x3fffffff;
828         break;
829     case 0x80:  /* RFBI_CYCLE_TIME1 */
830         s->rfbi.time[3] = value & 0x0fffffff;
831         break;
832     case 0x84:  /* RFBI_DATA_CYCLE1_1 */
833         s->rfbi.data[3] = value & 0x0f1f0f1f;
834         break;
835     case 0x88:  /* RFBI_DATA_CYCLE2_1 */
836         s->rfbi.data[4] = value & 0x0f1f0f1f;
837         break;
838     case 0x8c:  /* RFBI_DATA_CYCLE3_1 */
839         s->rfbi.data[5] = value & 0x0f1f0f1f;
840         break;
841
842     case 0x90:  /* RFBI_VSYNC_WIDTH */
843         s->rfbi.vsync = value & 0xffff;
844         break;
845     case 0x94:  /* RFBI_HSYNC_WIDTH */
846         s->rfbi.hsync = value & 0xffff;
847         break;
848
849     default:
850         OMAP_BAD_REG(addr);
851     }
852 }
853
854 static CPUReadMemoryFunc *omap_rfbi1_readfn[] = {
855     omap_badwidth_read32,
856     omap_badwidth_read32,
857     omap_rfbi_read,
858 };
859
860 static CPUWriteMemoryFunc *omap_rfbi1_writefn[] = {
861     omap_badwidth_write32,
862     omap_badwidth_write32,
863     omap_rfbi_write,
864 };
865
866 static uint32_t omap_venc_read(void *opaque, target_phys_addr_t addr)
867 {
868     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
869     int offset = addr - s->venc_base;
870
871     switch (offset) {
872     case 0x00:  /* REV_ID */
873     case 0x04:  /* STATUS */
874     case 0x08:  /* F_CONTROL */
875     case 0x10:  /* VIDOUT_CTRL */
876     case 0x14:  /* SYNC_CTRL */
877     case 0x1c:  /* LLEN */
878     case 0x20:  /* FLENS */
879     case 0x24:  /* HFLTR_CTRL */
880     case 0x28:  /* CC_CARR_WSS_CARR */
881     case 0x2c:  /* C_PHASE */
882     case 0x30:  /* GAIN_U */
883     case 0x34:  /* GAIN_V */
884     case 0x38:  /* GAIN_Y */
885     case 0x3c:  /* BLACK_LEVEL */
886     case 0x40:  /* BLANK_LEVEL */
887     case 0x44:  /* X_COLOR */
888     case 0x48:  /* M_CONTROL */
889     case 0x4c:  /* BSTAMP_WSS_DATA */
890     case 0x50:  /* S_CARR */
891     case 0x54:  /* LINE21 */
892     case 0x58:  /* LN_SEL */
893     case 0x5c:  /* L21__WC_CTL */
894     case 0x60:  /* HTRIGGER_VTRIGGER */
895     case 0x64:  /* SAVID__EAVID */
896     case 0x68:  /* FLEN__FAL */
897     case 0x6c:  /* LAL__PHASE_RESET */
898     case 0x70:  /* HS_INT_START_STOP_X */
899     case 0x74:  /* HS_EXT_START_STOP_X */
900     case 0x78:  /* VS_INT_START_X */
901     case 0x7c:  /* VS_INT_STOP_X__VS_INT_START_Y */
902     case 0x80:  /* VS_INT_STOP_Y__VS_INT_START_X */
903     case 0x84:  /* VS_EXT_STOP_X__VS_EXT_START_Y */
904     case 0x88:  /* VS_EXT_STOP_Y */
905     case 0x90:  /* AVID_START_STOP_X */
906     case 0x94:  /* AVID_START_STOP_Y */
907     case 0xa0:  /* FID_INT_START_X__FID_INT_START_Y */
908     case 0xa4:  /* FID_INT_OFFSET_Y__FID_EXT_START_X */
909     case 0xa8:  /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
910     case 0xb0:  /* TVDETGP_INT_START_STOP_X */
911     case 0xb4:  /* TVDETGP_INT_START_STOP_Y */
912     case 0xb8:  /* GEN_CTRL */
913     case 0xc4:  /* DAC_TST__DAC_A */
914     case 0xc8:  /* DAC_B__DAC_C */
915         return 0;
916
917     default:
918         break;
919     }
920     OMAP_BAD_REG(addr);
921     return 0;
922 }
923
924 static void omap_venc_write(void *opaque, target_phys_addr_t addr,
925                 uint32_t value)
926 {
927     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
928     int offset = addr - s->venc_base;
929
930     switch (offset) {
931     case 0x08:  /* F_CONTROL */
932     case 0x10:  /* VIDOUT_CTRL */
933     case 0x14:  /* SYNC_CTRL */
934     case 0x1c:  /* LLEN */
935     case 0x20:  /* FLENS */
936     case 0x24:  /* HFLTR_CTRL */
937     case 0x28:  /* CC_CARR_WSS_CARR */
938     case 0x2c:  /* C_PHASE */
939     case 0x30:  /* GAIN_U */
940     case 0x34:  /* GAIN_V */
941     case 0x38:  /* GAIN_Y */
942     case 0x3c:  /* BLACK_LEVEL */
943     case 0x40:  /* BLANK_LEVEL */
944     case 0x44:  /* X_COLOR */
945     case 0x48:  /* M_CONTROL */
946     case 0x4c:  /* BSTAMP_WSS_DATA */
947     case 0x50:  /* S_CARR */
948     case 0x54:  /* LINE21 */
949     case 0x58:  /* LN_SEL */
950     case 0x5c:  /* L21__WC_CTL */
951     case 0x60:  /* HTRIGGER_VTRIGGER */
952     case 0x64:  /* SAVID__EAVID */
953     case 0x68:  /* FLEN__FAL */
954     case 0x6c:  /* LAL__PHASE_RESET */
955     case 0x70:  /* HS_INT_START_STOP_X */
956     case 0x74:  /* HS_EXT_START_STOP_X */
957     case 0x78:  /* VS_INT_START_X */
958     case 0x7c:  /* VS_INT_STOP_X__VS_INT_START_Y */
959     case 0x80:  /* VS_INT_STOP_Y__VS_INT_START_X */
960     case 0x84:  /* VS_EXT_STOP_X__VS_EXT_START_Y */
961     case 0x88:  /* VS_EXT_STOP_Y */
962     case 0x90:  /* AVID_START_STOP_X */
963     case 0x94:  /* AVID_START_STOP_Y */
964     case 0xa0:  /* FID_INT_START_X__FID_INT_START_Y */
965     case 0xa4:  /* FID_INT_OFFSET_Y__FID_EXT_START_X */
966     case 0xa8:  /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
967     case 0xb0:  /* TVDETGP_INT_START_STOP_X */
968     case 0xb4:  /* TVDETGP_INT_START_STOP_Y */
969     case 0xb8:  /* GEN_CTRL */
970     case 0xc4:  /* DAC_TST__DAC_A */
971     case 0xc8:  /* DAC_B__DAC_C */
972         break;
973
974     default:
975         OMAP_BAD_REG(addr);
976     }
977 }
978
979 static CPUReadMemoryFunc *omap_venc1_readfn[] = {
980     omap_badwidth_read32,
981     omap_badwidth_read32,
982     omap_venc_read,
983 };
984
985 static CPUWriteMemoryFunc *omap_venc1_writefn[] = {
986     omap_badwidth_write32,
987     omap_badwidth_write32,
988     omap_venc_write,
989 };
990
991 static uint32_t omap_im3_read(void *opaque, target_phys_addr_t addr)
992 {
993     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
994     int offset = addr - s->im3_base;
995
996     switch (offset) {
997     case 0x0a8: /* SBIMERRLOGA */
998     case 0x0b0: /* SBIMERRLOG */
999     case 0x190: /* SBIMSTATE */
1000     case 0x198: /* SBTMSTATE_L */
1001     case 0x19c: /* SBTMSTATE_H */
1002     case 0x1a8: /* SBIMCONFIG_L */
1003     case 0x1ac: /* SBIMCONFIG_H */
1004     case 0x1f8: /* SBID_L */
1005     case 0x1fc: /* SBID_H */
1006         return 0;
1007
1008     default:
1009         break;
1010     }
1011     OMAP_BAD_REG(addr);
1012     return 0;
1013 }
1014
1015 static void omap_im3_write(void *opaque, target_phys_addr_t addr,
1016                 uint32_t value)
1017 {
1018     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
1019     int offset = addr - s->im3_base;
1020
1021     switch (offset) {
1022     case 0x0b0: /* SBIMERRLOG */
1023     case 0x190: /* SBIMSTATE */
1024     case 0x198: /* SBTMSTATE_L */
1025     case 0x19c: /* SBTMSTATE_H */
1026     case 0x1a8: /* SBIMCONFIG_L */
1027     case 0x1ac: /* SBIMCONFIG_H */
1028         break;
1029
1030     default:
1031         OMAP_BAD_REG(addr);
1032     }
1033 }
1034
1035 static CPUReadMemoryFunc *omap_im3_readfn[] = {
1036     omap_badwidth_read32,
1037     omap_badwidth_read32,
1038     omap_im3_read,
1039 };
1040
1041 static CPUWriteMemoryFunc *omap_im3_writefn[] = {
1042     omap_badwidth_write32,
1043     omap_badwidth_write32,
1044     omap_im3_write,
1045 };
1046
1047 struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
1048                 target_phys_addr_t l3_base, DisplayState *ds,
1049                 qemu_irq irq, qemu_irq drq,
1050                 omap_clk fck1, omap_clk fck2, omap_clk ck54m,
1051                 omap_clk ick1, omap_clk ick2)
1052 {
1053     int iomemtype[5];
1054     struct omap_dss_s *s = (struct omap_dss_s *)
1055             qemu_mallocz(sizeof(struct omap_dss_s));
1056
1057     s->irq = irq;
1058     s->drq = drq;
1059     s->state = ds;
1060     omap_dss_reset(s);
1061
1062     iomemtype[0] = cpu_register_io_memory(0, omap_diss1_readfn,
1063                     omap_diss1_writefn, s);
1064     iomemtype[1] = cpu_register_io_memory(0, omap_disc1_readfn,
1065                     omap_disc1_writefn, s);
1066     iomemtype[2] = cpu_register_io_memory(0, omap_rfbi1_readfn,
1067                     omap_rfbi1_writefn, s);
1068     iomemtype[3] = cpu_register_io_memory(0, omap_venc1_readfn,
1069                     omap_venc1_writefn, s);
1070     iomemtype[4] = cpu_register_io_memory(0, omap_im3_readfn,
1071                     omap_im3_writefn, s);
1072     s->diss_base = omap_l4_attach(ta, 0, iomemtype[0]);
1073     s->disc_base = omap_l4_attach(ta, 1, iomemtype[1]);
1074     s->rfbi_base = omap_l4_attach(ta, 2, iomemtype[2]);
1075     s->venc_base = omap_l4_attach(ta, 3, iomemtype[3]);
1076     s->im3_base = l3_base;
1077     cpu_register_physical_memory(s->im3_base, 0x1000, iomemtype[4]);
1078
1079 #if 0
1080     if (ds)
1081         graphic_console_init(ds, omap_update_display,
1082                         omap_invalidate_display, omap_screen_dump, s);
1083 #endif
1084
1085     return s;
1086 }
1087
1088 void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
1089 {
1090     if (cs < 0 || cs > 1)
1091         cpu_abort(cpu_single_env, "%s: wrong CS %i\n", __FUNCTION__, cs);
1092     s->rfbi.chip[cs] = chip;
1093 }