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 "ui/console.h"
  22#include "omap.h"
  23
  24struct 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
  93static 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
  98static 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
 122void 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
 171static 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
 209static 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
 243static const MemoryRegionOps omap_diss_ops = {
 244    .read = omap_diss_read,
 245    .write = omap_diss_write,
 246    .endianness = DEVICE_NATIVE_ENDIAN,
 247};
 248
 249static 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
 374static 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
 586static const MemoryRegionOps omap_disc_ops = {
 587    .read = omap_disc_read,
 588    .write = omap_disc_write,
 589    .endianness = DEVICE_NATIVE_ENDIAN,
 590};
 591
 592static 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
 602static 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
 666static 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
 733static 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
 861static const MemoryRegionOps omap_rfbi_ops = {
 862    .read = omap_rfbi_read,
 863    .write = omap_rfbi_write,
 864    .endianness = DEVICE_NATIVE_ENDIAN,
 865};
 866
 867static 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
 927static 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
 983static const MemoryRegionOps omap_venc_ops = {
 984    .read = omap_venc_read,
 985    .write = omap_venc_write,
 986    .endianness = DEVICE_NATIVE_ENDIAN,
 987};
 988
 989static 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
1015static 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
1036static const MemoryRegionOps omap_im3_ops = {
1037    .read = omap_im3_read,
1038    .write = omap_im3_write,
1039    .endianness = DEVICE_NATIVE_ENDIAN,
1040};
1041
1042struct 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
1081void 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