xref: /openbmc/qemu/hw/display/omap_dss.c (revision 2993683b)
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         return omap_badwidth_write32(opaque, addr, value);
216     }
217 
218     switch (addr) {
219     case 0x00:	/* DSS_REVISIONNUMBER */
220     case 0x14:	/* DSS_SYSSTATUS */
221     case 0x50:	/* DSS_PSA_LCD_REG_1 */
222     case 0x54:	/* DSS_PSA_LCD_REG_2 */
223     case 0x58:	/* DSS_PSA_VIDEO_REG */
224     case 0x5c:	/* DSS_STATUS */
225         OMAP_RO_REG(addr);
226         break;
227 
228     case 0x10:	/* DSS_SYSCONFIG */
229         if (value & 2)						/* SOFTRESET */
230             omap_dss_reset(s);
231         s->autoidle = value & 1;
232         break;
233 
234     case 0x40:	/* DSS_CONTROL */
235         s->control = value & 0x3dd;
236         break;
237 
238     default:
239         OMAP_BAD_REG(addr);
240     }
241 }
242 
243 static const MemoryRegionOps omap_diss_ops = {
244     .read = omap_diss_read,
245     .write = omap_diss_write,
246     .endianness = DEVICE_NATIVE_ENDIAN,
247 };
248 
249 static uint64_t omap_disc_read(void *opaque, hwaddr addr,
250                                unsigned size)
251 {
252     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
253 
254     if (size != 4) {
255         return omap_badwidth_read32(opaque, addr);
256     }
257 
258     switch (addr) {
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, hwaddr addr,
375                             uint64_t value, unsigned size)
376 {
377     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
378 
379     if (size != 4) {
380         return omap_badwidth_write32(opaque, addr, value);
381     }
382 
383     switch (addr) {
384     case 0x010:	/* DISPC_SYSCONFIG */
385         if (value & 2)						/* SOFTRESET */
386             omap_dss_reset(s);
387         s->dispc.idlemode = value & 0x301b;
388         break;
389 
390     case 0x018:	/* DISPC_IRQSTATUS */
391         s->dispc.irqst &= ~value;
392         omap_dispc_interrupt_update(s);
393         break;
394 
395     case 0x01c:	/* DISPC_IRQENABLE */
396         s->dispc.irqen = value & 0xffff;
397         omap_dispc_interrupt_update(s);
398         break;
399 
400     case 0x040:	/* DISPC_CONTROL */
401         s->dispc.control = value & 0x07ff9fff;
402         s->dig.enable = (value >> 1) & 1;
403         s->lcd.enable = (value >> 0) & 1;
404         if (value & (1 << 12))			/* OVERLAY_OPTIMIZATION */
405             if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
406                 fprintf(stderr, "%s: Overlay Optimization when no overlay "
407                         "region effectively exists leads to "
408                         "unpredictable behaviour!\n", __func__);
409             }
410         if (value & (1 << 6)) {				/* GODIGITAL */
411             /* XXX: Shadowed fields are:
412              * s->dispc.config
413              * s->dispc.capable
414              * s->dispc.bg[0]
415              * s->dispc.bg[1]
416              * s->dispc.trans[0]
417              * s->dispc.trans[1]
418              * s->dispc.line
419              * s->dispc.timing[0]
420              * s->dispc.timing[1]
421              * s->dispc.timing[2]
422              * s->dispc.timing[3]
423              * s->lcd.nx
424              * s->lcd.ny
425              * s->dig.nx
426              * s->dig.ny
427              * s->dispc.l[0].addr[0]
428              * s->dispc.l[0].addr[1]
429              * s->dispc.l[0].addr[2]
430              * s->dispc.l[0].posx
431              * s->dispc.l[0].posy
432              * s->dispc.l[0].nx
433              * s->dispc.l[0].ny
434              * s->dispc.l[0].tresh
435              * s->dispc.l[0].rowinc
436              * s->dispc.l[0].colinc
437              * s->dispc.l[0].wininc
438              * All they need to be loaded here from their shadow registers.
439              */
440         }
441         if (value & (1 << 5)) {				/* GOLCD */
442              /* XXX: Likewise for LCD here.  */
443         }
444         s->dispc.invalidate = 1;
445         break;
446 
447     case 0x044:	/* DISPC_CONFIG */
448         s->dispc.config = value & 0x3fff;
449         /* XXX:
450          * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
451          * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
452          */
453         s->dispc.invalidate = 1;
454         break;
455 
456     case 0x048:	/* DISPC_CAPABLE */
457         s->dispc.capable = value & 0x3ff;
458         break;
459 
460     case 0x04c:	/* DISPC_DEFAULT_COLOR0 */
461         s->dispc.bg[0] = value & 0xffffff;
462         s->dispc.invalidate = 1;
463         break;
464     case 0x050:	/* DISPC_DEFAULT_COLOR1 */
465         s->dispc.bg[1] = value & 0xffffff;
466         s->dispc.invalidate = 1;
467         break;
468     case 0x054:	/* DISPC_TRANS_COLOR0 */
469         s->dispc.trans[0] = value & 0xffffff;
470         s->dispc.invalidate = 1;
471         break;
472     case 0x058:	/* DISPC_TRANS_COLOR1 */
473         s->dispc.trans[1] = value & 0xffffff;
474         s->dispc.invalidate = 1;
475         break;
476 
477     case 0x060:	/* DISPC_LINE_NUMBER */
478         s->dispc.line = value & 0x7ff;
479         break;
480 
481     case 0x064:	/* DISPC_TIMING_H */
482         s->dispc.timing[0] = value & 0x0ff0ff3f;
483         break;
484     case 0x068:	/* DISPC_TIMING_V */
485         s->dispc.timing[1] = value & 0x0ff0ff3f;
486         break;
487     case 0x06c:	/* DISPC_POL_FREQ */
488         s->dispc.timing[2] = value & 0x0003ffff;
489         break;
490     case 0x070:	/* DISPC_DIVISOR */
491         s->dispc.timing[3] = value & 0x00ff00ff;
492         break;
493 
494     case 0x078:	/* DISPC_SIZE_DIG */
495         s->dig.nx = ((value >>  0) & 0x7ff) + 1;		/* PPL */
496         s->dig.ny = ((value >> 16) & 0x7ff) + 1;		/* LPP */
497         s->dispc.invalidate = 1;
498         break;
499     case 0x07c:	/* DISPC_SIZE_LCD */
500         s->lcd.nx = ((value >>  0) & 0x7ff) + 1;		/* PPL */
501         s->lcd.ny = ((value >> 16) & 0x7ff) + 1;		/* LPP */
502         s->dispc.invalidate = 1;
503         break;
504     case 0x080:	/* DISPC_GFX_BA0 */
505         s->dispc.l[0].addr[0] = (hwaddr) value;
506         s->dispc.invalidate = 1;
507         break;
508     case 0x084:	/* DISPC_GFX_BA1 */
509         s->dispc.l[0].addr[1] = (hwaddr) value;
510         s->dispc.invalidate = 1;
511         break;
512     case 0x088:	/* DISPC_GFX_POSITION */
513         s->dispc.l[0].posx = ((value >>  0) & 0x7ff);		/* GFXPOSX */
514         s->dispc.l[0].posy = ((value >> 16) & 0x7ff);		/* GFXPOSY */
515         s->dispc.invalidate = 1;
516         break;
517     case 0x08c:	/* DISPC_GFX_SIZE */
518         s->dispc.l[0].nx = ((value >>  0) & 0x7ff) + 1;		/* GFXSIZEX */
519         s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1;		/* GFXSIZEY */
520         s->dispc.invalidate = 1;
521         break;
522     case 0x0a0:	/* DISPC_GFX_ATTRIBUTES */
523         s->dispc.l[0].attr = value & 0x7ff;
524         if (value & (3 << 9))
525             fprintf(stderr, "%s: Big-endian pixel format not supported\n",
526                             __FUNCTION__);
527         s->dispc.l[0].enable = value & 1;
528         s->dispc.l[0].bpp = (value >> 1) & 0xf;
529         s->dispc.invalidate = 1;
530         break;
531     case 0x0a4:	/* DISPC_GFX_FIFO_TRESHOLD */
532         s->dispc.l[0].tresh = value & 0x01ff01ff;
533         break;
534     case 0x0ac:	/* DISPC_GFX_ROW_INC */
535         s->dispc.l[0].rowinc = value;
536         s->dispc.invalidate = 1;
537         break;
538     case 0x0b0:	/* DISPC_GFX_PIXEL_INC */
539         s->dispc.l[0].colinc = value;
540         s->dispc.invalidate = 1;
541         break;
542     case 0x0b4:	/* DISPC_GFX_WINDOW_SKIP */
543         s->dispc.l[0].wininc = value;
544         break;
545     case 0x0b8:	/* DISPC_GFX_TABLE_BA */
546         s->dispc.l[0].addr[2] = (hwaddr) value;
547         s->dispc.invalidate = 1;
548         break;
549 
550     case 0x0bc:	/* DISPC_VID1_BA0 */
551     case 0x0c0:	/* DISPC_VID1_BA1 */
552     case 0x0c4:	/* DISPC_VID1_POSITION */
553     case 0x0c8:	/* DISPC_VID1_SIZE */
554     case 0x0cc:	/* DISPC_VID1_ATTRIBUTES */
555     case 0x0d0:	/* DISPC_VID1_FIFO_TRESHOLD */
556     case 0x0d8:	/* DISPC_VID1_ROW_INC */
557     case 0x0dc:	/* DISPC_VID1_PIXEL_INC */
558     case 0x0e0:	/* DISPC_VID1_FIR */
559     case 0x0e4:	/* DISPC_VID1_PICTURE_SIZE */
560     case 0x0e8:	/* DISPC_VID1_ACCU0 */
561     case 0x0ec:	/* DISPC_VID1_ACCU1 */
562     case 0x0f0 ... 0x140:	/* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
563     case 0x14c:	/* DISPC_VID2_BA0 */
564     case 0x150:	/* DISPC_VID2_BA1 */
565     case 0x154:	/* DISPC_VID2_POSITION */
566     case 0x158:	/* DISPC_VID2_SIZE */
567     case 0x15c:	/* DISPC_VID2_ATTRIBUTES */
568     case 0x160:	/* DISPC_VID2_FIFO_TRESHOLD */
569     case 0x168:	/* DISPC_VID2_ROW_INC */
570     case 0x16c:	/* DISPC_VID2_PIXEL_INC */
571     case 0x170:	/* DISPC_VID2_FIR */
572     case 0x174:	/* DISPC_VID2_PICTURE_SIZE */
573     case 0x178:	/* DISPC_VID2_ACCU0 */
574     case 0x17c:	/* DISPC_VID2_ACCU1 */
575     case 0x180 ... 0x1d0:	/* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
576     case 0x1d4:	/* DISPC_DATA_CYCLE1 */
577     case 0x1d8:	/* DISPC_DATA_CYCLE2 */
578     case 0x1dc:	/* DISPC_DATA_CYCLE3 */
579         break;
580 
581     default:
582         OMAP_BAD_REG(addr);
583     }
584 }
585 
586 static const MemoryRegionOps omap_disc_ops = {
587     .read = omap_disc_read,
588     .write = omap_disc_write,
589     .endianness = DEVICE_NATIVE_ENDIAN,
590 };
591 
592 static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
593 {
594     if (!s->rfbi.busy)
595         return;
596 
597     /* TODO: in non-Bypass mode we probably need to just deassert the DRQ.  */
598 
599     s->rfbi.busy = 0;
600 }
601 
602 static void omap_rfbi_transfer_start(struct omap_dss_s *s)
603 {
604     void *data;
605     hwaddr len;
606     hwaddr data_addr;
607     int pitch;
608     static void *bounce_buffer;
609     static hwaddr bounce_len;
610 
611     if (!s->rfbi.enable || s->rfbi.busy)
612         return;
613 
614     if (s->rfbi.control & (1 << 1)) {				/* BYPASS */
615         /* TODO: in non-Bypass mode we probably need to just assert the
616          * DRQ and wait for DMA to write the pixels.  */
617         fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
618         return;
619     }
620 
621     if (!(s->dispc.control & (1 << 11)))			/* RFBIMODE */
622         return;
623     /* TODO: check that LCD output is enabled in DISPC.  */
624 
625     s->rfbi.busy = 1;
626 
627     len = s->rfbi.pixels * 2;
628 
629     data_addr = s->dispc.l[0].addr[0];
630     data = cpu_physical_memory_map(data_addr, &len, 0);
631     if (data && len != s->rfbi.pixels * 2) {
632         cpu_physical_memory_unmap(data, len, 0, 0);
633         data = NULL;
634         len = s->rfbi.pixels * 2;
635     }
636     if (!data) {
637         if (len > bounce_len) {
638             bounce_buffer = g_realloc(bounce_buffer, len);
639         }
640         data = bounce_buffer;
641         cpu_physical_memory_read(data_addr, data, len);
642     }
643 
644     /* TODO bpp */
645     s->rfbi.pixels = 0;
646 
647     /* TODO: negative values */
648     pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
649 
650     if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
651         s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
652     if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
653         s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
654 
655     if (data != bounce_buffer) {
656         cpu_physical_memory_unmap(data, len, 0, len);
657     }
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 uint64_t omap_rfbi_read(void *opaque, hwaddr addr,
667                                unsigned size)
668 {
669     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
670 
671     if (size != 4) {
672         return omap_badwidth_read32(opaque, addr);
673     }
674 
675     switch (addr) {
676     case 0x00:	/* RFBI_REVISION */
677         return 0x10;
678 
679     case 0x10:	/* RFBI_SYSCONFIG */
680         return s->rfbi.idlemode;
681 
682     case 0x14:	/* RFBI_SYSSTATUS */
683         return 1 | (s->rfbi.busy << 8);				/* RESETDONE */
684 
685     case 0x40:	/* RFBI_CONTROL */
686         return s->rfbi.control;
687 
688     case 0x44:	/* RFBI_PIXELCNT */
689         return s->rfbi.pixels;
690 
691     case 0x48:	/* RFBI_LINE_NUMBER */
692         return s->rfbi.skiplines;
693 
694     case 0x58:	/* RFBI_READ */
695     case 0x5c:	/* RFBI_STATUS */
696         return s->rfbi.rxbuf;
697 
698     case 0x60:	/* RFBI_CONFIG0 */
699         return s->rfbi.config[0];
700     case 0x64:	/* RFBI_ONOFF_TIME0 */
701         return s->rfbi.time[0];
702     case 0x68:	/* RFBI_CYCLE_TIME0 */
703         return s->rfbi.time[1];
704     case 0x6c:	/* RFBI_DATA_CYCLE1_0 */
705         return s->rfbi.data[0];
706     case 0x70:	/* RFBI_DATA_CYCLE2_0 */
707         return s->rfbi.data[1];
708     case 0x74:	/* RFBI_DATA_CYCLE3_0 */
709         return s->rfbi.data[2];
710 
711     case 0x78:	/* RFBI_CONFIG1 */
712         return s->rfbi.config[1];
713     case 0x7c:	/* RFBI_ONOFF_TIME1 */
714         return s->rfbi.time[2];
715     case 0x80:	/* RFBI_CYCLE_TIME1 */
716         return s->rfbi.time[3];
717     case 0x84:	/* RFBI_DATA_CYCLE1_1 */
718         return s->rfbi.data[3];
719     case 0x88:	/* RFBI_DATA_CYCLE2_1 */
720         return s->rfbi.data[4];
721     case 0x8c:	/* RFBI_DATA_CYCLE3_1 */
722         return s->rfbi.data[5];
723 
724     case 0x90:	/* RFBI_VSYNC_WIDTH */
725         return s->rfbi.vsync;
726     case 0x94:	/* RFBI_HSYNC_WIDTH */
727         return s->rfbi.hsync;
728     }
729     OMAP_BAD_REG(addr);
730     return 0;
731 }
732 
733 static void omap_rfbi_write(void *opaque, hwaddr addr,
734                             uint64_t value, unsigned size)
735 {
736     struct omap_dss_s *s = (struct omap_dss_s *) opaque;
737 
738     if (size != 4) {
739         return omap_badwidth_write32(opaque, addr, value);
740     }
741 
742     switch (addr) {
743     case 0x10:	/* RFBI_SYSCONFIG */
744         if (value & 2)						/* SOFTRESET */
745             omap_rfbi_reset(s);
746         s->rfbi.idlemode = value & 0x19;
747         break;
748 
749     case 0x40:	/* RFBI_CONTROL */
750         s->rfbi.control = value & 0xf;
751         s->rfbi.enable = value & 1;
752         if (value & (1 << 4) &&					/* ITE */
753                         !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
754             omap_rfbi_transfer_start(s);
755         break;
756 
757     case 0x44:	/* RFBI_PIXELCNT */
758         s->rfbi.pixels = value;
759         break;
760 
761     case 0x48:	/* RFBI_LINE_NUMBER */
762         s->rfbi.skiplines = value & 0x7ff;
763         break;
764 
765     case 0x4c:	/* RFBI_CMD */
766         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
767             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
768         if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
769             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
770         break;
771     case 0x50:	/* RFBI_PARAM */
772         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
773             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
774         if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
775             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
776         break;
777     case 0x54:	/* RFBI_DATA */
778         /* TODO: take into account the format set up in s->rfbi.config[?] and
779          * s->rfbi.data[?], but special-case the most usual scenario so that
780          * speed doesn't suffer.  */
781         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
782             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
783             s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
784         }
785         if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
786             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
787             s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
788         }
789         if (!-- s->rfbi.pixels)
790             omap_rfbi_transfer_stop(s);
791         break;
792     case 0x58:	/* RFBI_READ */
793         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
794             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
795         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
796             s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 1);
797         if (!-- s->rfbi.pixels)
798             omap_rfbi_transfer_stop(s);
799         break;
800 
801     case 0x5c:	/* RFBI_STATUS */
802         if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
803             s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
804         else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
805             s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 0);
806         if (!-- s->rfbi.pixels)
807             omap_rfbi_transfer_stop(s);
808         break;
809 
810     case 0x60:	/* RFBI_CONFIG0 */
811         s->rfbi.config[0] = value & 0x003f1fff;
812         break;
813 
814     case 0x64:	/* RFBI_ONOFF_TIME0 */
815         s->rfbi.time[0] = value & 0x3fffffff;
816         break;
817     case 0x68:	/* RFBI_CYCLE_TIME0 */
818         s->rfbi.time[1] = value & 0x0fffffff;
819         break;
820     case 0x6c:	/* RFBI_DATA_CYCLE1_0 */
821         s->rfbi.data[0] = value & 0x0f1f0f1f;
822         break;
823     case 0x70:	/* RFBI_DATA_CYCLE2_0 */
824         s->rfbi.data[1] = value & 0x0f1f0f1f;
825         break;
826     case 0x74:	/* RFBI_DATA_CYCLE3_0 */
827         s->rfbi.data[2] = value & 0x0f1f0f1f;
828         break;
829     case 0x78:	/* RFBI_CONFIG1 */
830         s->rfbi.config[1] = value & 0x003f1fff;
831         break;
832 
833     case 0x7c:	/* RFBI_ONOFF_TIME1 */
834         s->rfbi.time[2] = value & 0x3fffffff;
835         break;
836     case 0x80:	/* RFBI_CYCLE_TIME1 */
837         s->rfbi.time[3] = value & 0x0fffffff;
838         break;
839     case 0x84:	/* RFBI_DATA_CYCLE1_1 */
840         s->rfbi.data[3] = value & 0x0f1f0f1f;
841         break;
842     case 0x88:	/* RFBI_DATA_CYCLE2_1 */
843         s->rfbi.data[4] = value & 0x0f1f0f1f;
844         break;
845     case 0x8c:	/* RFBI_DATA_CYCLE3_1 */
846         s->rfbi.data[5] = value & 0x0f1f0f1f;
847         break;
848 
849     case 0x90:	/* RFBI_VSYNC_WIDTH */
850         s->rfbi.vsync = value & 0xffff;
851         break;
852     case 0x94:	/* RFBI_HSYNC_WIDTH */
853         s->rfbi.hsync = value & 0xffff;
854         break;
855 
856     default:
857         OMAP_BAD_REG(addr);
858     }
859 }
860 
861 static const MemoryRegionOps omap_rfbi_ops = {
862     .read = omap_rfbi_read,
863     .write = omap_rfbi_write,
864     .endianness = DEVICE_NATIVE_ENDIAN,
865 };
866 
867 static uint64_t omap_venc_read(void *opaque, hwaddr addr,
868                                unsigned size)
869 {
870     if (size != 4) {
871         return omap_badwidth_read32(opaque, addr);
872     }
873 
874     switch (addr) {
875     case 0x00:	/* REV_ID */
876     case 0x04:	/* STATUS */
877     case 0x08:	/* F_CONTROL */
878     case 0x10:	/* VIDOUT_CTRL */
879     case 0x14:	/* SYNC_CTRL */
880     case 0x1c:	/* LLEN */
881     case 0x20:	/* FLENS */
882     case 0x24:	/* HFLTR_CTRL */
883     case 0x28:	/* CC_CARR_WSS_CARR */
884     case 0x2c:	/* C_PHASE */
885     case 0x30:	/* GAIN_U */
886     case 0x34:	/* GAIN_V */
887     case 0x38:	/* GAIN_Y */
888     case 0x3c:	/* BLACK_LEVEL */
889     case 0x40:	/* BLANK_LEVEL */
890     case 0x44:	/* X_COLOR */
891     case 0x48:	/* M_CONTROL */
892     case 0x4c:	/* BSTAMP_WSS_DATA */
893     case 0x50:	/* S_CARR */
894     case 0x54:	/* LINE21 */
895     case 0x58:	/* LN_SEL */
896     case 0x5c:	/* L21__WC_CTL */
897     case 0x60:	/* HTRIGGER_VTRIGGER */
898     case 0x64:	/* SAVID__EAVID */
899     case 0x68:	/* FLEN__FAL */
900     case 0x6c:	/* LAL__PHASE_RESET */
901     case 0x70:	/* HS_INT_START_STOP_X */
902     case 0x74:	/* HS_EXT_START_STOP_X */
903     case 0x78:	/* VS_INT_START_X */
904     case 0x7c:	/* VS_INT_STOP_X__VS_INT_START_Y */
905     case 0x80:	/* VS_INT_STOP_Y__VS_INT_START_X */
906     case 0x84:	/* VS_EXT_STOP_X__VS_EXT_START_Y */
907     case 0x88:	/* VS_EXT_STOP_Y */
908     case 0x90:	/* AVID_START_STOP_X */
909     case 0x94:	/* AVID_START_STOP_Y */
910     case 0xa0:	/* FID_INT_START_X__FID_INT_START_Y */
911     case 0xa4:	/* FID_INT_OFFSET_Y__FID_EXT_START_X */
912     case 0xa8:	/* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
913     case 0xb0:	/* TVDETGP_INT_START_STOP_X */
914     case 0xb4:	/* TVDETGP_INT_START_STOP_Y */
915     case 0xb8:	/* GEN_CTRL */
916     case 0xc4:	/* DAC_TST__DAC_A */
917     case 0xc8:	/* DAC_B__DAC_C */
918         return 0;
919 
920     default:
921         break;
922     }
923     OMAP_BAD_REG(addr);
924     return 0;
925 }
926 
927 static void omap_venc_write(void *opaque, hwaddr addr,
928                             uint64_t value, unsigned size)
929 {
930     if (size != 4) {
931         return omap_badwidth_write32(opaque, addr, size);
932     }
933 
934     switch (addr) {
935     case 0x08:	/* F_CONTROL */
936     case 0x10:	/* VIDOUT_CTRL */
937     case 0x14:	/* SYNC_CTRL */
938     case 0x1c:	/* LLEN */
939     case 0x20:	/* FLENS */
940     case 0x24:	/* HFLTR_CTRL */
941     case 0x28:	/* CC_CARR_WSS_CARR */
942     case 0x2c:	/* C_PHASE */
943     case 0x30:	/* GAIN_U */
944     case 0x34:	/* GAIN_V */
945     case 0x38:	/* GAIN_Y */
946     case 0x3c:	/* BLACK_LEVEL */
947     case 0x40:	/* BLANK_LEVEL */
948     case 0x44:	/* X_COLOR */
949     case 0x48:	/* M_CONTROL */
950     case 0x4c:	/* BSTAMP_WSS_DATA */
951     case 0x50:	/* S_CARR */
952     case 0x54:	/* LINE21 */
953     case 0x58:	/* LN_SEL */
954     case 0x5c:	/* L21__WC_CTL */
955     case 0x60:	/* HTRIGGER_VTRIGGER */
956     case 0x64:	/* SAVID__EAVID */
957     case 0x68:	/* FLEN__FAL */
958     case 0x6c:	/* LAL__PHASE_RESET */
959     case 0x70:	/* HS_INT_START_STOP_X */
960     case 0x74:	/* HS_EXT_START_STOP_X */
961     case 0x78:	/* VS_INT_START_X */
962     case 0x7c:	/* VS_INT_STOP_X__VS_INT_START_Y */
963     case 0x80:	/* VS_INT_STOP_Y__VS_INT_START_X */
964     case 0x84:	/* VS_EXT_STOP_X__VS_EXT_START_Y */
965     case 0x88:	/* VS_EXT_STOP_Y */
966     case 0x90:	/* AVID_START_STOP_X */
967     case 0x94:	/* AVID_START_STOP_Y */
968     case 0xa0:	/* FID_INT_START_X__FID_INT_START_Y */
969     case 0xa4:	/* FID_INT_OFFSET_Y__FID_EXT_START_X */
970     case 0xa8:	/* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
971     case 0xb0:	/* TVDETGP_INT_START_STOP_X */
972     case 0xb4:	/* TVDETGP_INT_START_STOP_Y */
973     case 0xb8:	/* GEN_CTRL */
974     case 0xc4:	/* DAC_TST__DAC_A */
975     case 0xc8:	/* DAC_B__DAC_C */
976         break;
977 
978     default:
979         OMAP_BAD_REG(addr);
980     }
981 }
982 
983 static const MemoryRegionOps omap_venc_ops = {
984     .read = omap_venc_read,
985     .write = omap_venc_write,
986     .endianness = DEVICE_NATIVE_ENDIAN,
987 };
988 
989 static uint64_t omap_im3_read(void *opaque, hwaddr addr,
990                               unsigned size)
991 {
992     if (size != 4) {
993         return omap_badwidth_read32(opaque, addr);
994     }
995 
996     switch (addr) {
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, hwaddr addr,
1016                            uint64_t value, unsigned size)
1017 {
1018     if (size != 4) {
1019         return omap_badwidth_write32(opaque, addr, value);
1020     }
1021 
1022     switch (addr) {
1023     case 0x0b0:	/* SBIMERRLOG */
1024     case 0x190:	/* SBIMSTATE */
1025     case 0x198:	/* SBTMSTATE_L */
1026     case 0x19c:	/* SBTMSTATE_H */
1027     case 0x1a8:	/* SBIMCONFIG_L */
1028     case 0x1ac:	/* SBIMCONFIG_H */
1029         break;
1030 
1031     default:
1032         OMAP_BAD_REG(addr);
1033     }
1034 }
1035 
1036 static const MemoryRegionOps omap_im3_ops = {
1037     .read = omap_im3_read,
1038     .write = omap_im3_write,
1039     .endianness = DEVICE_NATIVE_ENDIAN,
1040 };
1041 
1042 struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
1043                 MemoryRegion *sysmem,
1044                 hwaddr l3_base,
1045                 qemu_irq irq, qemu_irq drq,
1046                 omap_clk fck1, omap_clk fck2, omap_clk ck54m,
1047                 omap_clk ick1, omap_clk ick2)
1048 {
1049     struct omap_dss_s *s = (struct omap_dss_s *)
1050             g_malloc0(sizeof(struct omap_dss_s));
1051 
1052     s->irq = irq;
1053     s->drq = drq;
1054     omap_dss_reset(s);
1055 
1056     memory_region_init_io(&s->iomem_diss1, &omap_diss_ops, s, "omap.diss1",
1057                           omap_l4_region_size(ta, 0));
1058     memory_region_init_io(&s->iomem_disc1, &omap_disc_ops, s, "omap.disc1",
1059                           omap_l4_region_size(ta, 1));
1060     memory_region_init_io(&s->iomem_rfbi1, &omap_rfbi_ops, s, "omap.rfbi1",
1061                           omap_l4_region_size(ta, 2));
1062     memory_region_init_io(&s->iomem_venc1, &omap_venc_ops, s, "omap.venc1",
1063                           omap_l4_region_size(ta, 3));
1064     memory_region_init_io(&s->iomem_im3, &omap_im3_ops, s,
1065                           "omap.im3", 0x1000);
1066 
1067     omap_l4_attach(ta, 0, &s->iomem_diss1);
1068     omap_l4_attach(ta, 1, &s->iomem_disc1);
1069     omap_l4_attach(ta, 2, &s->iomem_rfbi1);
1070     omap_l4_attach(ta, 3, &s->iomem_venc1);
1071     memory_region_add_subregion(sysmem, l3_base, &s->iomem_im3);
1072 
1073 #if 0
1074     s->state = graphic_console_init(omap_update_display,
1075                                     omap_invalidate_display, omap_screen_dump, s);
1076 #endif
1077 
1078     return s;
1079 }
1080 
1081 void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
1082 {
1083     if (cs < 0 || cs > 1)
1084         hw_error("%s: wrong CS %i\n", __FUNCTION__, cs);
1085     s->rfbi.chip[cs] = chip;
1086 }
1087