2
* SSD0323 OLED controller with OSRAM Pictiva 128x64 display.
4
* Copyright (c) 2006-2007 CodeSourcery.
5
* Written by Paul Brook
7
* This code is licensed under the GPL.
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
16
//#define DEBUG_SSD0323 1
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)
24
#define DPRINTF(fmt, ...) do {} while(0)
25
#define BADF(fmt, ...) \
26
do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__);} while (0)
29
/* Scaling factor for pixels. */
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
59
enum ssd0323_mode mode;
60
uint8_t framebuffer[128 * 80 / 2];
63
static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data)
65
ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
69
DPRINTF("data 0x%02x\n", data);
70
s->framebuffer[s->col + s->row * 64] = data;
71
if (s->remap & REMAP_VERTICAL) {
73
if (s->row > s->row_end) {
74
s->row = s->row_start;
77
if (s->col > s->col_end) {
78
s->col = s->col_start;
82
if (s->col > s->col_end) {
84
s->col = s->col_start;
86
if (s->row > s->row_end) {
87
s->row = s->row_start;
93
DPRINTF("cmd 0x%02x\n", data);
94
if (s->cmd_len == 0) {
97
s->cmd_data[s->cmd_len - 1] = data;
101
#define DATA(x) if (s->cmd_len <= (x)) return 0
102
case 0x15: /* Set column. */
104
s->col = s->col_start = s->cmd_data[0] % 64;
105
s->col_end = s->cmd_data[1] % 64;
107
case 0x75: /* Set row. */
109
s->row = s->row_start = s->cmd_data[0] % 80;
110
s->row_end = s->cmd_data[1] % 80;
112
case 0x81: /* Set contrast */
115
case 0x84: case 0x85: case 0x86: /* Max current. */
118
case 0xa0: /* Set remapping. */
119
/* FIXME: Implement this. */
121
s->remap = s->cmd_data[0];
123
case 0xa1: /* Set display start line. */
124
case 0xa2: /* Set display offset. */
125
/* FIXME: Implement these. */
128
case 0xa4: /* Normal mode. */
129
case 0xa5: /* All on. */
130
case 0xa6: /* All off. */
131
case 0xa7: /* Inverse. */
132
/* FIXME: Implement these. */
135
case 0xa8: /* Set multiplex ratio. */
136
case 0xad: /* Set DC-DC converter. */
138
/* Ignored. Don't care. */
140
case 0xae: /* Display off. */
141
case 0xaf: /* Display on. */
143
/* TODO: Implement power control. */
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. */
152
/* Ignored. Don't care. */
154
case 0xb8: /* Set grey scale table. */
155
/* FIXME: Implement this. */
158
case 0xe3: /* NOP. */
161
case 0xff: /* Nasty hack because we don't handle chip selects
165
BADF("Unknown command: 0x%x\n", data);
173
static void ssd0323_update_display(void *opaque)
175
ssd0323_state *s = (ssd0323_state *)opaque;
183
char colortab[MAGNIFY * 64];
190
switch (ds_get_bits_per_pixel(s->ds)) {
206
BADF("Bad color depth\n");
210
for (i = 0; i < 16; i++) {
213
switch (ds_get_bits_per_pixel(s->ds)) {
215
n = i * 2 + (i >> 3);
217
p[1] = (n << 2) | (n >> 3);
220
n = i * 2 + (i >> 3);
221
p[0] = n | (n << 6) | ((n << 1) & 0x20);
222
p[1] = (n << 3) | (n >> 2);
227
p[0] = p[1] = p[2] = n;
230
BADF("Bad color depth\n");
235
/* TODO: Implement row/column remapping. */
236
dest = ds_get_data(s->ds);
237
for (y = 0; y < 64; y++) {
239
src = s->framebuffer + 64 * line;
240
for (x = 0; x < 64; x++) {
243
for (i = 0; i < MAGNIFY; i++) {
244
memcpy(dest, colors[val], dest_width);
248
for (i = 0; i < MAGNIFY; i++) {
249
memcpy(dest, colors[val], dest_width);
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;
261
dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
264
static void ssd0323_invalidate_display(void * opaque)
266
ssd0323_state *s = (ssd0323_state *)opaque;
270
/* Command/data input. */
271
static void ssd0323_cd(void *opaque, int n, int level)
273
ssd0323_state *s = (ssd0323_state *)opaque;
274
DPRINTF("%s mode\n", level ? "Data" : "Command");
275
s->mode = level ? SSD0323_DATA : SSD0323_CMD;
278
static void ssd0323_save(QEMUFile *f, void *opaque)
280
ssd0323_state *s = (ssd0323_state *)opaque;
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));
299
static int ssd0323_load(QEMUFile *f, void *opaque, int version_id)
301
ssd0323_state *s = (ssd0323_state *)opaque;
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));
325
static int ssd0323_init(SSISlave *dev)
327
ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
331
s->ds = graphic_console_init(ssd0323_update_display,
332
ssd0323_invalidate_display,
334
qemu_console_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY);
336
qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
338
register_savevm(&dev->qdev, "ssd0323_oled", -1, 1,
339
ssd0323_save, ssd0323_load, s);
343
static SSISlaveInfo ssd0323_info = {
344
.qdev.name = "ssd0323",
345
.qdev.size = sizeof(ssd0323_state),
346
.init = ssd0323_init,
347
.transfer = ssd0323_transfer
350
static void ssd03232_register_devices(void)
352
ssi_register_slave(&ssd0323_info);
355
device_init(ssd03232_register_devices)