ssd0303.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * SSD0303 OLED controller with OSRAM Pictiva 96x16 display.
  3. *
  4. * Copyright (c) 2006-2007 CodeSourcery.
  5. * Written by Paul Brook
  6. *
  7. * This code is licenced under the GPL.
  8. */
  9. /* The controller can support a variety of different displays, but we only
  10. implement one. Most of the commends relating to brightness and geometry
  11. setup are ignored. */
  12. #include "hw.h"
  13. #include "i2c.h"
  14. #include "console.h"
  15. //#define DEBUG_SSD0303 1
  16. #ifdef DEBUG_SSD0303
  17. #define DPRINTF(fmt, args...) \
  18. do { printf("ssd0303: " fmt , ##args); } while (0)
  19. #define BADF(fmt, args...) \
  20. do { fprintf(stderr, "ssd0303: error: " fmt , ##args); exit(1);} while (0)
  21. #else
  22. #define DPRINTF(fmt, args...) do {} while(0)
  23. #define BADF(fmt, args...) \
  24. do { fprintf(stderr, "ssd0303: error: " fmt , ##args);} while (0)
  25. #endif
  26. /* Scaling factor for pixels. */
  27. #define MAGNIFY 4
  28. enum ssd0303_mode
  29. {
  30. SSD0303_IDLE,
  31. SSD0303_DATA,
  32. SSD0303_CMD
  33. };
  34. enum ssd0303_cmd {
  35. SSD0303_CMD_NONE,
  36. SSD0303_CMD_SKIP1
  37. };
  38. typedef struct {
  39. i2c_slave i2c;
  40. DisplayState *ds;
  41. int row;
  42. int col;
  43. int start_line;
  44. int mirror;
  45. int flash;
  46. int enabled;
  47. int inverse;
  48. int redraw;
  49. enum ssd0303_mode mode;
  50. enum ssd0303_cmd cmd_state;
  51. uint8_t framebuffer[132*8];
  52. } ssd0303_state;
  53. static int ssd0303_recv(i2c_slave *i2c)
  54. {
  55. BADF("Reads not implemented\n");
  56. return -1;
  57. }
  58. static int ssd0303_send(i2c_slave *i2c, uint8_t data)
  59. {
  60. ssd0303_state *s = (ssd0303_state *)i2c;
  61. enum ssd0303_cmd old_cmd_state;
  62. switch (s->mode) {
  63. case SSD0303_IDLE:
  64. DPRINTF("byte 0x%02x\n", data);
  65. if (data == 0x80)
  66. s->mode = SSD0303_CMD;
  67. else if (data == 0x40)
  68. s->mode = SSD0303_DATA;
  69. else
  70. BADF("Unexpected byte 0x%x\n", data);
  71. break;
  72. case SSD0303_DATA:
  73. DPRINTF("data 0x%02x\n", data);
  74. if (s->col < 132) {
  75. s->framebuffer[s->col + s->row * 132] = data;
  76. s->col++;
  77. s->redraw = 1;
  78. }
  79. break;
  80. case SSD0303_CMD:
  81. old_cmd_state = s->cmd_state;
  82. s->cmd_state = SSD0303_CMD_NONE;
  83. switch (old_cmd_state) {
  84. case SSD0303_CMD_NONE:
  85. DPRINTF("cmd 0x%02x\n", data);
  86. s->mode = SSD0303_IDLE;
  87. switch (data) {
  88. case 0x00 ... 0x0f: /* Set lower colum address. */
  89. s->col = (s->col & 0xf0) | (data & 0xf);
  90. break;
  91. case 0x10 ... 0x20: /* Set higher column address. */
  92. s->col = (s->col & 0x0f) | ((data & 0xf) << 4);
  93. break;
  94. case 0x40 ... 0x7f: /* Set start line. */
  95. s->start_line = 0;
  96. break;
  97. case 0x81: /* Set contrast (Ignored). */
  98. s->cmd_state = SSD0303_CMD_SKIP1;
  99. break;
  100. case 0xa0: /* Mirror off. */
  101. s->mirror = 0;
  102. break;
  103. case 0xa1: /* Mirror off. */
  104. s->mirror = 1;
  105. break;
  106. case 0xa4: /* Entire display off. */
  107. s->flash = 0;
  108. break;
  109. case 0xa5: /* Entire display on. */
  110. s->flash = 1;
  111. break;
  112. case 0xa6: /* Inverse off. */
  113. s->inverse = 0;
  114. break;
  115. case 0xa7: /* Inverse on. */
  116. s->inverse = 1;
  117. break;
  118. case 0xa8: /* Set multipled ratio (Ignored). */
  119. s->cmd_state = SSD0303_CMD_SKIP1;
  120. break;
  121. case 0xad: /* DC-DC power control. */
  122. s->cmd_state = SSD0303_CMD_SKIP1;
  123. break;
  124. case 0xae: /* Display off. */
  125. s->enabled = 0;
  126. break;
  127. case 0xaf: /* Display on. */
  128. s->enabled = 1;
  129. break;
  130. case 0xb0 ... 0xbf: /* Set Page address. */
  131. s->row = data & 7;
  132. break;
  133. case 0xc0 ... 0xc8: /* Set COM output direction (Ignored). */
  134. break;
  135. case 0xd3: /* Set display offset (Ignored). */
  136. s->cmd_state = SSD0303_CMD_SKIP1;
  137. break;
  138. case 0xd5: /* Set display clock (Ignored). */
  139. s->cmd_state = SSD0303_CMD_SKIP1;
  140. break;
  141. case 0xd8: /* Set color and power mode (Ignored). */
  142. s->cmd_state = SSD0303_CMD_SKIP1;
  143. break;
  144. case 0xd9: /* Set pre-charge period (Ignored). */
  145. s->cmd_state = SSD0303_CMD_SKIP1;
  146. break;
  147. case 0xda: /* Set COM pin configuration (Ignored). */
  148. s->cmd_state = SSD0303_CMD_SKIP1;
  149. break;
  150. case 0xdb: /* Set VCOM dselect level (Ignored). */
  151. s->cmd_state = SSD0303_CMD_SKIP1;
  152. break;
  153. case 0xe3: /* no-op. */
  154. break;
  155. default:
  156. BADF("Unknown command: 0x%x\n", data);
  157. }
  158. break;
  159. case SSD0303_CMD_SKIP1:
  160. DPRINTF("skip 0x%02x\n", data);
  161. break;
  162. }
  163. break;
  164. }
  165. return 0;
  166. }
  167. static void ssd0303_event(i2c_slave *i2c, enum i2c_event event)
  168. {
  169. ssd0303_state *s = (ssd0303_state *)i2c;
  170. switch (event) {
  171. case I2C_FINISH:
  172. s->mode = SSD0303_IDLE;
  173. break;
  174. case I2C_START_RECV:
  175. case I2C_START_SEND:
  176. case I2C_NACK:
  177. /* Nothing to do. */
  178. break;
  179. }
  180. }
  181. static void ssd0303_update_display(void *opaque)
  182. {
  183. ssd0303_state *s = (ssd0303_state *)opaque;
  184. uint8_t *dest;
  185. uint8_t *src;
  186. int x;
  187. int y;
  188. int line;
  189. char *colors[2];
  190. char colortab[MAGNIFY * 8];
  191. int dest_width;
  192. uint8_t mask;
  193. if (!s->redraw)
  194. return;
  195. switch (ds_get_bits_per_pixel(s->ds)) {
  196. case 0:
  197. return;
  198. case 15:
  199. dest_width = 2;
  200. break;
  201. case 16:
  202. dest_width = 2;
  203. break;
  204. case 24:
  205. dest_width = 3;
  206. break;
  207. case 32:
  208. dest_width = 4;
  209. break;
  210. default:
  211. BADF("Bad color depth\n");
  212. return;
  213. }
  214. dest_width *= MAGNIFY;
  215. memset(colortab, 0xff, dest_width);
  216. memset(colortab + dest_width, 0, dest_width);
  217. if (s->flash) {
  218. colors[0] = colortab;
  219. colors[1] = colortab;
  220. } else if (s->inverse) {
  221. colors[0] = colortab;
  222. colors[1] = colortab + dest_width;
  223. } else {
  224. colors[0] = colortab + dest_width;
  225. colors[1] = colortab;
  226. }
  227. dest = ds_get_data(s->ds);
  228. for (y = 0; y < 16; y++) {
  229. line = (y + s->start_line) & 63;
  230. src = s->framebuffer + 132 * (line >> 3) + 36;
  231. mask = 1 << (line & 7);
  232. for (x = 0; x < 96; x++) {
  233. memcpy(dest, colors[(*src & mask) != 0], dest_width);
  234. dest += dest_width;
  235. src++;
  236. }
  237. for (x = 1; x < MAGNIFY; x++) {
  238. memcpy(dest, dest - dest_width * 96, dest_width * 96);
  239. dest += dest_width * 96;
  240. }
  241. }
  242. s->redraw = 0;
  243. dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
  244. }
  245. static void ssd0303_invalidate_display(void * opaque)
  246. {
  247. ssd0303_state *s = (ssd0303_state *)opaque;
  248. s->redraw = 1;
  249. }
  250. static void ssd0303_save(QEMUFile *f, void *opaque)
  251. {
  252. ssd0303_state *s = (ssd0303_state *)opaque;
  253. qemu_put_be32(f, s->row);
  254. qemu_put_be32(f, s->col);
  255. qemu_put_be32(f, s->start_line);
  256. qemu_put_be32(f, s->mirror);
  257. qemu_put_be32(f, s->flash);
  258. qemu_put_be32(f, s->enabled);
  259. qemu_put_be32(f, s->inverse);
  260. qemu_put_be32(f, s->redraw);
  261. qemu_put_be32(f, s->mode);
  262. qemu_put_be32(f, s->cmd_state);
  263. qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
  264. i2c_slave_save(f, &s->i2c);
  265. }
  266. static int ssd0303_load(QEMUFile *f, void *opaque, int version_id)
  267. {
  268. ssd0303_state *s = (ssd0303_state *)opaque;
  269. if (version_id != 1)
  270. return -EINVAL;
  271. s->row = qemu_get_be32(f);
  272. s->col = qemu_get_be32(f);
  273. s->start_line = qemu_get_be32(f);
  274. s->mirror = qemu_get_be32(f);
  275. s->flash = qemu_get_be32(f);
  276. s->enabled = qemu_get_be32(f);
  277. s->inverse = qemu_get_be32(f);
  278. s->redraw = qemu_get_be32(f);
  279. s->mode = qemu_get_be32(f);
  280. s->cmd_state = qemu_get_be32(f);
  281. qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
  282. i2c_slave_load(f, &s->i2c);
  283. return 0;
  284. }
  285. void ssd0303_init(i2c_bus *bus, int address)
  286. {
  287. ssd0303_state *s;
  288. s = (ssd0303_state *)i2c_slave_init(bus, address, sizeof(ssd0303_state));
  289. s->i2c.event = ssd0303_event;
  290. s->i2c.recv = ssd0303_recv;
  291. s->i2c.send = ssd0303_send;
  292. s->ds = graphic_console_init(ssd0303_update_display,
  293. ssd0303_invalidate_display,
  294. NULL, NULL, s);
  295. qemu_console_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY);
  296. register_savevm("ssd0303_oled", -1, 1, ssd0303_save, ssd0303_load, s);
  297. }