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