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