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

ssd0323.c (10487B)


      1/*
      2 * SSD0323 OLED controller with OSRAM Pictiva 128x64 display.
      3 *
      4 * Copyright (c) 2006-2007 CodeSourcery.
      5 * Written by Paul Brook
      6 *
      7 * This code is licensed under the GPL.
      8 */
      9
     10/* The controller can support a variety of different displays, but we only
     11   implement one.  Most of the commends relating to brightness and geometry
     12   setup are ignored. */
     13
     14#include "qemu/osdep.h"
     15#include "hw/ssi/ssi.h"
     16#include "migration/vmstate.h"
     17#include "qemu/module.h"
     18#include "ui/console.h"
     19#include "qom/object.h"
     20
     21//#define DEBUG_SSD0323 1
     22
     23#ifdef DEBUG_SSD0323
     24#define DPRINTF(fmt, ...) \
     25do { printf("ssd0323: " fmt , ## __VA_ARGS__); } while (0)
     26#define BADF(fmt, ...) \
     27do { \
     28    fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); abort(); \
     29} while (0)
     30#else
     31#define DPRINTF(fmt, ...) do {} while(0)
     32#define BADF(fmt, ...) \
     33do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__);} while (0)
     34#endif
     35
     36/* Scaling factor for pixels.  */
     37#define MAGNIFY 4
     38
     39#define REMAP_SWAP_COLUMN 0x01
     40#define REMAP_SWAP_NYBBLE 0x02
     41#define REMAP_VERTICAL    0x04
     42#define REMAP_SWAP_COM    0x10
     43#define REMAP_SPLIT_COM   0x40
     44
     45enum ssd0323_mode
     46{
     47    SSD0323_CMD,
     48    SSD0323_DATA
     49};
     50
     51struct ssd0323_state {
     52    SSIPeripheral ssidev;
     53    QemuConsole *con;
     54
     55    uint32_t cmd_len;
     56    int32_t cmd;
     57    int32_t cmd_data[8];
     58    int32_t row;
     59    int32_t row_start;
     60    int32_t row_end;
     61    int32_t col;
     62    int32_t col_start;
     63    int32_t col_end;
     64    int32_t redraw;
     65    int32_t remap;
     66    uint32_t mode;
     67    uint8_t framebuffer[128 * 80 / 2];
     68};
     69
     70#define TYPE_SSD0323 "ssd0323"
     71OBJECT_DECLARE_SIMPLE_TYPE(ssd0323_state, SSD0323)
     72
     73
     74static uint32_t ssd0323_transfer(SSIPeripheral *dev, uint32_t data)
     75{
     76    ssd0323_state *s = SSD0323(dev);
     77
     78    switch (s->mode) {
     79    case SSD0323_DATA:
     80        DPRINTF("data 0x%02x\n", data);
     81        s->framebuffer[s->col + s->row * 64] = data;
     82        if (s->remap & REMAP_VERTICAL) {
     83            s->row++;
     84            if (s->row > s->row_end) {
     85                s->row = s->row_start;
     86                s->col++;
     87            }
     88            if (s->col > s->col_end) {
     89                s->col = s->col_start;
     90            }
     91        } else {
     92            s->col++;
     93            if (s->col > s->col_end) {
     94                s->row++;
     95                s->col = s->col_start;
     96            }
     97            if (s->row > s->row_end) {
     98                s->row = s->row_start;
     99            }
    100        }
    101        s->redraw = 1;
    102        break;
    103    case SSD0323_CMD:
    104        DPRINTF("cmd 0x%02x\n", data);
    105        if (s->cmd_len == 0) {
    106            s->cmd = data;
    107        } else {
    108            s->cmd_data[s->cmd_len - 1] = data;
    109        }
    110        s->cmd_len++;
    111        switch (s->cmd) {
    112#define DATA(x) if (s->cmd_len <= (x)) return 0
    113        case 0x15: /* Set column.  */
    114            DATA(2);
    115            s->col = s->col_start = s->cmd_data[0] % 64;
    116            s->col_end = s->cmd_data[1] % 64;
    117            break;
    118        case 0x75: /* Set row.  */
    119            DATA(2);
    120            s->row = s->row_start = s->cmd_data[0] % 80;
    121            s->row_end = s->cmd_data[1] % 80;
    122            break;
    123        case 0x81: /* Set contrast */
    124            DATA(1);
    125            break;
    126        case 0x84: case 0x85: case 0x86: /* Max current.  */
    127            DATA(0);
    128            break;
    129        case 0xa0: /* Set remapping.  */
    130            /* FIXME: Implement this.  */
    131            DATA(1);
    132            s->remap = s->cmd_data[0];
    133            break;
    134        case 0xa1: /* Set display start line.  */
    135        case 0xa2: /* Set display offset.  */
    136            /* FIXME: Implement these.  */
    137            DATA(1);
    138            break;
    139        case 0xa4: /* Normal mode.  */
    140        case 0xa5: /* All on.  */
    141        case 0xa6: /* All off.  */
    142        case 0xa7: /* Inverse.  */
    143            /* FIXME: Implement these.  */
    144            DATA(0);
    145            break;
    146        case 0xa8: /* Set multiplex ratio.  */
    147        case 0xad: /* Set DC-DC converter.  */
    148            DATA(1);
    149            /* Ignored.  Don't care.  */
    150            break;
    151        case 0xae: /* Display off.  */
    152        case 0xaf: /* Display on.  */
    153            DATA(0);
    154            /* TODO: Implement power control.  */
    155            break;
    156        case 0xb1: /* Set phase length.  */
    157        case 0xb2: /* Set row period.  */
    158        case 0xb3: /* Set clock rate.  */
    159        case 0xbc: /* Set precharge.  */
    160        case 0xbe: /* Set VCOMH.  */
    161        case 0xbf: /* Set segment low.  */
    162            DATA(1);
    163            /* Ignored.  Don't care.  */
    164            break;
    165        case 0xb8: /* Set grey scale table.  */
    166            /* FIXME: Implement this.  */
    167            DATA(8);
    168            break;
    169        case 0xe3: /* NOP.  */
    170            DATA(0);
    171            break;
    172        case 0xff: /* Nasty hack because we don't handle chip selects
    173                      properly.  */
    174            break;
    175        default:
    176            BADF("Unknown command: 0x%x\n", data);
    177        }
    178        s->cmd_len = 0;
    179        return 0;
    180    }
    181    return 0;
    182}
    183
    184static void ssd0323_update_display(void *opaque)
    185{
    186    ssd0323_state *s = (ssd0323_state *)opaque;
    187    DisplaySurface *surface = qemu_console_surface(s->con);
    188    uint8_t *dest;
    189    uint8_t *src;
    190    int x;
    191    int y;
    192    int i;
    193    int line;
    194    char *colors[16];
    195    char colortab[MAGNIFY * 64];
    196    char *p;
    197    int dest_width;
    198
    199    if (!s->redraw)
    200        return;
    201
    202    switch (surface_bits_per_pixel(surface)) {
    203    case 0:
    204        return;
    205    case 15:
    206        dest_width = 2;
    207        break;
    208    case 16:
    209        dest_width = 2;
    210        break;
    211    case 24:
    212        dest_width = 3;
    213        break;
    214    case 32:
    215        dest_width = 4;
    216        break;
    217    default:
    218        BADF("Bad color depth\n");
    219        return;
    220    }
    221    p = colortab;
    222    for (i = 0; i < 16; i++) {
    223        int n;
    224        colors[i] = p;
    225        switch (surface_bits_per_pixel(surface)) {
    226        case 15:
    227            n = i * 2 + (i >> 3);
    228            p[0] = n | (n << 5);
    229            p[1] = (n << 2) | (n >> 3);
    230            break;
    231        case 16:
    232            n = i * 2 + (i >> 3);
    233            p[0] = n | (n << 6) | ((n << 1) & 0x20);
    234            p[1] = (n << 3) | (n >> 2);
    235            break;
    236        case 24:
    237        case 32:
    238            n = (i << 4) | i;
    239            p[0] = p[1] = p[2] = n;
    240            break;
    241        default:
    242            BADF("Bad color depth\n");
    243            return;
    244        }
    245        p += dest_width;
    246    }
    247    /* TODO: Implement row/column remapping.  */
    248    dest = surface_data(surface);
    249    for (y = 0; y < 64; y++) {
    250        line = y;
    251        src = s->framebuffer + 64 * line;
    252        for (x = 0; x < 64; x++) {
    253            int val;
    254            val = *src >> 4;
    255            for (i = 0; i < MAGNIFY; i++) {
    256                memcpy(dest, colors[val], dest_width);
    257                dest += dest_width;
    258            }
    259            val = *src & 0xf;
    260            for (i = 0; i < MAGNIFY; i++) {
    261                memcpy(dest, colors[val], dest_width);
    262                dest += dest_width;
    263            }
    264            src++;
    265        }
    266        for (i = 1; i < MAGNIFY; i++) {
    267            memcpy(dest, dest - dest_width * MAGNIFY * 128,
    268                   dest_width * 128 * MAGNIFY);
    269            dest += dest_width * 128 * MAGNIFY;
    270        }
    271    }
    272    s->redraw = 0;
    273    dpy_gfx_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
    274}
    275
    276static void ssd0323_invalidate_display(void * opaque)
    277{
    278    ssd0323_state *s = (ssd0323_state *)opaque;
    279    s->redraw = 1;
    280}
    281
    282/* Command/data input.  */
    283static void ssd0323_cd(void *opaque, int n, int level)
    284{
    285    ssd0323_state *s = (ssd0323_state *)opaque;
    286    DPRINTF("%s mode\n", level ? "Data" : "Command");
    287    s->mode = level ? SSD0323_DATA : SSD0323_CMD;
    288}
    289
    290static int ssd0323_post_load(void *opaque, int version_id)
    291{
    292    ssd0323_state *s = (ssd0323_state *)opaque;
    293
    294    if (s->cmd_len > ARRAY_SIZE(s->cmd_data)) {
    295        return -EINVAL;
    296    }
    297    if (s->row < 0 || s->row >= 80) {
    298        return -EINVAL;
    299    }
    300    if (s->row_start < 0 || s->row_start >= 80) {
    301        return -EINVAL;
    302    }
    303    if (s->row_end < 0 || s->row_end >= 80) {
    304        return -EINVAL;
    305    }
    306    if (s->col < 0 || s->col >= 64) {
    307        return -EINVAL;
    308    }
    309    if (s->col_start < 0 || s->col_start >= 64) {
    310        return -EINVAL;
    311    }
    312    if (s->col_end < 0 || s->col_end >= 64) {
    313        return -EINVAL;
    314    }
    315    if (s->mode != SSD0323_CMD && s->mode != SSD0323_DATA) {
    316        return -EINVAL;
    317    }
    318
    319    return 0;
    320}
    321
    322static const VMStateDescription vmstate_ssd0323 = {
    323    .name = "ssd0323_oled",
    324    .version_id = 2,
    325    .minimum_version_id = 2,
    326    .post_load = ssd0323_post_load,
    327    .fields      = (VMStateField []) {
    328        VMSTATE_UINT32(cmd_len, ssd0323_state),
    329        VMSTATE_INT32(cmd, ssd0323_state),
    330        VMSTATE_INT32_ARRAY(cmd_data, ssd0323_state, 8),
    331        VMSTATE_INT32(row, ssd0323_state),
    332        VMSTATE_INT32(row_start, ssd0323_state),
    333        VMSTATE_INT32(row_end, ssd0323_state),
    334        VMSTATE_INT32(col, ssd0323_state),
    335        VMSTATE_INT32(col_start, ssd0323_state),
    336        VMSTATE_INT32(col_end, ssd0323_state),
    337        VMSTATE_INT32(redraw, ssd0323_state),
    338        VMSTATE_INT32(remap, ssd0323_state),
    339        VMSTATE_UINT32(mode, ssd0323_state),
    340        VMSTATE_BUFFER(framebuffer, ssd0323_state),
    341        VMSTATE_SSI_PERIPHERAL(ssidev, ssd0323_state),
    342        VMSTATE_END_OF_LIST()
    343    }
    344};
    345
    346static const GraphicHwOps ssd0323_ops = {
    347    .invalidate  = ssd0323_invalidate_display,
    348    .gfx_update  = ssd0323_update_display,
    349};
    350
    351static void ssd0323_realize(SSIPeripheral *d, Error **errp)
    352{
    353    DeviceState *dev = DEVICE(d);
    354    ssd0323_state *s = SSD0323(d);
    355
    356    s->col_end = 63;
    357    s->row_end = 79;
    358    s->con = graphic_console_init(dev, 0, &ssd0323_ops, s);
    359    qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
    360
    361    qdev_init_gpio_in(dev, ssd0323_cd, 1);
    362}
    363
    364static void ssd0323_class_init(ObjectClass *klass, void *data)
    365{
    366    DeviceClass *dc = DEVICE_CLASS(klass);
    367    SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
    368
    369    k->realize = ssd0323_realize;
    370    k->transfer = ssd0323_transfer;
    371    k->cs_polarity = SSI_CS_HIGH;
    372    dc->vmsd = &vmstate_ssd0323;
    373    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
    374}
    375
    376static const TypeInfo ssd0323_info = {
    377    .name          = TYPE_SSD0323,
    378    .parent        = TYPE_SSI_PERIPHERAL,
    379    .instance_size = sizeof(ssd0323_state),
    380    .class_init    = ssd0323_class_init,
    381};
    382
    383static void ssd03232_register_types(void)
    384{
    385    type_register_static(&ssd0323_info);
    386}
    387
    388type_init(ssd03232_register_types)