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