2
0

pl110.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * Arm PrimeCell PL110 Color LCD Controller
  3. *
  4. * Copyright (c) 2005-2006 CodeSourcery.
  5. * Written by Paul Brook
  6. *
  7. * This code is licenced under the GNU LGPL
  8. */
  9. #include "hw.h"
  10. #include "primecell.h"
  11. #include "console.h"
  12. #define PL110_CR_EN 0x001
  13. #define PL110_CR_BGR 0x100
  14. #define PL110_CR_BEBO 0x200
  15. #define PL110_CR_BEPO 0x400
  16. #define PL110_CR_PWR 0x800
  17. enum pl110_bppmode
  18. {
  19. BPP_1,
  20. BPP_2,
  21. BPP_4,
  22. BPP_8,
  23. BPP_16,
  24. BPP_32
  25. };
  26. typedef struct {
  27. DisplayState *ds;
  28. /* The Versatile/PB uses a slightly modified PL110 controller. */
  29. int versatile;
  30. uint32_t timing[4];
  31. uint32_t cr;
  32. uint32_t upbase;
  33. uint32_t lpbase;
  34. uint32_t int_status;
  35. uint32_t int_mask;
  36. int cols;
  37. int rows;
  38. enum pl110_bppmode bpp;
  39. int invalidate;
  40. uint32_t pallette[256];
  41. uint32_t raw_pallette[128];
  42. qemu_irq irq;
  43. } pl110_state;
  44. static const unsigned char pl110_id[] =
  45. { 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
  46. /* The Arm documentation (DDI0224C) says the CLDC on the Versatile board
  47. has a different ID. However Linux only looks for the normal ID. */
  48. #if 0
  49. static const unsigned char pl110_versatile_id[] =
  50. { 0x93, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
  51. #else
  52. #define pl110_versatile_id pl110_id
  53. #endif
  54. static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
  55. {
  56. return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
  57. }
  58. static inline uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
  59. {
  60. return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
  61. }
  62. static inline uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
  63. {
  64. return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
  65. }
  66. static inline uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b)
  67. {
  68. return (r << 16) | (g << 8) | b;
  69. }
  70. static inline uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
  71. {
  72. return (r << 16) | (g << 8) | b;
  73. }
  74. typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int);
  75. #define BITS 8
  76. #include "pl110_template.h"
  77. #define BITS 15
  78. #include "pl110_template.h"
  79. #define BITS 16
  80. #include "pl110_template.h"
  81. #define BITS 24
  82. #include "pl110_template.h"
  83. #define BITS 32
  84. #include "pl110_template.h"
  85. static int pl110_enabled(pl110_state *s)
  86. {
  87. return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR);
  88. }
  89. static void pl110_update_display(void *opaque)
  90. {
  91. pl110_state *s = (pl110_state *)opaque;
  92. drawfn* fntable;
  93. drawfn fn;
  94. uint32_t *pallette;
  95. uint32_t addr;
  96. uint32_t base;
  97. int dest_width;
  98. int src_width;
  99. uint8_t *dest;
  100. uint8_t *src;
  101. int first, last = 0;
  102. int dirty, new_dirty;
  103. int i;
  104. int bpp_offset;
  105. if (!pl110_enabled(s))
  106. return;
  107. switch (ds_get_bits_per_pixel(s->ds)) {
  108. case 0:
  109. return;
  110. case 8:
  111. fntable = pl110_draw_fn_8;
  112. dest_width = 1;
  113. break;
  114. case 15:
  115. fntable = pl110_draw_fn_15;
  116. dest_width = 2;
  117. break;
  118. case 16:
  119. fntable = pl110_draw_fn_16;
  120. dest_width = 2;
  121. break;
  122. case 24:
  123. fntable = pl110_draw_fn_24;
  124. dest_width = 3;
  125. break;
  126. case 32:
  127. fntable = pl110_draw_fn_32;
  128. dest_width = 4;
  129. break;
  130. default:
  131. fprintf(stderr, "pl110: Bad color depth\n");
  132. exit(1);
  133. }
  134. if (s->cr & PL110_CR_BGR)
  135. bpp_offset = 0;
  136. else
  137. bpp_offset = 18;
  138. if (s->cr & PL110_CR_BEBO)
  139. fn = fntable[s->bpp + 6 + bpp_offset];
  140. else if (s->cr & PL110_CR_BEPO)
  141. fn = fntable[s->bpp + 12 + bpp_offset];
  142. else
  143. fn = fntable[s->bpp + bpp_offset];
  144. src_width = s->cols;
  145. switch (s->bpp) {
  146. case BPP_1:
  147. src_width >>= 3;
  148. break;
  149. case BPP_2:
  150. src_width >>= 2;
  151. break;
  152. case BPP_4:
  153. src_width >>= 1;
  154. break;
  155. case BPP_8:
  156. break;
  157. case BPP_16:
  158. src_width <<= 1;
  159. break;
  160. case BPP_32:
  161. src_width <<= 2;
  162. break;
  163. }
  164. dest_width *= s->cols;
  165. pallette = s->pallette;
  166. base = s->upbase;
  167. /* HACK: Arm aliases physical memory at 0x80000000. */
  168. if (base > 0x80000000)
  169. base -= 0x80000000;
  170. src = phys_ram_base + base;
  171. dest = ds_get_data(s->ds);
  172. first = -1;
  173. addr = base;
  174. dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
  175. new_dirty = dirty;
  176. for (i = 0; i < s->rows; i++) {
  177. if ((addr & ~TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) {
  178. uint32_t tmp;
  179. new_dirty = 0;
  180. for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) {
  181. new_dirty |= cpu_physical_memory_get_dirty(addr + tmp,
  182. VGA_DIRTY_FLAG);
  183. }
  184. }
  185. if (dirty || new_dirty || s->invalidate) {
  186. fn(pallette, dest, src, s->cols);
  187. if (first == -1)
  188. first = i;
  189. last = i;
  190. }
  191. dirty = new_dirty;
  192. addr += src_width;
  193. dest += dest_width;
  194. src += src_width;
  195. }
  196. if (first < 0)
  197. return;
  198. s->invalidate = 0;
  199. cpu_physical_memory_reset_dirty(base + first * src_width,
  200. base + (last + 1) * src_width,
  201. VGA_DIRTY_FLAG);
  202. dpy_update(s->ds, 0, first, s->cols, last - first + 1);
  203. }
  204. static void pl110_invalidate_display(void * opaque)
  205. {
  206. pl110_state *s = (pl110_state *)opaque;
  207. s->invalidate = 1;
  208. }
  209. static void pl110_update_pallette(pl110_state *s, int n)
  210. {
  211. int i;
  212. uint32_t raw;
  213. unsigned int r, g, b;
  214. raw = s->raw_pallette[n];
  215. n <<= 1;
  216. for (i = 0; i < 2; i++) {
  217. r = (raw & 0x1f) << 3;
  218. raw >>= 5;
  219. g = (raw & 0x1f) << 3;
  220. raw >>= 5;
  221. b = (raw & 0x1f) << 3;
  222. /* The I bit is ignored. */
  223. raw >>= 6;
  224. switch (ds_get_bits_per_pixel(s->ds)) {
  225. case 8:
  226. s->pallette[n] = rgb_to_pixel8(r, g, b);
  227. break;
  228. case 15:
  229. s->pallette[n] = rgb_to_pixel15(r, g, b);
  230. break;
  231. case 16:
  232. s->pallette[n] = rgb_to_pixel16(r, g, b);
  233. break;
  234. case 24:
  235. case 32:
  236. s->pallette[n] = rgb_to_pixel32(r, g, b);
  237. break;
  238. }
  239. n++;
  240. }
  241. }
  242. static void pl110_resize(pl110_state *s, int width, int height)
  243. {
  244. if (width != s->cols || height != s->rows) {
  245. if (pl110_enabled(s)) {
  246. qemu_console_resize(s->ds, width, height);
  247. }
  248. }
  249. s->cols = width;
  250. s->rows = height;
  251. }
  252. /* Update interrupts. */
  253. static void pl110_update(pl110_state *s)
  254. {
  255. /* TODO: Implement interrupts. */
  256. }
  257. static uint32_t pl110_read(void *opaque, target_phys_addr_t offset)
  258. {
  259. pl110_state *s = (pl110_state *)opaque;
  260. if (offset >= 0xfe0 && offset < 0x1000) {
  261. if (s->versatile)
  262. return pl110_versatile_id[(offset - 0xfe0) >> 2];
  263. else
  264. return pl110_id[(offset - 0xfe0) >> 2];
  265. }
  266. if (offset >= 0x200 && offset < 0x400) {
  267. return s->raw_pallette[(offset - 0x200) >> 2];
  268. }
  269. switch (offset >> 2) {
  270. case 0: /* LCDTiming0 */
  271. return s->timing[0];
  272. case 1: /* LCDTiming1 */
  273. return s->timing[1];
  274. case 2: /* LCDTiming2 */
  275. return s->timing[2];
  276. case 3: /* LCDTiming3 */
  277. return s->timing[3];
  278. case 4: /* LCDUPBASE */
  279. return s->upbase;
  280. case 5: /* LCDLPBASE */
  281. return s->lpbase;
  282. case 6: /* LCDIMSC */
  283. if (s->versatile)
  284. return s->cr;
  285. return s->int_mask;
  286. case 7: /* LCDControl */
  287. if (s->versatile)
  288. return s->int_mask;
  289. return s->cr;
  290. case 8: /* LCDRIS */
  291. return s->int_status;
  292. case 9: /* LCDMIS */
  293. return s->int_status & s->int_mask;
  294. case 11: /* LCDUPCURR */
  295. /* TODO: Implement vertical refresh. */
  296. return s->upbase;
  297. case 12: /* LCDLPCURR */
  298. return s->lpbase;
  299. default:
  300. cpu_abort (cpu_single_env, "pl110_read: Bad offset %x\n", (int)offset);
  301. return 0;
  302. }
  303. }
  304. static void pl110_write(void *opaque, target_phys_addr_t offset,
  305. uint32_t val)
  306. {
  307. pl110_state *s = (pl110_state *)opaque;
  308. int n;
  309. /* For simplicity invalidate the display whenever a control register
  310. is writen to. */
  311. s->invalidate = 1;
  312. if (offset >= 0x200 && offset < 0x400) {
  313. /* Pallette. */
  314. n = (offset - 0x200) >> 2;
  315. s->raw_pallette[(offset - 0x200) >> 2] = val;
  316. pl110_update_pallette(s, n);
  317. return;
  318. }
  319. switch (offset >> 2) {
  320. case 0: /* LCDTiming0 */
  321. s->timing[0] = val;
  322. n = ((val & 0xfc) + 4) * 4;
  323. pl110_resize(s, n, s->rows);
  324. break;
  325. case 1: /* LCDTiming1 */
  326. s->timing[1] = val;
  327. n = (val & 0x3ff) + 1;
  328. pl110_resize(s, s->cols, n);
  329. break;
  330. case 2: /* LCDTiming2 */
  331. s->timing[2] = val;
  332. break;
  333. case 3: /* LCDTiming3 */
  334. s->timing[3] = val;
  335. break;
  336. case 4: /* LCDUPBASE */
  337. s->upbase = val;
  338. break;
  339. case 5: /* LCDLPBASE */
  340. s->lpbase = val;
  341. break;
  342. case 6: /* LCDIMSC */
  343. if (s->versatile)
  344. goto control;
  345. imsc:
  346. s->int_mask = val;
  347. pl110_update(s);
  348. break;
  349. case 7: /* LCDControl */
  350. if (s->versatile)
  351. goto imsc;
  352. control:
  353. s->cr = val;
  354. s->bpp = (val >> 1) & 7;
  355. if (pl110_enabled(s)) {
  356. qemu_console_resize(s->ds, s->cols, s->rows);
  357. }
  358. break;
  359. case 10: /* LCDICR */
  360. s->int_status &= ~val;
  361. pl110_update(s);
  362. break;
  363. default:
  364. cpu_abort (cpu_single_env, "pl110_write: Bad offset %x\n", (int)offset);
  365. }
  366. }
  367. static CPUReadMemoryFunc *pl110_readfn[] = {
  368. pl110_read,
  369. pl110_read,
  370. pl110_read
  371. };
  372. static CPUWriteMemoryFunc *pl110_writefn[] = {
  373. pl110_write,
  374. pl110_write,
  375. pl110_write
  376. };
  377. void *pl110_init(uint32_t base, qemu_irq irq, int versatile)
  378. {
  379. pl110_state *s;
  380. int iomemtype;
  381. s = (pl110_state *)qemu_mallocz(sizeof(pl110_state));
  382. iomemtype = cpu_register_io_memory(0, pl110_readfn,
  383. pl110_writefn, s);
  384. cpu_register_physical_memory(base, 0x00001000, iomemtype);
  385. s->versatile = versatile;
  386. s->irq = irq;
  387. s->ds = graphic_console_init(pl110_update_display,
  388. pl110_invalidate_display,
  389. NULL, NULL, s);
  390. /* ??? Save/restore. */
  391. return s;
  392. }