symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/ssd0323.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 licenced 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 #include "hw.h"
       
    14 #include "devices.h"
       
    15 #include "gui.h"
       
    16 
       
    17 //#define DEBUG_SSD0323 1
       
    18 
       
    19 #ifdef DEBUG_SSD0323
       
    20 #define DPRINTF(fmt, args...) \
       
    21 do { printf("ssd0323: " fmt , ##args); } while (0)
       
    22 #define BADF(fmt, args...) \
       
    23 do { fprintf(stderr, "ssd0323: error: " fmt , ##args); exit(1);} while (0)
       
    24 #else
       
    25 #define DPRINTF(fmt, args...) do {} while(0)
       
    26 #define BADF(fmt, args...) \
       
    27 do { fprintf(stderr, "ssd0323: error: " fmt , ##args);} while (0)
       
    28 #endif
       
    29 
       
    30 /* Scaling factor for pixels.  */
       
    31 #define MAGNIFY 4
       
    32 
       
    33 #define REMAP_SWAP_COLUMN 0x01
       
    34 #define REMAP_SWAP_NYBBLE 0x02
       
    35 #define REMAP_VERTICAL    0x04
       
    36 #define REMAP_SWAP_COM    0x10
       
    37 #define REMAP_SPLIT_COM   0x40
       
    38 
       
    39 enum ssd0323_mode
       
    40 {
       
    41     SSD0323_CMD,
       
    42     SSD0323_DATA
       
    43 };
       
    44 
       
    45 typedef struct {
       
    46     DisplayState *ds;
       
    47 //    QEMUConsole *console;
       
    48 
       
    49     int cmd_len;
       
    50     int cmd;
       
    51     int cmd_data[8];
       
    52     int row;
       
    53     int row_start;
       
    54     int row_end;
       
    55     int col;
       
    56     int col_start;
       
    57     int col_end;
       
    58     int redraw;
       
    59     int remap;
       
    60     enum ssd0323_mode mode;
       
    61     uint8_t framebuffer[128 * 80 / 2];
       
    62 } ssd0323_state;
       
    63 
       
    64 int ssd0323_xfer_ssi(void *opaque, int data)
       
    65 {
       
    66     ssd0323_state *s = (ssd0323_state *)opaque;
       
    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 
       
   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)) {
       
   214         case 15:
       
   215             n = i * 2 + (i >> 3);
       
   216             p[0] = n | (n << 5);
       
   217             p[1] = (n << 2) | (n >> 3);
       
   218             break;
       
   219         case 16:
       
   220             n = i * 2 + (i >> 3);
       
   221             p[0] = n | (n << 6) | ((n << 1) & 0x20);
       
   222             p[1] = (n << 3) | (n >> 2);
       
   223             break;
       
   224         case 24:
       
   225         case 32:
       
   226             n = (i << 4) | i;
       
   227             p[0] = p[1] = p[2] = n;
       
   228             break;
       
   229         default:
       
   230             BADF("Bad color depth\n");
       
   231             return;
       
   232         }
       
   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;
       
   246             }
       
   247             val = *src & 0xf;
       
   248             for (i = 0; i < MAGNIFY; i++) {
       
   249                 memcpy(dest, colors[val], dest_width);
       
   250                 dest += dest_width;
       
   251             }
       
   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;
       
   258         }
       
   259     }
       
   260     s->redraw = 0;
       
   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 
       
   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 
       
   325 void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p)
       
   326 {
       
   327     ssd0323_state *s;
       
   328     qemu_irq *cmd;
       
   329 
       
   330     s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state));
       
   331     s->col_end = 63;
       
   332     s->row_end = 79;
       
   333     s->ds = gui_get_graphic_console(NULL,
       
   334                                     ssd0323_update_display,
       
   335                                     ssd0323_invalidate_display,
       
   336                                     NULL, s);
       
   337     gui_resize_vt(s->ds, 128 * MAGNIFY, 64 * MAGNIFY);
       
   338 
       
   339     cmd = qemu_allocate_irqs(ssd0323_cd, s, 1);
       
   340     *cmd_p = *cmd;
       
   341 
       
   342     register_savevm("ssd0323_oled", -1, 1, ssd0323_save, ssd0323_load, s);
       
   343 
       
   344     return s;
       
   345 }