]>
Commit | Line | Data |
---|---|---|
0621f6f9 SR |
1 | /* |
2 | * (C) Copyright 2003-2004 | |
3 | * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com | |
4 | * | |
98f4a3df SR |
5 | * (C) Copyright 2005 |
6 | * Stefan Roese, DENX Software Engineering, sr@denx.de. | |
7 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
0621f6f9 SR |
9 | */ |
10 | ||
b5bf5cb3 | 11 | #include <asm/io.h> |
0621f6f9 SR |
12 | #include "lcd.h" |
13 | ||
14 | ||
98f4a3df SR |
15 | extern int video_display_bitmap (ulong, int, int); |
16 | ||
17 | ||
0621f6f9 SR |
18 | int palette_index; |
19 | int palette_value; | |
98f4a3df SR |
20 | int lcd_depth; |
21 | unsigned char *glob_lcd_reg; | |
22 | unsigned char *glob_lcd_mem; | |
0621f6f9 | 23 | |
6d0f6bcf | 24 | #if defined(CONFIG_SYS_LCD_ENDIAN) |
0621f6f9 SR |
25 | void lcd_setup(int lcd, int config) |
26 | { | |
27 | if (lcd == 0) { | |
28 | /* | |
29 | * Set endianess and reset lcd controller 0 (small) | |
30 | */ | |
b9233fe5 MF |
31 | |
32 | /* set reset to low */ | |
33 | out_be32((void*)GPIO0_OR, | |
6d0f6bcf | 34 | in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD0_RST); |
0621f6f9 | 35 | udelay(10); /* wait 10us */ |
b9233fe5 MF |
36 | if (config == 1) { |
37 | /* big-endian */ | |
38 | out_be32((void*)GPIO0_OR, | |
6d0f6bcf | 39 | in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD_ENDIAN); |
b9233fe5 MF |
40 | } else { |
41 | /* little-endian */ | |
42 | out_be32((void*)GPIO0_OR, | |
6d0f6bcf | 43 | in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD_ENDIAN); |
b9233fe5 | 44 | } |
0621f6f9 | 45 | udelay(10); /* wait 10us */ |
b9233fe5 MF |
46 | /* set reset to high */ |
47 | out_be32((void*)GPIO0_OR, | |
6d0f6bcf | 48 | in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD0_RST); |
0621f6f9 SR |
49 | } else { |
50 | /* | |
51 | * Set endianess and reset lcd controller 1 (big) | |
52 | */ | |
b9233fe5 MF |
53 | |
54 | /* set reset to low */ | |
55 | out_be32((void*)GPIO0_OR, | |
6d0f6bcf | 56 | in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD1_RST); |
0621f6f9 | 57 | udelay(10); /* wait 10us */ |
b9233fe5 MF |
58 | if (config == 1) { |
59 | /* big-endian */ | |
60 | out_be32((void*)GPIO0_OR, | |
6d0f6bcf | 61 | in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD_ENDIAN); |
b9233fe5 MF |
62 | } else { |
63 | /* little-endian */ | |
64 | out_be32((void*)GPIO0_OR, | |
6d0f6bcf | 65 | in_be32((void*)GPIO0_OR) & ~CONFIG_SYS_LCD_ENDIAN); |
b9233fe5 | 66 | } |
0621f6f9 | 67 | udelay(10); /* wait 10us */ |
b9233fe5 MF |
68 | /* set reset to high */ |
69 | out_be32((void*)GPIO0_OR, | |
6d0f6bcf | 70 | in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD1_RST); |
0621f6f9 SR |
71 | } |
72 | ||
73 | /* | |
6d0f6bcf | 74 | * CONFIG_SYS_LCD_ENDIAN may also be FPGA_RESET, so set inactive |
0621f6f9 | 75 | */ |
6d0f6bcf | 76 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) | CONFIG_SYS_LCD_ENDIAN); |
0621f6f9 | 77 | } |
6d0f6bcf | 78 | #endif /* CONFIG_SYS_LCD_ENDIAN */ |
0621f6f9 SR |
79 | |
80 | ||
b9233fe5 | 81 | int lcd_bmp(uchar *logo_bmp) |
0621f6f9 SR |
82 | { |
83 | int i; | |
0621f6f9 SR |
84 | uchar *ptr; |
85 | ushort *ptr2; | |
86 | ushort val; | |
c29ab9d7 | 87 | unsigned char *dst = NULL; |
0621f6f9 SR |
88 | 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; | |
98f4a3df | 94 | ulong len; |
0621f6f9 SR |
95 | |
96 | /* | |
98f4a3df | 97 | * Check for bmp mark 'BM' |
0621f6f9 | 98 | */ |
98f4a3df | 99 | if (*(ushort *)logo_bmp != 0x424d) { |
0621f6f9 | 100 | /* |
98f4a3df | 101 | * Decompress bmp image |
0621f6f9 | 102 | */ |
6d0f6bcf JCPV |
103 | len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE; |
104 | dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE); | |
c29ab9d7 | 105 | if (dst == NULL) { |
b9233fe5 MF |
106 | printf("Error: malloc for gunzip failed!\n"); |
107 | return 1; | |
108 | } | |
6d0f6bcf | 109 | if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, |
b9233fe5 MF |
110 | (uchar *)logo_bmp, &len) != 0) { |
111 | free(dst); | |
112 | return 1; | |
113 | } | |
6d0f6bcf | 114 | if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) { |
b9233fe5 | 115 | printf("Image could be truncated" |
6d0f6bcf | 116 | " (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n"); |
98f4a3df SR |
117 | } |
118 | ||
0621f6f9 | 119 | /* |
98f4a3df | 120 | * Check for bmp mark 'BM' |
0621f6f9 | 121 | */ |
98f4a3df SR |
122 | if (*(ushort *)dst != 0x424d) { |
123 | printf("LCD: Unknown image format!\n"); | |
124 | free(dst); | |
b9233fe5 | 125 | return 1; |
98f4a3df SR |
126 | } |
127 | } else { | |
0621f6f9 | 128 | /* |
98f4a3df | 129 | * Uncompressed BMP image, just use this pointer |
0621f6f9 | 130 | */ |
98f4a3df | 131 | dst = (uchar *)logo_bmp; |
0621f6f9 SR |
132 | } |
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); | |
e174ac34 | 160 | if ((dst != NULL) && (dst != (uchar *)logo_bmp)) |
c29ab9d7 | 161 | free(dst); |
b9233fe5 | 162 | return 1; |
0621f6f9 SR |
163 | } |
164 | printf(" (%d*%d, %dbpp)\n", width, height, bpp); | |
165 | ||
166 | /* | |
167 | * Write color palette | |
168 | */ | |
98f4a3df | 169 | if ((colors <= 256) && (lcd_depth <= 8)) { |
0621f6f9 | 170 | ptr = (unsigned char *)(dst + 14 + 40); |
9ac6b6f3 | 171 | for (i = 0; i < colors; i++) { |
0621f6f9 SR |
172 | b = *ptr++; |
173 | g = *ptr++; | |
174 | r = *ptr++; | |
175 | ptr++; | |
98f4a3df | 176 | S1D_WRITE_PALETTE(glob_lcd_reg, i, r, g, b); |
0621f6f9 SR |
177 | } |
178 | } | |
179 | ||
180 | /* | |
181 | * Write bitmap data into framebuffer | |
182 | */ | |
98f4a3df SR |
183 | ptr = glob_lcd_mem; |
184 | ptr2 = (ushort *)glob_lcd_mem; | |
0621f6f9 | 185 | header_size = 14 + 40 + 4*colors; /* skip bmp header */ |
9ac6b6f3 | 186 | for (y = 0; y < height; y++) { |
0621f6f9 | 187 | bmp = &dst[(height-1-y)*line_size + header_size]; |
98f4a3df SR |
188 | if (lcd_depth == 16) { |
189 | if (bpp == 24) { | |
9ac6b6f3 | 190 | for (x = 0; x < width; x++) { |
98f4a3df | 191 | /* |
b9233fe5 MF |
192 | * Generate epson 16bpp fb-format |
193 | * from 24bpp image | |
98f4a3df SR |
194 | */ |
195 | b = *bmp++ >> 3; | |
196 | g = *bmp++ >> 2; | |
197 | r = *bmp++ >> 3; | |
b9233fe5 MF |
198 | val = ((r & 0x1f) << 11) | |
199 | ((g & 0x3f) << 5) | | |
200 | (b & 0x1f); | |
98f4a3df SR |
201 | *ptr2++ = val; |
202 | } | |
203 | } else if (bpp == 8) { | |
9ac6b6f3 | 204 | for (x = 0; x < line_size; x++) { |
98f4a3df | 205 | /* query rgb value from palette */ |
b9233fe5 | 206 | ptr = (unsigned char *)(dst + 14 + 40); |
98f4a3df SR |
207 | ptr += (*bmp++) << 2; |
208 | b = *ptr++ >> 3; | |
209 | g = *ptr++ >> 2; | |
210 | r = *ptr++ >> 3; | |
b9233fe5 MF |
211 | val = ((r & 0x1f) << 11) | |
212 | ((g & 0x3f) << 5) | | |
213 | (b & 0x1f); | |
98f4a3df SR |
214 | *ptr2++ = val; |
215 | } | |
0621f6f9 SR |
216 | } |
217 | } else { | |
9ac6b6f3 | 218 | for (x = 0; x < line_size; x++) |
0621f6f9 | 219 | *ptr++ = *bmp++; |
0621f6f9 SR |
220 | } |
221 | } | |
222 | ||
e174ac34 | 223 | if ((dst != NULL) && (dst != (uchar *)logo_bmp)) |
98f4a3df | 224 | free(dst); |
b9233fe5 | 225 | return 0; |
98f4a3df SR |
226 | } |
227 | ||
228 | ||
b9233fe5 MF |
229 | int lcd_init(uchar *lcd_reg, uchar *lcd_mem, S1D_REGS *regs, int reg_count, |
230 | uchar *logo_bmp, ulong len) | |
98f4a3df SR |
231 | { |
232 | int i; | |
233 | ushort s1dReg; | |
234 | uchar s1dValue; | |
235 | int reg_byte_swap; | |
236 | ||
237 | /* | |
238 | * Detect epson | |
239 | */ | |
77660c4b MF |
240 | out_8(&lcd_reg[0], 0x00); |
241 | out_8(&lcd_reg[1], 0x00); | |
48a05a51 | 242 | |
e174ac34 | 243 | if (in_8(&lcd_reg[0]) == 0x1c) { |
98f4a3df SR |
244 | /* |
245 | * Big epson detected | |
246 | */ | |
472d5460 | 247 | reg_byte_swap = false; |
98f4a3df SR |
248 | palette_index = 0x1e2; |
249 | palette_value = 0x1e4; | |
250 | lcd_depth = 16; | |
251 | puts("LCD: S1D13806"); | |
e174ac34 | 252 | } else if (in_8(&lcd_reg[1]) == 0x1c) { |
98f4a3df SR |
253 | /* |
254 | * Big epson detected (with register swap bug) | |
255 | */ | |
472d5460 | 256 | reg_byte_swap = true; |
98f4a3df SR |
257 | palette_index = 0x1e3; |
258 | palette_value = 0x1e5; | |
259 | lcd_depth = 16; | |
260 | puts("LCD: S1D13806S"); | |
e174ac34 | 261 | } else if (in_8(&lcd_reg[0]) == 0x18) { |
98f4a3df SR |
262 | /* |
263 | * Small epson detected (704) | |
264 | */ | |
472d5460 | 265 | reg_byte_swap = false; |
98f4a3df SR |
266 | palette_index = 0x15; |
267 | palette_value = 0x17; | |
268 | lcd_depth = 8; | |
269 | puts("LCD: S1D13704"); | |
9ac6b6f3 | 270 | } else if (in_8(&lcd_reg[0x10000]) == 0x24) { |
98f4a3df SR |
271 | /* |
272 | * Small epson detected (705) | |
273 | */ | |
472d5460 | 274 | reg_byte_swap = false; |
98f4a3df SR |
275 | 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 { | |
b9233fe5 MF |
281 | out_8(&lcd_reg[0x1a], 0x00); |
282 | udelay(1000); | |
283 | if (in_8(&lcd_reg[1]) == 0x0c) { | |
284 | /* | |
285 | * S1D13505 detected | |
286 | */ | |
472d5460 | 287 | reg_byte_swap = true; |
b9233fe5 MF |
288 | 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 | } | |
98f4a3df SR |
297 | } |
298 | ||
299 | /* | |
300 | * Setup lcd controller regs | |
301 | */ | |
77660c4b | 302 | for (i = 0; i < reg_count; i++) { |
98f4a3df SR |
303 | 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; | |
b9233fe5 | 311 | out_8(&lcd_reg[s1dReg], s1dValue); |
98f4a3df SR |
312 | } |
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 | */ | |
b9233fe5 | 323 | return lcd_bmp(logo_bmp); |
0621f6f9 | 324 | } |
98f4a3df | 325 | |
54841ab5 | 326 | int do_esdbmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
98f4a3df SR |
327 | { |
328 | ulong addr; | |
b9233fe5 | 329 | #ifdef CONFIG_VIDEO_SM501 |
98f4a3df | 330 | char *str; |
b9233fe5 | 331 | #endif |
47e26b1b WD |
332 | if (argc != 2) |
333 | return cmd_usage(cmdtp); | |
98f4a3df SR |
334 | |
335 | addr = simple_strtoul(argv[1], NULL, 16); | |
336 | ||
b9233fe5 | 337 | #ifdef CONFIG_VIDEO_SM501 |
98f4a3df SR |
338 | str = getenv("bd_type"); |
339 | if ((strcmp(str, "ppc221") == 0) || (strcmp(str, "ppc231") == 0)) { | |
340 | /* | |
341 | * SM501 available, use standard bmp command | |
342 | */ | |
b9233fe5 | 343 | return video_display_bitmap(addr, 0, 0); |
98f4a3df SR |
344 | } else { |
345 | /* | |
346 | * No SM501 available, use esd epson bmp command | |
347 | */ | |
b9233fe5 | 348 | return lcd_bmp((uchar *)addr); |
98f4a3df | 349 | } |
b9233fe5 MF |
350 | #else |
351 | return lcd_bmp((uchar *)addr); | |
352 | #endif | |
98f4a3df SR |
353 | } |
354 | ||
355 | U_BOOT_CMD( | |
356 | esdbmp, 2, 1, do_esdbmp, | |
2fb2604d | 357 | "display BMP image", |
a89c33db | 358 | "<imageAddr> - display image" |
98f4a3df | 359 | ); |