cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

omap_dss.c (32724B)


      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}