qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

omap_dss.c (33102B)


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