xref: /openbmc/u-boot/drivers/video/cfb_console.c (revision 5187d8dd)
1 /*
2  * (C) Copyright 2002 ELTEC Elektronik AG
3  * Frank Gottschling <fgottschling@eltec.de>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 /*
25  * cfb_console.c
26  *
27  * Color Framebuffer Console driver for 8/15/16/24/32 bits per pixel.
28  *
29  * At the moment only the 8x16 font is tested and the font fore- and
30  * background color is limited to black/white/gray colors. The Linux
31  * logo can be placed in the upper left corner and additional board
32  * information strings (that normally goes to serial port) can be drawn.
33  *
34  * The console driver can use the standard PC keyboard interface (i8042)
35  * for character input. Character output goes to a memory mapped video
36  * framebuffer with little or big-endian organisation.
37  * With environment setting 'console=serial' the console i/o can be
38  * forced to serial port.
39  *
40  * The driver uses graphic specific defines/parameters/functions:
41  *
42  * (for SMI LynxE graphic chip)
43  *
44  * CONFIG_VIDEO_SMI_LYNXEM    - use graphic driver for SMI 710,712,810
45  * VIDEO_FB_LITTLE_ENDIAN     - framebuffer organisation default: big endian
46  * VIDEO_HW_RECTFILL	      - graphic driver supports hardware rectangle fill
47  * VIDEO_HW_BITBLT	      - graphic driver supports hardware bit blt
48  *
49  * Console Parameters are set by graphic drivers global struct:
50  *
51  * VIDEO_VISIBLE_COLS	      - x resolution
52  * VIDEO_VISIBLE_ROWS	      - y resolution
53  * VIDEO_PIXEL_SIZE	      - storage size in byte per pixel
54  * VIDEO_DATA_FORMAT	      - graphical data format GDF
55  * VIDEO_FB_ADRS	      - start of video memory
56  *
57  * CONFIG_I8042_KBD	      - AT Keyboard driver for i8042
58  * VIDEO_KBD_INIT_FCT	      - init function for keyboard
59  * VIDEO_TSTC_FCT	      - keyboard_tstc function
60  * VIDEO_GETC_FCT	      - keyboard_getc function
61  *
62  * CONFIG_CONSOLE_CURSOR      - on/off drawing cursor is done with
63  *				delay loop in VIDEO_TSTC_FCT (i8042)
64  *
65  * CONFIG_SYS_CONSOLE_BLINK_COUNT - value for delay loop - blink rate
66  * CONFIG_CONSOLE_TIME	      - display time/date in upper right
67  *				corner, needs CONFIG_CMD_DATE and
68  *				CONFIG_CONSOLE_CURSOR
69  * CONFIG_VIDEO_LOGO	      - display Linux Logo in upper left corner
70  * CONFIG_VIDEO_BMP_LOGO      - use bmp_logo instead of linux_logo
71  * CONFIG_CONSOLE_EXTRA_INFO  - display additional board information
72  *				strings that normaly goes to serial
73  *				port.  This define requires a board
74  *				specific function:
75  *				video_drawstring (VIDEO_INFO_X,
76  *					VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT,
77  *					info);
78  *				that fills a info buffer at i=row.
79  *				s.a: board/eltec/bab7xx.
80  * CONFIG_VGA_AS_SINGLE_DEVICE - If set the framebuffer device will be
81  *				initialized as an output only device.
82  *				The Keyboard driver will not be
83  *				set-up.  This may be used, if you have
84  *				no or more than one Keyboard devices
85  *				(USB Keyboard, AT Keyboard).
86  *
87  * CONFIG_VIDEO_SW_CURSOR:    - Draws a cursor after the last
88  *				character. No blinking is provided.
89  *				Uses the macros CURSOR_SET and
90  *				CURSOR_OFF.
91  *
92  * CONFIG_VIDEO_HW_CURSOR:    - Uses the hardware cursor capability
93  *				of the graphic chip. Uses the macro
94  *				CURSOR_SET. ATTENTION: If booting an
95  *				OS, the display driver must disable
96  *				the hardware register of the graphic
97  *				chip. Otherwise a blinking field is
98  *				displayed.
99  */
100 
101 #include <common.h>
102 #include <version.h>
103 #include <malloc.h>
104 
105 /*
106  * Console device defines with SMI graphic
107  * Any other graphic must change this section
108  */
109 
110 #ifdef	CONFIG_VIDEO_SMI_LYNXEM
111 
112 #define VIDEO_FB_LITTLE_ENDIAN
113 #define VIDEO_HW_RECTFILL
114 #define VIDEO_HW_BITBLT
115 #endif
116 
117 /*
118  * Defines for the CT69000 driver
119  */
120 #ifdef	CONFIG_VIDEO_CT69000
121 
122 #define VIDEO_FB_LITTLE_ENDIAN
123 #define VIDEO_HW_RECTFILL
124 #define VIDEO_HW_BITBLT
125 #endif
126 
127 /*
128  * Defines for the SED13806 driver
129  */
130 #ifdef CONFIG_VIDEO_SED13806
131 
132 #ifndef CONFIG_TOTAL5200
133 #define VIDEO_FB_LITTLE_ENDIAN
134 #endif
135 #define VIDEO_HW_RECTFILL
136 #define VIDEO_HW_BITBLT
137 #endif
138 
139 /*
140  * Defines for the SED13806 driver
141  */
142 #ifdef CONFIG_VIDEO_SM501
143 
144 #ifdef CONFIG_HH405
145 #define VIDEO_FB_LITTLE_ENDIAN
146 #endif
147 #endif
148 
149 /*
150  * Defines for the MB862xx driver
151  */
152 #ifdef CONFIG_VIDEO_MB862xx
153 
154 #ifdef CONFIG_VIDEO_CORALP
155 #define VIDEO_FB_LITTLE_ENDIAN
156 #endif
157 #ifdef CONFIG_VIDEO_MB862xx_ACCEL
158 #define VIDEO_HW_RECTFILL
159 #define VIDEO_HW_BITBLT
160 #endif
161 #endif
162 
163 /*
164  * Defines for the i.MX31 driver (mx3fb.c)
165  */
166 #ifdef CONFIG_VIDEO_MX3
167 #define VIDEO_FB_16BPP_WORD_SWAP
168 #endif
169 
170 /*
171  * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc.
172  */
173 #include <video_fb.h>
174 
175 /*
176  * some Macros
177  */
178 #define VIDEO_VISIBLE_COLS	(pGD->winSizeX)
179 #define VIDEO_VISIBLE_ROWS	(pGD->winSizeY)
180 #define VIDEO_PIXEL_SIZE	(pGD->gdfBytesPP)
181 #define VIDEO_DATA_FORMAT	(pGD->gdfIndex)
182 #define VIDEO_FB_ADRS		(pGD->frameAdrs)
183 
184 /*
185  * Console device defines with i8042 keyboard controller
186  * Any other keyboard controller must change this section
187  */
188 
189 #ifdef	CONFIG_I8042_KBD
190 #include <i8042.h>
191 
192 #define VIDEO_KBD_INIT_FCT	i8042_kbd_init()
193 #define VIDEO_TSTC_FCT		i8042_tstc
194 #define VIDEO_GETC_FCT		i8042_getc
195 #endif
196 
197 /*
198  * Console device
199  */
200 
201 #include <version.h>
202 #include <linux/types.h>
203 #include <stdio_dev.h>
204 #include <video_font.h>
205 
206 #if defined(CONFIG_CMD_DATE)
207 #include <rtc.h>
208 #endif
209 
210 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
211 #include <watchdog.h>
212 #include <bmp_layout.h>
213 
214 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
215 #define BMP_ALIGN_CENTER	0x7FFF
216 #endif
217 
218 #endif
219 
220 /*
221  * Cursor definition:
222  * CONFIG_CONSOLE_CURSOR:  Uses a timer function (see drivers/input/i8042.c)
223  *			   to let the cursor blink. Uses the macros
224  *			   CURSOR_OFF and CURSOR_ON.
225  * CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No
226  *			   blinking is provided. Uses the macros CURSOR_SET
227  *			   and CURSOR_OFF.
228  * CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the
229  *			   graphic chip. Uses the macro CURSOR_SET.
230  *			   ATTENTION: If booting an OS, the display driver
231  *			   must disable the hardware register of the graphic
232  *			   chip. Otherwise a blinking field is displayed
233  */
234 #if !defined(CONFIG_CONSOLE_CURSOR) && \
235     !defined(CONFIG_VIDEO_SW_CURSOR) && \
236     !defined(CONFIG_VIDEO_HW_CURSOR)
237 /* no Cursor defined */
238 #define CURSOR_ON
239 #define CURSOR_OFF
240 #define CURSOR_SET
241 #endif
242 
243 #ifdef	CONFIG_CONSOLE_CURSOR
244 #ifdef	CURSOR_ON
245 #error	only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
246 	or CONFIG_VIDEO_HW_CURSOR can be defined
247 #endif
248 void console_cursor(int state);
249 
250 #define CURSOR_ON  console_cursor(1)
251 #define CURSOR_OFF console_cursor(0)
252 #define CURSOR_SET
253 #ifndef CONFIG_I8042_KBD
254 #warning Cursor drawing on/off needs timer function s.a. drivers/input/i8042.c
255 #endif
256 #else
257 #ifdef	CONFIG_CONSOLE_TIME
258 #error	CONFIG_CONSOLE_CURSOR must be defined for CONFIG_CONSOLE_TIME
259 #endif
260 #endif /* CONFIG_CONSOLE_CURSOR */
261 
262 #ifdef	CONFIG_VIDEO_SW_CURSOR
263 #ifdef	CURSOR_ON
264 #error	only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
265 	or CONFIG_VIDEO_HW_CURSOR can be defined
266 #endif
267 #define CURSOR_ON
268 #define CURSOR_OFF video_putchar(console_col * VIDEO_FONT_WIDTH,\
269 				 console_row * VIDEO_FONT_HEIGHT, ' ')
270 #define CURSOR_SET video_set_cursor()
271 #endif /* CONFIG_VIDEO_SW_CURSOR */
272 
273 
274 #ifdef CONFIG_VIDEO_HW_CURSOR
275 #ifdef	CURSOR_ON
276 #error	only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
277 	or CONFIG_VIDEO_HW_CURSOR can be defined
278 #endif
279 #define CURSOR_ON
280 #define CURSOR_OFF
281 #define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \
282 		  (console_row * VIDEO_FONT_HEIGHT) + video_logo_height)
283 #endif /* CONFIG_VIDEO_HW_CURSOR */
284 
285 #ifdef	CONFIG_VIDEO_LOGO
286 #ifdef	CONFIG_VIDEO_BMP_LOGO
287 #include <bmp_logo.h>
288 #define VIDEO_LOGO_WIDTH	BMP_LOGO_WIDTH
289 #define VIDEO_LOGO_HEIGHT	BMP_LOGO_HEIGHT
290 #define VIDEO_LOGO_LUT_OFFSET	BMP_LOGO_OFFSET
291 #define VIDEO_LOGO_COLORS	BMP_LOGO_COLORS
292 
293 #else  /* CONFIG_VIDEO_BMP_LOGO */
294 #define LINUX_LOGO_WIDTH	80
295 #define LINUX_LOGO_HEIGHT	80
296 #define LINUX_LOGO_COLORS	214
297 #define LINUX_LOGO_LUT_OFFSET	0x20
298 #define __initdata
299 #include <linux_logo.h>
300 #define VIDEO_LOGO_WIDTH	LINUX_LOGO_WIDTH
301 #define VIDEO_LOGO_HEIGHT	LINUX_LOGO_HEIGHT
302 #define VIDEO_LOGO_LUT_OFFSET	LINUX_LOGO_LUT_OFFSET
303 #define VIDEO_LOGO_COLORS	LINUX_LOGO_COLORS
304 #endif /* CONFIG_VIDEO_BMP_LOGO */
305 #define VIDEO_INFO_X		(VIDEO_LOGO_WIDTH)
306 #define VIDEO_INFO_Y		(VIDEO_FONT_HEIGHT/2)
307 #else  /* CONFIG_VIDEO_LOGO */
308 #define VIDEO_LOGO_WIDTH	0
309 #define VIDEO_LOGO_HEIGHT	0
310 #endif /* CONFIG_VIDEO_LOGO */
311 
312 #define VIDEO_COLS		VIDEO_VISIBLE_COLS
313 #define VIDEO_ROWS		VIDEO_VISIBLE_ROWS
314 #define VIDEO_SIZE		(VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE)
315 #define VIDEO_PIX_BLOCKS	(VIDEO_SIZE >> 2)
316 #define VIDEO_LINE_LEN		(VIDEO_COLS*VIDEO_PIXEL_SIZE)
317 #define VIDEO_BURST_LEN		(VIDEO_COLS/8)
318 
319 #ifdef	CONFIG_VIDEO_LOGO
320 #define CONSOLE_ROWS		((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT)
321 #else
322 #define CONSOLE_ROWS		(VIDEO_ROWS / VIDEO_FONT_HEIGHT)
323 #endif
324 
325 #define CONSOLE_COLS		(VIDEO_COLS / VIDEO_FONT_WIDTH)
326 #define CONSOLE_ROW_SIZE	(VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
327 #define CONSOLE_ROW_FIRST	(video_console_address)
328 #define CONSOLE_ROW_SECOND	(video_console_address + CONSOLE_ROW_SIZE)
329 #define CONSOLE_ROW_LAST	(video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
330 #define CONSOLE_SIZE		(CONSOLE_ROW_SIZE * CONSOLE_ROWS)
331 #define CONSOLE_SCROLL_SIZE	(CONSOLE_SIZE - CONSOLE_ROW_SIZE)
332 
333 /* Macros */
334 #ifdef	VIDEO_FB_LITTLE_ENDIAN
335 #define SWAP16(x)		((((x) & 0x00ff) << 8) | \
336 				  ((x) >> 8) \
337 				)
338 #define SWAP32(x)		((((x) & 0x000000ff) << 24) | \
339 				 (((x) & 0x0000ff00) <<  8) | \
340 				 (((x) & 0x00ff0000) >>  8) | \
341 				 (((x) & 0xff000000) >> 24)   \
342 				)
343 #define SHORTSWAP32(x)		((((x) & 0x000000ff) <<  8) | \
344 				 (((x) & 0x0000ff00) >>  8) | \
345 				 (((x) & 0x00ff0000) <<  8) | \
346 				 (((x) & 0xff000000) >>  8)   \
347 				)
348 #else
349 #define SWAP16(x)		(x)
350 #define SWAP32(x)		(x)
351 #if defined(VIDEO_FB_16BPP_WORD_SWAP)
352 #define SHORTSWAP32(x)		(((x) >> 16) | ((x) << 16))
353 #else
354 #define SHORTSWAP32(x)		(x)
355 #endif
356 #endif
357 
358 #ifdef CONFIG_CONSOLE_EXTRA_INFO
359 /*
360  * setup a board string: type, speed, etc.
361  *
362  * line_number:	location to place info string beside logo
363  * info:	buffer for info string
364  */
365 extern void video_get_info_str(int line_number,	char *info);
366 #endif
367 
368 /* Locals */
369 static GraphicDevice *pGD;	/* Pointer to Graphic array */
370 
371 static void *video_fb_address;	/* frame buffer address */
372 static void *video_console_address;	/* console buffer start address */
373 
374 static int video_logo_height = VIDEO_LOGO_HEIGHT;
375 
376 static int console_col;		/* cursor col */
377 static int console_row;		/* cursor row */
378 
379 static u32 eorx, fgx, bgx;	/* color pats */
380 
381 static const int video_font_draw_table8[] = {
382 	0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
383 	0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
384 	0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
385 	0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
386 };
387 
388 static const int video_font_draw_table15[] = {
389 	0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff
390 };
391 
392 static const int video_font_draw_table16[] = {
393 	0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
394 };
395 
396 static const int video_font_draw_table24[16][3] = {
397 	{0x00000000, 0x00000000, 0x00000000},
398 	{0x00000000, 0x00000000, 0x00ffffff},
399 	{0x00000000, 0x0000ffff, 0xff000000},
400 	{0x00000000, 0x0000ffff, 0xffffffff},
401 	{0x000000ff, 0xffff0000, 0x00000000},
402 	{0x000000ff, 0xffff0000, 0x00ffffff},
403 	{0x000000ff, 0xffffffff, 0xff000000},
404 	{0x000000ff, 0xffffffff, 0xffffffff},
405 	{0xffffff00, 0x00000000, 0x00000000},
406 	{0xffffff00, 0x00000000, 0x00ffffff},
407 	{0xffffff00, 0x0000ffff, 0xff000000},
408 	{0xffffff00, 0x0000ffff, 0xffffffff},
409 	{0xffffffff, 0xffff0000, 0x00000000},
410 	{0xffffffff, 0xffff0000, 0x00ffffff},
411 	{0xffffffff, 0xffffffff, 0xff000000},
412 	{0xffffffff, 0xffffffff, 0xffffffff}
413 };
414 
415 static const int video_font_draw_table32[16][4] = {
416 	{0x00000000, 0x00000000, 0x00000000, 0x00000000},
417 	{0x00000000, 0x00000000, 0x00000000, 0x00ffffff},
418 	{0x00000000, 0x00000000, 0x00ffffff, 0x00000000},
419 	{0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff},
420 	{0x00000000, 0x00ffffff, 0x00000000, 0x00000000},
421 	{0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff},
422 	{0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000},
423 	{0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff},
424 	{0x00ffffff, 0x00000000, 0x00000000, 0x00000000},
425 	{0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff},
426 	{0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000},
427 	{0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff},
428 	{0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000},
429 	{0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff},
430 	{0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000},
431 	{0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff}
432 };
433 
434 
435 static void video_drawchars(int xx, int yy, unsigned char *s, int count)
436 {
437 	u8 *cdat, *dest, *dest0;
438 	int rows, offset, c;
439 
440 	offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE;
441 	dest0 = video_fb_address + offset;
442 
443 	switch (VIDEO_DATA_FORMAT) {
444 	case GDF__8BIT_INDEX:
445 	case GDF__8BIT_332RGB:
446 		while (count--) {
447 			c = *s;
448 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
449 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
450 			     rows--; dest += VIDEO_LINE_LEN) {
451 				u8 bits = *cdat++;
452 
453 				((u32 *) dest)[0] =
454 					(video_font_draw_table8[bits >> 4] &
455 					 eorx) ^ bgx;
456 				((u32 *) dest)[1] =
457 					(video_font_draw_table8[bits & 15] &
458 					 eorx) ^ bgx;
459 			}
460 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
461 			s++;
462 		}
463 		break;
464 
465 	case GDF_15BIT_555RGB:
466 		while (count--) {
467 			c = *s;
468 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
469 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
470 			     rows--; dest += VIDEO_LINE_LEN) {
471 				u8 bits = *cdat++;
472 
473 				((u32 *) dest)[0] =
474 					SHORTSWAP32((video_font_draw_table15
475 						     [bits >> 6] & eorx) ^
476 						    bgx);
477 				((u32 *) dest)[1] =
478 					SHORTSWAP32((video_font_draw_table15
479 						     [bits >> 4 & 3] & eorx) ^
480 						    bgx);
481 				((u32 *) dest)[2] =
482 					SHORTSWAP32((video_font_draw_table15
483 						     [bits >> 2 & 3] & eorx) ^
484 						    bgx);
485 				((u32 *) dest)[3] =
486 					SHORTSWAP32((video_font_draw_table15
487 						     [bits & 3] & eorx) ^
488 						    bgx);
489 			}
490 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
491 			s++;
492 		}
493 		break;
494 
495 	case GDF_16BIT_565RGB:
496 		while (count--) {
497 			c = *s;
498 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
499 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
500 			     rows--; dest += VIDEO_LINE_LEN) {
501 				u8 bits = *cdat++;
502 
503 				((u32 *) dest)[0] =
504 					SHORTSWAP32((video_font_draw_table16
505 						     [bits >> 6] & eorx) ^
506 						    bgx);
507 				((u32 *) dest)[1] =
508 					SHORTSWAP32((video_font_draw_table16
509 						     [bits >> 4 & 3] & eorx) ^
510 						    bgx);
511 				((u32 *) dest)[2] =
512 					SHORTSWAP32((video_font_draw_table16
513 						     [bits >> 2 & 3] & eorx) ^
514 						    bgx);
515 				((u32 *) dest)[3] =
516 					SHORTSWAP32((video_font_draw_table16
517 						     [bits & 3] & eorx) ^
518 						    bgx);
519 			}
520 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
521 			s++;
522 		}
523 		break;
524 
525 	case GDF_32BIT_X888RGB:
526 		while (count--) {
527 			c = *s;
528 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
529 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
530 			     rows--; dest += VIDEO_LINE_LEN) {
531 				u8 bits = *cdat++;
532 
533 				((u32 *) dest)[0] =
534 					SWAP32((video_font_draw_table32
535 						[bits >> 4][0] & eorx) ^ bgx);
536 				((u32 *) dest)[1] =
537 					SWAP32((video_font_draw_table32
538 						[bits >> 4][1] & eorx) ^ bgx);
539 				((u32 *) dest)[2] =
540 					SWAP32((video_font_draw_table32
541 						[bits >> 4][2] & eorx) ^ bgx);
542 				((u32 *) dest)[3] =
543 					SWAP32((video_font_draw_table32
544 						[bits >> 4][3] & eorx) ^ bgx);
545 				((u32 *) dest)[4] =
546 					SWAP32((video_font_draw_table32
547 						[bits & 15][0] & eorx) ^ bgx);
548 				((u32 *) dest)[5] =
549 					SWAP32((video_font_draw_table32
550 						[bits & 15][1] & eorx) ^ bgx);
551 				((u32 *) dest)[6] =
552 					SWAP32((video_font_draw_table32
553 						[bits & 15][2] & eorx) ^ bgx);
554 				((u32 *) dest)[7] =
555 					SWAP32((video_font_draw_table32
556 						[bits & 15][3] & eorx) ^ bgx);
557 			}
558 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
559 			s++;
560 		}
561 		break;
562 
563 	case GDF_24BIT_888RGB:
564 		while (count--) {
565 			c = *s;
566 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
567 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
568 			     rows--; dest += VIDEO_LINE_LEN) {
569 				u8 bits = *cdat++;
570 
571 				((u32 *) dest)[0] =
572 					(video_font_draw_table24[bits >> 4][0]
573 					 & eorx) ^ bgx;
574 				((u32 *) dest)[1] =
575 					(video_font_draw_table24[bits >> 4][1]
576 					 & eorx) ^ bgx;
577 				((u32 *) dest)[2] =
578 					(video_font_draw_table24[bits >> 4][2]
579 					 & eorx) ^ bgx;
580 				((u32 *) dest)[3] =
581 					(video_font_draw_table24[bits & 15][0]
582 					 & eorx) ^ bgx;
583 				((u32 *) dest)[4] =
584 					(video_font_draw_table24[bits & 15][1]
585 					 & eorx) ^ bgx;
586 				((u32 *) dest)[5] =
587 					(video_font_draw_table24[bits & 15][2]
588 					 & eorx) ^ bgx;
589 			}
590 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
591 			s++;
592 		}
593 		break;
594 	}
595 }
596 
597 static inline void video_drawstring(int xx, int yy, unsigned char *s)
598 {
599 	video_drawchars(xx, yy, s, strlen((char *) s));
600 }
601 
602 static void video_putchar(int xx, int yy, unsigned char c)
603 {
604 	video_drawchars(xx, yy + video_logo_height, &c, 1);
605 }
606 
607 #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR)
608 static void video_set_cursor(void)
609 {
610 	/* swap drawing colors */
611 	eorx = fgx;
612 	fgx = bgx;
613 	bgx = eorx;
614 	eorx = fgx ^ bgx;
615 	/* draw cursor */
616 	video_putchar(console_col * VIDEO_FONT_WIDTH,
617 		      console_row * VIDEO_FONT_HEIGHT, ' ');
618 	/* restore drawing colors */
619 	eorx = fgx;
620 	fgx = bgx;
621 	bgx = eorx;
622 	eorx = fgx ^ bgx;
623 }
624 #endif
625 
626 #ifdef CONFIG_CONSOLE_CURSOR
627 void console_cursor(int state)
628 {
629 	static int last_state = 0;
630 
631 #ifdef CONFIG_CONSOLE_TIME
632 	struct rtc_time tm;
633 	char info[16];
634 
635 	/* time update only if cursor is on (faster scroll) */
636 	if (state) {
637 		rtc_get(&tm);
638 
639 		sprintf(info, " %02d:%02d:%02d ", tm.tm_hour, tm.tm_min,
640 			tm.tm_sec);
641 		video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH,
642 				 VIDEO_INFO_Y, (uchar *) info);
643 
644 		sprintf(info, "%02d.%02d.%04d", tm.tm_mday, tm.tm_mon,
645 			tm.tm_year);
646 		video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH,
647 				 VIDEO_INFO_Y + 1 * VIDEO_FONT_HEIGHT,
648 				 (uchar *) info);
649 	}
650 #endif
651 
652 	if (state && (last_state != state)) {
653 		video_set_cursor();
654 	}
655 
656 	if (!state && (last_state != state)) {
657 		/* clear cursor */
658 		video_putchar(console_col * VIDEO_FONT_WIDTH,
659 			      console_row * VIDEO_FONT_HEIGHT, ' ');
660 	}
661 
662 	last_state = state;
663 }
664 #endif
665 
666 #ifndef VIDEO_HW_RECTFILL
667 static void memsetl(int *p, int c, int v)
668 {
669 	while (c--)
670 		*(p++) = v;
671 }
672 #endif
673 
674 #ifndef VIDEO_HW_BITBLT
675 static void memcpyl(int *d, int *s, int c)
676 {
677 	while (c--)
678 		*(d++) = *(s++);
679 }
680 #endif
681 
682 static void console_scrollup(void)
683 {
684 	/* copy up rows ignoring the first one */
685 
686 #ifdef VIDEO_HW_BITBLT
687 	video_hw_bitblt(VIDEO_PIXEL_SIZE,	/* bytes per pixel */
688 			0,			/* source pos x */
689 			video_logo_height +
690 				VIDEO_FONT_HEIGHT, /* source pos y */
691 			0,			/* dest pos x */
692 			video_logo_height,	/* dest pos y */
693 			VIDEO_VISIBLE_COLS,	/* frame width */
694 			VIDEO_VISIBLE_ROWS
695 			- video_logo_height
696 			- VIDEO_FONT_HEIGHT	/* frame height */
697 		);
698 #else
699 	memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND,
700 		CONSOLE_SCROLL_SIZE >> 2);
701 #endif
702 
703 	/* clear the last one */
704 #ifdef VIDEO_HW_RECTFILL
705 	video_hw_rectfill(VIDEO_PIXEL_SIZE,	/* bytes per pixel */
706 			  0,			/* dest pos x */
707 			  VIDEO_VISIBLE_ROWS
708 			  - VIDEO_FONT_HEIGHT,	/* dest pos y */
709 			  VIDEO_VISIBLE_COLS,	/* frame width */
710 			  VIDEO_FONT_HEIGHT,	/* frame height */
711 			  CONSOLE_BG_COL	/* fill color */
712 		);
713 #else
714 	memsetl(CONSOLE_ROW_LAST, CONSOLE_ROW_SIZE >> 2, CONSOLE_BG_COL);
715 #endif
716 }
717 
718 static void console_back(void)
719 {
720 	CURSOR_OFF;
721 	console_col--;
722 
723 	if (console_col < 0) {
724 		console_col = CONSOLE_COLS - 1;
725 		console_row--;
726 		if (console_row < 0)
727 			console_row = 0;
728 	}
729 	video_putchar(console_col * VIDEO_FONT_WIDTH,
730 		      console_row * VIDEO_FONT_HEIGHT, ' ');
731 }
732 
733 static void console_newline(void)
734 {
735 	/* Check if last character in the line was just drawn. If so, cursor was
736 	   overwriten and need not to be cleared. Cursor clearing without this
737 	   check causes overwriting the 1st character of the line if line lenght
738 	   is >= CONSOLE_COLS
739 	 */
740 	if (console_col < CONSOLE_COLS)
741 		CURSOR_OFF;
742 	console_row++;
743 	console_col = 0;
744 
745 	/* Check if we need to scroll the terminal */
746 	if (console_row >= CONSOLE_ROWS) {
747 		/* Scroll everything up */
748 		console_scrollup();
749 
750 		/* Decrement row number */
751 		console_row--;
752 	}
753 }
754 
755 static void console_cr(void)
756 {
757 	CURSOR_OFF;
758 	console_col = 0;
759 }
760 
761 void video_putc(const char c)
762 {
763 	static int nl = 1;
764 
765 	switch (c) {
766 	case 13:		/* back to first column */
767 		console_cr();
768 		break;
769 
770 	case '\n':		/* next line */
771 		if (console_col || (!console_col && nl))
772 			console_newline();
773 		nl = 1;
774 		break;
775 
776 	case 9:		/* tab 8 */
777 		CURSOR_OFF;
778 		console_col |= 0x0008;
779 		console_col &= ~0x0007;
780 
781 		if (console_col >= CONSOLE_COLS)
782 			console_newline();
783 		break;
784 
785 	case 8:		/* backspace */
786 		console_back();
787 		break;
788 
789 	default:		/* draw the char */
790 		video_putchar(console_col * VIDEO_FONT_WIDTH,
791 			      console_row * VIDEO_FONT_HEIGHT, c);
792 		console_col++;
793 
794 		/* check for newline */
795 		if (console_col >= CONSOLE_COLS) {
796 			console_newline();
797 			nl = 0;
798 		}
799 	}
800 	CURSOR_SET;
801 }
802 
803 void video_puts(const char *s)
804 {
805 	int count = strlen(s);
806 
807 	while (count--)
808 		video_putc(*s++);
809 }
810 
811 /*
812  * Do not enforce drivers (or board code) to provide empty
813  * video_set_lut() if they do not support 8 bpp format.
814  * Implement weak default function instead.
815  */
816 void __video_set_lut(unsigned int index, unsigned char r,
817 		     unsigned char g, unsigned char b)
818 {
819 }
820 
821 void video_set_lut(unsigned int, unsigned char, unsigned char, unsigned char)
822 	__attribute__ ((weak, alias("__video_set_lut")));
823 
824 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
825 
826 #define FILL_8BIT_332RGB(r,g,b)	{			\
827 	*fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6);	\
828 	fb ++;						\
829 }
830 
831 #define FILL_15BIT_555RGB(r,g,b) {			\
832 	*(unsigned short *)fb =				\
833 		SWAP16((unsigned short)(((r>>3)<<10) |	\
834 					((g>>3)<<5)  |	\
835 					 (b>>3)));	\
836 	fb += 2;					\
837 }
838 
839 #define FILL_16BIT_565RGB(r,g,b) {			\
840 	*(unsigned short *)fb =				\
841 		SWAP16((unsigned short)((((r)>>3)<<11)| \
842 					(((g)>>2)<<5) | \
843 					 ((b)>>3)));	\
844 	fb += 2;					\
845 }
846 
847 #define FILL_32BIT_X888RGB(r,g,b) {			\
848 	*(unsigned long *)fb =				\
849 		SWAP32((unsigned long)(((r<<16) |	\
850 					(g<<8)  |	\
851 					 b)));		\
852 	fb += 4;					\
853 }
854 
855 #ifdef VIDEO_FB_LITTLE_ENDIAN
856 #define FILL_24BIT_888RGB(r,g,b) {			\
857 	fb[0] = b;					\
858 	fb[1] = g;					\
859 	fb[2] = r;					\
860 	fb += 3;					\
861 }
862 #else
863 #define FILL_24BIT_888RGB(r,g,b) {			\
864 	fb[0] = r;					\
865 	fb[1] = g;					\
866 	fb[2] = b;					\
867 	fb += 3;					\
868 }
869 #endif
870 
871 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
872 static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b)
873 {
874 	ushort *dst = (ushort *) fb;
875 	ushort color = (ushort) (((r >> 3) << 10) |
876 				 ((g >> 3) <<  5) |
877 				  (b >> 3));
878 	if (x & 1)
879 		*(--dst) = color;
880 	else
881 		*(++dst) = color;
882 }
883 #endif
884 
885 /*
886  * RLE8 bitmap support
887  */
888 
889 #ifdef CONFIG_VIDEO_BMP_RLE8
890 /* Pre-calculated color table entry */
891 struct palette {
892 	union {
893 		unsigned short w;	/* word */
894 		unsigned int dw;	/* double word */
895 	} ce;				/* color entry */
896 };
897 
898 /*
899  * Helper to draw encoded/unencoded run.
900  */
901 static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p,
902 			int cnt, int enc)
903 {
904 	ulong addr = (ulong) *fb;
905 	int *off;
906 	int enc_off = 1;
907 	int i;
908 
909 	/*
910 	 * Setup offset of the color index in the bitmap.
911 	 * Color index of encoded run is at offset 1.
912 	 */
913 	off = enc ? &enc_off : &i;
914 
915 	switch (VIDEO_DATA_FORMAT) {
916 	case GDF__8BIT_INDEX:
917 		for (i = 0; i < cnt; i++)
918 			*(unsigned char *) addr++ = bm[*off];
919 		break;
920 	case GDF_15BIT_555RGB:
921 	case GDF_16BIT_565RGB:
922 		/* differences handled while pre-calculating palette */
923 		for (i = 0; i < cnt; i++) {
924 			*(unsigned short *) addr = p[bm[*off]].ce.w;
925 			addr += 2;
926 		}
927 		break;
928 	case GDF_32BIT_X888RGB:
929 		for (i = 0; i < cnt; i++) {
930 			*(unsigned long *) addr = p[bm[*off]].ce.dw;
931 			addr += 4;
932 		}
933 		break;
934 	}
935 	*fb = (uchar *) addr;	/* return modified address */
936 }
937 
938 static int display_rle8_bitmap(bmp_image_t *img, int xoff, int yoff,
939 			       int width, int height)
940 {
941 	unsigned char *bm;
942 	unsigned char *fbp;
943 	unsigned int cnt, runlen;
944 	int decode = 1;
945 	int x, y, bpp, i, ncolors;
946 	struct palette p[256];
947 	bmp_color_table_entry_t cte;
948 	int green_shift, red_off;
949 	int limit = VIDEO_COLS * VIDEO_ROWS;
950 	int pixels = 0;
951 
952 	x = 0;
953 	y = __le32_to_cpu(img->header.height) - 1;
954 	ncolors = __le32_to_cpu(img->header.colors_used);
955 	bpp = VIDEO_PIXEL_SIZE;
956 	fbp = (unsigned char *) ((unsigned int) video_fb_address +
957 				 (((y + yoff) * VIDEO_COLS) + xoff) * bpp);
958 
959 	bm = (uchar *) img + __le32_to_cpu(img->header.data_offset);
960 
961 	/* pre-calculate and setup palette */
962 	switch (VIDEO_DATA_FORMAT) {
963 	case GDF__8BIT_INDEX:
964 		for (i = 0; i < ncolors; i++) {
965 			cte = img->color_table[i];
966 			video_set_lut(i, cte.red, cte.green, cte.blue);
967 		}
968 		break;
969 	case GDF_15BIT_555RGB:
970 	case GDF_16BIT_565RGB:
971 		if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) {
972 			green_shift = 3;
973 			red_off = 10;
974 		} else {
975 			green_shift = 2;
976 			red_off = 11;
977 		}
978 		for (i = 0; i < ncolors; i++) {
979 			cte = img->color_table[i];
980 			p[i].ce.w = SWAP16((unsigned short)
981 					   (((cte.red >> 3) << red_off) |
982 					    ((cte.green >> green_shift) << 5) |
983 					    cte.blue >> 3));
984 		}
985 		break;
986 	case GDF_32BIT_X888RGB:
987 		for (i = 0; i < ncolors; i++) {
988 			cte = img->color_table[i];
989 			p[i].ce.dw = SWAP32((cte.red << 16) |
990 					    (cte.green << 8) |
991 					     cte.blue);
992 		}
993 		break;
994 	default:
995 		printf("RLE Bitmap unsupported in video mode 0x%x\n",
996 		       VIDEO_DATA_FORMAT);
997 		return -1;
998 	}
999 
1000 	while (decode) {
1001 		switch (bm[0]) {
1002 		case 0:
1003 			switch (bm[1]) {
1004 			case 0:
1005 				/* scan line end marker */
1006 				bm += 2;
1007 				x = 0;
1008 				y--;
1009 				fbp = (unsigned char *)
1010 					((unsigned int) video_fb_address +
1011 					 (((y + yoff) * VIDEO_COLS) +
1012 					  xoff) * bpp);
1013 				continue;
1014 			case 1:
1015 				/* end of bitmap data marker */
1016 				decode = 0;
1017 				break;
1018 			case 2:
1019 				/* run offset marker */
1020 				x += bm[2];
1021 				y -= bm[3];
1022 				fbp = (unsigned char *)
1023 					((unsigned int) video_fb_address +
1024 					 (((y + yoff) * VIDEO_COLS) +
1025 					  x + xoff) * bpp);
1026 				bm += 4;
1027 				break;
1028 			default:
1029 				/* unencoded run */
1030 				cnt = bm[1];
1031 				runlen = cnt;
1032 				pixels += cnt;
1033 				if (pixels > limit)
1034 					goto error;
1035 
1036 				bm += 2;
1037 				if (y < height) {
1038 					if (x >= width) {
1039 						x += runlen;
1040 						goto next_run;
1041 					}
1042 					if (x + runlen > width)
1043 						cnt = width - x;
1044 					draw_bitmap(&fbp, bm, p, cnt, 0);
1045 					x += runlen;
1046 				}
1047 next_run:
1048 				bm += runlen;
1049 				if (runlen & 1)
1050 					bm++;	/* 0 padding if length is odd */
1051 			}
1052 			break;
1053 		default:
1054 			/* encoded run */
1055 			cnt = bm[0];
1056 			runlen = cnt;
1057 			pixels += cnt;
1058 			if (pixels > limit)
1059 				goto error;
1060 
1061 			if (y < height) {     /* only draw into visible area */
1062 				if (x >= width) {
1063 					x += runlen;
1064 					bm += 2;
1065 					continue;
1066 				}
1067 				if (x + runlen > width)
1068 					cnt = width - x;
1069 				draw_bitmap(&fbp, bm, p, cnt, 1);
1070 				x += runlen;
1071 			}
1072 			bm += 2;
1073 			break;
1074 		}
1075 	}
1076 	return 0;
1077 error:
1078 	printf("Error: Too much encoded pixel data, validate your bitmap\n");
1079 	return -1;
1080 }
1081 #endif
1082 
1083 /*
1084  * Display the BMP file located at address bmp_image.
1085  */
1086 int video_display_bitmap(ulong bmp_image, int x, int y)
1087 {
1088 	ushort xcount, ycount;
1089 	uchar *fb;
1090 	bmp_image_t *bmp = (bmp_image_t *) bmp_image;
1091 	uchar *bmap;
1092 	ushort padded_line;
1093 	unsigned long width, height, bpp;
1094 	unsigned colors;
1095 	unsigned long compression;
1096 	bmp_color_table_entry_t cte;
1097 
1098 #ifdef CONFIG_VIDEO_BMP_GZIP
1099 	unsigned char *dst = NULL;
1100 	ulong len;
1101 #endif
1102 
1103 	WATCHDOG_RESET();
1104 
1105 	if (!((bmp->header.signature[0] == 'B') &&
1106 	      (bmp->header.signature[1] == 'M'))) {
1107 
1108 #ifdef CONFIG_VIDEO_BMP_GZIP
1109 		/*
1110 		 * Could be a gzipped bmp image, try to decrompress...
1111 		 */
1112 		len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
1113 		dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
1114 		if (dst == NULL) {
1115 			printf("Error: malloc in gunzip failed!\n");
1116 			return 1;
1117 		}
1118 		if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE,
1119 			   (uchar *) bmp_image,
1120 			   &len) != 0) {
1121 			printf("Error: no valid bmp or bmp.gz image at %lx\n",
1122 			       bmp_image);
1123 			free(dst);
1124 			return 1;
1125 		}
1126 		if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
1127 			printf("Image could be truncated "
1128 				"(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
1129 		}
1130 
1131 		/*
1132 		 * Set addr to decompressed image
1133 		 */
1134 		bmp = (bmp_image_t *) dst;
1135 
1136 		if (!((bmp->header.signature[0] == 'B') &&
1137 		      (bmp->header.signature[1] == 'M'))) {
1138 			printf("Error: no valid bmp.gz image at %lx\n",
1139 			       bmp_image);
1140 			free(dst);
1141 			return 1;
1142 		}
1143 #else
1144 		printf("Error: no valid bmp image at %lx\n", bmp_image);
1145 		return 1;
1146 #endif /* CONFIG_VIDEO_BMP_GZIP */
1147 	}
1148 
1149 	width = le32_to_cpu(bmp->header.width);
1150 	height = le32_to_cpu(bmp->header.height);
1151 	bpp = le16_to_cpu(bmp->header.bit_count);
1152 	colors = le32_to_cpu(bmp->header.colors_used);
1153 	compression = le32_to_cpu(bmp->header.compression);
1154 
1155 	debug("Display-bmp: %ld x %ld  with %d colors\n",
1156 	      width, height, colors);
1157 
1158 	if (compression != BMP_BI_RGB
1159 #ifdef CONFIG_VIDEO_BMP_RLE8
1160 	    && compression != BMP_BI_RLE8
1161 #endif
1162 		) {
1163 		printf("Error: compression type %ld not supported\n",
1164 		       compression);
1165 #ifdef CONFIG_VIDEO_BMP_GZIP
1166 		if (dst)
1167 			free(dst);
1168 #endif
1169 		return 1;
1170 	}
1171 
1172 	padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
1173 
1174 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1175 	if (x == BMP_ALIGN_CENTER)
1176 		x = max(0, (VIDEO_VISIBLE_COLS - width) / 2);
1177 	else if (x < 0)
1178 		x = max(0, VIDEO_VISIBLE_COLS - width + x + 1);
1179 
1180 	if (y == BMP_ALIGN_CENTER)
1181 		y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2);
1182 	else if (y < 0)
1183 		y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1);
1184 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1185 
1186 	if ((x + width) > VIDEO_VISIBLE_COLS)
1187 		width = VIDEO_VISIBLE_COLS - x;
1188 	if ((y + height) > VIDEO_VISIBLE_ROWS)
1189 		height = VIDEO_VISIBLE_ROWS - y;
1190 
1191 	bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
1192 	fb = (uchar *) (video_fb_address +
1193 			((y + height - 1) * VIDEO_COLS * VIDEO_PIXEL_SIZE) +
1194 			x * VIDEO_PIXEL_SIZE);
1195 
1196 #ifdef CONFIG_VIDEO_BMP_RLE8
1197 	if (compression == BMP_BI_RLE8) {
1198 		return display_rle8_bitmap(bmp, x, y, width, height);
1199 	}
1200 #endif
1201 
1202 	/* We handle only 4, 8, or 24 bpp bitmaps */
1203 	switch (le16_to_cpu(bmp->header.bit_count)) {
1204 	case 4:
1205 		padded_line -= width / 2;
1206 		ycount = height;
1207 
1208 		switch (VIDEO_DATA_FORMAT) {
1209 		case GDF_32BIT_X888RGB:
1210 			while (ycount--) {
1211 				WATCHDOG_RESET();
1212 				/*
1213 				 * Don't assume that 'width' is an
1214 				 * even number
1215 				 */
1216 				for (xcount = 0; xcount < width; xcount++) {
1217 					uchar idx;
1218 
1219 					if (xcount & 1) {
1220 						idx = *bmap & 0xF;
1221 						bmap++;
1222 					} else
1223 						idx = *bmap >> 4;
1224 					cte = bmp->color_table[idx];
1225 					FILL_32BIT_X888RGB(cte.red, cte.green,
1226 							   cte.blue);
1227 				}
1228 				bmap += padded_line;
1229 				fb -= (VIDEO_VISIBLE_COLS + width) *
1230 					VIDEO_PIXEL_SIZE;
1231 			}
1232 			break;
1233 		default:
1234 			puts("4bpp bitmap unsupported with current "
1235 			     "video mode\n");
1236 			break;
1237 		}
1238 		break;
1239 
1240 	case 8:
1241 		padded_line -= width;
1242 		if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1243 			/* Copy colormap */
1244 			for (xcount = 0; xcount < colors; ++xcount) {
1245 				cte = bmp->color_table[xcount];
1246 				video_set_lut(xcount, cte.red, cte.green,
1247 					      cte.blue);
1248 			}
1249 		}
1250 		ycount = height;
1251 		switch (VIDEO_DATA_FORMAT) {
1252 		case GDF__8BIT_INDEX:
1253 			while (ycount--) {
1254 				WATCHDOG_RESET();
1255 				xcount = width;
1256 				while (xcount--) {
1257 					*fb++ = *bmap++;
1258 				}
1259 				bmap += padded_line;
1260 				fb -= (VIDEO_VISIBLE_COLS + width) *
1261 							VIDEO_PIXEL_SIZE;
1262 			}
1263 			break;
1264 		case GDF__8BIT_332RGB:
1265 			while (ycount--) {
1266 				WATCHDOG_RESET();
1267 				xcount = width;
1268 				while (xcount--) {
1269 					cte = bmp->color_table[*bmap++];
1270 					FILL_8BIT_332RGB(cte.red, cte.green,
1271 							 cte.blue);
1272 				}
1273 				bmap += padded_line;
1274 				fb -= (VIDEO_VISIBLE_COLS + width) *
1275 							VIDEO_PIXEL_SIZE;
1276 			}
1277 			break;
1278 		case GDF_15BIT_555RGB:
1279 			while (ycount--) {
1280 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1281 				int xpos = x;
1282 #endif
1283 				WATCHDOG_RESET();
1284 				xcount = width;
1285 				while (xcount--) {
1286 					cte = bmp->color_table[*bmap++];
1287 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1288 					fill_555rgb_pswap(fb, xpos++, cte.red,
1289 							  cte.green,
1290 							  cte.blue);
1291 					fb += 2;
1292 #else
1293 					FILL_15BIT_555RGB(cte.red, cte.green,
1294 							  cte.blue);
1295 #endif
1296 				}
1297 				bmap += padded_line;
1298 				fb -= (VIDEO_VISIBLE_COLS + width) *
1299 							VIDEO_PIXEL_SIZE;
1300 			}
1301 			break;
1302 		case GDF_16BIT_565RGB:
1303 			while (ycount--) {
1304 				WATCHDOG_RESET();
1305 				xcount = width;
1306 				while (xcount--) {
1307 					cte = bmp->color_table[*bmap++];
1308 					FILL_16BIT_565RGB(cte.red, cte.green,
1309 							  cte.blue);
1310 				}
1311 				bmap += padded_line;
1312 				fb -= (VIDEO_VISIBLE_COLS + width) *
1313 							VIDEO_PIXEL_SIZE;
1314 			}
1315 			break;
1316 		case GDF_32BIT_X888RGB:
1317 			while (ycount--) {
1318 				WATCHDOG_RESET();
1319 				xcount = width;
1320 				while (xcount--) {
1321 					cte = bmp->color_table[*bmap++];
1322 					FILL_32BIT_X888RGB(cte.red, cte.green,
1323 							   cte.blue);
1324 				}
1325 				bmap += padded_line;
1326 				fb -= (VIDEO_VISIBLE_COLS + width) *
1327 							VIDEO_PIXEL_SIZE;
1328 			}
1329 			break;
1330 		case GDF_24BIT_888RGB:
1331 			while (ycount--) {
1332 				WATCHDOG_RESET();
1333 				xcount = width;
1334 				while (xcount--) {
1335 					cte = bmp->color_table[*bmap++];
1336 					FILL_24BIT_888RGB(cte.red, cte.green,
1337 							  cte.blue);
1338 				}
1339 				bmap += padded_line;
1340 				fb -= (VIDEO_VISIBLE_COLS + width) *
1341 							VIDEO_PIXEL_SIZE;
1342 			}
1343 			break;
1344 		}
1345 		break;
1346 	case 24:
1347 		padded_line -= 3 * width;
1348 		ycount = height;
1349 		switch (VIDEO_DATA_FORMAT) {
1350 		case GDF__8BIT_332RGB:
1351 			while (ycount--) {
1352 				WATCHDOG_RESET();
1353 				xcount = width;
1354 				while (xcount--) {
1355 					FILL_8BIT_332RGB(bmap[2], bmap[1],
1356 							 bmap[0]);
1357 					bmap += 3;
1358 				}
1359 				bmap += padded_line;
1360 				fb -= (VIDEO_VISIBLE_COLS + width) *
1361 							VIDEO_PIXEL_SIZE;
1362 			}
1363 			break;
1364 		case GDF_15BIT_555RGB:
1365 			while (ycount--) {
1366 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1367 				int xpos = x;
1368 #endif
1369 				WATCHDOG_RESET();
1370 				xcount = width;
1371 				while (xcount--) {
1372 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1373 					fill_555rgb_pswap(fb, xpos++, bmap[2],
1374 							  bmap[1], bmap[0]);
1375 					fb += 2;
1376 #else
1377 					FILL_15BIT_555RGB(bmap[2], bmap[1],
1378 							  bmap[0]);
1379 #endif
1380 					bmap += 3;
1381 				}
1382 				bmap += padded_line;
1383 				fb -= (VIDEO_VISIBLE_COLS + width) *
1384 							VIDEO_PIXEL_SIZE;
1385 			}
1386 			break;
1387 		case GDF_16BIT_565RGB:
1388 			while (ycount--) {
1389 				WATCHDOG_RESET();
1390 				xcount = width;
1391 				while (xcount--) {
1392 					FILL_16BIT_565RGB(bmap[2], bmap[1],
1393 							  bmap[0]);
1394 					bmap += 3;
1395 				}
1396 				bmap += padded_line;
1397 				fb -= (VIDEO_VISIBLE_COLS + width) *
1398 							VIDEO_PIXEL_SIZE;
1399 			}
1400 			break;
1401 		case GDF_32BIT_X888RGB:
1402 			while (ycount--) {
1403 				WATCHDOG_RESET();
1404 				xcount = width;
1405 				while (xcount--) {
1406 					FILL_32BIT_X888RGB(bmap[2], bmap[1],
1407 							   bmap[0]);
1408 					bmap += 3;
1409 				}
1410 				bmap += padded_line;
1411 				fb -= (VIDEO_VISIBLE_COLS + width) *
1412 							VIDEO_PIXEL_SIZE;
1413 			}
1414 			break;
1415 		case GDF_24BIT_888RGB:
1416 			while (ycount--) {
1417 				WATCHDOG_RESET();
1418 				xcount = width;
1419 				while (xcount--) {
1420 					FILL_24BIT_888RGB(bmap[2], bmap[1],
1421 							  bmap[0]);
1422 					bmap += 3;
1423 				}
1424 				bmap += padded_line;
1425 				fb -= (VIDEO_VISIBLE_COLS + width) *
1426 							VIDEO_PIXEL_SIZE;
1427 			}
1428 			break;
1429 		default:
1430 			printf("Error: 24 bits/pixel bitmap incompatible "
1431 				"with current video mode\n");
1432 			break;
1433 		}
1434 		break;
1435 	default:
1436 		printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
1437 			le16_to_cpu(bmp->header.bit_count));
1438 		break;
1439 	}
1440 
1441 #ifdef CONFIG_VIDEO_BMP_GZIP
1442 	if (dst) {
1443 		free(dst);
1444 	}
1445 #endif
1446 
1447 	return (0);
1448 }
1449 #endif
1450 
1451 
1452 #ifdef CONFIG_VIDEO_LOGO
1453 void logo_plot(void *screen, int width, int x, int y)
1454 {
1455 
1456 	int xcount, i;
1457 	int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE;
1458 	int ycount = video_logo_height;
1459 	unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
1460 	unsigned char *source;
1461 	unsigned char *dest = (unsigned char *) screen +
1462 		((y * width * VIDEO_PIXEL_SIZE) + x * VIDEO_PIXEL_SIZE);
1463 
1464 #ifdef CONFIG_VIDEO_BMP_LOGO
1465 	source = bmp_logo_bitmap;
1466 
1467 	/* Allocate temporary space for computing colormap */
1468 	logo_red = malloc(BMP_LOGO_COLORS);
1469 	logo_green = malloc(BMP_LOGO_COLORS);
1470 	logo_blue = malloc(BMP_LOGO_COLORS);
1471 	/* Compute color map */
1472 	for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1473 		logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
1474 		logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
1475 		logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
1476 	}
1477 #else
1478 	source = linux_logo;
1479 	logo_red = linux_logo_red;
1480 	logo_green = linux_logo_green;
1481 	logo_blue = linux_logo_blue;
1482 #endif
1483 
1484 	if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1485 		for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1486 			video_set_lut(i + VIDEO_LOGO_LUT_OFFSET,
1487 				      logo_red[i], logo_green[i],
1488 				      logo_blue[i]);
1489 		}
1490 	}
1491 
1492 	while (ycount--) {
1493 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1494 		int xpos = x;
1495 #endif
1496 		xcount = VIDEO_LOGO_WIDTH;
1497 		while (xcount--) {
1498 			r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
1499 			g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
1500 			b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
1501 
1502 			switch (VIDEO_DATA_FORMAT) {
1503 			case GDF__8BIT_INDEX:
1504 				*dest = *source;
1505 				break;
1506 			case GDF__8BIT_332RGB:
1507 				*dest = ((r >> 5) << 5) |
1508 					((g >> 5) << 2) |
1509 					 (b >> 6);
1510 				break;
1511 			case GDF_15BIT_555RGB:
1512 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1513 				fill_555rgb_pswap(dest, xpos++, r, g, b);
1514 #else
1515 				*(unsigned short *) dest =
1516 					SWAP16((unsigned short) (
1517 							((r >> 3) << 10) |
1518 							((g >> 3) <<  5) |
1519 							 (b >> 3)));
1520 #endif
1521 				break;
1522 			case GDF_16BIT_565RGB:
1523 				*(unsigned short *) dest =
1524 					SWAP16((unsigned short) (
1525 							((r >> 3) << 11) |
1526 							((g >> 2) <<  5) |
1527 							 (b >> 3)));
1528 				break;
1529 			case GDF_32BIT_X888RGB:
1530 				*(unsigned long *) dest =
1531 					SWAP32((unsigned long) (
1532 							(r << 16) |
1533 							(g <<  8) |
1534 							 b));
1535 				break;
1536 			case GDF_24BIT_888RGB:
1537 #ifdef VIDEO_FB_LITTLE_ENDIAN
1538 				dest[0] = b;
1539 				dest[1] = g;
1540 				dest[2] = r;
1541 #else
1542 				dest[0] = r;
1543 				dest[1] = g;
1544 				dest[2] = b;
1545 #endif
1546 				break;
1547 			}
1548 			source++;
1549 			dest += VIDEO_PIXEL_SIZE;
1550 		}
1551 		dest += skip;
1552 	}
1553 #ifdef CONFIG_VIDEO_BMP_LOGO
1554 	free(logo_red);
1555 	free(logo_green);
1556 	free(logo_blue);
1557 #endif
1558 }
1559 
1560 static void *video_logo(void)
1561 {
1562 	char info[128];
1563 	int space, len, y_off = 0;
1564 
1565 #ifdef CONFIG_SPLASH_SCREEN
1566 	char *s;
1567 	ulong addr;
1568 
1569 	s = getenv("splashimage");
1570 	if (s != NULL) {
1571 		int x = 0, y = 0;
1572 
1573 		addr = simple_strtoul(s, NULL, 16);
1574 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1575 		s = getenv("splashpos");
1576 		if (s != NULL) {
1577 			if (s[0] == 'm')
1578 				x = BMP_ALIGN_CENTER;
1579 			else
1580 				x = simple_strtol(s, NULL, 0);
1581 
1582 			s = strchr(s + 1, ',');
1583 			if (s != NULL) {
1584 				if (s[1] == 'm')
1585 					y = BMP_ALIGN_CENTER;
1586 				else
1587 					y = simple_strtol(s + 1, NULL, 0);
1588 			}
1589 		}
1590 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1591 
1592 		if (video_display_bitmap(addr, x, y) == 0) {
1593 			video_logo_height = 0;
1594 			return ((void *) (video_fb_address));
1595 		}
1596 	}
1597 #endif /* CONFIG_SPLASH_SCREEN */
1598 
1599 	logo_plot(video_fb_address, VIDEO_COLS, 0, 0);
1600 
1601 	sprintf(info, " %s", version_string);
1602 
1603 	space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
1604 	len = strlen(info);
1605 
1606 	if (len > space) {
1607 		video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y,
1608 				(uchar *) info, space);
1609 		video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH,
1610 				VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
1611 				(uchar *) info + space, len - space);
1612 		y_off = 1;
1613 	} else
1614 		video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);
1615 
1616 #ifdef CONFIG_CONSOLE_EXTRA_INFO
1617 	{
1618 		int i, n =
1619 			((video_logo_height -
1620 			  VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
1621 
1622 		for (i = 1; i < n; i++) {
1623 			video_get_info_str(i, info);
1624 			if (!*info)
1625 				continue;
1626 
1627 			len = strlen(info);
1628 			if (len > space) {
1629 				video_drawchars(VIDEO_INFO_X,
1630 						VIDEO_INFO_Y +
1631 						(i + y_off) *
1632 							VIDEO_FONT_HEIGHT,
1633 						(uchar *) info, space);
1634 				y_off++;
1635 				video_drawchars(VIDEO_INFO_X +
1636 						VIDEO_FONT_WIDTH,
1637 						VIDEO_INFO_Y +
1638 							(i + y_off) *
1639 							VIDEO_FONT_HEIGHT,
1640 						(uchar *) info + space,
1641 						len - space);
1642 			} else {
1643 				video_drawstring(VIDEO_INFO_X,
1644 						 VIDEO_INFO_Y +
1645 						 (i + y_off) *
1646 							VIDEO_FONT_HEIGHT,
1647 						 (uchar *) info);
1648 			}
1649 		}
1650 	}
1651 #endif
1652 
1653 	return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
1654 }
1655 #endif
1656 
1657 static int video_init(void)
1658 {
1659 	unsigned char color8;
1660 
1661 	pGD = video_hw_init();
1662 	if (pGD == NULL)
1663 		return -1;
1664 
1665 	video_fb_address = (void *) VIDEO_FB_ADRS;
1666 #ifdef CONFIG_VIDEO_HW_CURSOR
1667 	video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
1668 #endif
1669 
1670 	/* Init drawing pats */
1671 	switch (VIDEO_DATA_FORMAT) {
1672 	case GDF__8BIT_INDEX:
1673 		video_set_lut(0x01, CONSOLE_FG_COL, CONSOLE_FG_COL,
1674 			      CONSOLE_FG_COL);
1675 		video_set_lut(0x00, CONSOLE_BG_COL, CONSOLE_BG_COL,
1676 			      CONSOLE_BG_COL);
1677 		fgx = 0x01010101;
1678 		bgx = 0x00000000;
1679 		break;
1680 	case GDF__8BIT_332RGB:
1681 		color8 = ((CONSOLE_FG_COL & 0xe0) |
1682 			  ((CONSOLE_FG_COL >> 3) & 0x1c) |
1683 			  CONSOLE_FG_COL >> 6);
1684 		fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
1685 			color8;
1686 		color8 = ((CONSOLE_BG_COL & 0xe0) |
1687 			  ((CONSOLE_BG_COL >> 3) & 0x1c) |
1688 			  CONSOLE_BG_COL >> 6);
1689 		bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
1690 			color8;
1691 		break;
1692 	case GDF_15BIT_555RGB:
1693 		fgx = (((CONSOLE_FG_COL >> 3) << 26) |
1694 		       ((CONSOLE_FG_COL >> 3) << 21) |
1695 		       ((CONSOLE_FG_COL >> 3) << 16) |
1696 		       ((CONSOLE_FG_COL >> 3) << 10) |
1697 		       ((CONSOLE_FG_COL >> 3) <<  5) |
1698 			(CONSOLE_FG_COL >> 3));
1699 		bgx = (((CONSOLE_BG_COL >> 3) << 26) |
1700 		       ((CONSOLE_BG_COL >> 3) << 21) |
1701 		       ((CONSOLE_BG_COL >> 3) << 16) |
1702 		       ((CONSOLE_BG_COL >> 3) << 10) |
1703 		       ((CONSOLE_BG_COL >> 3) <<  5) |
1704 			(CONSOLE_BG_COL >> 3));
1705 		break;
1706 	case GDF_16BIT_565RGB:
1707 		fgx = (((CONSOLE_FG_COL >> 3) << 27) |
1708 		       ((CONSOLE_FG_COL >> 2) << 21) |
1709 		       ((CONSOLE_FG_COL >> 3) << 16) |
1710 		       ((CONSOLE_FG_COL >> 3) << 11) |
1711 		       ((CONSOLE_FG_COL >> 2) <<  5) |
1712 			(CONSOLE_FG_COL >> 3));
1713 		bgx = (((CONSOLE_BG_COL >> 3) << 27) |
1714 		       ((CONSOLE_BG_COL >> 2) << 21) |
1715 		       ((CONSOLE_BG_COL >> 3) << 16) |
1716 		       ((CONSOLE_BG_COL >> 3) << 11) |
1717 		       ((CONSOLE_BG_COL >> 2) <<  5) |
1718 			(CONSOLE_BG_COL >> 3));
1719 		break;
1720 	case GDF_32BIT_X888RGB:
1721 		fgx =	(CONSOLE_FG_COL << 16) |
1722 			(CONSOLE_FG_COL <<  8) |
1723 			 CONSOLE_FG_COL;
1724 		bgx =	(CONSOLE_BG_COL << 16) |
1725 			(CONSOLE_BG_COL <<  8) |
1726 			 CONSOLE_BG_COL;
1727 		break;
1728 	case GDF_24BIT_888RGB:
1729 		fgx =	(CONSOLE_FG_COL << 24) |
1730 			(CONSOLE_FG_COL << 16) |
1731 			(CONSOLE_FG_COL <<  8) |
1732 			 CONSOLE_FG_COL;
1733 		bgx =	(CONSOLE_BG_COL << 24) |
1734 			(CONSOLE_BG_COL << 16) |
1735 			(CONSOLE_BG_COL <<  8) |
1736 			 CONSOLE_BG_COL;
1737 		break;
1738 	}
1739 	eorx = fgx ^ bgx;
1740 
1741 #ifdef CONFIG_VIDEO_LOGO
1742 	/* Plot the logo and get start point of console */
1743 	debug("Video: Drawing the logo ...\n");
1744 	video_console_address = video_logo();
1745 #else
1746 	video_console_address = video_fb_address;
1747 #endif
1748 
1749 	/* Initialize the console */
1750 	console_col = 0;
1751 	console_row = 0;
1752 
1753 	return 0;
1754 }
1755 
1756 /*
1757  * Implement a weak default function for boards that optionally
1758  * need to skip the video initialization.
1759  */
1760 int __board_video_skip(void)
1761 {
1762 	/* As default, don't skip test */
1763 	return 0;
1764 }
1765 
1766 int board_video_skip(void)
1767 	__attribute__ ((weak, alias("__board_video_skip")));
1768 
1769 int drv_video_init(void)
1770 {
1771 	int skip_dev_init;
1772 	struct stdio_dev console_dev;
1773 
1774 	/* Check if video initialization should be skipped */
1775 	if (board_video_skip())
1776 		return 0;
1777 
1778 	/* Init video chip - returns with framebuffer cleared */
1779 	skip_dev_init = (video_init() == -1);
1780 
1781 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
1782 	debug("KBD: Keyboard init ...\n");
1783 	skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
1784 #endif
1785 
1786 	if (skip_dev_init)
1787 		return 0;
1788 
1789 	/* Init vga device */
1790 	memset(&console_dev, 0, sizeof(console_dev));
1791 	strcpy(console_dev.name, "vga");
1792 	console_dev.ext = DEV_EXT_VIDEO;	/* Video extensions */
1793 	console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
1794 	console_dev.putc = video_putc;	/* 'putc' function */
1795 	console_dev.puts = video_puts;	/* 'puts' function */
1796 	console_dev.tstc = NULL;	/* 'tstc' function */
1797 	console_dev.getc = NULL;	/* 'getc' function */
1798 
1799 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
1800 	/* Also init console device */
1801 	console_dev.flags |= DEV_FLAGS_INPUT;
1802 	console_dev.tstc = VIDEO_TSTC_FCT;	/* 'tstc' function */
1803 	console_dev.getc = VIDEO_GETC_FCT;	/* 'getc' function */
1804 #endif /* CONFIG_VGA_AS_SINGLE_DEVICE */
1805 
1806 	if (stdio_register(&console_dev) != 0)
1807 		return 0;
1808 
1809 	/* Return success */
1810 	return 1;
1811 }
1812