]>
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 | * | |
0621f6f9 SR |
8 | * See file CREDITS for list of people who contributed to this |
9 | * project. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License as | |
13 | * published by the Free Software Foundation; either version 2 of | |
14 | * the License, or (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
24 | * MA 02111-1307 USA | |
25 | */ | |
26 | ||
77660c4b | 27 | #include "asm/io.h" |
0621f6f9 SR |
28 | #include "lcd.h" |
29 | ||
30 | ||
98f4a3df SR |
31 | extern int video_display_bitmap (ulong, int, int); |
32 | ||
33 | ||
0621f6f9 SR |
34 | int palette_index; |
35 | int palette_value; | |
98f4a3df SR |
36 | int lcd_depth; |
37 | unsigned char *glob_lcd_reg; | |
38 | unsigned char *glob_lcd_mem; | |
0621f6f9 | 39 | |
9ac6b6f3 | 40 | #if defined(CFG_LCD_ENDIAN) |
0621f6f9 SR |
41 | void lcd_setup(int lcd, int config) |
42 | { | |
43 | if (lcd == 0) { | |
44 | /* | |
45 | * Set endianess and reset lcd controller 0 (small) | |
46 | */ | |
9ac6b6f3 | 47 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) & ~CFG_LCD0_RST); /* set reset to low */ |
0621f6f9 | 48 | udelay(10); /* wait 10us */ |
e174ac34 | 49 | if (config == 1) |
9ac6b6f3 | 50 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) | CFG_LCD_ENDIAN); /* big-endian */ |
e174ac34 | 51 | else |
9ac6b6f3 | 52 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) & ~CFG_LCD_ENDIAN); /* little-endian */ |
0621f6f9 | 53 | udelay(10); /* wait 10us */ |
9ac6b6f3 | 54 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) | CFG_LCD0_RST); /* set reset to high */ |
0621f6f9 SR |
55 | } else { |
56 | /* | |
57 | * Set endianess and reset lcd controller 1 (big) | |
58 | */ | |
9ac6b6f3 | 59 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) & ~CFG_LCD1_RST); /* set reset to low */ |
0621f6f9 | 60 | udelay(10); /* wait 10us */ |
e174ac34 | 61 | if (config == 1) |
9ac6b6f3 | 62 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) | CFG_LCD_ENDIAN); /* big-endian */ |
e174ac34 | 63 | else |
9ac6b6f3 | 64 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) & ~CFG_LCD_ENDIAN); /* little-endian */ |
0621f6f9 | 65 | udelay(10); /* wait 10us */ |
9ac6b6f3 | 66 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) | CFG_LCD1_RST); /* set reset to high */ |
0621f6f9 SR |
67 | } |
68 | ||
69 | /* | |
70 | * CFG_LCD_ENDIAN may also be FPGA_RESET, so set inactive | |
71 | */ | |
9ac6b6f3 | 72 | out_be32((void*)GPIO0_OR, in_be32((void*)GPIO0_OR) | CFG_LCD_ENDIAN); /* set reset high again */ |
0621f6f9 | 73 | } |
9ac6b6f3 | 74 | #endif /* CFG_LCD_ENDIAN */ |
0621f6f9 SR |
75 | |
76 | ||
98f4a3df | 77 | void lcd_bmp(uchar *logo_bmp) |
0621f6f9 SR |
78 | { |
79 | int i; | |
0621f6f9 SR |
80 | uchar *ptr; |
81 | ushort *ptr2; | |
82 | ushort val; | |
c29ab9d7 | 83 | unsigned char *dst = NULL; |
0621f6f9 SR |
84 | int x, y; |
85 | int width, height, bpp, colors, line_size; | |
86 | int header_size; | |
87 | unsigned char *bmp; | |
88 | unsigned char r, g, b; | |
89 | BITMAPINFOHEADER *bm_info; | |
98f4a3df | 90 | ulong len; |
0621f6f9 SR |
91 | |
92 | /* | |
98f4a3df | 93 | * Check for bmp mark 'BM' |
0621f6f9 | 94 | */ |
98f4a3df | 95 | if (*(ushort *)logo_bmp != 0x424d) { |
0621f6f9 | 96 | /* |
98f4a3df | 97 | * Decompress bmp image |
0621f6f9 | 98 | */ |
c29ab9d7 SR |
99 | len = CFG_VIDEO_LOGO_MAX_SIZE; |
100 | dst = malloc(CFG_VIDEO_LOGO_MAX_SIZE); | |
101 | if (dst == NULL) { | |
102 | printf("Error: malloc in gunzip failed!\n"); | |
98f4a3df SR |
103 | return; |
104 | } | |
e174ac34 | 105 | if (gunzip(dst, CFG_VIDEO_LOGO_MAX_SIZE, (uchar *)logo_bmp, &len) != 0) |
c29ab9d7 | 106 | return; |
e174ac34 | 107 | if (len == CFG_VIDEO_LOGO_MAX_SIZE) |
c29ab9d7 | 108 | printf("Image could be truncated (increase CFG_VIDEO_LOGO_MAX_SIZE)!\n"); |
98f4a3df | 109 | |
0621f6f9 | 110 | /* |
98f4a3df | 111 | * Check for bmp mark 'BM' |
0621f6f9 | 112 | */ |
98f4a3df SR |
113 | if (*(ushort *)dst != 0x424d) { |
114 | printf("LCD: Unknown image format!\n"); | |
115 | free(dst); | |
116 | return; | |
117 | } | |
118 | } else { | |
0621f6f9 | 119 | /* |
98f4a3df | 120 | * Uncompressed BMP image, just use this pointer |
0621f6f9 | 121 | */ |
98f4a3df | 122 | dst = (uchar *)logo_bmp; |
0621f6f9 SR |
123 | } |
124 | ||
125 | /* | |
126 | * Get image info from bmp-header | |
127 | */ | |
128 | bm_info = (BITMAPINFOHEADER *)(dst + 14); | |
129 | bpp = LOAD_SHORT(bm_info->biBitCount); | |
130 | width = LOAD_LONG(bm_info->biWidth); | |
131 | height = LOAD_LONG(bm_info->biHeight); | |
132 | switch (bpp) { | |
133 | case 1: | |
134 | colors = 1; | |
135 | line_size = width >> 3; | |
136 | break; | |
137 | case 4: | |
138 | colors = 16; | |
139 | line_size = width >> 1; | |
140 | break; | |
141 | case 8: | |
142 | colors = 256; | |
143 | line_size = width; | |
144 | break; | |
145 | case 24: | |
146 | colors = 0; | |
147 | line_size = width * 3; | |
148 | break; | |
149 | default: | |
150 | printf("LCD: Unknown bpp (%d) im image!\n", bpp); | |
e174ac34 | 151 | if ((dst != NULL) && (dst != (uchar *)logo_bmp)) |
c29ab9d7 | 152 | free(dst); |
0621f6f9 SR |
153 | return; |
154 | } | |
155 | printf(" (%d*%d, %dbpp)\n", width, height, bpp); | |
156 | ||
157 | /* | |
158 | * Write color palette | |
159 | */ | |
98f4a3df | 160 | if ((colors <= 256) && (lcd_depth <= 8)) { |
0621f6f9 | 161 | ptr = (unsigned char *)(dst + 14 + 40); |
9ac6b6f3 | 162 | for (i = 0; i < colors; i++) { |
0621f6f9 SR |
163 | b = *ptr++; |
164 | g = *ptr++; | |
165 | r = *ptr++; | |
166 | ptr++; | |
98f4a3df | 167 | S1D_WRITE_PALETTE(glob_lcd_reg, i, r, g, b); |
0621f6f9 SR |
168 | } |
169 | } | |
170 | ||
171 | /* | |
172 | * Write bitmap data into framebuffer | |
173 | */ | |
98f4a3df SR |
174 | ptr = glob_lcd_mem; |
175 | ptr2 = (ushort *)glob_lcd_mem; | |
0621f6f9 | 176 | header_size = 14 + 40 + 4*colors; /* skip bmp header */ |
9ac6b6f3 | 177 | for (y = 0; y < height; y++) { |
0621f6f9 | 178 | bmp = &dst[(height-1-y)*line_size + header_size]; |
98f4a3df SR |
179 | if (lcd_depth == 16) { |
180 | if (bpp == 24) { | |
9ac6b6f3 | 181 | for (x = 0; x < width; x++) { |
98f4a3df SR |
182 | /* |
183 | * Generate epson 16bpp fb-format from 24bpp image | |
184 | */ | |
185 | b = *bmp++ >> 3; | |
186 | g = *bmp++ >> 2; | |
187 | r = *bmp++ >> 3; | |
188 | val = ((r & 0x1f) << 11) | ((g & 0x3f) << 5) | (b & 0x1f); | |
189 | *ptr2++ = val; | |
190 | } | |
191 | } else if (bpp == 8) { | |
9ac6b6f3 | 192 | for (x = 0; x < line_size; x++) { |
98f4a3df SR |
193 | /* query rgb value from palette */ |
194 | ptr = (unsigned char *)(dst + 14 + 40) ; | |
195 | ptr += (*bmp++) << 2; | |
196 | b = *ptr++ >> 3; | |
197 | g = *ptr++ >> 2; | |
198 | r = *ptr++ >> 3; | |
199 | val = ((r & 0x1f) << 11) | ((g & 0x3f) << 5) | (b & 0x1f); | |
200 | *ptr2++ = val; | |
201 | } | |
0621f6f9 SR |
202 | } |
203 | } else { | |
9ac6b6f3 | 204 | for (x = 0; x < line_size; x++) |
0621f6f9 | 205 | *ptr++ = *bmp++; |
0621f6f9 SR |
206 | } |
207 | } | |
208 | ||
e174ac34 | 209 | if ((dst != NULL) && (dst != (uchar *)logo_bmp)) |
98f4a3df | 210 | free(dst); |
98f4a3df SR |
211 | } |
212 | ||
213 | ||
214 | void lcd_init(uchar *lcd_reg, uchar *lcd_mem, S1D_REGS *regs, int reg_count, | |
215 | uchar *logo_bmp, ulong len) | |
216 | { | |
217 | int i; | |
218 | ushort s1dReg; | |
219 | uchar s1dValue; | |
220 | int reg_byte_swap; | |
221 | ||
222 | /* | |
223 | * Detect epson | |
224 | */ | |
77660c4b MF |
225 | out_8(&lcd_reg[0], 0x00); |
226 | out_8(&lcd_reg[1], 0x00); | |
48a05a51 | 227 | |
e174ac34 | 228 | if (in_8(&lcd_reg[0]) == 0x1c) { |
98f4a3df SR |
229 | /* |
230 | * Big epson detected | |
231 | */ | |
232 | reg_byte_swap = FALSE; | |
233 | palette_index = 0x1e2; | |
234 | palette_value = 0x1e4; | |
235 | lcd_depth = 16; | |
236 | puts("LCD: S1D13806"); | |
e174ac34 | 237 | } else if (in_8(&lcd_reg[1]) == 0x1c) { |
98f4a3df SR |
238 | /* |
239 | * Big epson detected (with register swap bug) | |
240 | */ | |
241 | reg_byte_swap = TRUE; | |
242 | palette_index = 0x1e3; | |
243 | palette_value = 0x1e5; | |
244 | lcd_depth = 16; | |
245 | puts("LCD: S1D13806S"); | |
e174ac34 | 246 | } else if (in_8(&lcd_reg[0]) == 0x18) { |
98f4a3df SR |
247 | /* |
248 | * Small epson detected (704) | |
249 | */ | |
250 | reg_byte_swap = FALSE; | |
251 | palette_index = 0x15; | |
252 | palette_value = 0x17; | |
253 | lcd_depth = 8; | |
254 | puts("LCD: S1D13704"); | |
9ac6b6f3 | 255 | } else if (in_8(&lcd_reg[0x10000]) == 0x24) { |
98f4a3df SR |
256 | /* |
257 | * Small epson detected (705) | |
258 | */ | |
259 | reg_byte_swap = FALSE; | |
260 | palette_index = 0x15; | |
261 | palette_value = 0x17; | |
262 | lcd_depth = 8; | |
263 | lcd_reg += 0x10000; /* add offset for 705 regs */ | |
264 | puts("LCD: S1D13705"); | |
265 | } else { | |
266 | puts("LCD: No controller detected!\n"); | |
267 | return; | |
268 | } | |
269 | ||
270 | /* | |
271 | * Setup lcd controller regs | |
272 | */ | |
77660c4b | 273 | for (i = 0; i < reg_count; i++) { |
98f4a3df SR |
274 | s1dReg = regs[i].Index; |
275 | if (reg_byte_swap) { | |
276 | if ((s1dReg & 0x0001) == 0) | |
277 | s1dReg |= 0x0001; | |
278 | else | |
279 | s1dReg &= ~0x0001; | |
280 | } | |
281 | s1dValue = regs[i].Value; | |
282 | lcd_reg[s1dReg] = s1dValue; | |
283 | } | |
284 | ||
285 | /* | |
286 | * Save reg & mem pointer for later usage (e.g. bmp command) | |
287 | */ | |
288 | glob_lcd_reg = lcd_reg; | |
289 | glob_lcd_mem = lcd_mem; | |
290 | ||
291 | /* | |
292 | * Display bmp image | |
293 | */ | |
294 | lcd_bmp(logo_bmp); | |
0621f6f9 | 295 | } |
98f4a3df | 296 | |
9ac6b6f3 | 297 | #if defined(CONFIG_VIDEO_SM501) |
98f4a3df SR |
298 | int do_esdbmp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
299 | { | |
300 | ulong addr; | |
301 | char *str; | |
302 | ||
303 | if (argc != 2) { | |
304 | printf ("Usage:\n%s\n", cmdtp->usage); | |
305 | return 1; | |
306 | } | |
307 | ||
308 | addr = simple_strtoul(argv[1], NULL, 16); | |
309 | ||
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 | lcd_bmp((uchar *)addr); | |
321 | return 0; | |
322 | } | |
323 | } | |
324 | ||
325 | U_BOOT_CMD( | |
326 | esdbmp, 2, 1, do_esdbmp, | |
327 | "esdbmp - display BMP image\n", | |
328 | "<imageAddr> - display image\n" | |
329 | ); | |
c177bb5f | 330 | #endif |