Annotation of qemu/hw/ssd0323.c, revision 1.1.1.7

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

unix.superglobalmegacorp.com