lcd.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * (C) Copyright 2003-2004
  3. * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
  4. *
  5. * (C) Copyright 2005
  6. * Stefan Roese, DENX Software Engineering, sr@denx.de.
  7. *
  8. * SPDX-License-Identifier: GPL-2.0+
  9. */
  10. #include <asm/io.h>
  11. #include "lcd.h"
  12. extern int video_display_bitmap (ulong, int, int);
  13. int palette_index;
  14. int palette_value;
  15. int lcd_depth;
  16. unsigned char *glob_lcd_reg;
  17. unsigned char *glob_lcd_mem;
  18. #if defined(CONFIG_SYS_LCD_ENDIAN)
  19. void lcd_setup(int lcd, int config)
  20. {
  21. if (lcd == 0) {
  22. /*
  23. * Set endianess and reset lcd controller 0 (small)
  24. */
  25. /* set reset to low */
  26. out_be32((void*)GPIO0_OR,
  27. in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD0_RST);
  28. udelay(10); /* wait 10us */
  29. if (config == 1) {
  30. /* big-endian */
  31. out_be32((void*)GPIO0_OR,
  32. in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD_ENDIAN);
  33. } else {
  34. /* little-endian */
  35. out_be32((void*)GPIO0_OR,
  36. in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD_ENDIAN);
  37. }
  38. udelay(10); /* wait 10us */
  39. /* set reset to high */
  40. out_be32((void*)GPIO0_OR,
  41. in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD0_RST);
  42. } else {
  43. /*
  44. * Set endianess and reset lcd controller 1 (big)
  45. */
  46. /* set reset to low */
  47. out_be32((void*)GPIO0_OR,
  48. in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD1_RST);
  49. udelay(10); /* wait 10us */
  50. if (config == 1) {
  51. /* big-endian */
  52. out_be32((void*)GPIO0_OR,
  53. in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD_ENDIAN);
  54. } else {
  55. /* little-endian */
  56. out_be32((void*)GPIO0_OR,
  57. in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD_ENDIAN);
  58. }
  59. udelay(10); /* wait 10us */
  60. /* set reset to high */
  61. out_be32((void*)GPIO0_OR,
  62. in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD1_RST);
  63. }
  64. /*
  65. * CONFIG_SYS_LCD_ENDIAN may also be FPGA_RESET, so set inactive
  66. */
  67. out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD_ENDIAN);
  68. }
  69. #endif /* CONFIG_SYS_LCD_ENDIAN */
  70. int lcd_bmp(uchar *logo_bmp)
  71. {
  72. int i;
  73. uchar *ptr;
  74. ushort *ptr2;
  75. ushort val;
  76. unsigned char *dst = NULL;
  77. int x, y;
  78. int width, height, bpp, colors, line_size;
  79. int header_size;
  80. unsigned char *bmp;
  81. unsigned char r, g, b;
  82. BITMAPINFOHEADER *bm_info;
  83. ulong len;
  84. /*
  85. * Check for bmp mark 'BM'
  86. */
  87. if (*(ushort *)logo_bmp != 0x424d) {
  88. /*
  89. * Decompress bmp image
  90. */
  91. len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
  92. dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
  93. if (dst == NULL) {
  94. printf("Error: malloc for gunzip failed!\n");
  95. return 1;
  96. }
  97. if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE,
  98. (uchar *)logo_bmp, &len) != 0) {
  99. free(dst);
  100. return 1;
  101. }
  102. if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
  103. printf("Image could be truncated"
  104. " (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
  105. }
  106. /*
  107. * Check for bmp mark 'BM'
  108. */
  109. if (*(ushort *)dst != 0x424d) {
  110. printf("LCD: Unknown image format!\n");
  111. free(dst);
  112. return 1;
  113. }
  114. } else {
  115. /*
  116. * Uncompressed BMP image, just use this pointer
  117. */
  118. dst = (uchar *)logo_bmp;
  119. }
  120. /*
  121. * Get image info from bmp-header
  122. */
  123. bm_info = (BITMAPINFOHEADER *)(dst + 14);
  124. bpp = LOAD_SHORT(bm_info->biBitCount);
  125. width = LOAD_LONG(bm_info->biWidth);
  126. height = LOAD_LONG(bm_info->biHeight);
  127. switch (bpp) {
  128. case 1:
  129. colors = 1;
  130. line_size = width >> 3;
  131. break;
  132. case 4:
  133. colors = 16;
  134. line_size = width >> 1;
  135. break;
  136. case 8:
  137. colors = 256;
  138. line_size = width;
  139. break;
  140. case 24:
  141. colors = 0;
  142. line_size = width * 3;
  143. break;
  144. default:
  145. printf("LCD: Unknown bpp (%d) im image!\n", bpp);
  146. if ((dst != NULL) && (dst != (uchar *)logo_bmp))
  147. free(dst);
  148. return 1;
  149. }
  150. printf(" (%d*%d, %dbpp)\n", width, height, bpp);
  151. /*
  152. * Write color palette
  153. */
  154. if ((colors <= 256) && (lcd_depth <= 8)) {
  155. ptr = (unsigned char *)(dst + 14 + 40);
  156. for (i = 0; i < colors; i++) {
  157. b = *ptr++;
  158. g = *ptr++;
  159. r = *ptr++;
  160. ptr++;
  161. S1D_WRITE_PALETTE(glob_lcd_reg, i, r, g, b);
  162. }
  163. }
  164. /*
  165. * Write bitmap data into framebuffer
  166. */
  167. ptr = glob_lcd_mem;
  168. ptr2 = (ushort *)glob_lcd_mem;
  169. header_size = 14 + 40 + 4*colors; /* skip bmp header */
  170. for (y = 0; y < height; y++) {
  171. bmp = &dst[(height-1-y)*line_size + header_size];
  172. if (lcd_depth == 16) {
  173. if (bpp == 24) {
  174. for (x = 0; x < width; x++) {
  175. /*
  176. * Generate epson 16bpp fb-format
  177. * from 24bpp image
  178. */
  179. b = *bmp++ >> 3;
  180. g = *bmp++ >> 2;
  181. r = *bmp++ >> 3;
  182. val = ((r & 0x1f) << 11) |
  183. ((g & 0x3f) << 5) |
  184. (b & 0x1f);
  185. *ptr2++ = val;
  186. }
  187. } else if (bpp == 8) {
  188. for (x = 0; x < line_size; x++) {
  189. /* query rgb value from palette */
  190. ptr = (unsigned char *)(dst + 14 + 40);
  191. ptr += (*bmp++) << 2;
  192. b = *ptr++ >> 3;
  193. g = *ptr++ >> 2;
  194. r = *ptr++ >> 3;
  195. val = ((r & 0x1f) << 11) |
  196. ((g & 0x3f) << 5) |
  197. (b & 0x1f);
  198. *ptr2++ = val;
  199. }
  200. }
  201. } else {
  202. for (x = 0; x < line_size; x++)
  203. *ptr++ = *bmp++;
  204. }
  205. }
  206. if ((dst != NULL) && (dst != (uchar *)logo_bmp))
  207. free(dst);
  208. return 0;
  209. }
  210. int lcd_init(uchar *lcd_reg, uchar *lcd_mem, S1D_REGS *regs, int reg_count,
  211. uchar *logo_bmp, ulong len)
  212. {
  213. int i;
  214. ushort s1dReg;
  215. uchar s1dValue;
  216. int reg_byte_swap;
  217. /*
  218. * Detect epson
  219. */
  220. out_8(&lcd_reg[0], 0x00);
  221. out_8(&lcd_reg[1], 0x00);
  222. if (in_8(&lcd_reg[0]) == 0x1c) {
  223. /*
  224. * Big epson detected
  225. */
  226. reg_byte_swap = false;
  227. palette_index = 0x1e2;
  228. palette_value = 0x1e4;
  229. lcd_depth = 16;
  230. puts("LCD: S1D13806");
  231. } else if (in_8(&lcd_reg[1]) == 0x1c) {
  232. /*
  233. * Big epson detected (with register swap bug)
  234. */
  235. reg_byte_swap = true;
  236. palette_index = 0x1e3;
  237. palette_value = 0x1e5;
  238. lcd_depth = 16;
  239. puts("LCD: S1D13806S");
  240. } else if (in_8(&lcd_reg[0]) == 0x18) {
  241. /*
  242. * Small epson detected (704)
  243. */
  244. reg_byte_swap = false;
  245. palette_index = 0x15;
  246. palette_value = 0x17;
  247. lcd_depth = 8;
  248. puts("LCD: S1D13704");
  249. } else if (in_8(&lcd_reg[0x10000]) == 0x24) {
  250. /*
  251. * Small epson detected (705)
  252. */
  253. reg_byte_swap = false;
  254. palette_index = 0x15;
  255. palette_value = 0x17;
  256. lcd_depth = 8;
  257. lcd_reg += 0x10000; /* add offset for 705 regs */
  258. puts("LCD: S1D13705");
  259. } else {
  260. out_8(&lcd_reg[0x1a], 0x00);
  261. udelay(1000);
  262. if (in_8(&lcd_reg[1]) == 0x0c) {
  263. /*
  264. * S1D13505 detected
  265. */
  266. reg_byte_swap = true;
  267. palette_index = 0x25;
  268. palette_value = 0x27;
  269. lcd_depth = 16;
  270. puts("LCD: S1D13505");
  271. } else {
  272. puts("LCD: No controller detected!\n");
  273. return 1;
  274. }
  275. }
  276. /*
  277. * Setup lcd controller regs
  278. */
  279. for (i = 0; i < reg_count; i++) {
  280. s1dReg = regs[i].Index;
  281. if (reg_byte_swap) {
  282. if ((s1dReg & 0x0001) == 0)
  283. s1dReg |= 0x0001;
  284. else
  285. s1dReg &= ~0x0001;
  286. }
  287. s1dValue = regs[i].Value;
  288. out_8(&lcd_reg[s1dReg], s1dValue);
  289. }
  290. /*
  291. * Save reg & mem pointer for later usage (e.g. bmp command)
  292. */
  293. glob_lcd_reg = lcd_reg;
  294. glob_lcd_mem = lcd_mem;
  295. /*
  296. * Display bmp image
  297. */
  298. return lcd_bmp(logo_bmp);
  299. }
  300. int do_esdbmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  301. {
  302. ulong addr;
  303. #ifdef CONFIG_VIDEO_SM501
  304. char *str;
  305. #endif
  306. if (argc != 2)
  307. return cmd_usage(cmdtp);
  308. addr = simple_strtoul(argv[1], NULL, 16);
  309. #ifdef CONFIG_VIDEO_SM501
  310. str = getenv("bd_type");
  311. if ((strcmp(str, "ppc221") == 0) || (strcmp(str, "ppc231") == 0)) {
  312. /*
  313. * SM501 available, use standard bmp command
  314. */
  315. return video_display_bitmap(addr, 0, 0);
  316. } else {
  317. /*
  318. * No SM501 available, use esd epson bmp command
  319. */
  320. return lcd_bmp((uchar *)addr);
  321. }
  322. #else
  323. return lcd_bmp((uchar *)addr);
  324. #endif
  325. }
  326. U_BOOT_CMD(
  327. esdbmp, 2, 1, do_esdbmp,
  328. "display BMP image",
  329. "<imageAddr> - display image"
  330. );