|
|
1.1 root 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: #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:
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: int ssd0323_xfer_ssi(void *opaque, int data)
64: {
65: ssd0323_state *s = (ssd0323_state *)opaque;
66: switch (s->mode) {
67: case SSD0323_DATA:
68: DPRINTF("data 0x%02x\n", data);
69: s->framebuffer[s->col + s->row * 64] = data;
70: if (s->remap & REMAP_VERTICAL) {
71: s->row++;
72: if (s->row > s->row_end) {
73: s->row = s->row_start;
74: s->col++;
75: }
76: if (s->col > s->col_end) {
77: s->col = s->col_start;
78: }
79: } else {
80: s->col++;
81: if (s->col > s->col_end) {
82: s->row++;
83: s->col = s->col_start;
84: }
85: if (s->row > s->row_end) {
86: s->row = s->row_start;
87: }
88: }
89: s->redraw = 1;
90: break;
91: case SSD0323_CMD:
92: DPRINTF("cmd 0x%02x\n", data);
93: if (s->cmd_len == 0) {
94: s->cmd = data;
95: } else {
96: s->cmd_data[s->cmd_len - 1] = data;
97: }
98: s->cmd_len++;
99: switch (s->cmd) {
100: #define DATA(x) if (s->cmd_len <= (x)) return 0
101: case 0x15: /* Set column. */
102: DATA(2);
103: s->col = s->col_start = s->cmd_data[0] % 64;
104: s->col_end = s->cmd_data[1] % 64;
105: break;
106: case 0x75: /* Set row. */
107: DATA(2);
108: s->row = s->row_start = s->cmd_data[0] % 80;
109: s->row_end = s->cmd_data[1] % 80;
110: break;
111: case 0x81: /* Set contrast */
112: DATA(1);
113: break;
114: case 0x84: case 0x85: case 0x86: /* Max current. */
115: DATA(0);
116: break;
117: case 0xa0: /* Set remapping. */
118: /* FIXME: Implement this. */
119: DATA(1);
120: s->remap = s->cmd_data[0];
121: break;
122: case 0xa1: /* Set display start line. */
123: case 0xa2: /* Set display offset. */
124: /* FIXME: Implement these. */
125: DATA(1);
126: break;
127: case 0xa4: /* Normal mode. */
128: case 0xa5: /* All on. */
129: case 0xa6: /* All off. */
130: case 0xa7: /* Inverse. */
131: /* FIXME: Implement these. */
132: DATA(0);
133: break;
134: case 0xa8: /* Set multiplex ratio. */
135: case 0xad: /* Set DC-DC converter. */
136: DATA(1);
137: /* Ignored. Don't care. */
138: break;
139: case 0xae: /* Display off. */
140: case 0xaf: /* Display on. */
141: DATA(0);
142: /* TODO: Implement power control. */
143: break;
144: case 0xb1: /* Set phase length. */
145: case 0xb2: /* Set row period. */
146: case 0xb3: /* Set clock rate. */
147: case 0xbc: /* Set precharge. */
148: case 0xbe: /* Set VCOMH. */
149: case 0xbf: /* Set segment low. */
150: DATA(1);
151: /* Ignored. Don't care. */
152: break;
153: case 0xb8: /* Set grey scale table. */
154: /* FIXME: Implement this. */
155: DATA(8);
156: break;
157: case 0xe3: /* NOP. */
158: DATA(0);
159: break;
160: case 0xff: /* Nasty hack because we don't handle chip selects
161: properly. */
162: break;
163: default:
164: BADF("Unknown command: 0x%x\n", data);
165: }
166: s->cmd_len = 0;
167: return 0;
168: }
169: return 0;
170: }
171:
172: static void ssd0323_update_display(void *opaque)
173: {
174: ssd0323_state *s = (ssd0323_state *)opaque;
175: uint8_t *dest;
176: uint8_t *src;
177: int x;
178: int y;
179: int i;
180: int line;
181: char *colors[16];
182: char colortab[MAGNIFY * 64];
183: char *p;
184: int dest_width;
185:
186: if (s->redraw) {
187: switch (s->ds->depth) {
188: case 0:
189: return;
190: case 15:
191: dest_width = 2;
192: break;
193: case 16:
194: dest_width = 2;
195: break;
196: case 24:
197: dest_width = 3;
198: break;
199: case 32:
200: dest_width = 4;
201: break;
202: default:
203: BADF("Bad color depth\n");
204: return;
205: }
206: p = colortab;
207: for (i = 0; i < 16; i++) {
208: int n;
209: colors[i] = p;
210: switch (s->ds->depth) {
211: case 15:
212: n = i * 2 + (i >> 3);
213: p[0] = n | (n << 5);
214: p[1] = (n << 2) | (n >> 3);
215: break;
216: case 16:
217: n = i * 2 + (i >> 3);
218: p[0] = n | (n << 6) | ((n << 1) & 0x20);
219: p[1] = (n << 3) | (n >> 2);
220: break;
221: case 24:
222: case 32:
223: n = (i << 4) | i;
224: p[0] = p[1] = p[2] = n;
225: break;
226: default:
227: BADF("Bad color depth\n");
228: return;
229: }
230: p += dest_width;
231: }
232: /* TODO: Implement row/column remapping. */
233: dest = s->ds->data;
234: for (y = 0; y < 64; y++) {
235: line = y;
236: src = s->framebuffer + 64 * line;
237: for (x = 0; x < 64; x++) {
238: int val;
239: val = *src >> 4;
240: for (i = 0; i < MAGNIFY; i++) {
241: memcpy(dest, colors[val], dest_width);
242: dest += dest_width;
243: }
244: val = *src & 0xf;
245: for (i = 0; i < MAGNIFY; i++) {
246: memcpy(dest, colors[val], dest_width);
247: dest += dest_width;
248: }
249: src++;
250: }
251: for (i = 1; i < MAGNIFY; i++) {
252: memcpy(dest, dest - dest_width * MAGNIFY * 128,
253: dest_width * 128 * MAGNIFY);
254: dest += dest_width * 128 * MAGNIFY;
255: }
256: }
257: }
258: dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
259: }
260:
261: static void ssd0323_invalidate_display(void * opaque)
262: {
263: ssd0323_state *s = (ssd0323_state *)opaque;
264: s->redraw = 1;
265: }
266:
267: /* Command/data input. */
268: static void ssd0323_cd(void *opaque, int n, int level)
269: {
270: ssd0323_state *s = (ssd0323_state *)opaque;
271: DPRINTF("%s mode\n", level ? "Data" : "Command");
272: s->mode = level ? SSD0323_DATA : SSD0323_CMD;
273: }
274:
275: void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p)
276: {
277: ssd0323_state *s;
278: qemu_irq *cmd;
279:
280: s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state));
281: s->ds = ds;
282: graphic_console_init(ds, ssd0323_update_display, ssd0323_invalidate_display,
283: NULL, s);
284: dpy_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY);
285: s->col_end = 63;
286: s->row_end = 79;
287:
288: cmd = qemu_allocate_irqs(ssd0323_cd, s, 1);
289: *cmd_p = *cmd;
290:
291: return s;
292: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.