~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to hw/ssd0323.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include "ssi.h"
 
14
#include "console.h"
 
15
 
 
16
//#define DEBUG_SSD0323 1
 
17
 
 
18
#ifdef DEBUG_SSD0323
 
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)
 
23
#else
 
24
#define DPRINTF(fmt, ...) do {} while(0)
 
25
#define BADF(fmt, ...) \
 
26
do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__);} while (0)
 
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 {
 
45
    SSISlave ssidev;
 
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
 
 
63
static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data)
 
64
{
 
65
    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
 
66
 
 
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
static int ssd0323_init(SSISlave *dev)
 
326
{
 
327
    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
 
328
 
 
329
    s->col_end = 63;
 
330
    s->row_end = 79;
 
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);
 
335
 
 
336
    qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
 
337
 
 
338
    register_savevm(&dev->qdev, "ssd0323_oled", -1, 1,
 
339
                    ssd0323_save, ssd0323_load, s);
 
340
    return 0;
 
341
}
 
342
 
 
343
static SSISlaveInfo ssd0323_info = {
 
344
    .qdev.name = "ssd0323",
 
345
    .qdev.size = sizeof(ssd0323_state),
 
346
    .init = ssd0323_init,
 
347
    .transfer = ssd0323_transfer
 
348
};
 
349
 
 
350
static void ssd03232_register_devices(void)
 
351
{
 
352
    ssi_register_slave(&ssd0323_info);
 
353
}
 
354
 
 
355
device_init(ssd03232_register_devices)