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