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