Statistics
| Branch: | Revision:

root / hw / ssd0323.c @ 87ecb68b

History | View | Annotate | Download (7.1 kB)

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 "console.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
enum ssd0323_mode
34
{
35
    SSD0323_CMD,
36
    SSD0323_DATA
37
};
38

    
39
typedef struct {
40
    DisplayState *ds;
41

    
42
    int cmd_len;
43
    int cmd;
44
    int cmd_data[8];
45
    int row;
46
    int row_start;
47
    int row_end;
48
    int col;
49
    int col_start;
50
    int col_end;
51
    int redraw;
52
    enum ssd0323_mode mode;
53
    uint8_t framebuffer[128 * 80 / 2];
54
} ssd0323_state;
55

    
56
int ssd0323_xfer_ssi(void *opaque, int data)
57
{
58
    ssd0323_state *s = (ssd0323_state *)opaque;
59
    switch (s->mode) {
60
    case SSD0323_DATA:
61
        DPRINTF("data 0x%02x\n", data);
62
        s->framebuffer[s->col + s->row * 64] = data;
63
        s->col++;
64
        if (s->col > s->col_end) {
65
            s->row++;
66
            s->col = s->col_start;
67
        }
68
        if (s->row > s->row_end) {
69
            s->row = s->row_start;
70
        }
71
        s->redraw = 1;
72
        break;
73
    case SSD0323_CMD:
74
        DPRINTF("cmd 0x%02x\n", data);
75
        if (s->cmd_len == 0) {
76
            s->cmd = data;
77
        } else {
78
            s->cmd_data[s->cmd_len - 1] = data;
79
        }
80
        s->cmd_len++;
81
        switch (s->cmd) {
82
#define DATA(x) if (s->cmd_len <= (x)) return 0
83
        case 0x15: /* Set column.  */
84
            DATA(2);
85
            s->col_start = s->cmd_data[0] % 64;
86
            s->col_end = s->cmd_data[1] % 64;
87
            break;
88
        case 0x75: /* Set row.  */
89
            DATA(2);
90
            s->row_start = s->cmd_data[0] % 80;
91
            s->row_end = s->cmd_data[1] % 80;
92
            break;
93
        case 0x81: /* Set contrast */
94
            DATA(1);
95
            break;
96
        case 0x84: case 0x85: case 0x86: /* Max current.  */
97
            DATA(0);
98
            break;
99
        case 0xa0: /* Set remapping.  */
100
            /* FIXME: Implement this.  */
101
            DATA(1);
102
            break;
103
        case 0xa1: /* Set display start line.  */
104
        case 0xa2: /* Set display offset.  */
105
            /* FIXME: Implement these.  */
106
            DATA(1);
107
            break;
108
        case 0xa4: /* Normal mode.  */
109
        case 0xa5: /* All on.  */
110
        case 0xa6: /* All off.  */
111
        case 0xa7: /* Inverse.  */
112
            /* FIXME: Implement these.  */
113
            DATA(0);
114
            break;
115
        case 0xa8: /* Set multiplex ratio.  */
116
        case 0xad: /* Set DC-DC converter.  */
117
            DATA(1);
118
            /* Ignored.  Don't care.  */
119
            break;
120
        case 0xae: /* Display off.  */
121
        case 0xaf: /* Display on.  */
122
            DATA(0);
123
            /* TODO: Implement power control.  */
124
            break;
125
        case 0xb1: /* Set phase length.  */
126
        case 0xb2: /* Set row period.  */
127
        case 0xb3: /* Set clock rate.  */
128
        case 0xbc: /* Set precharge.  */
129
        case 0xbe: /* Set VCOMH.  */
130
        case 0xbf: /* Set segment low.  */
131
            DATA(1);
132
            /* Ignored.  Don't care.  */
133
            break;
134
        case 0xb8: /* Set grey scale table.  */
135
            /* FIXME: Implement this.  */
136
            DATA(8);
137
            break;
138
        case 0xe3: /* NOP.  */
139
            DATA(0);
140
            break;
141
        default:
142
            BADF("Unknown command: 0x%x\n", data);
143
        }
144
        s->cmd_len = 0;
145
        return 0;
146
    }
147
    return 0;
148
}
149

    
150
static void ssd0323_update_display(void *opaque)
151
{
152
    ssd0323_state *s = (ssd0323_state *)opaque;
153
    uint8_t *dest;
154
    uint8_t *src;
155
    int x;
156
    int y;
157
    int i;
158
    int line;
159
    char *colors[16];
160
    char colortab[MAGNIFY * 64];
161
    char *p;
162
    int dest_width;
163

    
164
    if (s->redraw) {
165
        switch (s->ds->depth) {
166
        case 0:
167
            return;
168
        case 15:
169
            dest_width = 2;
170
            break;
171
        case 16:
172
            dest_width = 2;
173
            break;
174
        case 24:
175
            dest_width = 3;
176
            break;
177
        case 32:
178
            dest_width = 4;
179
            break;
180
        default:
181
            BADF("Bad color depth\n");
182
            return;
183
        }
184
        p = colortab;
185
        for (i = 0; i < 16; i++) {
186
            int n;
187
            colors[i] = p;
188
            switch (s->ds->depth) {
189
            case 15:
190
                n = i * 2 + (i >> 3);
191
                p[0] = n | (n << 5);
192
                p[1] = (n << 2) | (n >> 3);
193
                break;
194
            case 16:
195
                n = i * 2 + (i >> 3);
196
                p[0] = n | (n << 6) | ((n << 1) & 0x20);
197
                p[1] = (n << 3) | (n >> 2);
198
                break;
199
            case 24:
200
            case 32:
201
                n = (i << 4) | i;
202
                p[0] = p[1] = p[2] = n;
203
                break;
204
            default:
205
                BADF("Bad color depth\n");
206
                return;
207
            }
208
            p += dest_width;
209
        }
210
        dest = s->ds->data;
211
        for (y = 0; y < 64; y++) {
212
            line = y;
213
            src = s->framebuffer + 64 * line;
214
            for (x = 0; x < 64; x++) {
215
                int val;
216
                val = *src >> 4;
217
                for (i = 0; i < MAGNIFY; i++) {
218
                    memcpy(dest, colors[val], dest_width);
219
                    dest += dest_width;
220
                }
221
                val = *src & 0xf;
222
                for (i = 0; i < MAGNIFY; i++) {
223
                    memcpy(dest, colors[val], dest_width);
224
                    dest += dest_width;
225
                }
226
                src++;
227
            }
228
            for (i = 1; i < MAGNIFY; i++) {
229
                memcpy(dest, dest - dest_width * MAGNIFY * 128,
230
                       dest_width * 128 * MAGNIFY);
231
                dest += dest_width * 128 * MAGNIFY;
232
            }
233
        }
234
    }
235
    dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
236
}
237

    
238
static void ssd0323_invalidate_display(void * opaque)
239
{
240
    ssd0323_state *s = (ssd0323_state *)opaque;
241
    s->redraw = 1;
242
}
243

    
244
/* Command/data input.  */
245
static void ssd0323_cd(void *opaque, int n, int level)
246
{
247
    ssd0323_state *s = (ssd0323_state *)opaque;
248
    DPRINTF("%s mode\n", level ? "Data" : "Command");
249
    s->mode = level ? SSD0323_DATA : SSD0323_CMD;
250
}
251

    
252
void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p)
253
{
254
    ssd0323_state *s;
255
    qemu_irq *cmd;
256

    
257
    s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state));
258
    s->ds = ds;
259
    graphic_console_init(ds, ssd0323_update_display, ssd0323_invalidate_display,
260
                         NULL, s);
261
    dpy_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY);
262
    s->col_end = 63;
263
    s->row_end = 79;
264

    
265
    cmd = qemu_allocate_irqs(ssd0323_cd, s, 1);
266
    *cmd_p = *cmd;
267

    
268
    return s;
269
}