blob: 29421fce2ee772bcc4815e355c59ab80a8556790 [file] [log] [blame]
stroese0621f6f2004-12-16 18:43:13 +00001/*
2 * (C) Copyright 2003-2004
3 * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
4 *
Stefan Roese98f4a3d2005-09-22 09:04:17 +02005 * (C) Copyright 2005
6 * Stefan Roese, DENX Software Engineering, sr@denx.de.
7 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
stroese0621f6f2004-12-16 18:43:13 +00009 */
10
Masahiro Yamadab5bf5cb2016-09-21 11:28:53 +090011#include <asm/io.h>
stroese0621f6f2004-12-16 18:43:13 +000012#include "lcd.h"
13
14
Stefan Roese98f4a3d2005-09-22 09:04:17 +020015extern int video_display_bitmap (ulong, int, int);
16
17
stroese0621f6f2004-12-16 18:43:13 +000018int palette_index;
19int palette_value;
Stefan Roese98f4a3d2005-09-22 09:04:17 +020020int lcd_depth;
21unsigned char *glob_lcd_reg;
22unsigned char *glob_lcd_mem;
stroese0621f6f2004-12-16 18:43:13 +000023
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020024#if defined(CONFIG_SYS_LCD_ENDIAN)
stroese0621f6f2004-12-16 18:43:13 +000025void lcd_setup(int lcd, int config)
26{
27 if (lcd == 0) {
28 /*
29 * Set endianess and reset lcd controller 0 (small)
30 */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020031
32 /* set reset to low */
33 out_be32((void*)GPIO0_OR,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020034 in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD0_RST);
stroese0621f6f2004-12-16 18:43:13 +000035 udelay(10); /* wait 10us */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020036 if (config == 1) {
37 /* big-endian */
38 out_be32((void*)GPIO0_OR,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020039 in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD_ENDIAN);
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020040 } else {
41 /* little-endian */
42 out_be32((void*)GPIO0_OR,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020043 in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD_ENDIAN);
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020044 }
stroese0621f6f2004-12-16 18:43:13 +000045 udelay(10); /* wait 10us */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020046 /* set reset to high */
47 out_be32((void*)GPIO0_OR,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020048 in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD0_RST);
stroese0621f6f2004-12-16 18:43:13 +000049 } else {
50 /*
51 * Set endianess and reset lcd controller 1 (big)
52 */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020053
54 /* set reset to low */
55 out_be32((void*)GPIO0_OR,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020056 in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD1_RST);
stroese0621f6f2004-12-16 18:43:13 +000057 udelay(10); /* wait 10us */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020058 if (config == 1) {
59 /* big-endian */
60 out_be32((void*)GPIO0_OR,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020061 in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD_ENDIAN);
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020062 } else {
63 /* little-endian */
64 out_be32((void*)GPIO0_OR,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020065 in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD_ENDIAN);
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020066 }
stroese0621f6f2004-12-16 18:43:13 +000067 udelay(10); /* wait 10us */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020068 /* set reset to high */
69 out_be32((void*)GPIO0_OR,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020070 in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD1_RST);
stroese0621f6f2004-12-16 18:43:13 +000071 }
72
73 /*
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020074 * CONFIG_SYS_LCD_ENDIAN may also be FPGA_RESET, so set inactive
stroese0621f6f2004-12-16 18:43:13 +000075 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020076 out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD_ENDIAN);
stroese0621f6f2004-12-16 18:43:13 +000077}
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020078#endif /* CONFIG_SYS_LCD_ENDIAN */
stroese0621f6f2004-12-16 18:43:13 +000079
80
Matthias Fuchsb9233fe2008-04-21 14:41:59 +020081int lcd_bmp(uchar *logo_bmp)
stroese0621f6f2004-12-16 18:43:13 +000082{
83 int i;
stroese0621f6f2004-12-16 18:43:13 +000084 uchar *ptr;
85 ushort *ptr2;
86 ushort val;
Stefan Roesec29ab9d2005-10-08 10:19:07 +020087 unsigned char *dst = NULL;
stroese0621f6f2004-12-16 18:43:13 +000088 int x, y;
89 int width, height, bpp, colors, line_size;
90 int header_size;
91 unsigned char *bmp;
92 unsigned char r, g, b;
93 BITMAPINFOHEADER *bm_info;
Stefan Roese98f4a3d2005-09-22 09:04:17 +020094 ulong len;
stroese0621f6f2004-12-16 18:43:13 +000095
96 /*
97 * Check for bmp mark 'BM'
98 */
Stefan Roese98f4a3d2005-09-22 09:04:17 +020099 if (*(ushort *)logo_bmp != 0x424d) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200100 /*
101 * Decompress bmp image
102 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200103 len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
104 dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
Stefan Roesec29ab9d2005-10-08 10:19:07 +0200105 if (dst == NULL) {
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200106 printf("Error: malloc for gunzip failed!\n");
107 return 1;
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200108 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200109 if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE,
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200110 (uchar *)logo_bmp, &len) != 0) {
111 free(dst);
112 return 1;
113 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200114 if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200115 printf("Image could be truncated"
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200116 " (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200117 }
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200118
119 /*
120 * Check for bmp mark 'BM'
121 */
122 if (*(ushort *)dst != 0x424d) {
123 printf("LCD: Unknown image format!\n");
124 free(dst);
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200125 return 1;
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200126 }
127 } else {
128 /*
129 * Uncompressed BMP image, just use this pointer
130 */
131 dst = (uchar *)logo_bmp;
stroese0621f6f2004-12-16 18:43:13 +0000132 }
133
134 /*
135 * Get image info from bmp-header
136 */
137 bm_info = (BITMAPINFOHEADER *)(dst + 14);
138 bpp = LOAD_SHORT(bm_info->biBitCount);
139 width = LOAD_LONG(bm_info->biWidth);
140 height = LOAD_LONG(bm_info->biHeight);
141 switch (bpp) {
142 case 1:
143 colors = 1;
144 line_size = width >> 3;
145 break;
146 case 4:
147 colors = 16;
148 line_size = width >> 1;
149 break;
150 case 8:
151 colors = 256;
152 line_size = width;
153 break;
154 case 24:
155 colors = 0;
156 line_size = width * 3;
157 break;
158 default:
159 printf("LCD: Unknown bpp (%d) im image!\n", bpp);
Stefan Roesee174ac32007-12-28 17:29:56 +0100160 if ((dst != NULL) && (dst != (uchar *)logo_bmp))
Stefan Roesec29ab9d2005-10-08 10:19:07 +0200161 free(dst);
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200162 return 1;
stroese0621f6f2004-12-16 18:43:13 +0000163 }
164 printf(" (%d*%d, %dbpp)\n", width, height, bpp);
165
166 /*
167 * Write color palette
168 */
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200169 if ((colors <= 256) && (lcd_depth <= 8)) {
stroese0621f6f2004-12-16 18:43:13 +0000170 ptr = (unsigned char *)(dst + 14 + 40);
Matthias Fuchs9ac6b6f2008-01-02 12:05:14 +0100171 for (i = 0; i < colors; i++) {
stroese0621f6f2004-12-16 18:43:13 +0000172 b = *ptr++;
173 g = *ptr++;
174 r = *ptr++;
175 ptr++;
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200176 S1D_WRITE_PALETTE(glob_lcd_reg, i, r, g, b);
stroese0621f6f2004-12-16 18:43:13 +0000177 }
178 }
179
180 /*
181 * Write bitmap data into framebuffer
182 */
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200183 ptr = glob_lcd_mem;
184 ptr2 = (ushort *)glob_lcd_mem;
stroese0621f6f2004-12-16 18:43:13 +0000185 header_size = 14 + 40 + 4*colors; /* skip bmp header */
Matthias Fuchs9ac6b6f2008-01-02 12:05:14 +0100186 for (y = 0; y < height; y++) {
stroese0621f6f2004-12-16 18:43:13 +0000187 bmp = &dst[(height-1-y)*line_size + header_size];
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200188 if (lcd_depth == 16) {
189 if (bpp == 24) {
Matthias Fuchs9ac6b6f2008-01-02 12:05:14 +0100190 for (x = 0; x < width; x++) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200191 /*
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200192 * Generate epson 16bpp fb-format
193 * from 24bpp image
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200194 */
195 b = *bmp++ >> 3;
196 g = *bmp++ >> 2;
197 r = *bmp++ >> 3;
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200198 val = ((r & 0x1f) << 11) |
199 ((g & 0x3f) << 5) |
200 (b & 0x1f);
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200201 *ptr2++ = val;
202 }
203 } else if (bpp == 8) {
Matthias Fuchs9ac6b6f2008-01-02 12:05:14 +0100204 for (x = 0; x < line_size; x++) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200205 /* query rgb value from palette */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200206 ptr = (unsigned char *)(dst + 14 + 40);
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200207 ptr += (*bmp++) << 2;
208 b = *ptr++ >> 3;
209 g = *ptr++ >> 2;
210 r = *ptr++ >> 3;
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200211 val = ((r & 0x1f) << 11) |
212 ((g & 0x3f) << 5) |
213 (b & 0x1f);
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200214 *ptr2++ = val;
215 }
stroese0621f6f2004-12-16 18:43:13 +0000216 }
217 } else {
Matthias Fuchs9ac6b6f2008-01-02 12:05:14 +0100218 for (x = 0; x < line_size; x++)
stroese0621f6f2004-12-16 18:43:13 +0000219 *ptr++ = *bmp++;
stroese0621f6f2004-12-16 18:43:13 +0000220 }
221 }
222
Stefan Roesee174ac32007-12-28 17:29:56 +0100223 if ((dst != NULL) && (dst != (uchar *)logo_bmp))
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200224 free(dst);
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200225 return 0;
stroese0621f6f2004-12-16 18:43:13 +0000226}
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200227
228
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200229int lcd_init(uchar *lcd_reg, uchar *lcd_mem, S1D_REGS *regs, int reg_count,
230 uchar *logo_bmp, ulong len)
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200231{
232 int i;
233 ushort s1dReg;
234 uchar s1dValue;
235 int reg_byte_swap;
236
237 /*
238 * Detect epson
239 */
Matthias Fuchs77660c42007-12-28 17:10:44 +0100240 out_8(&lcd_reg[0], 0x00);
241 out_8(&lcd_reg[1], 0x00);
Stefan Roese48a05a52006-02-07 16:51:04 +0100242
Stefan Roesee174ac32007-12-28 17:29:56 +0100243 if (in_8(&lcd_reg[0]) == 0x1c) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200244 /*
245 * Big epson detected
246 */
York Sun472d5462013-04-01 11:29:11 -0700247 reg_byte_swap = false;
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200248 palette_index = 0x1e2;
249 palette_value = 0x1e4;
250 lcd_depth = 16;
251 puts("LCD: S1D13806");
Stefan Roesee174ac32007-12-28 17:29:56 +0100252 } else if (in_8(&lcd_reg[1]) == 0x1c) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200253 /*
254 * Big epson detected (with register swap bug)
255 */
York Sun472d5462013-04-01 11:29:11 -0700256 reg_byte_swap = true;
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200257 palette_index = 0x1e3;
258 palette_value = 0x1e5;
259 lcd_depth = 16;
260 puts("LCD: S1D13806S");
Stefan Roesee174ac32007-12-28 17:29:56 +0100261 } else if (in_8(&lcd_reg[0]) == 0x18) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200262 /*
263 * Small epson detected (704)
264 */
York Sun472d5462013-04-01 11:29:11 -0700265 reg_byte_swap = false;
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200266 palette_index = 0x15;
267 palette_value = 0x17;
268 lcd_depth = 8;
269 puts("LCD: S1D13704");
Matthias Fuchs9ac6b6f2008-01-02 12:05:14 +0100270 } else if (in_8(&lcd_reg[0x10000]) == 0x24) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200271 /*
272 * Small epson detected (705)
273 */
York Sun472d5462013-04-01 11:29:11 -0700274 reg_byte_swap = false;
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200275 palette_index = 0x15;
276 palette_value = 0x17;
277 lcd_depth = 8;
278 lcd_reg += 0x10000; /* add offset for 705 regs */
279 puts("LCD: S1D13705");
280 } else {
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200281 out_8(&lcd_reg[0x1a], 0x00);
282 udelay(1000);
283 if (in_8(&lcd_reg[1]) == 0x0c) {
284 /*
285 * S1D13505 detected
286 */
York Sun472d5462013-04-01 11:29:11 -0700287 reg_byte_swap = true;
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200288 palette_index = 0x25;
289 palette_value = 0x27;
290 lcd_depth = 16;
291
292 puts("LCD: S1D13505");
293 } else {
294 puts("LCD: No controller detected!\n");
295 return 1;
296 }
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200297 }
298
299 /*
300 * Setup lcd controller regs
301 */
Matthias Fuchs77660c42007-12-28 17:10:44 +0100302 for (i = 0; i < reg_count; i++) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200303 s1dReg = regs[i].Index;
304 if (reg_byte_swap) {
305 if ((s1dReg & 0x0001) == 0)
306 s1dReg |= 0x0001;
307 else
308 s1dReg &= ~0x0001;
309 }
310 s1dValue = regs[i].Value;
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200311 out_8(&lcd_reg[s1dReg], s1dValue);
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200312 }
313
314 /*
315 * Save reg & mem pointer for later usage (e.g. bmp command)
316 */
317 glob_lcd_reg = lcd_reg;
318 glob_lcd_mem = lcd_mem;
319
320 /*
321 * Display bmp image
322 */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200323 return lcd_bmp(logo_bmp);
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200324}
325
Wolfgang Denk54841ab2010-06-28 22:00:46 +0200326int do_esdbmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200327{
328 ulong addr;
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200329#ifdef CONFIG_VIDEO_SM501
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200330 char *str;
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200331#endif
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200332 if (argc != 2)
333 return cmd_usage(cmdtp);
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200334
335 addr = simple_strtoul(argv[1], NULL, 16);
336
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200337#ifdef CONFIG_VIDEO_SM501
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200338 str = getenv("bd_type");
339 if ((strcmp(str, "ppc221") == 0) || (strcmp(str, "ppc231") == 0)) {
340 /*
341 * SM501 available, use standard bmp command
342 */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200343 return video_display_bitmap(addr, 0, 0);
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200344 } else {
345 /*
346 * No SM501 available, use esd epson bmp command
347 */
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200348 return lcd_bmp((uchar *)addr);
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200349 }
Matthias Fuchsb9233fe2008-04-21 14:41:59 +0200350#else
351 return lcd_bmp((uchar *)addr);
352#endif
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200353}
354
355U_BOOT_CMD(
356 esdbmp, 2, 1, do_esdbmp,
Peter Tyser2fb26042009-01-27 18:03:12 -0600357 "display BMP image",
Wolfgang Denka89c33d2009-05-24 17:06:54 +0200358 "<imageAddr> - display image"
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200359);