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