symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/ssd0303.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * SSD0303 OLED controller with OSRAM Pictiva 96x16 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 "i2c.h"
       
    15 #include "gui.h"
       
    16 
       
    17 //#define DEBUG_SSD0303 1
       
    18 
       
    19 #ifdef DEBUG_SSD0303
       
    20 #define DPRINTF(fmt, args...) \
       
    21 do { printf("ssd0303: " fmt , ##args); } while (0)
       
    22 #define BADF(fmt, args...) \
       
    23 do { fprintf(stderr, "ssd0303: 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, "ssd0303: error: " fmt , ##args);} while (0)
       
    28 #endif
       
    29 
       
    30 /* Scaling factor for pixels.  */
       
    31 #define MAGNIFY 4
       
    32 
       
    33 enum ssd0303_mode
       
    34 {
       
    35     SSD0303_IDLE,
       
    36     SSD0303_DATA,
       
    37     SSD0303_CMD
       
    38 };
       
    39 
       
    40 enum ssd0303_cmd {
       
    41     SSD0303_CMD_NONE,
       
    42     SSD0303_CMD_SKIP1
       
    43 };
       
    44 
       
    45 typedef struct {
       
    46     i2c_slave i2c;
       
    47     DisplayState *ds;
       
    48     int row;
       
    49     int col;
       
    50     int start_line;
       
    51     int mirror;
       
    52     int flash;
       
    53     int enabled;
       
    54     int inverse;
       
    55     int redraw;
       
    56     enum ssd0303_mode mode;
       
    57     enum ssd0303_cmd cmd_state;
       
    58     uint8_t framebuffer[132*8];
       
    59 } ssd0303_state;
       
    60 
       
    61 static int ssd0303_recv(i2c_slave *i2c)
       
    62 {
       
    63     BADF("Reads not implemented\n");
       
    64     return -1;
       
    65 }
       
    66 
       
    67 static int ssd0303_send(i2c_slave *i2c, uint8_t data)
       
    68 {
       
    69     ssd0303_state *s = (ssd0303_state *)i2c;
       
    70     enum ssd0303_cmd old_cmd_state;
       
    71     switch (s->mode) {
       
    72     case SSD0303_IDLE:
       
    73         DPRINTF("byte 0x%02x\n", data);
       
    74         if (data == 0x80)
       
    75             s->mode = SSD0303_CMD;
       
    76         else if (data == 0x40)
       
    77             s->mode = SSD0303_DATA;
       
    78         else
       
    79             BADF("Unexpected byte 0x%x\n", data);
       
    80         break;
       
    81     case SSD0303_DATA:
       
    82         DPRINTF("data 0x%02x\n", data);
       
    83         if (s->col < 132) {
       
    84             s->framebuffer[s->col + s->row * 132] = data;
       
    85             s->col++;
       
    86             s->redraw = 1;
       
    87         }
       
    88         break;
       
    89     case SSD0303_CMD:
       
    90         old_cmd_state = s->cmd_state;
       
    91         s->cmd_state = SSD0303_CMD_NONE;
       
    92         switch (old_cmd_state) {
       
    93         case SSD0303_CMD_NONE:
       
    94             DPRINTF("cmd 0x%02x\n", data);
       
    95             s->mode = SSD0303_IDLE;
       
    96             switch (data) {
       
    97             case 0x00 ... 0x0f: /* Set lower colum address.  */
       
    98                 s->col = (s->col & 0xf0) | (data & 0xf);
       
    99                 break;
       
   100             case 0x10 ... 0x20: /* Set higher column address.  */
       
   101                 s->col = (s->col & 0x0f) | ((data & 0xf) << 4);
       
   102                 break;
       
   103             case 0x40 ... 0x7f: /* Set start line.  */
       
   104                 s->start_line = 0;
       
   105                 break;
       
   106             case 0x81: /* Set contrast (Ignored).  */
       
   107                 s->cmd_state = SSD0303_CMD_SKIP1;
       
   108                 break;
       
   109             case 0xa0: /* Mirror off.  */
       
   110                 s->mirror = 0;
       
   111                 break;
       
   112             case 0xa1: /* Mirror off.  */
       
   113                 s->mirror = 1;
       
   114                 break;
       
   115             case 0xa4: /* Entire display off.  */
       
   116                 s->flash = 0;
       
   117                 break;
       
   118             case 0xa5: /* Entire display on.  */
       
   119                 s->flash = 1;
       
   120                 break;
       
   121             case 0xa6: /* Inverse off.  */
       
   122                 s->inverse = 0;
       
   123                 break;
       
   124             case 0xa7: /* Inverse on.  */
       
   125                 s->inverse = 1;
       
   126                 break;
       
   127             case 0xa8: /* Set multipled ratio (Ignored).  */
       
   128                 s->cmd_state = SSD0303_CMD_SKIP1;
       
   129                 break;
       
   130             case 0xad: /* DC-DC power control.  */
       
   131                 s->cmd_state = SSD0303_CMD_SKIP1;
       
   132                 break;
       
   133             case 0xae: /* Display off.  */
       
   134                 s->enabled = 0;
       
   135                 break;
       
   136             case 0xaf: /* Display on.  */
       
   137                 s->enabled = 1;
       
   138                 break;
       
   139             case 0xb0 ... 0xbf: /* Set Page address.  */
       
   140                 s->row = data & 7;
       
   141                 break;
       
   142             case 0xc0 ... 0xc8: /* Set COM output direction (Ignored).  */
       
   143                 break;
       
   144             case 0xd3: /* Set display offset (Ignored).  */
       
   145                 s->cmd_state = SSD0303_CMD_SKIP1;
       
   146                 break;
       
   147             case 0xd5: /* Set display clock (Ignored).  */
       
   148                 s->cmd_state = SSD0303_CMD_SKIP1;
       
   149                 break;
       
   150             case 0xd8: /* Set color and power mode (Ignored).  */
       
   151                 s->cmd_state = SSD0303_CMD_SKIP1;
       
   152                 break;
       
   153             case 0xd9: /* Set pre-charge period (Ignored).  */
       
   154                 s->cmd_state = SSD0303_CMD_SKIP1;
       
   155                 break;
       
   156             case 0xda: /* Set COM pin configuration (Ignored).  */
       
   157                 s->cmd_state = SSD0303_CMD_SKIP1;
       
   158                 break;
       
   159             case 0xdb: /* Set VCOM dselect level (Ignored).  */
       
   160                 s->cmd_state = SSD0303_CMD_SKIP1;
       
   161                 break;
       
   162             case 0xe3: /* no-op.  */
       
   163                 break;
       
   164             default:
       
   165                 BADF("Unknown command: 0x%x\n", data);
       
   166             }
       
   167             break;
       
   168         case SSD0303_CMD_SKIP1:
       
   169             DPRINTF("skip 0x%02x\n", data);
       
   170             break;
       
   171         }
       
   172         break;
       
   173     }
       
   174     return 0;
       
   175 }
       
   176 
       
   177 static void ssd0303_event(i2c_slave *i2c, enum i2c_event event)
       
   178 {
       
   179     ssd0303_state *s = (ssd0303_state *)i2c;
       
   180     switch (event) {
       
   181     case I2C_FINISH:
       
   182         s->mode = SSD0303_IDLE;
       
   183         break;
       
   184     case I2C_START_RECV:
       
   185     case I2C_START_SEND:
       
   186     case I2C_NACK:
       
   187         /* Nothing to do.  */
       
   188         break;
       
   189     }
       
   190 }
       
   191 
       
   192 static void ssd0303_update_display(void *opaque)
       
   193 {
       
   194     ssd0303_state *s = (ssd0303_state *)opaque;
       
   195     uint8_t *dest;
       
   196     uint8_t *src;
       
   197     int x;
       
   198     int y;
       
   199     int line;
       
   200     char *colors[2];
       
   201     char colortab[MAGNIFY * 8];
       
   202     int dest_width;
       
   203     uint8_t mask;
       
   204 
       
   205     if (!s->redraw)
       
   206         return;
       
   207 
       
   208     switch (ds_get_bits_per_pixel(s->ds)) {
       
   209     case 0:
       
   210         return;
       
   211     case 15:
       
   212         dest_width = 2;
       
   213         break;
       
   214     case 16:
       
   215         dest_width = 2;
       
   216         break;
       
   217     case 24:
       
   218         dest_width = 3;
       
   219         break;
       
   220     case 32:
       
   221         dest_width = 4;
       
   222         break;
       
   223     default:
       
   224         BADF("Bad color depth\n");
       
   225         return;
       
   226     }
       
   227     dest_width *= MAGNIFY;
       
   228     memset(colortab, 0xff, dest_width);
       
   229     memset(colortab + dest_width, 0, dest_width);
       
   230     if (s->flash) {
       
   231         colors[0] = colortab;
       
   232         colors[1] = colortab;
       
   233     } else if (s->inverse) {
       
   234         colors[0] = colortab;
       
   235         colors[1] = colortab + dest_width;
       
   236     } else {
       
   237         colors[0] = colortab + dest_width;
       
   238         colors[1] = colortab;
       
   239     }
       
   240     dest = ds_get_data(s->ds);
       
   241     for (y = 0; y < 16; y++) {
       
   242         line = (y + s->start_line) & 63;
       
   243         src = s->framebuffer + 132 * (line >> 3) + 36;
       
   244         mask = 1 << (line & 7);
       
   245         for (x = 0; x < 96; x++) {
       
   246             memcpy(dest, colors[(*src & mask) != 0], dest_width);
       
   247             dest += dest_width;
       
   248             src++;
       
   249         }
       
   250         for (x = 1; x < MAGNIFY; x++) {
       
   251             memcpy(dest, dest - dest_width * 96, dest_width * 96);
       
   252             dest += dest_width * 96;
       
   253         }
       
   254     }
       
   255     s->redraw = 0;
       
   256     dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
       
   257 }
       
   258 
       
   259 static void ssd0303_invalidate_display(void * opaque)
       
   260 {
       
   261     ssd0303_state *s = (ssd0303_state *)opaque;
       
   262     s->redraw = 1;
       
   263 }
       
   264 
       
   265 static void ssd0303_save(QEMUFile *f, void *opaque)
       
   266 {
       
   267     ssd0303_state *s = (ssd0303_state *)opaque;
       
   268 
       
   269     qemu_put_be32(f, s->row);
       
   270     qemu_put_be32(f, s->col);
       
   271     qemu_put_be32(f, s->start_line);
       
   272     qemu_put_be32(f, s->mirror);
       
   273     qemu_put_be32(f, s->flash);
       
   274     qemu_put_be32(f, s->enabled);
       
   275     qemu_put_be32(f, s->inverse);
       
   276     qemu_put_be32(f, s->redraw);
       
   277     qemu_put_be32(f, s->mode);
       
   278     qemu_put_be32(f, s->cmd_state);
       
   279     qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
       
   280 
       
   281     i2c_slave_save(f, &s->i2c);
       
   282 }
       
   283 
       
   284 static int ssd0303_load(QEMUFile *f, void *opaque, int version_id)
       
   285 {
       
   286     ssd0303_state *s = (ssd0303_state *)opaque;
       
   287 
       
   288     if (version_id != 1)
       
   289         return -EINVAL;
       
   290 
       
   291     s->row = qemu_get_be32(f);
       
   292     s->col = qemu_get_be32(f);
       
   293     s->start_line = qemu_get_be32(f);
       
   294     s->mirror = qemu_get_be32(f);
       
   295     s->flash = qemu_get_be32(f);
       
   296     s->enabled = qemu_get_be32(f);
       
   297     s->inverse = qemu_get_be32(f);
       
   298     s->redraw = qemu_get_be32(f);
       
   299     s->mode = qemu_get_be32(f);
       
   300     s->cmd_state = qemu_get_be32(f);
       
   301     qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
       
   302 
       
   303     i2c_slave_load(f, &s->i2c);
       
   304 
       
   305     return 0;
       
   306 }
       
   307 
       
   308 void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address)
       
   309 {
       
   310     ssd0303_state *s;
       
   311 
       
   312     s = (ssd0303_state *)i2c_slave_init(bus, address, sizeof(ssd0303_state));
       
   313  
       
   314     s->i2c.event = ssd0303_event;
       
   315     s->i2c.recv = ssd0303_recv;
       
   316     s->i2c.send = ssd0303_send;
       
   317 
       
   318     s->ds = gui_get_graphic_console(NULL,
       
   319                                     ssd0303_update_display,
       
   320                                     ssd0303_invalidate_display,
       
   321                                     NULL, s);
       
   322     gui_resize_vt(s->ds, 96 * MAGNIFY, 16 * MAGNIFY);
       
   323 
       
   324     register_savevm("ssd0303_oled", -1, 1, ssd0303_save, ssd0303_load, s);
       
   325 }