syborg_fb.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /*
  2. * Syborg Framebuffer
  3. *
  4. * Copyright (c) 2009 CodeSourcery
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "sysbus.h"
  25. #include "console.h"
  26. #include "syborg.h"
  27. #include "framebuffer.h"
  28. //#define DEBUG_SYBORG_FB
  29. #ifdef DEBUG_SYBORG_FB
  30. #define DPRINTF(fmt, ...) \
  31. do { printf("syborg_fb: " fmt , ## __VA_ARGS__); } while (0)
  32. #define BADF(fmt, ...) \
  33. do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__); \
  34. exit(1);} while (0)
  35. #else
  36. #define DPRINTF(fmt, ...) do {} while(0)
  37. #define BADF(fmt, ...) \
  38. do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__);} while (0)
  39. #endif
  40. enum {
  41. FB_ID = 0,
  42. FB_BASE = 1,
  43. FB_HEIGHT = 2,
  44. FB_WIDTH = 3,
  45. FB_ORIENTATION = 4,
  46. FB_BLANK = 5,
  47. FB_INT_MASK = 6,
  48. FB_INTERRUPT_CAUSE = 7,
  49. FB_BPP = 8,
  50. FB_COLOR_ORDER = 9,
  51. FB_BYTE_ORDER = 10,
  52. FB_PIXEL_ORDER = 11,
  53. FB_ROW_PITCH = 12,
  54. FB_ENABLED = 13,
  55. FB_PALETTE_START = 0x400 >> 2,
  56. FB_PALETTE_END = FB_PALETTE_START+256-1,
  57. };
  58. #define FB_INT_VSYNC (1U << 0)
  59. #define FB_INT_BASE_UPDATE_DONE (1U << 1)
  60. typedef struct {
  61. SysBusDevice busdev;
  62. DisplayState *ds;
  63. /*QEMUConsole *console;*/
  64. uint32_t need_update : 1;
  65. uint32_t need_int : 1;
  66. uint32_t enabled : 1;
  67. uint32_t int_status;
  68. uint32_t int_enable;
  69. qemu_irq irq;
  70. uint32_t base;
  71. uint32_t pitch;
  72. uint32_t rows;
  73. uint32_t cols;
  74. int blank;
  75. int bpp;
  76. int rgb; /* 0 = BGR, 1 = RGB */
  77. int endian; /* 0 = Little, 1 = Big */
  78. uint32_t raw_palette[256];
  79. uint32_t palette[256];
  80. } SyborgFBState;
  81. enum {
  82. BPP_SRC_1,
  83. BPP_SRC_2,
  84. BPP_SRC_4,
  85. BPP_SRC_8,
  86. BPP_SRC_16,
  87. BPP_SRC_32,
  88. /* TODO: Implement these. */
  89. BPP_SRC_15 = -1,
  90. BPP_SRC_24 = -2
  91. };
  92. #include "pixel_ops.h"
  93. #define BITS 8
  94. #include "pl110_template.h"
  95. #define BITS 15
  96. #include "pl110_template.h"
  97. #define BITS 16
  98. #include "pl110_template.h"
  99. #define BITS 24
  100. #include "pl110_template.h"
  101. #define BITS 32
  102. #include "pl110_template.h"
  103. /* Update interrupts. */
  104. static void syborg_fb_update(SyborgFBState *s)
  105. {
  106. if ((s->int_status & s->int_enable) != 0) {
  107. DPRINTF("Raise IRQ\n");
  108. qemu_irq_raise(s->irq);
  109. } else {
  110. DPRINTF("Lower IRQ\n");
  111. qemu_irq_lower(s->irq);
  112. }
  113. }
  114. static int syborg_fb_enabled(const SyborgFBState *s)
  115. {
  116. return s->enabled;
  117. }
  118. static void syborg_fb_update_palette(SyborgFBState *s)
  119. {
  120. int n, i;
  121. uint32_t raw;
  122. unsigned int r, g, b;
  123. switch (s->bpp) {
  124. case BPP_SRC_1: n = 2; break;
  125. case BPP_SRC_2: n = 4; break;
  126. case BPP_SRC_4: n = 16; break;
  127. case BPP_SRC_8: n = 256; break;
  128. default: return;
  129. }
  130. for (i = 0; i < n; i++) {
  131. raw = s->raw_palette[i];
  132. r = (raw >> 16) & 0xff;
  133. g = (raw >> 8) & 0xff;
  134. b = raw & 0xff;
  135. switch (ds_get_bits_per_pixel(s->ds)) {
  136. case 8:
  137. s->palette[i] = rgb_to_pixel8(r, g, b);
  138. break;
  139. case 15:
  140. s->palette[i] = rgb_to_pixel15(r, g, b);
  141. break;
  142. case 16:
  143. s->palette[i] = rgb_to_pixel16(r, g, b);
  144. break;
  145. case 24:
  146. case 32:
  147. s->palette[i] = rgb_to_pixel32(r, g, b);
  148. break;
  149. default:
  150. abort();
  151. }
  152. }
  153. }
  154. static void syborg_fb_update_display(void *opaque)
  155. {
  156. SyborgFBState *s = (SyborgFBState *)opaque;
  157. drawfn* fntable;
  158. drawfn fn;
  159. int dest_width;
  160. int src_width;
  161. int bpp_offset;
  162. int first;
  163. int last;
  164. if (!syborg_fb_enabled(s))
  165. return;
  166. switch (ds_get_bits_per_pixel(s->ds)) {
  167. case 0:
  168. return;
  169. case 8:
  170. fntable = pl110_draw_fn_8;
  171. dest_width = 1;
  172. break;
  173. case 15:
  174. fntable = pl110_draw_fn_15;
  175. dest_width = 2;
  176. break;
  177. case 16:
  178. fntable = pl110_draw_fn_16;
  179. dest_width = 2;
  180. break;
  181. case 24:
  182. fntable = pl110_draw_fn_24;
  183. dest_width = 3;
  184. break;
  185. case 32:
  186. fntable = pl110_draw_fn_32;
  187. dest_width = 4;
  188. break;
  189. default:
  190. fprintf(stderr, "syborg_fb: Bad color depth\n");
  191. exit(1);
  192. }
  193. if (s->need_int) {
  194. s->int_status |= FB_INT_BASE_UPDATE_DONE;
  195. syborg_fb_update(s);
  196. s->need_int = 0;
  197. }
  198. if (s->rgb) {
  199. bpp_offset = 24;
  200. } else {
  201. bpp_offset = 0;
  202. }
  203. if (s->endian) {
  204. bpp_offset += 8;
  205. }
  206. /* Our bpp constants mostly match the PL110/PL111 but
  207. * not for the 16 bit case
  208. */
  209. switch (s->bpp) {
  210. case BPP_SRC_16:
  211. bpp_offset += 6;
  212. break;
  213. default:
  214. bpp_offset += s->bpp;
  215. }
  216. fn = fntable[bpp_offset];
  217. if (s->pitch) {
  218. src_width = s->pitch;
  219. } else {
  220. src_width = s->cols;
  221. switch (s->bpp) {
  222. case BPP_SRC_1:
  223. src_width >>= 3;
  224. break;
  225. case BPP_SRC_2:
  226. src_width >>= 2;
  227. break;
  228. case BPP_SRC_4:
  229. src_width >>= 1;
  230. break;
  231. case BPP_SRC_8:
  232. break;
  233. case BPP_SRC_15:
  234. case BPP_SRC_16:
  235. src_width <<= 1;
  236. break;
  237. case BPP_SRC_24:
  238. src_width *= 3;
  239. break;
  240. case BPP_SRC_32:
  241. src_width <<= 2;
  242. break;
  243. }
  244. }
  245. dest_width *= s->cols;
  246. first = 0;
  247. /* TODO: Implement blanking. */
  248. if (!s->blank) {
  249. if (s->need_update && s->bpp <= BPP_SRC_8) {
  250. syborg_fb_update_palette(s);
  251. }
  252. framebuffer_update_display(s->ds,
  253. s->base, s->cols, s->rows,
  254. src_width, dest_width, 0,
  255. s->need_update,
  256. fn, s->palette,
  257. &first, &last);
  258. if (first >= 0) {
  259. dpy_update(s->ds, 0, first, s->cols, last - first + 1);
  260. }
  261. s->int_status |= FB_INT_VSYNC;
  262. syborg_fb_update(s);
  263. }
  264. s->need_update = 0;
  265. }
  266. static void syborg_fb_invalidate_display(void * opaque)
  267. {
  268. SyborgFBState *s = (SyborgFBState *)opaque;
  269. s->need_update = 1;
  270. }
  271. static uint32_t syborg_fb_read(void *opaque, target_phys_addr_t offset)
  272. {
  273. SyborgFBState *s = opaque;
  274. DPRINTF("read reg %d\n", (int)offset);
  275. offset &= 0xfff;
  276. switch (offset >> 2) {
  277. case FB_ID:
  278. return SYBORG_ID_FRAMEBUFFER;
  279. case FB_BASE:
  280. return s->base;
  281. case FB_HEIGHT:
  282. return s->rows;
  283. case FB_WIDTH:
  284. return s->cols;
  285. case FB_ORIENTATION:
  286. return 0;
  287. case FB_BLANK:
  288. return s->blank;
  289. case FB_INT_MASK:
  290. return s->int_enable;
  291. case FB_INTERRUPT_CAUSE:
  292. return s->int_status;
  293. case FB_BPP:
  294. switch (s->bpp) {
  295. case BPP_SRC_1: return 1;
  296. case BPP_SRC_2: return 2;
  297. case BPP_SRC_4: return 4;
  298. case BPP_SRC_8: return 8;
  299. case BPP_SRC_15: return 15;
  300. case BPP_SRC_16: return 16;
  301. case BPP_SRC_24: return 24;
  302. case BPP_SRC_32: return 32;
  303. default: return 0;
  304. }
  305. case FB_COLOR_ORDER:
  306. return s->rgb;
  307. case FB_BYTE_ORDER:
  308. return s->endian;
  309. case FB_PIXEL_ORDER:
  310. return 0;
  311. case FB_ROW_PITCH:
  312. return s->pitch;
  313. case FB_ENABLED:
  314. return s->enabled;
  315. default:
  316. if ((offset >> 2) >= FB_PALETTE_START
  317. && (offset >> 2) <= FB_PALETTE_END) {
  318. return s->raw_palette[(offset >> 2) - FB_PALETTE_START];
  319. } else {
  320. cpu_abort (cpu_single_env, "syborg_fb_read: Bad offset %x\n",
  321. (int)offset);
  322. }
  323. return 0;
  324. }
  325. }
  326. static void syborg_fb_write(void *opaque, target_phys_addr_t offset,
  327. uint32_t val)
  328. {
  329. SyborgFBState *s = opaque;
  330. DPRINTF("write reg %d = %d\n", (int)offset, val);
  331. s->need_update = 1;
  332. offset &= 0xfff;
  333. switch (offset >> 2) {
  334. case FB_BASE:
  335. s->base = val;
  336. s->need_int = 1;
  337. s->need_update = 1;
  338. syborg_fb_update(s);
  339. break;
  340. case FB_HEIGHT:
  341. s->rows = val;
  342. break;
  343. case FB_WIDTH:
  344. s->cols = val;
  345. break;
  346. case FB_ORIENTATION:
  347. /* TODO: Implement rotation. */
  348. break;
  349. case FB_BLANK:
  350. s->blank = val & 1;
  351. break;
  352. case FB_INT_MASK:
  353. s->int_enable = val;
  354. syborg_fb_update(s);
  355. break;
  356. case FB_INTERRUPT_CAUSE:
  357. s->int_status &= ~val;
  358. syborg_fb_update(s);
  359. break;
  360. case FB_BPP:
  361. switch (val) {
  362. case 1: val = BPP_SRC_1; break;
  363. case 2: val = BPP_SRC_2; break;
  364. case 4: val = BPP_SRC_4; break;
  365. case 8: val = BPP_SRC_8; break;
  366. /* case 15: val = BPP_SRC_15; break; */
  367. case 16: val = BPP_SRC_16; break;
  368. /* case 24: val = BPP_SRC_24; break; */
  369. case 32: val = BPP_SRC_32; break;
  370. default: val = s->bpp; break;
  371. }
  372. s->bpp = val;
  373. break;
  374. case FB_COLOR_ORDER:
  375. s->rgb = (val != 0);
  376. break;
  377. case FB_BYTE_ORDER:
  378. s->endian = (val != 0);
  379. break;
  380. case FB_PIXEL_ORDER:
  381. /* TODO: Implement this. */
  382. break;
  383. case FB_ROW_PITCH:
  384. s->pitch = val;
  385. break;
  386. case FB_ENABLED:
  387. s->enabled = val;
  388. break;
  389. default:
  390. if ((offset >> 2) >= FB_PALETTE_START
  391. && (offset >> 2) <= FB_PALETTE_END) {
  392. s->raw_palette[(offset >> 2) - FB_PALETTE_START] = val;
  393. } else {
  394. cpu_abort (cpu_single_env, "syborg_fb_write: Bad offset %x\n",
  395. (int)offset);
  396. }
  397. break;
  398. }
  399. }
  400. static CPUReadMemoryFunc * const syborg_fb_readfn[] = {
  401. syborg_fb_read,
  402. syborg_fb_read,
  403. syborg_fb_read
  404. };
  405. static CPUWriteMemoryFunc * const syborg_fb_writefn[] = {
  406. syborg_fb_write,
  407. syborg_fb_write,
  408. syborg_fb_write
  409. };
  410. static void syborg_fb_save(QEMUFile *f, void *opaque)
  411. {
  412. SyborgFBState *s = opaque;
  413. int i;
  414. qemu_put_be32(f, s->need_int);
  415. qemu_put_be32(f, s->int_status);
  416. qemu_put_be32(f, s->int_enable);
  417. qemu_put_be32(f, s->enabled);
  418. qemu_put_be32(f, s->base);
  419. qemu_put_be32(f, s->pitch);
  420. qemu_put_be32(f, s->rows);
  421. qemu_put_be32(f, s->cols);
  422. qemu_put_be32(f, s->bpp);
  423. qemu_put_be32(f, s->rgb);
  424. for (i = 0; i < 256; i++) {
  425. qemu_put_be32(f, s->raw_palette[i]);
  426. }
  427. }
  428. static int syborg_fb_load(QEMUFile *f, void *opaque, int version_id)
  429. {
  430. SyborgFBState *s = opaque;
  431. int i;
  432. if (version_id != 1)
  433. return -EINVAL;
  434. s->need_int = qemu_get_be32(f);
  435. s->int_status = qemu_get_be32(f);
  436. s->int_enable = qemu_get_be32(f);
  437. s->enabled = qemu_get_be32(f);
  438. s->base = qemu_get_be32(f);
  439. s->pitch = qemu_get_be32(f);
  440. s->rows = qemu_get_be32(f);
  441. s->cols = qemu_get_be32(f);
  442. s->bpp = qemu_get_be32(f);
  443. s->rgb = qemu_get_be32(f);
  444. for (i = 0; i < 256; i++) {
  445. s->raw_palette[i] = qemu_get_be32(f);
  446. }
  447. s->need_update = 1;
  448. return 0;
  449. }
  450. static int syborg_fb_init(SysBusDevice *dev)
  451. {
  452. SyborgFBState *s = FROM_SYSBUS(SyborgFBState, dev);
  453. int iomemtype;
  454. sysbus_init_irq(dev, &s->irq);
  455. iomemtype = cpu_register_io_memory(syborg_fb_readfn,
  456. syborg_fb_writefn, s,
  457. DEVICE_NATIVE_ENDIAN);
  458. sysbus_init_mmio(dev, 0x1000, iomemtype);
  459. s->ds = graphic_console_init(syborg_fb_update_display,
  460. syborg_fb_invalidate_display,
  461. NULL, NULL, s);
  462. if (s->cols != 0 && s->rows != 0) {
  463. qemu_console_resize(s->ds, s->cols, s->rows);
  464. }
  465. if (!s->cols)
  466. s->cols = ds_get_width(s->ds);
  467. if (!s->rows)
  468. s->rows = ds_get_height(s->ds);
  469. register_savevm(&dev->qdev, "syborg_framebuffer", -1, 1,
  470. syborg_fb_save, syborg_fb_load, s);
  471. return 0;
  472. }
  473. static SysBusDeviceInfo syborg_fb_info = {
  474. .init = syborg_fb_init,
  475. .qdev.name = "syborg,framebuffer",
  476. .qdev.size = sizeof(SyborgFBState),
  477. .qdev.props = (Property[]) {
  478. DEFINE_PROP_UINT32("width", SyborgFBState, cols, 0),
  479. DEFINE_PROP_UINT32("height", SyborgFBState, rows, 0),
  480. DEFINE_PROP_END_OF_LIST(),
  481. }
  482. };
  483. static void syborg_fb_register_devices(void)
  484. {
  485. sysbus_register_withprop(&syborg_fb_info);
  486. }
  487. device_init(syborg_fb_register_devices)