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