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