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