2 * OMAP2 Display Subsystem.
4 * Copyright (C) 2008 Nokia Corporation
5 * Written by Andrzej Zaborowski <andrew@openedhand.com>
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.
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.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "qemu-common.h"
28 #include "pixel_ops.h"
40 struct omap_dss_panel_s {
49 struct omap3_lcd_panel_s *omap_lcd_panel[2];
63 struct omap_dss_plane_s {
75 target_phys_addr_t addr[3];
85 uint16_t palette[256];
101 struct rfbi_chip_s *chip[2];
109 static void omap_dispc_interrupt_update(struct omap_dss_s *s)
111 qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
114 static void omap_rfbi_reset(struct omap_dss_s *s)
116 s->rfbi.idlemode = 0;
120 s->rfbi.skiplines = 0;
122 s->rfbi.config[0] = 0x00310000;
123 s->rfbi.config[1] = 0x00310000;
138 void omap_dss_reset(struct omap_dss_s *s)
153 s->dispc.idlemode = 0;
156 s->dispc.control = 0;
158 s->dispc.capable = 0x161;
159 s->dispc.timing[0] = 0;
160 s->dispc.timing[1] = 0;
161 s->dispc.timing[2] = 0;
162 s->dispc.timing[3] = 0;
166 s->dispc.trans[0] = 0;
167 s->dispc.trans[1] = 0;
169 s->dispc.l[0].enable = 0;
170 s->dispc.l[0].bpp = 0;
171 s->dispc.l[0].addr[0] = 0;
172 s->dispc.l[0].addr[1] = 0;
173 s->dispc.l[0].addr[2] = 0;
174 s->dispc.l[0].posx = 0;
175 s->dispc.l[0].posy = 0;
176 s->dispc.l[0].nx = 1;
177 s->dispc.l[0].ny = 1;
178 s->dispc.l[0].attr = 0;
179 s->dispc.l[0].tresh = 0;
180 s->dispc.l[0].rowinc = 1;
181 s->dispc.l[0].colinc = 1;
182 s->dispc.l[0].wininc = 0;
187 omap_dispc_interrupt_update(s);
190 static uint32_t omap_diss_read(void *opaque, target_phys_addr_t addr)
192 struct omap_dss_s *s = (struct omap_dss_s *) opaque;
195 case 0x00: /* DSS_REVISIONNUMBER */
198 case 0x10: /* DSS_SYSCONFIG */
201 case 0x14: /* DSS_SYSSTATUS */
202 return 1; /* RESETDONE */
204 case 0x18: /* DSS_IRQSTATUS */
205 return ((s->dispc.irqst & s->dispc.irqen) ? 0x1 : 0x0)
206 | ((s->dsi.irqst) ? 0x2 : 0x0);
208 case 0x40: /* DSS_CONTROL */
211 case 0x44: /* DSS_SDI_CONTROL */
212 return s->sdi_control;
214 case 0x50: /* DSS_PSA_LCD_REG_1 */
215 case 0x54: /* DSS_PSA_LCD_REG_2 */
216 case 0x58: /* DSS_PSA_VIDEO_REG */
217 /* TODO: fake some values when appropriate s->control bits are set */
220 case 0x5c: /* DSS_STATUS */
221 return 1 + (s->control & 1);
230 static void omap_diss_write(void *opaque, target_phys_addr_t addr,
233 struct omap_dss_s *s = (struct omap_dss_s *) opaque;
236 case 0x00: /* DSS_REVISIONNUMBER */
237 case 0x14: /* DSS_SYSSTATUS */
238 case 0x50: /* DSS_PSA_LCD_REG_1 */
239 case 0x54: /* DSS_PSA_LCD_REG_2 */
240 case 0x58: /* DSS_PSA_VIDEO_REG */
241 case 0x5c: /* DSS_STATUS */
242 OMAP_RO_REGV(addr, value);
245 case 0x10: /* DSS_SYSCONFIG */
246 if (value & 2) /* SOFTRESET */
248 s->autoidle = value & 1;
251 case 0x40: /* DSS_CONTROL */
252 s->control = value & 0x3dd;
255 case 0x44: /* DSS_SDI_CONTROL */
256 s->sdi_control = value & 0x000ff80f;
260 OMAP_BAD_REGV(addr, value);
265 static CPUReadMemoryFunc *omap_diss1_readfn[] = {
266 omap_badwidth_read32,
267 omap_badwidth_read32,
271 static CPUWriteMemoryFunc *omap_diss1_writefn[] = {
272 omap_badwidth_write32,
273 omap_badwidth_write32,
277 static uint32_t omap_disc_read(void *opaque, target_phys_addr_t addr)
279 struct omap_dss_s *s = (struct omap_dss_s *) opaque;
282 case 0x000: /* DISPC_REVISION */
283 return 0x20; // 0x30 in OMAP3
285 case 0x010: /* DISPC_SYSCONFIG */
286 return s->dispc.idlemode;
288 case 0x014: /* DISPC_SYSSTATUS */
289 return 1; /* RESETDONE */
291 case 0x018: /* DISPC_IRQSTATUS */
292 return s->dispc.irqst;
294 case 0x01c: /* DISPC_IRQENABLE */
295 return s->dispc.irqen;
297 case 0x040: /* DISPC_CONTROL */
298 return s->dispc.control;
300 case 0x044: /* DISPC_CONFIG */
301 return s->dispc.config;
303 case 0x048: /* DISPC_CAPABLE */
304 return s->dispc.capable;
306 case 0x04c: /* DISPC_DEFAULT_COLOR0 */
307 return s->dispc.bg[0];
308 case 0x050: /* DISPC_DEFAULT_COLOR1 */
309 return s->dispc.bg[1];
310 case 0x054: /* DISPC_TRANS_COLOR0 */
311 return s->dispc.trans[0];
312 case 0x058: /* DISPC_TRANS_COLOR1 */
313 return s->dispc.trans[1];
315 case 0x05c: /* DISPC_LINE_STATUS */
317 case 0x060: /* DISPC_LINE_NUMBER */
318 return s->dispc.line;
320 case 0x064: /* DISPC_TIMING_H */
321 return s->dispc.timing[0];
322 case 0x068: /* DISPC_TIMING_V */
323 return s->dispc.timing[1];
324 case 0x06c: /* DISPC_POL_FREQ */
325 return s->dispc.timing[2];
326 case 0x070: /* DISPC_DIVISOR */
327 return s->dispc.timing[3];
329 case 0x078: /* DISPC_SIZE_DIG */
330 return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
331 case 0x07c: /* DISPC_SIZE_LCD */
332 return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
334 case 0x080: /* DISPC_GFX_BA0 */
335 return s->dispc.l[0].addr[0];
336 case 0x084: /* DISPC_GFX_BA1 */
337 return s->dispc.l[0].addr[1];
338 case 0x088: /* DISPC_GFX_POSITION */
339 return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
340 case 0x08c: /* DISPC_GFX_SIZE */
341 return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
342 case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
343 return s->dispc.l[0].attr;
344 case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
345 return s->dispc.l[0].tresh;
346 case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */
348 case 0x0ac: /* DISPC_GFX_ROW_INC */
349 return s->dispc.l[0].rowinc;
350 case 0x0b0: /* DISPC_GFX_PIXEL_INC */
351 return s->dispc.l[0].colinc;
352 case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
353 return s->dispc.l[0].wininc;
354 case 0x0b8: /* DISPC_GFX_TABLE_BA */
355 return s->dispc.l[0].addr[2];
357 case 0x0bc: /* DISPC_VID1_BA0 */
358 case 0x0c0: /* DISPC_VID1_BA1 */
359 case 0x0c4: /* DISPC_VID1_POSITION */
360 case 0x0c8: /* DISPC_VID1_SIZE */
361 case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
362 case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
363 case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */
364 case 0x0d8: /* DISPC_VID1_ROW_INC */
365 case 0x0dc: /* DISPC_VID1_PIXEL_INC */
366 case 0x0e0: /* DISPC_VID1_FIR */
367 case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
368 case 0x0e8: /* DISPC_VID1_ACCU0 */
369 case 0x0ec: /* DISPC_VID1_ACCU1 */
370 case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
371 case 0x14c: /* DISPC_VID2_BA0 */
372 case 0x150: /* DISPC_VID2_BA1 */
373 case 0x154: /* DISPC_VID2_POSITION */
374 case 0x158: /* DISPC_VID2_SIZE */
375 case 0x15c: /* DISPC_VID2_ATTRIBUTES */
376 case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
377 case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */
378 case 0x168: /* DISPC_VID2_ROW_INC */
379 case 0x16c: /* DISPC_VID2_PIXEL_INC */
380 case 0x170: /* DISPC_VID2_FIR */
381 case 0x174: /* DISPC_VID2_PICTURE_SIZE */
382 case 0x178: /* DISPC_VID2_ACCU0 */
383 case 0x17c: /* DISPC_VID2_ACCU1 */
384 case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
385 case 0x1d4: /* DISPC_DATA_CYCLE1 */
386 case 0x1d8: /* DISPC_DATA_CYCLE2 */
387 case 0x1dc: /* DISPC_DATA_CYCLE3 */
397 static void omap_disc_write(void *opaque, target_phys_addr_t addr,
400 struct omap_dss_s *s = (struct omap_dss_s *) opaque;
403 case 0x000: /* DISPC_REVISION */
404 case 0x014: /* DISPC_SYSSTATUS */
405 case 0x05c: /* DISPC_LINE_STATUS */
406 case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */
407 OMAP_RO_REGV(addr, value);
410 case 0x010: /* DISPC_SYSCONFIG */
411 if (value & 2) /* SOFTRESET */
413 s->dispc.idlemode = value & 0x301b;
416 case 0x018: /* DISPC_IRQSTATUS */
417 s->dispc.irqst &= ~value;
418 omap_dispc_interrupt_update(s);
421 case 0x01c: /* DISPC_IRQENABLE */
422 s->dispc.irqen = value & 0xffff;
423 omap_dispc_interrupt_update(s);
426 case 0x040: /* DISPC_CONTROL */
427 s->dispc.control = value & 0x07ff9fff;
428 s->dig.enable = (value >> 1) & 1;
429 s->lcd.enable = (value >> 0) & 1;
430 s->lcd.active = (value >> 5) & 1;
431 if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */
432 if (~((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1))
433 fprintf(stderr, "%s: Overlay Optimization when no overlay "
434 "region effectively exists leads to "
435 "unpredictable behaviour!\n", __FUNCTION__);
436 if (value & (1 << 6)) { /* GODIGITAL */
437 /* XXX: Shadowed fields are:
453 * s->dispc.l[0].addr[0]
454 * s->dispc.l[0].addr[1]
455 * s->dispc.l[0].addr[2]
460 * s->dispc.l[0].tresh
461 * s->dispc.l[0].rowinc
462 * s->dispc.l[0].colinc
463 * s->dispc.l[0].wininc
464 * All they need to be loaded here from their shadow registers.
467 if (value & (1 << 5)) { /* GOLCD */
468 /* XXX: Likewise for LCD here. */
470 s->dispc.invalidate = 1;
473 case 0x044: /* DISPC_CONFIG */
474 s->dispc.config = value & 0x3fff;
476 * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
477 * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
479 s->dispc.invalidate = 1;
482 case 0x048: /* DISPC_CAPABLE */
483 s->dispc.capable = value & 0x3ff;
486 case 0x04c: /* DISPC_DEFAULT_COLOR0 */
487 s->dispc.bg[0] = value & 0xffffff;
488 s->dispc.invalidate = 1;
490 case 0x050: /* DISPC_DEFAULT_COLOR1 */
491 s->dispc.bg[1] = value & 0xffffff;
492 s->dispc.invalidate = 1;
494 case 0x054: /* DISPC_TRANS_COLOR0 */
495 s->dispc.trans[0] = value & 0xffffff;
496 s->dispc.invalidate = 1;
498 case 0x058: /* DISPC_TRANS_COLOR1 */
499 s->dispc.trans[1] = value & 0xffffff;
500 s->dispc.invalidate = 1;
503 case 0x060: /* DISPC_LINE_NUMBER */
504 s->dispc.line = value & 0x7ff;
507 case 0x064: /* DISPC_TIMING_H */
508 s->dispc.timing[0] = value & 0x0ff0ff3f;
510 case 0x068: /* DISPC_TIMING_V */
511 s->dispc.timing[1] = value & 0x0ff0ff3f;
513 case 0x06c: /* DISPC_POL_FREQ */
514 s->dispc.timing[2] = value & 0x0003ffff;
516 case 0x070: /* DISPC_DIVISOR */
517 s->dispc.timing[3] = value & 0x00ff00ff;
520 case 0x078: /* DISPC_SIZE_DIG */
521 s->dig.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
522 s->dig.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
523 s->dispc.invalidate = 1;
525 case 0x07c: /* DISPC_SIZE_LCD */
526 s->lcd.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
527 s->lcd.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
528 s->dispc.invalidate = 1;
530 case 0x080: /* DISPC_GFX_BA0 */
531 s->dispc.l[0].addr[0] = (target_phys_addr_t) value;
532 s->dispc.invalidate = 1;
534 case 0x084: /* DISPC_GFX_BA1 */
535 s->dispc.l[0].addr[1] = (target_phys_addr_t) value;
536 s->dispc.invalidate = 1;
538 case 0x088: /* DISPC_GFX_POSITION */
539 s->dispc.l[0].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */
540 s->dispc.l[0].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */
541 s->dispc.invalidate = 1;
543 case 0x08c: /* DISPC_GFX_SIZE */
544 s->dispc.l[0].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */
545 s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */
546 s->dispc.invalidate = 1;
548 case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
549 s->dispc.l[0].attr = value & 0xffff;
550 if (value & (3 << 9))
551 fprintf(stderr, "%s: Big-endian pixel format not supported\n",
553 s->dispc.l[0].enable = value & 1;
554 s->dispc.l[0].bpp = (value >> 1) & 0xf;
555 s->dispc.l[0].rotation_flag = (value >> 12) & 0x3;
556 s->dispc.l[0].gfx_format = (value >> 1) & 0xf;
557 s->dispc.l[0].gfx_channel = (value >> 8) & 0x1;
558 s->dispc.invalidate = 1;
560 case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
561 s->dispc.l[0].tresh = value & 0x01ff01ff;
563 case 0x0ac: /* DISPC_GFX_ROW_INC */
564 s->dispc.l[0].rowinc = value;
565 s->dispc.invalidate = 1;
567 case 0x0b0: /* DISPC_GFX_PIXEL_INC */
568 s->dispc.l[0].colinc = value;
569 s->dispc.invalidate = 1;
571 case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
572 s->dispc.l[0].wininc = value;
574 case 0x0b8: /* DISPC_GFX_TABLE_BA */
575 s->dispc.l[0].addr[2] = (target_phys_addr_t) value;
576 s->dispc.invalidate = 1;
579 case 0x0bc: /* DISPC_VID1_BA0 */
580 case 0x0c0: /* DISPC_VID1_BA1 */
581 case 0x0c4: /* DISPC_VID1_POSITION */
582 case 0x0c8: /* DISPC_VID1_SIZE */
583 case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
584 case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
585 case 0x0d8: /* DISPC_VID1_ROW_INC */
586 case 0x0dc: /* DISPC_VID1_PIXEL_INC */
587 case 0x0e0: /* DISPC_VID1_FIR */
588 case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
589 case 0x0e8: /* DISPC_VID1_ACCU0 */
590 case 0x0ec: /* DISPC_VID1_ACCU1 */
591 case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
592 case 0x14c: /* DISPC_VID2_BA0 */
593 case 0x150: /* DISPC_VID2_BA1 */
594 case 0x154: /* DISPC_VID2_POSITION */
595 case 0x158: /* DISPC_VID2_SIZE */
596 case 0x15c: /* DISPC_VID2_ATTRIBUTES */
597 case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
598 case 0x168: /* DISPC_VID2_ROW_INC */
599 case 0x16c: /* DISPC_VID2_PIXEL_INC */
600 case 0x170: /* DISPC_VID2_FIR */
601 case 0x174: /* DISPC_VID2_PICTURE_SIZE */
602 case 0x178: /* DISPC_VID2_ACCU0 */
603 case 0x17c: /* DISPC_VID2_ACCU1 */
604 case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
605 case 0x1d4: /* DISPC_DATA_CYCLE1 */
606 case 0x1d8: /* DISPC_DATA_CYCLE2 */
607 case 0x1dc: /* DISPC_DATA_CYCLE3 */
611 OMAP_BAD_REGV(addr, value);
616 static CPUReadMemoryFunc *omap_disc1_readfn[] = {
617 omap_badwidth_read32,
618 omap_badwidth_read32,
622 static CPUWriteMemoryFunc *omap_disc1_writefn[] = {
623 omap_badwidth_write32,
624 omap_badwidth_write32,
628 static void *omap_rfbi_get_buffer(struct omap_dss_s *s)
630 target_phys_addr_t fb;
634 fb = s->dispc.l[0].addr[0];
636 pd = cpu_get_physical_page_desc(fb);
637 if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
639 cpu_abort(cpu_single_env, "%s: framebuffer outside RAM!\n",
642 return phys_ram_base +
643 (pd & TARGET_PAGE_MASK) +
644 (fb & ~TARGET_PAGE_MASK);
647 static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
652 /* TODO: in non-Bypass mode we probably need to just deassert the DRQ. */
657 static void omap_rfbi_transfer_start(struct omap_dss_s *s)
663 if (!s->rfbi.enable || s->rfbi.busy)
666 if (s->rfbi.control & (1 << 1)) { /* BYPASS */
667 /* TODO: in non-Bypass mode we probably need to just assert the
668 * DRQ and wait for DMA to write the pixels. */
669 fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
673 if (!(s->dispc.control & (1 << 11))) /* RFBIMODE */
675 /* TODO: check that LCD output is enabled in DISPC. */
679 data = omap_rfbi_get_buffer(s);
682 len = s->rfbi.pixels * 2;
685 /* TODO: negative values */
686 pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
688 if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
689 s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
690 if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
691 s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
693 omap_rfbi_transfer_stop(s);
696 s->dispc.irqst |= 1; /* FRAMEDONE */
697 omap_dispc_interrupt_update(s);
700 static uint32_t omap_rfbi_read(void *opaque, target_phys_addr_t addr)
702 struct omap_dss_s *s = (struct omap_dss_s *) opaque;
705 case 0x00: /* RFBI_REVISION */
708 case 0x10: /* RFBI_SYSCONFIG */
709 return s->rfbi.idlemode;
711 case 0x14: /* RFBI_SYSSTATUS */
712 return 1 | (s->rfbi.busy << 8); /* RESETDONE */
714 case 0x40: /* RFBI_CONTROL */
715 return s->rfbi.control;
717 case 0x44: /* RFBI_PIXELCNT */
718 return s->rfbi.pixels;
720 case 0x48: /* RFBI_LINE_NUMBER */
721 return s->rfbi.skiplines;
723 case 0x58: /* RFBI_READ */
724 case 0x5c: /* RFBI_STATUS */
725 return s->rfbi.rxbuf;
727 case 0x60: /* RFBI_CONFIG0 */
728 return s->rfbi.config[0];
729 case 0x64: /* RFBI_ONOFF_TIME0 */
730 return s->rfbi.time[0];
731 case 0x68: /* RFBI_CYCLE_TIME0 */
732 return s->rfbi.time[1];
733 case 0x6c: /* RFBI_DATA_CYCLE1_0 */
734 return s->rfbi.data[0];
735 case 0x70: /* RFBI_DATA_CYCLE2_0 */
736 return s->rfbi.data[1];
737 case 0x74: /* RFBI_DATA_CYCLE3_0 */
738 return s->rfbi.data[2];
740 case 0x78: /* RFBI_CONFIG1 */
741 return s->rfbi.config[1];
742 case 0x7c: /* RFBI_ONOFF_TIME1 */
743 return s->rfbi.time[2];
744 case 0x80: /* RFBI_CYCLE_TIME1 */
745 return s->rfbi.time[3];
746 case 0x84: /* RFBI_DATA_CYCLE1_1 */
747 return s->rfbi.data[3];
748 case 0x88: /* RFBI_DATA_CYCLE2_1 */
749 return s->rfbi.data[4];
750 case 0x8c: /* RFBI_DATA_CYCLE3_1 */
751 return s->rfbi.data[5];
753 case 0x90: /* RFBI_VSYNC_WIDTH */
754 return s->rfbi.vsync;
755 case 0x94: /* RFBI_HSYNC_WIDTH */
756 return s->rfbi.hsync;
762 static void omap_rfbi_write(void *opaque, target_phys_addr_t addr,
765 struct omap_dss_s *s = (struct omap_dss_s *) opaque;
768 case 0x10: /* RFBI_SYSCONFIG */
769 if (value & 2) /* SOFTRESET */
771 s->rfbi.idlemode = value & 0x19;
774 case 0x40: /* RFBI_CONTROL */
775 s->rfbi.control = value & 0xf;
776 s->rfbi.enable = value & 1;
777 if (value & (1 << 4) && /* ITE */
778 !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
779 omap_rfbi_transfer_start(s);
782 case 0x44: /* RFBI_PIXELCNT */
783 s->rfbi.pixels = value;
786 case 0x48: /* RFBI_LINE_NUMBER */
787 s->rfbi.skiplines = value & 0x7ff;
790 case 0x4c: /* RFBI_CMD */
791 if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
792 s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
793 if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
794 s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
796 case 0x50: /* RFBI_PARAM */
797 if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
798 s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
799 if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
800 s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
802 case 0x54: /* RFBI_DATA */
803 /* TODO: take into account the format set up in s->rfbi.config[?] and
804 * s->rfbi.data[?], but special-case the most usual scenario so that
805 * speed doesn't suffer. */
806 if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
807 s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
808 s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
810 if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
811 s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
812 s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
814 if (!-- s->rfbi.pixels)
815 omap_rfbi_transfer_stop(s);
817 case 0x58: /* RFBI_READ */
818 if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
819 s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
820 else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
821 s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
822 if (!-- s->rfbi.pixels)
823 omap_rfbi_transfer_stop(s);
826 case 0x5c: /* RFBI_STATUS */
827 if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
828 s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
829 else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
830 s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
831 if (!-- s->rfbi.pixels)
832 omap_rfbi_transfer_stop(s);
835 case 0x60: /* RFBI_CONFIG0 */
836 s->rfbi.config[0] = value & 0x003f1fff;
839 case 0x64: /* RFBI_ONOFF_TIME0 */
840 s->rfbi.time[0] = value & 0x3fffffff;
842 case 0x68: /* RFBI_CYCLE_TIME0 */
843 s->rfbi.time[1] = value & 0x0fffffff;
845 case 0x6c: /* RFBI_DATA_CYCLE1_0 */
846 s->rfbi.data[0] = value & 0x0f1f0f1f;
848 case 0x70: /* RFBI_DATA_CYCLE2_0 */
849 s->rfbi.data[1] = value & 0x0f1f0f1f;
851 case 0x74: /* RFBI_DATA_CYCLE3_0 */
852 s->rfbi.data[2] = value & 0x0f1f0f1f;
854 case 0x78: /* RFBI_CONFIG1 */
855 s->rfbi.config[1] = value & 0x003f1fff;
858 case 0x7c: /* RFBI_ONOFF_TIME1 */
859 s->rfbi.time[2] = value & 0x3fffffff;
861 case 0x80: /* RFBI_CYCLE_TIME1 */
862 s->rfbi.time[3] = value & 0x0fffffff;
864 case 0x84: /* RFBI_DATA_CYCLE1_1 */
865 s->rfbi.data[3] = value & 0x0f1f0f1f;
867 case 0x88: /* RFBI_DATA_CYCLE2_1 */
868 s->rfbi.data[4] = value & 0x0f1f0f1f;
870 case 0x8c: /* RFBI_DATA_CYCLE3_1 */
871 s->rfbi.data[5] = value & 0x0f1f0f1f;
874 case 0x90: /* RFBI_VSYNC_WIDTH */
875 s->rfbi.vsync = value & 0xffff;
877 case 0x94: /* RFBI_HSYNC_WIDTH */
878 s->rfbi.hsync = value & 0xffff;
882 OMAP_BAD_REGV(addr, value);
887 static CPUReadMemoryFunc *omap_rfbi1_readfn[] = {
888 omap_badwidth_read32,
889 omap_badwidth_read32,
893 static CPUWriteMemoryFunc *omap_rfbi1_writefn[] = {
894 omap_badwidth_write32,
895 omap_badwidth_write32,
899 static uint32_t omap_venc_read(void *opaque, target_phys_addr_t addr)
902 case 0x00: /* REV_ID */
903 case 0x04: /* STATUS */
904 case 0x08: /* F_CONTROL */
905 case 0x10: /* VIDOUT_CTRL */
906 case 0x14: /* SYNC_CTRL */
907 case 0x1c: /* LLEN */
908 case 0x20: /* FLENS */
909 case 0x24: /* HFLTR_CTRL */
910 case 0x28: /* CC_CARR_WSS_CARR */
911 case 0x2c: /* C_PHASE */
912 case 0x30: /* GAIN_U */
913 case 0x34: /* GAIN_V */
914 case 0x38: /* GAIN_Y */
915 case 0x3c: /* BLACK_LEVEL */
916 case 0x40: /* BLANK_LEVEL */
917 case 0x44: /* X_COLOR */
918 case 0x48: /* M_CONTROL */
919 case 0x4c: /* BSTAMP_WSS_DATA */
920 case 0x50: /* S_CARR */
921 case 0x54: /* LINE21 */
922 case 0x58: /* LN_SEL */
923 case 0x5c: /* L21__WC_CTL */
924 case 0x60: /* HTRIGGER_VTRIGGER */
925 case 0x64: /* SAVID__EAVID */
926 case 0x68: /* FLEN__FAL */
927 case 0x6c: /* LAL__PHASE_RESET */
928 case 0x70: /* HS_INT_START_STOP_X */
929 case 0x74: /* HS_EXT_START_STOP_X */
930 case 0x78: /* VS_INT_START_X */
931 case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
932 case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
933 case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
934 case 0x88: /* VS_EXT_STOP_Y */
935 case 0x90: /* AVID_START_STOP_X */
936 case 0x94: /* AVID_START_STOP_Y */
937 case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
938 case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
939 case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
940 case 0xb0: /* TVDETGP_INT_START_STOP_X */
941 case 0xb4: /* TVDETGP_INT_START_STOP_Y */
942 case 0xb8: /* GEN_CTRL */
943 case 0xc4: /* DAC_TST__DAC_A */
944 case 0xc8: /* DAC_B__DAC_C */
954 static void omap_venc_write(void *opaque, target_phys_addr_t addr,
958 case 0x08: /* F_CONTROL */
959 case 0x10: /* VIDOUT_CTRL */
960 case 0x14: /* SYNC_CTRL */
961 case 0x1c: /* LLEN */
962 case 0x20: /* FLENS */
963 case 0x24: /* HFLTR_CTRL */
964 case 0x28: /* CC_CARR_WSS_CARR */
965 case 0x2c: /* C_PHASE */
966 case 0x30: /* GAIN_U */
967 case 0x34: /* GAIN_V */
968 case 0x38: /* GAIN_Y */
969 case 0x3c: /* BLACK_LEVEL */
970 case 0x40: /* BLANK_LEVEL */
971 case 0x44: /* X_COLOR */
972 case 0x48: /* M_CONTROL */
973 case 0x4c: /* BSTAMP_WSS_DATA */
974 case 0x50: /* S_CARR */
975 case 0x54: /* LINE21 */
976 case 0x58: /* LN_SEL */
977 case 0x5c: /* L21__WC_CTL */
978 case 0x60: /* HTRIGGER_VTRIGGER */
979 case 0x64: /* SAVID__EAVID */
980 case 0x68: /* FLEN__FAL */
981 case 0x6c: /* LAL__PHASE_RESET */
982 case 0x70: /* HS_INT_START_STOP_X */
983 case 0x74: /* HS_EXT_START_STOP_X */
984 case 0x78: /* VS_INT_START_X */
985 case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
986 case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
987 case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
988 case 0x88: /* VS_EXT_STOP_Y */
989 case 0x90: /* AVID_START_STOP_X */
990 case 0x94: /* AVID_START_STOP_Y */
991 case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
992 case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
993 case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
994 case 0xb0: /* TVDETGP_INT_START_STOP_X */
995 case 0xb4: /* TVDETGP_INT_START_STOP_Y */
996 case 0xb8: /* GEN_CTRL */
997 case 0xc4: /* DAC_TST__DAC_A */
998 case 0xc8: /* DAC_B__DAC_C */
1002 OMAP_BAD_REGV(addr, value);
1007 static CPUReadMemoryFunc *omap_venc1_readfn[] = {
1008 omap_badwidth_read32,
1009 omap_badwidth_read32,
1013 static CPUWriteMemoryFunc *omap_venc1_writefn[] = {
1014 omap_badwidth_write32,
1015 omap_badwidth_write32,
1019 static uint32_t omap_im3_read(void *opaque, target_phys_addr_t addr)
1022 case 0x0a8: /* SBIMERRLOGA */
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 case 0x1f8: /* SBID_L */
1030 case 0x1fc: /* SBID_H */
1040 static void omap_im3_write(void *opaque, target_phys_addr_t addr,
1044 case 0x0b0: /* SBIMERRLOG */
1045 case 0x190: /* SBIMSTATE */
1046 case 0x198: /* SBTMSTATE_L */
1047 case 0x19c: /* SBTMSTATE_H */
1048 case 0x1a8: /* SBIMCONFIG_L */
1049 case 0x1ac: /* SBIMCONFIG_H */
1053 OMAP_BAD_REGV(addr, value);
1058 static CPUReadMemoryFunc *omap_im3_readfn[] = {
1059 omap_badwidth_read32,
1060 omap_badwidth_read32,
1064 static CPUWriteMemoryFunc *omap_im3_writefn[] = {
1065 omap_badwidth_write32,
1066 omap_badwidth_write32,
1070 struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
1071 target_phys_addr_t l3_base, DisplayState *ds,
1072 qemu_irq irq, qemu_irq drq,
1073 omap_clk fck1, omap_clk fck2, omap_clk ck54m,
1074 omap_clk ick1, omap_clk ick2)
1077 struct omap_dss_s *s = (struct omap_dss_s *)
1078 qemu_mallocz(sizeof(struct omap_dss_s));
1085 iomemtype[0] = l4_register_io_memory(0, omap_diss1_readfn,
1086 omap_diss1_writefn, s);
1087 iomemtype[1] = l4_register_io_memory(0, omap_disc1_readfn,
1088 omap_disc1_writefn, s);
1089 iomemtype[2] = l4_register_io_memory(0, omap_rfbi1_readfn,
1090 omap_rfbi1_writefn, s);
1091 iomemtype[3] = l4_register_io_memory(0, omap_venc1_readfn,
1092 omap_venc1_writefn, s);
1093 iomemtype[4] = cpu_register_io_memory(0, omap_im3_readfn,
1094 omap_im3_writefn, s);
1095 omap_l4_attach(ta, 0, iomemtype[0]);
1096 omap_l4_attach(ta, 1, iomemtype[1]);
1097 omap_l4_attach(ta, 2, iomemtype[2]);
1098 omap_l4_attach(ta, 3, iomemtype[3]);
1099 cpu_register_physical_memory(l3_base, 0x1000, iomemtype[4]);
1102 graphic_console_init(ds, omap_update_display,
1103 omap_invalidate_display, omap_screen_dump, s);
1109 void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
1111 if (cs < 0 || cs > 1)
1112 cpu_abort(cpu_single_env, "%s: wrong CS %i\n", __FUNCTION__, cs);
1113 s->rfbi.chip[cs] = chip;
1116 void omap3_lcd_panel_attach(struct omap_dss_s *s, int cs, struct omap3_lcd_panel_s *lcd_panel)
1118 if (cs < 0 || cs > 1)
1119 cpu_abort(cpu_single_env, "%s: wrong CS %i\n", __FUNCTION__, cs);
1120 s->omap_lcd_panel[cs] = lcd_panel;
1123 /*omap3 lcd panel stuff*/
1125 /* Bytes(!) per pixel */
1126 static const int omap3_lcd_panel_bpp[0x10] = {
1135 4, /*0x8: RGB 24 (un-packed in 32-bit container) */
1136 3, /*0x9: RGB 24 (packed in 24-bit container) */
1141 4, /*0xe: RGBx 32 (24-bit RGB aligned on MSB of the 32-bit container) */
1145 static inline void omap3_lcd_panel_invalidate_display(void *opaque)
1147 struct omap3_lcd_panel_s *s = (struct omap3_lcd_panel_s *)opaque;
1151 static void omap3_lcd_panel_update_display(void *opaque)
1153 struct omap3_lcd_panel_s *s = (struct omap3_lcd_panel_s *)opaque;
1154 struct omap_dss_s *dss = s->dss;
1155 uint32_t lcd_width,lcd_height;
1156 uint32_t graphic_width,graphic_height;
1157 uint32_t start_x,start_y;
1158 uint32_t lcd_Bpp,dss_Bpp;
1159 uint32_t linesize,y;
1160 uint32_t copy_width,copy_height;
1161 uint8_t *src, *dest;
1163 //printf("dss->lcd.active %d dss->lcd.enable %d \n",dss->lcd.active,dss->lcd.enable);
1164 if (!dss->lcd.active)
1167 /*check whether LCD is enabled*/
1168 if (!dss->lcd.enable)
1171 if ((dss->dispc.control & (1 << 11))) /* RFBIMODE */
1174 if (dss->dispc.l[0].gfx_channel) /* 24 bit digital out */
1177 if (!(dss->dispc.l[0].rotation_flag)) { /* rotation*/
1178 s->line_fn = s->line_fn_tab[0][dss->dispc.l[0].gfx_format];
1180 fprintf(stderr, "%s: rotation is not supported \n", __FUNCTION__);
1184 fprintf(stderr, "%s:s->line_fn is NULL. Not supported gfx_format \n", __FUNCTION__);
1189 lcd_width = dss->lcd.nx;
1190 lcd_height = dss->lcd.ny;
1191 graphic_width = dss->dispc.l[0].nx;
1192 graphic_height = dss->dispc.l[0].ny;
1193 start_x = dss->dispc.l[0].posx;
1194 start_y = dss->dispc.l[0].posy;
1195 //printf("lcd_width %d lcd_height %d \n",lcd_width,lcd_height);
1196 //printf("graphic_width %d graphic_height %d \n",graphic_width,graphic_height);
1197 //printf("start_x %d start_y %d \n",start_x,start_y);
1199 if (lcd_width != ds_get_width(s->state)
1200 || lcd_height != ds_get_height(s->state)) {
1201 qemu_console_resize(s->console, lcd_width, lcd_height);
1202 dss->dispc.invalidate = 1;
1205 /*if ((start_x+graphic_width)>lcd_width) {
1206 fprintf(stderr, "%s: graphic window width(0x%x) > lcd width(0x%x) \n",__FUNCTION__,start_x+graphic_width,lcd_width );
1209 if ((start_y+graphic_height)>lcd_height) {
1210 fprintf(stderr, "%s: graphic window height(0x%x) > lcd height(0x%x) \n",__FUNCTION__,start_y+graphic_height,lcd_height);
1214 /*use the rfbi function*/
1215 src = (uint8_t *)omap_rfbi_get_buffer(dss);
1216 dest = ds_get_data(s->state);
1217 linesize = ds_get_linesize(s->state);
1219 lcd_Bpp = omap3_lcd_panel_bpp[dss->dispc.l[0].gfx_format];
1220 dss_Bpp = linesize/ds_get_width(s->state);
1222 //printf("LCD BPP %d dss_bpp %d \n",lcd_Bpp,dss_Bpp);
1224 dest += linesize*start_y;
1225 dest += start_x*dss_Bpp;
1227 if ((start_x+graphic_width)>lcd_width)
1228 copy_width = lcd_width - start_x;
1230 copy_width = graphic_width;
1231 copy_height = lcd_height>graphic_height ? graphic_height:lcd_height;
1233 for (y=start_y;y<copy_height;y++) {
1234 s->line_fn(dest,src,copy_width*lcd_Bpp);
1235 src += graphic_width*lcd_Bpp;
1239 dpy_update(s->state, start_x, start_y, graphic_width, graphic_height);
1244 #include "omap3_lcd_panel_template.h"
1246 #include "omap3_lcd_panel_template.h"
1248 #include "omap3_lcd_panel_template.h"
1250 #include "omap3_lcd_panel_template.h"
1252 #include "omap3_lcd_panel_template.h"
1254 void *omap3_lcd_panel_init(DisplayState *ds)
1256 struct omap3_lcd_panel_s *s = (struct omap3_lcd_panel_s *) qemu_mallocz(sizeof(*s));
1260 switch (ds_get_bits_per_pixel(s->state)) {
1262 s->line_fn_tab[0] = s->line_fn_tab[1] =
1263 qemu_mallocz(sizeof(omap3_lcd_panel_fn_t) * 0x10);
1266 s->line_fn_tab[0] = ds->bgr ? omap3_lcd_panel_draw_fn_bgr_8 : omap3_lcd_panel_draw_fn_8;
1267 s->line_fn_tab[1] = ds->bgr ? omap3_lcd_panel_draw_fn_r_bgr_8 : omap3_lcd_panel_draw_fn_r_8;
1270 s->line_fn_tab[0] = ds->bgr ? omap3_lcd_panel_draw_fn_bgr_15 : omap3_lcd_panel_draw_fn_15;
1271 s->line_fn_tab[1] = ds->bgr ? omap3_lcd_panel_draw_fn_r_bgr_15 : omap3_lcd_panel_draw_fn_r_15;
1274 s->line_fn_tab[0] = ds->bgr ? omap3_lcd_panel_draw_fn_bgr_16 : omap3_lcd_panel_draw_fn_16;
1275 s->line_fn_tab[1] = ds->bgr ? omap3_lcd_panel_draw_fn_r_bgr_16: omap3_lcd_panel_draw_fn_r_16;
1278 s->line_fn_tab[0] = ds->bgr ? omap3_lcd_panel_draw_fn_bgr_24 : omap3_lcd_panel_draw_fn_24;
1279 s->line_fn_tab[1] = ds->bgr ? omap3_lcd_panel_draw_fn_r_bgr_24 : omap3_lcd_panel_draw_fn_r_24;
1282 s->line_fn_tab[0] = ds->bgr ? omap3_lcd_panel_draw_fn_bgr_32 : omap3_lcd_panel_draw_fn_32;
1283 s->line_fn_tab[1] = ds->bgr ? omap3_lcd_panel_draw_fn_r_bgr_32 : omap3_lcd_panel_draw_fn_r_32;
1286 fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
1290 s->console = graphic_console_init(s->state, omap3_lcd_panel_update_display,
1291 omap3_lcd_panel_invalidate_display,