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