|
|
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.