xref: /openbmc/u-boot/drivers/video/cfb_console.c (revision bc8f8c26)
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 console_col--;
655 
656 	if (console_col < 0) {
657 		console_col = CONSOLE_COLS - 1;
658 		console_row--;
659 		if (console_row < 0)
660 			console_row = 0;
661 	}
662 	video_putchar (console_col * VIDEO_FONT_WIDTH,
663 		       console_row * VIDEO_FONT_HEIGHT,
664 		       ' ');
665 }
666 
667 /*****************************************************************************/
668 
669 static void console_newline (void)
670 {
671 	/* Check if last character in the line was just drawn. If so, cursor was
672 	   overwriten and need not to be cleared. Cursor clearing without this
673 	   check causes overwriting the 1st character of the line if line lenght
674 	   is >= CONSOLE_COLS
675 	 */
676 	if (console_col < CONSOLE_COLS)
677 		CURSOR_OFF
678 	console_row++;
679 	console_col = 0;
680 
681 	/* Check if we need to scroll the terminal */
682 	if (console_row >= CONSOLE_ROWS) {
683 		/* Scroll everything up */
684 		console_scrollup ();
685 
686 		/* Decrement row number */
687 		console_row--;
688 	}
689 }
690 
691 static void console_cr (void)
692 {
693 	CURSOR_OFF console_col = 0;
694 }
695 
696 /*****************************************************************************/
697 
698 void video_putc (const char c)
699 {
700 	static int nl = 1;
701 
702 	switch (c) {
703 	case 13:		/* back to first column */
704 		console_cr ();
705 		break;
706 
707 	case '\n':		/* next line */
708 		if (console_col || (!console_col && nl))
709 			console_newline ();
710 		nl = 1;
711 		break;
712 
713 	case 9:		/* tab 8 */
714 		CURSOR_OFF console_col |= 0x0008;
715 		console_col &= ~0x0007;
716 
717 		if (console_col >= CONSOLE_COLS)
718 			console_newline ();
719 		break;
720 
721 	case 8:		/* backspace */
722 		console_back ();
723 		break;
724 
725 	default:		/* draw the char */
726 		video_putchar (console_col * VIDEO_FONT_WIDTH,
727 			       console_row * VIDEO_FONT_HEIGHT,
728 			       c);
729 		console_col++;
730 
731 		/* check for newline */
732 		if (console_col >= CONSOLE_COLS) {
733 			console_newline ();
734 			nl = 0;
735 		}
736 	}
737 CURSOR_SET}
738 
739 
740 /*****************************************************************************/
741 
742 void video_puts (const char *s)
743 {
744 	int count = strlen (s);
745 
746 	while (count--)
747 		video_putc (*s++);
748 }
749 
750 /*****************************************************************************/
751 
752 /*
753  * Do not enforce drivers (or board code) to provide empty
754  * video_set_lut() if they do not support 8 bpp format.
755  * Implement weak default function instead.
756  */
757 void __video_set_lut (unsigned int index, unsigned char r,
758 		      unsigned char g, unsigned char b)
759 {
760 }
761 void video_set_lut (unsigned int, unsigned char, unsigned char, unsigned char)
762 			__attribute__((weak, alias("__video_set_lut")));
763 
764 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
765 
766 #define FILL_8BIT_332RGB(r,g,b)	{			\
767 	*fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6);	\
768 	fb ++;						\
769 }
770 
771 #define FILL_15BIT_555RGB(r,g,b) {			\
772 	*(unsigned short *)fb = SWAP16((unsigned short)(((r>>3)<<10) | ((g>>3)<<5) | (b>>3))); \
773 	fb += 2;					\
774 }
775 
776 #define FILL_16BIT_565RGB(r,g,b) {			\
777 	*(unsigned short *)fb = SWAP16((unsigned short)((((r)>>3)<<11) | (((g)>>2)<<5) | ((b)>>3))); \
778 	fb += 2;					\
779 }
780 
781 #define FILL_32BIT_X888RGB(r,g,b) {			\
782 	*(unsigned long *)fb = SWAP32((unsigned long)(((r<<16) | (g<<8) | b))); \
783 	fb += 4;					\
784 }
785 
786 #ifdef VIDEO_FB_LITTLE_ENDIAN
787 #define FILL_24BIT_888RGB(r,g,b) {			\
788 	fb[0] = b;					\
789 	fb[1] = g;					\
790 	fb[2] = r;					\
791 	fb += 3;					\
792 }
793 #else
794 #define FILL_24BIT_888RGB(r,g,b) {			\
795 	fb[0] = r;					\
796 	fb[1] = g;					\
797 	fb[2] = b;					\
798 	fb += 3;					\
799 }
800 #endif
801 
802 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
803 static void inline fill_555rgb_pswap(uchar *fb, int x,
804 				     u8 r, u8 g, u8 b)
805 {
806 	ushort *dst = (ushort *)fb;
807 	ushort color = (ushort)(((r >> 3) << 10) |
808 				((g >> 3) << 5) |
809 				(b >> 3));
810 	if (x & 1)
811 		*(--dst) = color;
812 	else
813 		*(++dst) = color;
814 }
815 #endif
816 
817 /*
818  * RLE8 bitmap support
819  */
820 
821 #ifdef CONFIG_VIDEO_BMP_RLE8
822 /* Pre-calculated color table entry */
823 struct palette {
824 	union {
825 		unsigned short	w;	/* word */
826 		unsigned int	dw;	/* double word */
827 	} ce; /* color entry */
828 };
829 
830 /*
831  * Helper to draw encoded/unencoded run.
832  */
833 static void draw_bitmap (uchar **fb, uchar *bm, struct palette *p,
834 			 int cnt, int enc)
835 {
836 	ulong addr = (ulong)*fb;
837 	int *off;
838 	int enc_off = 1;
839 	int i;
840 
841 	/*
842 	 * Setup offset of the color index in the bitmap.
843 	 * Color index of encoded run is at offset 1.
844 	 */
845 	off = enc ? &enc_off : &i;
846 
847 	switch (VIDEO_DATA_FORMAT) {
848 	case GDF__8BIT_INDEX:
849 		for (i = 0; i < cnt; i++)
850 			*(unsigned char *)addr++ = bm[*off];
851 		break;
852 	case GDF_15BIT_555RGB:
853 	case GDF_16BIT_565RGB:
854 		/* differences handled while pre-calculating palette */
855 		for (i = 0; i < cnt; i++) {
856 			*(unsigned short *)addr = p[bm[*off]].ce.w;
857 			addr += 2;
858 		}
859 		break;
860 	case GDF_32BIT_X888RGB:
861 		for (i = 0; i < cnt; i++) {
862 			*(unsigned long *)addr = p[bm[*off]].ce.dw;
863 			addr += 4;
864 		}
865 		break;
866 	}
867 	*fb = (uchar *)addr; /* return modified address */
868 }
869 
870 static int display_rle8_bitmap (bmp_image_t *img, int xoff, int yoff,
871 				int width, int height)
872 {
873 	unsigned char *bm;
874 	unsigned char *fbp;
875 	unsigned int cnt, runlen;
876 	int decode = 1;
877 	int x, y, bpp, i, ncolors;
878 	struct palette p[256];
879 	bmp_color_table_entry_t cte;
880 	int green_shift, red_off;
881 
882 	x = 0;
883 	y = __le32_to_cpu(img->header.height) - 1;
884 	ncolors = __le32_to_cpu(img->header.colors_used);
885 	bpp = VIDEO_PIXEL_SIZE;
886 	fbp = (unsigned char *)((unsigned int)video_fb_address +
887 				(((y + yoff) * VIDEO_COLS) + xoff) * bpp);
888 
889 	bm = (uchar *)img + __le32_to_cpu(img->header.data_offset);
890 
891 	/* pre-calculate and setup palette */
892 	switch (VIDEO_DATA_FORMAT) {
893 	case GDF__8BIT_INDEX:
894 		for (i = 0; i < ncolors; i++) {
895 			cte = img->color_table[i];
896 			video_set_lut (i, cte.red, cte.green, cte.blue);
897 		}
898 		break;
899 	case GDF_15BIT_555RGB:
900 	case GDF_16BIT_565RGB:
901 		if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) {
902 			green_shift = 3;
903 			red_off = 10;
904 		} else {
905 			green_shift = 2;
906 			red_off = 11;
907 		}
908 		for (i = 0; i < ncolors; i++) {
909 			cte = img->color_table[i];
910 			p[i].ce.w = SWAP16((unsigned short)
911 					   (((cte.red >> 3) << red_off) |
912 					    ((cte.green >> green_shift) << 5) |
913 					    cte.blue >> 3));
914 		}
915 		break;
916 	case GDF_32BIT_X888RGB:
917 		for (i = 0; i < ncolors; i++) {
918 			cte = img->color_table[i];
919 			p[i].ce.dw = SWAP32((cte.red << 16) | (cte.green << 8) |
920 					     cte.blue);
921 		}
922 		break;
923 	default:
924 		printf("RLE Bitmap unsupported in video mode 0x%x\n",
925 			VIDEO_DATA_FORMAT);
926 		return -1;
927 	}
928 
929 	while (decode) {
930 		switch (bm[0]) {
931 		case 0:
932 			switch (bm[1]) {
933 			case 0:
934 				/* scan line end marker */
935 				bm += 2;
936 				x = 0;
937 				y--;
938 				fbp = (unsigned char *)
939 					((unsigned int)video_fb_address +
940 					 (((y + yoff) * VIDEO_COLS) +
941 					  xoff) * bpp);
942 				continue;
943 			case 1:
944 				/* end of bitmap data marker */
945 				decode = 0;
946 				break;
947 			case 2:
948 				/* run offset marker */
949 				x += bm[2];
950 				y -= bm[3];
951 				fbp = (unsigned char *)
952 					((unsigned int)video_fb_address +
953 					 (((y + yoff) * VIDEO_COLS) +
954 					  x + xoff) * bpp);
955 				bm += 4;
956 				break;
957 			default:
958 				/* unencoded run */
959 				cnt = bm[1];
960 				runlen = cnt;
961 				bm += 2;
962 				if (y < height) {
963 					if (x >= width) {
964 						x += runlen;
965 						goto next_run;
966 					}
967 					if (x + runlen > width)
968 						cnt = width - x;
969 
970 					draw_bitmap (&fbp, bm, p, cnt, 0);
971 					x += runlen;
972 				}
973 next_run:
974 				bm += runlen;
975 				if (runlen & 1)
976 					bm++; /* 0 padding if length is odd */
977 			}
978 			break;
979 		default:
980 			/* encoded run */
981 			if (y < height) { /* only draw into visible area */
982 				cnt = bm[0];
983 				runlen = cnt;
984 				if (x >= width) {
985 					x += runlen;
986 					bm += 2;
987 					continue;
988 				}
989 				if (x + runlen > width)
990 					cnt = width - x;
991 
992 				draw_bitmap (&fbp, bm, p, cnt, 1);
993 				x += runlen;
994 			}
995 			bm += 2;
996 			break;
997 		}
998 	}
999 	return 0;
1000 }
1001 #endif
1002 
1003 /*
1004  * Display the BMP file located at address bmp_image.
1005  */
1006 int video_display_bitmap (ulong bmp_image, int x, int y)
1007 {
1008 	ushort xcount, ycount;
1009 	uchar *fb;
1010 	bmp_image_t *bmp = (bmp_image_t *) bmp_image;
1011 	uchar *bmap;
1012 	ushort padded_line;
1013 	unsigned long width, height, bpp;
1014 	unsigned colors;
1015 	unsigned long compression;
1016 	bmp_color_table_entry_t cte;
1017 #ifdef CONFIG_VIDEO_BMP_GZIP
1018 	unsigned char *dst = NULL;
1019 	ulong len;
1020 #endif
1021 
1022 	WATCHDOG_RESET ();
1023 
1024 	if (!((bmp->header.signature[0] == 'B') &&
1025 	      (bmp->header.signature[1] == 'M'))) {
1026 
1027 #ifdef CONFIG_VIDEO_BMP_GZIP
1028 		/*
1029 		 * Could be a gzipped bmp image, try to decrompress...
1030 		 */
1031 		len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
1032 		dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
1033 		if (dst == NULL) {
1034 			printf("Error: malloc in gunzip failed!\n");
1035 			return(1);
1036 		}
1037 		if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, (uchar *)bmp_image, &len) != 0) {
1038 			printf ("Error: no valid bmp or bmp.gz image at %lx\n", bmp_image);
1039 			free(dst);
1040 			return 1;
1041 		}
1042 		if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
1043 			printf("Image could be truncated (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
1044 		}
1045 
1046 		/*
1047 		 * Set addr to decompressed image
1048 		 */
1049 		bmp = (bmp_image_t *)dst;
1050 
1051 		if (!((bmp->header.signature[0] == 'B') &&
1052 		      (bmp->header.signature[1] == 'M'))) {
1053 			printf ("Error: no valid bmp.gz image at %lx\n", bmp_image);
1054 			free(dst);
1055 			return 1;
1056 		}
1057 #else
1058 		printf ("Error: no valid bmp image at %lx\n", bmp_image);
1059 		return 1;
1060 #endif /* CONFIG_VIDEO_BMP_GZIP */
1061 	}
1062 
1063 	width = le32_to_cpu (bmp->header.width);
1064 	height = le32_to_cpu (bmp->header.height);
1065 	bpp = le16_to_cpu (bmp->header.bit_count);
1066 	colors = le32_to_cpu (bmp->header.colors_used);
1067 	compression = le32_to_cpu (bmp->header.compression);
1068 
1069 	debug ("Display-bmp: %d x %d  with %d colors\n",
1070 	       width, height, colors);
1071 
1072 	if (compression != BMP_BI_RGB
1073 #ifdef CONFIG_VIDEO_BMP_RLE8
1074 	    && compression != BMP_BI_RLE8
1075 #endif
1076 	   ) {
1077 		printf ("Error: compression type %ld not supported\n",
1078 			compression);
1079 #ifdef CONFIG_VIDEO_BMP_GZIP
1080 		if (dst)
1081 			free(dst);
1082 #endif
1083 		return 1;
1084 	}
1085 
1086 	padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
1087 
1088 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1089 	if (x == BMP_ALIGN_CENTER)
1090 		x = max(0, (VIDEO_VISIBLE_COLS - width) / 2);
1091 	else if (x < 0)
1092 		x = max(0, VIDEO_VISIBLE_COLS - width + x + 1);
1093 
1094 	if (y == BMP_ALIGN_CENTER)
1095 		y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2);
1096 	else if (y < 0)
1097 		y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1);
1098 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1099 
1100 	if ((x + width) > VIDEO_VISIBLE_COLS)
1101 		width = VIDEO_VISIBLE_COLS - x;
1102 	if ((y + height) > VIDEO_VISIBLE_ROWS)
1103 		height = VIDEO_VISIBLE_ROWS - y;
1104 
1105 	bmap = (uchar *) bmp + le32_to_cpu (bmp->header.data_offset);
1106 	fb = (uchar *) (video_fb_address +
1107 			((y + height - 1) * VIDEO_COLS * VIDEO_PIXEL_SIZE) +
1108 			x * VIDEO_PIXEL_SIZE);
1109 
1110 #ifdef CONFIG_VIDEO_BMP_RLE8
1111 	if (compression == BMP_BI_RLE8) {
1112 		return display_rle8_bitmap(bmp,
1113 					   x, y, width, height);
1114 	}
1115 #endif
1116 
1117 	/* We handle only 4, 8, or 24 bpp bitmaps */
1118 	switch (le16_to_cpu (bmp->header.bit_count)) {
1119 	case 4:
1120 		padded_line -= width / 2;
1121 		ycount = height;
1122 
1123 		switch (VIDEO_DATA_FORMAT) {
1124 		case GDF_32BIT_X888RGB:
1125 			while (ycount--) {
1126 				WATCHDOG_RESET ();
1127 				/*
1128 				 * Don't assume that 'width' is an
1129 				 * even number
1130 				 */
1131 				for (xcount = 0; xcount < width; xcount++) {
1132 					uchar idx;
1133 
1134 					if (xcount & 1) {
1135 						idx = *bmap & 0xF;
1136 						bmap++;
1137 					} else
1138 						idx = *bmap >> 4;
1139 					cte = bmp->color_table[idx];
1140 					FILL_32BIT_X888RGB(cte.red, cte.green,
1141 							   cte.blue);
1142 				}
1143 				bmap += padded_line;
1144 				fb -= (VIDEO_VISIBLE_COLS + width) *
1145 				      VIDEO_PIXEL_SIZE;
1146 			}
1147 			break;
1148 		default:
1149 			puts("4bpp bitmap unsupported with current "
1150 			     "video mode\n");
1151 			break;
1152 		}
1153 		break;
1154 
1155 	case 8:
1156 		padded_line -= width;
1157 		if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1158 			/* Copy colormap */
1159 			for (xcount = 0; xcount < colors; ++xcount) {
1160 				cte = bmp->color_table[xcount];
1161 				video_set_lut (xcount, cte.red, cte.green, cte.blue);
1162 			}
1163 		}
1164 		ycount = height;
1165 		switch (VIDEO_DATA_FORMAT) {
1166 		case GDF__8BIT_INDEX:
1167 			while (ycount--) {
1168 				WATCHDOG_RESET ();
1169 				xcount = width;
1170 				while (xcount--) {
1171 					*fb++ = *bmap++;
1172 				}
1173 				bmap += padded_line;
1174 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1175 			}
1176 			break;
1177 		case GDF__8BIT_332RGB:
1178 			while (ycount--) {
1179 				WATCHDOG_RESET ();
1180 				xcount = width;
1181 				while (xcount--) {
1182 					cte = bmp->color_table[*bmap++];
1183 					FILL_8BIT_332RGB (cte.red, cte.green, cte.blue);
1184 				}
1185 				bmap += padded_line;
1186 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1187 			}
1188 			break;
1189 		case GDF_15BIT_555RGB:
1190 			while (ycount--) {
1191 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1192 				int xpos = x;
1193 #endif
1194 				WATCHDOG_RESET ();
1195 				xcount = width;
1196 				while (xcount--) {
1197 					cte = bmp->color_table[*bmap++];
1198 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1199 					fill_555rgb_pswap (fb, xpos++, cte.red,
1200 							   cte.green, cte.blue);
1201 					fb += 2;
1202 #else
1203 					FILL_15BIT_555RGB (cte.red, cte.green, cte.blue);
1204 #endif
1205 				}
1206 				bmap += padded_line;
1207 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1208 			}
1209 			break;
1210 		case GDF_16BIT_565RGB:
1211 			while (ycount--) {
1212 				WATCHDOG_RESET ();
1213 				xcount = width;
1214 				while (xcount--) {
1215 					cte = bmp->color_table[*bmap++];
1216 					FILL_16BIT_565RGB (cte.red, cte.green, cte.blue);
1217 				}
1218 				bmap += padded_line;
1219 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1220 			}
1221 			break;
1222 		case GDF_32BIT_X888RGB:
1223 			while (ycount--) {
1224 				WATCHDOG_RESET ();
1225 				xcount = width;
1226 				while (xcount--) {
1227 					cte = bmp->color_table[*bmap++];
1228 					FILL_32BIT_X888RGB (cte.red, cte.green, cte.blue);
1229 				}
1230 				bmap += padded_line;
1231 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1232 			}
1233 			break;
1234 		case GDF_24BIT_888RGB:
1235 			while (ycount--) {
1236 				WATCHDOG_RESET ();
1237 				xcount = width;
1238 				while (xcount--) {
1239 					cte = bmp->color_table[*bmap++];
1240 					FILL_24BIT_888RGB (cte.red, cte.green, cte.blue);
1241 				}
1242 				bmap += padded_line;
1243 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1244 			}
1245 			break;
1246 		}
1247 		break;
1248 	case 24:
1249 		padded_line -= 3 * width;
1250 		ycount = height;
1251 		switch (VIDEO_DATA_FORMAT) {
1252 		case GDF__8BIT_332RGB:
1253 			while (ycount--) {
1254 				WATCHDOG_RESET ();
1255 				xcount = width;
1256 				while (xcount--) {
1257 					FILL_8BIT_332RGB (bmap[2], bmap[1], bmap[0]);
1258 					bmap += 3;
1259 				}
1260 				bmap += padded_line;
1261 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1262 			}
1263 			break;
1264 		case GDF_15BIT_555RGB:
1265 			while (ycount--) {
1266 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1267 				int xpos = x;
1268 #endif
1269 				WATCHDOG_RESET ();
1270 				xcount = width;
1271 				while (xcount--) {
1272 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1273 					fill_555rgb_pswap (fb, xpos++, bmap[2],
1274 							   bmap[1], bmap[0]);
1275 					fb += 2;
1276 #else
1277 					FILL_15BIT_555RGB (bmap[2], bmap[1], bmap[0]);
1278 #endif
1279 					bmap += 3;
1280 				}
1281 				bmap += padded_line;
1282 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1283 			}
1284 			break;
1285 		case GDF_16BIT_565RGB:
1286 			while (ycount--) {
1287 				WATCHDOG_RESET ();
1288 				xcount = width;
1289 				while (xcount--) {
1290 					FILL_16BIT_565RGB (bmap[2], bmap[1], bmap[0]);
1291 					bmap += 3;
1292 				}
1293 				bmap += padded_line;
1294 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1295 			}
1296 			break;
1297 		case GDF_32BIT_X888RGB:
1298 			while (ycount--) {
1299 				WATCHDOG_RESET ();
1300 				xcount = width;
1301 				while (xcount--) {
1302 					FILL_32BIT_X888RGB (bmap[2], bmap[1], bmap[0]);
1303 					bmap += 3;
1304 				}
1305 				bmap += padded_line;
1306 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1307 			}
1308 			break;
1309 		case GDF_24BIT_888RGB:
1310 			while (ycount--) {
1311 				WATCHDOG_RESET ();
1312 				xcount = width;
1313 				while (xcount--) {
1314 					FILL_24BIT_888RGB (bmap[2], bmap[1], bmap[0]);
1315 					bmap += 3;
1316 				}
1317 				bmap += padded_line;
1318 				fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE;
1319 			}
1320 			break;
1321 		default:
1322 			printf ("Error: 24 bits/pixel bitmap incompatible with current video mode\n");
1323 			break;
1324 		}
1325 		break;
1326 	default:
1327 		printf ("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
1328 			le16_to_cpu (bmp->header.bit_count));
1329 		break;
1330 	}
1331 
1332 #ifdef CONFIG_VIDEO_BMP_GZIP
1333 	if (dst) {
1334 		free(dst);
1335 	}
1336 #endif
1337 
1338 	return (0);
1339 }
1340 #endif
1341 
1342 /*****************************************************************************/
1343 
1344 #ifdef CONFIG_VIDEO_LOGO
1345 void logo_plot (void *screen, int width, int x, int y)
1346 {
1347 
1348 	int xcount, i;
1349 	int skip   = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE;
1350 	int ycount = video_logo_height;
1351 	unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
1352 	unsigned char *source;
1353 	unsigned char *dest = (unsigned char *)screen +
1354 			      ((y * width * VIDEO_PIXEL_SIZE) +
1355 			       x * VIDEO_PIXEL_SIZE);
1356 
1357 #ifdef CONFIG_VIDEO_BMP_LOGO
1358 	source = bmp_logo_bitmap;
1359 
1360 	/* Allocate temporary space for computing colormap */
1361 	logo_red = malloc (BMP_LOGO_COLORS);
1362 	logo_green = malloc (BMP_LOGO_COLORS);
1363 	logo_blue = malloc (BMP_LOGO_COLORS);
1364 	/* Compute color map */
1365 	for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1366 		logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
1367 		logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
1368 		logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
1369 	}
1370 #else
1371 	source = linux_logo;
1372 	logo_red = linux_logo_red;
1373 	logo_green = linux_logo_green;
1374 	logo_blue = linux_logo_blue;
1375 #endif
1376 
1377 	if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1378 		for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1379 			video_set_lut (i + VIDEO_LOGO_LUT_OFFSET,
1380 				       logo_red[i], logo_green[i], logo_blue[i]);
1381 		}
1382 	}
1383 
1384 	while (ycount--) {
1385 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1386 		int xpos = x;
1387 #endif
1388 		xcount = VIDEO_LOGO_WIDTH;
1389 		while (xcount--) {
1390 			r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
1391 			g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
1392 			b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
1393 
1394 			switch (VIDEO_DATA_FORMAT) {
1395 			case GDF__8BIT_INDEX:
1396 				*dest = *source;
1397 				break;
1398 			case GDF__8BIT_332RGB:
1399 				*dest = ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
1400 				break;
1401 			case GDF_15BIT_555RGB:
1402 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1403 				fill_555rgb_pswap (dest, xpos++, r, g, b);
1404 #else
1405 				*(unsigned short *) dest =
1406 					SWAP16 ((unsigned short) (((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3)));
1407 #endif
1408 				break;
1409 			case GDF_16BIT_565RGB:
1410 				*(unsigned short *) dest =
1411 					SWAP16 ((unsigned short) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)));
1412 				break;
1413 			case GDF_32BIT_X888RGB:
1414 				*(unsigned long *) dest =
1415 					SWAP32 ((unsigned long) ((r << 16) | (g << 8) | b));
1416 				break;
1417 			case GDF_24BIT_888RGB:
1418 #ifdef VIDEO_FB_LITTLE_ENDIAN
1419 				dest[0] = b;
1420 				dest[1] = g;
1421 				dest[2] = r;
1422 #else
1423 				dest[0] = r;
1424 				dest[1] = g;
1425 				dest[2] = b;
1426 #endif
1427 				break;
1428 			}
1429 			source++;
1430 			dest += VIDEO_PIXEL_SIZE;
1431 		}
1432 		dest += skip;
1433 	}
1434 #ifdef CONFIG_VIDEO_BMP_LOGO
1435 	free (logo_red);
1436 	free (logo_green);
1437 	free (logo_blue);
1438 #endif
1439 }
1440 
1441 /*****************************************************************************/
1442 
1443 static void *video_logo (void)
1444 {
1445 	char info[128];
1446 	extern char version_string;
1447 	int space, len, y_off = 0;
1448 
1449 #ifdef CONFIG_SPLASH_SCREEN
1450 	char *s;
1451 	ulong addr;
1452 
1453 	if ((s = getenv ("splashimage")) != NULL) {
1454 		int x = 0, y = 0;
1455 
1456 		addr = simple_strtoul (s, NULL, 16);
1457 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1458 		if ((s = getenv ("splashpos")) != NULL) {
1459 			if (s[0] == 'm')
1460 				x = BMP_ALIGN_CENTER;
1461 			else
1462 				x = simple_strtol (s, NULL, 0);
1463 
1464 			if ((s = strchr (s + 1, ',')) != NULL) {
1465 				if (s[1] == 'm')
1466 					y = BMP_ALIGN_CENTER;
1467 				else
1468 					y = simple_strtol (s + 1, NULL, 0);
1469 			}
1470 		}
1471 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1472 
1473 		if (video_display_bitmap (addr, x, y) == 0) {
1474 			video_logo_height = 0;
1475 			return ((void *) (video_fb_address));
1476 		}
1477 	}
1478 #endif /* CONFIG_SPLASH_SCREEN */
1479 
1480 	logo_plot (video_fb_address, VIDEO_COLS, 0, 0);
1481 
1482 	sprintf (info, " %s", &version_string);
1483 
1484 	space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
1485 	len = strlen(info);
1486 
1487 	if (len > space) {
1488 		video_drawchars (VIDEO_INFO_X, VIDEO_INFO_Y,
1489 				 (uchar *)info, space);
1490 		video_drawchars (VIDEO_INFO_X + VIDEO_FONT_WIDTH,
1491 				 VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
1492 				 (uchar *)info + space, len - space);
1493 		y_off = 1;
1494 	} else
1495 		video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *)info);
1496 
1497 #ifdef CONFIG_CONSOLE_EXTRA_INFO
1498 	{
1499 		int i, n = ((video_logo_height - VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
1500 
1501 		for (i = 1; i < n; i++) {
1502 			video_get_info_str (i, info);
1503 			if (!*info)
1504 				continue;
1505 
1506 			len = strlen(info);
1507 			if (len > space) {
1508 				video_drawchars (VIDEO_INFO_X,
1509 						 VIDEO_INFO_Y +
1510 						 (i + y_off) * VIDEO_FONT_HEIGHT,
1511 						 (uchar *)info, space);
1512 				y_off++;
1513 				video_drawchars (VIDEO_INFO_X + VIDEO_FONT_WIDTH,
1514 						 VIDEO_INFO_Y +
1515 						 (i + y_off) * VIDEO_FONT_HEIGHT,
1516 						 (uchar *)info + space,
1517 						 len - space);
1518 			} else {
1519 				video_drawstring (VIDEO_INFO_X,
1520 						  VIDEO_INFO_Y +
1521 						  (i + y_off) * VIDEO_FONT_HEIGHT,
1522 						  (uchar *)info);
1523 			}
1524 		}
1525 	}
1526 #endif
1527 
1528 	return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
1529 }
1530 #endif
1531 
1532 
1533 /*****************************************************************************/
1534 
1535 static int video_init (void)
1536 {
1537 	unsigned char color8;
1538 
1539 	if ((pGD = video_hw_init ()) == NULL)
1540 		return -1;
1541 
1542 	video_fb_address = (void *) VIDEO_FB_ADRS;
1543 #ifdef CONFIG_VIDEO_HW_CURSOR
1544 	video_init_hw_cursor (VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
1545 #endif
1546 
1547 	/* Init drawing pats */
1548 	switch (VIDEO_DATA_FORMAT) {
1549 	case GDF__8BIT_INDEX:
1550 		video_set_lut (0x01, CONSOLE_FG_COL, CONSOLE_FG_COL, CONSOLE_FG_COL);
1551 		video_set_lut (0x00, CONSOLE_BG_COL, CONSOLE_BG_COL, CONSOLE_BG_COL);
1552 		fgx = 0x01010101;
1553 		bgx = 0x00000000;
1554 		break;
1555 	case GDF__8BIT_332RGB:
1556 		color8 = ((CONSOLE_FG_COL & 0xe0) |
1557 			  ((CONSOLE_FG_COL >> 3) & 0x1c) | CONSOLE_FG_COL >> 6);
1558 		fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8;
1559 		color8 = ((CONSOLE_BG_COL & 0xe0) |
1560 			  ((CONSOLE_BG_COL >> 3) & 0x1c) | CONSOLE_BG_COL >> 6);
1561 		bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8;
1562 		break;
1563 	case GDF_15BIT_555RGB:
1564 		fgx = (((CONSOLE_FG_COL >> 3) << 26) |
1565 		       ((CONSOLE_FG_COL >> 3) << 21) | ((CONSOLE_FG_COL >> 3) << 16) |
1566 		       ((CONSOLE_FG_COL >> 3) << 10) | ((CONSOLE_FG_COL >> 3) << 5) |
1567 		       (CONSOLE_FG_COL >> 3));
1568 		bgx = (((CONSOLE_BG_COL >> 3) << 26) |
1569 		       ((CONSOLE_BG_COL >> 3) << 21) | ((CONSOLE_BG_COL >> 3) << 16) |
1570 		       ((CONSOLE_BG_COL >> 3) << 10) | ((CONSOLE_BG_COL >> 3) << 5) |
1571 		       (CONSOLE_BG_COL >> 3));
1572 		break;
1573 	case GDF_16BIT_565RGB:
1574 		fgx = (((CONSOLE_FG_COL >> 3) << 27) |
1575 		       ((CONSOLE_FG_COL >> 2) << 21) | ((CONSOLE_FG_COL >> 3) << 16) |
1576 		       ((CONSOLE_FG_COL >> 3) << 11) | ((CONSOLE_FG_COL >> 2) << 5) |
1577 		       (CONSOLE_FG_COL >> 3));
1578 		bgx = (((CONSOLE_BG_COL >> 3) << 27) |
1579 		       ((CONSOLE_BG_COL >> 2) << 21) | ((CONSOLE_BG_COL >> 3) << 16) |
1580 		       ((CONSOLE_BG_COL >> 3) << 11) | ((CONSOLE_BG_COL >> 2) << 5) |
1581 		       (CONSOLE_BG_COL >> 3));
1582 		break;
1583 	case GDF_32BIT_X888RGB:
1584 		fgx = (CONSOLE_FG_COL << 16) | (CONSOLE_FG_COL << 8) | CONSOLE_FG_COL;
1585 		bgx = (CONSOLE_BG_COL << 16) | (CONSOLE_BG_COL << 8) | CONSOLE_BG_COL;
1586 		break;
1587 	case GDF_24BIT_888RGB:
1588 		fgx = (CONSOLE_FG_COL << 24) | (CONSOLE_FG_COL << 16) |
1589 			(CONSOLE_FG_COL << 8) | CONSOLE_FG_COL;
1590 		bgx = (CONSOLE_BG_COL << 24) | (CONSOLE_BG_COL << 16) |
1591 			(CONSOLE_BG_COL << 8) | CONSOLE_BG_COL;
1592 		break;
1593 	}
1594 	eorx = fgx ^ bgx;
1595 
1596 #ifdef CONFIG_VIDEO_LOGO
1597 	/* Plot the logo and get start point of console */
1598 	PRINTD ("Video: Drawing the logo ...\n");
1599 	video_console_address = video_logo ();
1600 #else
1601 	video_console_address = video_fb_address;
1602 #endif
1603 
1604 	/* Initialize the console */
1605 	console_col = 0;
1606 	console_row = 0;
1607 
1608 	return 0;
1609 }
1610 
1611 
1612 /*****************************************************************************/
1613 
1614 /*
1615  * Implement a weak default function for boards that optionally
1616  * need to skip the video initialization.
1617  */
1618 int __board_video_skip(void)
1619 {
1620 	/* As default, don't skip test */
1621 	return 0;
1622 }
1623 int board_video_skip(void) __attribute__((weak, alias("__board_video_skip")));
1624 
1625 int drv_video_init (void)
1626 {
1627 	int skip_dev_init;
1628 	struct stdio_dev console_dev;
1629 
1630 	/* Check if video initialization should be skipped */
1631 	if (board_video_skip())
1632 		return 0;
1633 
1634 	/* Init video chip - returns with framebuffer cleared */
1635 	skip_dev_init = (video_init () == -1);
1636 
1637 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
1638 	PRINTD ("KBD: Keyboard init ...\n");
1639 	skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
1640 #endif
1641 
1642 	if (skip_dev_init)
1643 		return 0;
1644 
1645 	/* Init vga device */
1646 	memset (&console_dev, 0, sizeof (console_dev));
1647 	strcpy (console_dev.name, "vga");
1648 	console_dev.ext = DEV_EXT_VIDEO;	/* Video extensions */
1649 	console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
1650 	console_dev.putc = video_putc;	/* 'putc' function */
1651 	console_dev.puts = video_puts;	/* 'puts' function */
1652 	console_dev.tstc = NULL;	/* 'tstc' function */
1653 	console_dev.getc = NULL;	/* 'getc' function */
1654 
1655 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
1656 	/* Also init console device */
1657 	console_dev.flags |= DEV_FLAGS_INPUT;
1658 	console_dev.tstc = VIDEO_TSTC_FCT;	/* 'tstc' function */
1659 	console_dev.getc = VIDEO_GETC_FCT;	/* 'getc' function */
1660 #endif /* CONFIG_VGA_AS_SINGLE_DEVICE */
1661 
1662 	if (stdio_register (&console_dev) != 0)
1663 		return 0;
1664 
1665 	/* Return success */
1666 	return 1;
1667 }
1668