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_lcdc.c (13586B)


      1/*
      2 * OMAP LCD controller.
      3 *
      4 * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
      5 *
      6 * This program is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU General Public License as
      8 * published by the Free Software Foundation; either version 2 of
      9 * the License, or (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License along
     17 * with this program; if not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "hw/irq.h"
     22#include "ui/console.h"
     23#include "hw/arm/omap.h"
     24#include "framebuffer.h"
     25#include "ui/pixel_ops.h"
     26
     27struct omap_lcd_panel_s {
     28    MemoryRegion *sysmem;
     29    MemoryRegion iomem;
     30    MemoryRegionSection fbsection;
     31    qemu_irq irq;
     32    QemuConsole *con;
     33
     34    int plm;
     35    int tft;
     36    int mono;
     37    int enable;
     38    int width;
     39    int height;
     40    int interrupts;
     41    uint32_t timing[3];
     42    uint32_t subpanel;
     43    uint32_t ctrl;
     44
     45    struct omap_dma_lcd_channel_s *dma;
     46    uint16_t palette[256];
     47    int palette_done;
     48    int frame_done;
     49    int invalidate;
     50    int sync_error;
     51};
     52
     53static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
     54{
     55    if (s->frame_done && (s->interrupts & 1)) {
     56        qemu_irq_raise(s->irq);
     57        return;
     58    }
     59
     60    if (s->palette_done && (s->interrupts & 2)) {
     61        qemu_irq_raise(s->irq);
     62        return;
     63    }
     64
     65    if (s->sync_error) {
     66        qemu_irq_raise(s->irq);
     67        return;
     68    }
     69
     70    qemu_irq_lower(s->irq);
     71}
     72
     73/*
     74 * 2-bit colour
     75 */
     76static void draw_line2_32(void *opaque, uint8_t *d, const uint8_t *s,
     77                          int width, int deststep)
     78{
     79    uint16_t *pal = opaque;
     80    uint8_t v, r, g, b;
     81
     82    do {
     83        v = ldub_p((void *) s);
     84        r = (pal[v & 3] >> 4) & 0xf0;
     85        g = pal[v & 3] & 0xf0;
     86        b = (pal[v & 3] << 4) & 0xf0;
     87        ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
     88        d += 4;
     89        v >>= 2;
     90        r = (pal[v & 3] >> 4) & 0xf0;
     91        g = pal[v & 3] & 0xf0;
     92        b = (pal[v & 3] << 4) & 0xf0;
     93        ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
     94        d += 4;
     95        v >>= 2;
     96        r = (pal[v & 3] >> 4) & 0xf0;
     97        g = pal[v & 3] & 0xf0;
     98        b = (pal[v & 3] << 4) & 0xf0;
     99        ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
    100        d += 4;
    101        v >>= 2;
    102        r = (pal[v & 3] >> 4) & 0xf0;
    103        g = pal[v & 3] & 0xf0;
    104        b = (pal[v & 3] << 4) & 0xf0;
    105        ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
    106        d += 4;
    107        s++;
    108        width -= 4;
    109    } while (width > 0);
    110}
    111
    112/*
    113 * 4-bit colour
    114 */
    115static void draw_line4_32(void *opaque, uint8_t *d, const uint8_t *s,
    116                          int width, int deststep)
    117{
    118    uint16_t *pal = opaque;
    119    uint8_t v, r, g, b;
    120
    121    do {
    122        v = ldub_p((void *) s);
    123        r = (pal[v & 0xf] >> 4) & 0xf0;
    124        g = pal[v & 0xf] & 0xf0;
    125        b = (pal[v & 0xf] << 4) & 0xf0;
    126        ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
    127        d += 4;
    128        v >>= 4;
    129        r = (pal[v & 0xf] >> 4) & 0xf0;
    130        g = pal[v & 0xf] & 0xf0;
    131        b = (pal[v & 0xf] << 4) & 0xf0;
    132        ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
    133        d += 4;
    134        s++;
    135        width -= 2;
    136    } while (width > 0);
    137}
    138
    139/*
    140 * 8-bit colour
    141 */
    142static void draw_line8_32(void *opaque, uint8_t *d, const uint8_t *s,
    143                          int width, int deststep)
    144{
    145    uint16_t *pal = opaque;
    146    uint8_t v, r, g, b;
    147
    148    do {
    149        v = ldub_p((void *) s);
    150        r = (pal[v] >> 4) & 0xf0;
    151        g = pal[v] & 0xf0;
    152        b = (pal[v] << 4) & 0xf0;
    153        ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
    154        s++;
    155        d += 4;
    156    } while (-- width != 0);
    157}
    158
    159/*
    160 * 12-bit colour
    161 */
    162static void draw_line12_32(void *opaque, uint8_t *d, const uint8_t *s,
    163                           int width, int deststep)
    164{
    165    uint16_t v;
    166    uint8_t r, g, b;
    167
    168    do {
    169        v = lduw_le_p((void *) s);
    170        r = (v >> 4) & 0xf0;
    171        g = v & 0xf0;
    172        b = (v << 4) & 0xf0;
    173        ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
    174        s += 2;
    175        d += 4;
    176    } while (-- width != 0);
    177}
    178
    179/*
    180 * 16-bit colour
    181 */
    182static void draw_line16_32(void *opaque, uint8_t *d, const uint8_t *s,
    183                           int width, int deststep)
    184{
    185    uint16_t v;
    186    uint8_t r, g, b;
    187
    188    do {
    189        v = lduw_le_p((void *) s);
    190        r = (v >> 8) & 0xf8;
    191        g = (v >> 3) & 0xfc;
    192        b = (v << 3) & 0xf8;
    193        ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
    194        s += 2;
    195        d += 4;
    196    } while (-- width != 0);
    197}
    198
    199static void omap_update_display(void *opaque)
    200{
    201    struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
    202    DisplaySurface *surface;
    203    drawfn draw_line;
    204    int size, height, first, last;
    205    int width, linesize, step, bpp, frame_offset;
    206    hwaddr frame_base;
    207
    208    if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable) {
    209        return;
    210    }
    211
    212    surface = qemu_console_surface(omap_lcd->con);
    213    if (!surface_bits_per_pixel(surface)) {
    214        return;
    215    }
    216
    217    frame_offset = 0;
    218    if (omap_lcd->plm != 2) {
    219        cpu_physical_memory_read(
    220                omap_lcd->dma->phys_framebuffer[omap_lcd->dma->current_frame],
    221                omap_lcd->palette, 0x200);
    222        switch (omap_lcd->palette[0] >> 12 & 7) {
    223        case 3 ... 7:
    224            frame_offset += 0x200;
    225            break;
    226        default:
    227            frame_offset += 0x20;
    228        }
    229    }
    230
    231    /* Colour depth */
    232    switch ((omap_lcd->palette[0] >> 12) & 7) {
    233    case 1:
    234        draw_line = draw_line2_32;
    235        bpp = 2;
    236        break;
    237
    238    case 2:
    239        draw_line = draw_line4_32;
    240        bpp = 4;
    241        break;
    242
    243    case 3:
    244        draw_line = draw_line8_32;
    245        bpp = 8;
    246        break;
    247
    248    case 4 ... 7:
    249        if (!omap_lcd->tft)
    250            draw_line = draw_line12_32;
    251        else
    252            draw_line = draw_line16_32;
    253        bpp = 16;
    254        break;
    255
    256    default:
    257        /* Unsupported at the moment.  */
    258        return;
    259    }
    260
    261    /* Resolution */
    262    width = omap_lcd->width;
    263    if (width != surface_width(surface) ||
    264        omap_lcd->height != surface_height(surface)) {
    265        qemu_console_resize(omap_lcd->con,
    266                            omap_lcd->width, omap_lcd->height);
    267        surface = qemu_console_surface(omap_lcd->con);
    268        omap_lcd->invalidate = 1;
    269    }
    270
    271    if (omap_lcd->dma->current_frame == 0)
    272        size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
    273    else
    274        size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
    275
    276    if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
    277        omap_lcd->sync_error = 1;
    278        omap_lcd_interrupts(omap_lcd);
    279        omap_lcd->enable = 0;
    280        return;
    281    }
    282
    283    /* Content */
    284    frame_base = omap_lcd->dma->phys_framebuffer[
    285            omap_lcd->dma->current_frame] + frame_offset;
    286    omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
    287    if (omap_lcd->dma->interrupts & 1)
    288        qemu_irq_raise(omap_lcd->dma->irq);
    289    if (omap_lcd->dma->dual)
    290        omap_lcd->dma->current_frame ^= 1;
    291
    292    if (!surface_bits_per_pixel(surface)) {
    293        return;
    294    }
    295
    296    first = 0;
    297    height = omap_lcd->height;
    298    if (omap_lcd->subpanel & (1 << 31)) {
    299        if (omap_lcd->subpanel & (1 << 29))
    300            first = (omap_lcd->subpanel >> 16) & 0x3ff;
    301        else
    302            height = (omap_lcd->subpanel >> 16) & 0x3ff;
    303        /* TODO: fill the rest of the panel with DPD */
    304    }
    305
    306    step = width * bpp >> 3;
    307    linesize = surface_stride(surface);
    308    if (omap_lcd->invalidate) {
    309        framebuffer_update_memory_section(&omap_lcd->fbsection,
    310                                          omap_lcd->sysmem, frame_base,
    311                                          height, step);
    312    }
    313
    314    framebuffer_update_display(surface, &omap_lcd->fbsection,
    315                               width, height,
    316                               step, linesize, 0,
    317                               omap_lcd->invalidate,
    318                               draw_line, omap_lcd->palette,
    319                               &first, &last);
    320
    321    if (first >= 0) {
    322        dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
    323    }
    324    omap_lcd->invalidate = 0;
    325}
    326
    327static void omap_invalidate_display(void *opaque) {
    328    struct omap_lcd_panel_s *omap_lcd = opaque;
    329    omap_lcd->invalidate = 1;
    330}
    331
    332static void omap_lcd_update(struct omap_lcd_panel_s *s) {
    333    if (!s->enable) {
    334        s->dma->current_frame = -1;
    335        s->sync_error = 0;
    336        if (s->plm != 1)
    337            s->frame_done = 1;
    338        omap_lcd_interrupts(s);
    339        return;
    340    }
    341
    342    if (s->dma->current_frame == -1) {
    343        s->frame_done = 0;
    344        s->palette_done = 0;
    345        s->dma->current_frame = 0;
    346    }
    347
    348    if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
    349                            s->dma->src_f1_top) ||
    350                    !s->dma->mpu->port[
    351                    s->dma->src].addr_valid(s->dma->mpu,
    352                            s->dma->src_f1_bottom) ||
    353                    (s->dma->dual &&
    354                     (!s->dma->mpu->port[
    355                      s->dma->src].addr_valid(s->dma->mpu,
    356                              s->dma->src_f2_top) ||
    357                      !s->dma->mpu->port[
    358                      s->dma->src].addr_valid(s->dma->mpu,
    359                              s->dma->src_f2_bottom)))) {
    360        s->dma->condition |= 1 << 2;
    361        if (s->dma->interrupts & (1 << 1))
    362            qemu_irq_raise(s->dma->irq);
    363        s->enable = 0;
    364        return;
    365    }
    366
    367    s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
    368    s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
    369
    370    if (s->plm != 2 && !s->palette_done) {
    371        cpu_physical_memory_read(
    372                            s->dma->phys_framebuffer[s->dma->current_frame],
    373                            s->palette, 0x200);
    374        s->palette_done = 1;
    375        omap_lcd_interrupts(s);
    376    }
    377}
    378
    379static uint64_t omap_lcdc_read(void *opaque, hwaddr addr,
    380                               unsigned size)
    381{
    382    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
    383
    384    switch (addr) {
    385    case 0x00:	/* LCD_CONTROL */
    386        return (s->tft << 23) | (s->plm << 20) |
    387                (s->tft << 7) | (s->interrupts << 3) |
    388                (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
    389
    390    case 0x04:	/* LCD_TIMING0 */
    391        return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
    392
    393    case 0x08:	/* LCD_TIMING1 */
    394        return (s->timing[1] << 10) | (s->height - 1);
    395
    396    case 0x0c:	/* LCD_TIMING2 */
    397        return s->timing[2] | 0xfc000000;
    398
    399    case 0x10:	/* LCD_STATUS */
    400        return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
    401
    402    case 0x14:	/* LCD_SUBPANEL */
    403        return s->subpanel;
    404
    405    default:
    406        break;
    407    }
    408    OMAP_BAD_REG(addr);
    409    return 0;
    410}
    411
    412static void omap_lcdc_write(void *opaque, hwaddr addr,
    413                            uint64_t value, unsigned size)
    414{
    415    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
    416
    417    switch (addr) {
    418    case 0x00:	/* LCD_CONTROL */
    419        s->plm = (value >> 20) & 3;
    420        s->tft = (value >> 7) & 1;
    421        s->interrupts = (value >> 3) & 3;
    422        s->mono = (value >> 1) & 1;
    423        s->ctrl = value & 0x01cff300;
    424        if (s->enable != (value & 1)) {
    425            s->enable = value & 1;
    426            omap_lcd_update(s);
    427        }
    428        break;
    429
    430    case 0x04:	/* LCD_TIMING0 */
    431        s->timing[0] = value >> 10;
    432        s->width = (value & 0x3ff) + 1;
    433        break;
    434
    435    case 0x08:	/* LCD_TIMING1 */
    436        s->timing[1] = value >> 10;
    437        s->height = (value & 0x3ff) + 1;
    438        break;
    439
    440    case 0x0c:	/* LCD_TIMING2 */
    441        s->timing[2] = value;
    442        break;
    443
    444    case 0x10:	/* LCD_STATUS */
    445        break;
    446
    447    case 0x14:	/* LCD_SUBPANEL */
    448        s->subpanel = value & 0xa1ffffff;
    449        break;
    450
    451    default:
    452        OMAP_BAD_REG(addr);
    453    }
    454}
    455
    456static const MemoryRegionOps omap_lcdc_ops = {
    457    .read = omap_lcdc_read,
    458    .write = omap_lcdc_write,
    459    .endianness = DEVICE_NATIVE_ENDIAN,
    460};
    461
    462void omap_lcdc_reset(struct omap_lcd_panel_s *s)
    463{
    464    s->dma->current_frame = -1;
    465    s->plm = 0;
    466    s->tft = 0;
    467    s->mono = 0;
    468    s->enable = 0;
    469    s->width = 0;
    470    s->height = 0;
    471    s->interrupts = 0;
    472    s->timing[0] = 0;
    473    s->timing[1] = 0;
    474    s->timing[2] = 0;
    475    s->subpanel = 0;
    476    s->palette_done = 0;
    477    s->frame_done = 0;
    478    s->sync_error = 0;
    479    s->invalidate = 1;
    480    s->subpanel = 0;
    481    s->ctrl = 0;
    482}
    483
    484static const GraphicHwOps omap_ops = {
    485    .invalidate  = omap_invalidate_display,
    486    .gfx_update  = omap_update_display,
    487};
    488
    489struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
    490                                        hwaddr base,
    491                                        qemu_irq irq,
    492                                        struct omap_dma_lcd_channel_s *dma,
    493                                        omap_clk clk)
    494{
    495    struct omap_lcd_panel_s *s = g_new0(struct omap_lcd_panel_s, 1);
    496
    497    s->irq = irq;
    498    s->dma = dma;
    499    s->sysmem = sysmem;
    500    omap_lcdc_reset(s);
    501
    502    memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
    503    memory_region_add_subregion(sysmem, base, &s->iomem);
    504
    505    s->con = graphic_console_init(NULL, 0, &omap_ops, s);
    506
    507    return s;
    508}