xref: /openbmc/u-boot/drivers/video/cfb_console.c (revision 6b44ae6b06967cefd6dbc1993827593341fd62f7)
1 /*
2  * (C) Copyright 2002 ELTEC Elektronik AG
3  * Frank Gottschling <fgottschling@eltec.de>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 /*
9  * cfb_console.c
10  *
11  * Color Framebuffer Console driver for 8/15/16/24/32 bits per pixel.
12  *
13  * At the moment only the 8x16 font is tested and the font fore- and
14  * background color is limited to black/white/gray colors. The Linux
15  * logo can be placed in the upper left corner and additional board
16  * information strings (that normally goes to serial port) can be drawn.
17  *
18  * The console driver can use the standard PC keyboard interface (i8042)
19  * for character input. Character output goes to a memory mapped video
20  * framebuffer with little or big-endian organisation.
21  * With environment setting 'console=serial' the console i/o can be
22  * forced to serial port.
23  *
24  * The driver uses graphic specific defines/parameters/functions:
25  *
26  * (for SMI LynxE graphic chip)
27  *
28  * CONFIG_VIDEO_SMI_LYNXEM    - use graphic driver for SMI 710,712,810
29  * VIDEO_FB_LITTLE_ENDIAN     - framebuffer organisation default: big endian
30  * VIDEO_HW_RECTFILL	      - graphic driver supports hardware rectangle fill
31  * VIDEO_HW_BITBLT	      - graphic driver supports hardware bit blt
32  *
33  * Console Parameters are set by graphic drivers global struct:
34  *
35  * VIDEO_VISIBLE_COLS	      - x resolution
36  * VIDEO_VISIBLE_ROWS	      - y resolution
37  * VIDEO_PIXEL_SIZE	      - storage size in byte per pixel
38  * VIDEO_DATA_FORMAT	      - graphical data format GDF
39  * VIDEO_FB_ADRS	      - start of video memory
40  *
41  * CONFIG_I8042_KBD	      - AT Keyboard driver for i8042
42  * VIDEO_KBD_INIT_FCT	      - init function for keyboard
43  * VIDEO_TSTC_FCT	      - keyboard_tstc function
44  * VIDEO_GETC_FCT	      - keyboard_getc function
45  *
46  * CONFIG_VIDEO_LOGO	      - display Linux Logo in upper left corner.
47  *				Use CONFIG_SPLASH_SCREEN_ALIGN with
48  *				environment variable "splashpos" to place
49  *				the logo on other position. In this case
50  *				no CONSOLE_EXTRA_INFO is possible.
51  * CONFIG_VIDEO_BMP_LOGO      - use bmp_logo instead of linux_logo
52  * CONFIG_CONSOLE_EXTRA_INFO  - display additional board information
53  *				strings that normaly goes to serial
54  *				port.  This define requires a board
55  *				specific function:
56  *				video_drawstring (VIDEO_INFO_X,
57  *					VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT,
58  *					info);
59  *				that fills a info buffer at i=row.
60  *				s.a: board/eltec/bab7xx.
61  * CONFIG_VGA_AS_SINGLE_DEVICE - If set the framebuffer device will be
62  *				initialized as an output only device.
63  *				The Keyboard driver will not be
64  *				set-up.  This may be used, if you have
65  *				no or more than one Keyboard devices
66  *				(USB Keyboard, AT Keyboard).
67  *
68  * CONFIG_VIDEO_SW_CURSOR:    - Draws a cursor after the last
69  *				character. No blinking is provided.
70  *				Uses the macros CURSOR_SET and
71  *				CURSOR_OFF.
72  *
73  * CONFIG_VIDEO_HW_CURSOR:    - Uses the hardware cursor capability
74  *				of the graphic chip. Uses the macro
75  *				CURSOR_SET. ATTENTION: If booting an
76  *				OS, the display driver must disable
77  *				the hardware register of the graphic
78  *				chip. Otherwise a blinking field is
79  *				displayed.
80  */
81 
82 #include <common.h>
83 #include <fdtdec.h>
84 #include <version.h>
85 #include <malloc.h>
86 #include <linux/compiler.h>
87 
88 /*
89  * Console device defines with SMI graphic
90  * Any other graphic must change this section
91  */
92 
93 #ifdef	CONFIG_VIDEO_SMI_LYNXEM
94 
95 #define VIDEO_FB_LITTLE_ENDIAN
96 #define VIDEO_HW_RECTFILL
97 #define VIDEO_HW_BITBLT
98 #endif
99 
100 /*
101  * Defines for the CT69000 driver
102  */
103 #ifdef	CONFIG_VIDEO_CT69000
104 
105 #define VIDEO_FB_LITTLE_ENDIAN
106 #define VIDEO_HW_RECTFILL
107 #define VIDEO_HW_BITBLT
108 #endif
109 
110 /*
111  * Defines for the SED13806 driver
112  */
113 #ifdef CONFIG_VIDEO_SED13806
114 #define VIDEO_FB_LITTLE_ENDIAN
115 #define VIDEO_HW_RECTFILL
116 #define VIDEO_HW_BITBLT
117 #endif
118 
119 #ifdef CONFIG_VIDEO_MXS
120 #define VIDEO_FB_16BPP_WORD_SWAP
121 #endif
122 
123 /*
124  * Defines for the MB862xx driver
125  */
126 #ifdef CONFIG_VIDEO_MB862xx
127 
128 #ifdef CONFIG_VIDEO_CORALP
129 #define VIDEO_FB_LITTLE_ENDIAN
130 #endif
131 #ifdef CONFIG_VIDEO_MB862xx_ACCEL
132 #define VIDEO_HW_RECTFILL
133 #define VIDEO_HW_BITBLT
134 #endif
135 #endif
136 
137 /*
138  * Defines for the i.MX31 driver (mx3fb.c)
139  */
140 #if defined(CONFIG_VIDEO_MX3) || defined(CONFIG_VIDEO_IPUV3)
141 #define VIDEO_FB_16BPP_WORD_SWAP
142 #endif
143 
144 /*
145  * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc.
146  */
147 #include <video_fb.h>
148 
149 #include <splash.h>
150 
151 /*
152  * some Macros
153  */
154 #define VIDEO_VISIBLE_COLS	(pGD->winSizeX)
155 #define VIDEO_VISIBLE_ROWS	(pGD->winSizeY)
156 #define VIDEO_PIXEL_SIZE	(pGD->gdfBytesPP)
157 #define VIDEO_DATA_FORMAT	(pGD->gdfIndex)
158 #define VIDEO_FB_ADRS		(pGD->frameAdrs)
159 
160 /*
161  * Console device defines with i8042 keyboard controller
162  * Any other keyboard controller must change this section
163  */
164 
165 #ifdef	CONFIG_I8042_KBD
166 #include <i8042.h>
167 
168 #define VIDEO_KBD_INIT_FCT	i8042_kbd_init()
169 #define VIDEO_TSTC_FCT		i8042_tstc
170 #define VIDEO_GETC_FCT		i8042_getc
171 #endif
172 
173 /*
174  * Console device
175  */
176 
177 #include <version.h>
178 #include <linux/types.h>
179 #include <stdio_dev.h>
180 #include <video_font.h>
181 
182 #if defined(CONFIG_CMD_DATE)
183 #include <rtc.h>
184 #endif
185 
186 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
187 #include <watchdog.h>
188 #include <bmp_layout.h>
189 #include <splash.h>
190 #endif
191 
192 /*
193  * Cursor definition:
194  * CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No
195  *			   blinking is provided. Uses the macros CURSOR_SET
196  *			   and CURSOR_OFF.
197  * CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the
198  *			   graphic chip. Uses the macro CURSOR_SET.
199  *			   ATTENTION: If booting an OS, the display driver
200  *			   must disable the hardware register of the graphic
201  *			   chip. Otherwise a blinking field is displayed
202  */
203 #if !defined(CONFIG_VIDEO_SW_CURSOR) && !defined(CONFIG_VIDEO_HW_CURSOR)
204 /* no Cursor defined */
205 #define CURSOR_ON
206 #define CURSOR_OFF
207 #define CURSOR_SET
208 #endif
209 
210 #if defined(CONFIG_VIDEO_SW_CURSOR)
211 #if defined(CONFIG_VIDEO_HW_CURSOR)
212 #error	only one of CONFIG_VIDEO_SW_CURSOR or CONFIG_VIDEO_HW_CURSOR can be \
213 	defined
214 #endif
215 void console_cursor(int state);
216 
217 #define CURSOR_ON  console_cursor(1)
218 #define CURSOR_OFF console_cursor(0)
219 #define CURSOR_SET video_set_cursor()
220 #endif /* CONFIG_VIDEO_SW_CURSOR */
221 
222 #ifdef CONFIG_VIDEO_HW_CURSOR
223 #ifdef	CURSOR_ON
224 #error	only one of CONFIG_VIDEO_SW_CURSOR or CONFIG_VIDEO_HW_CURSOR can be \
225 	defined
226 #endif
227 #define CURSOR_ON
228 #define CURSOR_OFF
229 #define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \
230 		  (console_row * VIDEO_FONT_HEIGHT) + video_logo_height)
231 #endif /* CONFIG_VIDEO_HW_CURSOR */
232 
233 #ifdef	CONFIG_VIDEO_LOGO
234 #ifdef	CONFIG_VIDEO_BMP_LOGO
235 #include <bmp_logo.h>
236 #include <bmp_logo_data.h>
237 #define VIDEO_LOGO_WIDTH	BMP_LOGO_WIDTH
238 #define VIDEO_LOGO_HEIGHT	BMP_LOGO_HEIGHT
239 #define VIDEO_LOGO_LUT_OFFSET	BMP_LOGO_OFFSET
240 #define VIDEO_LOGO_COLORS	BMP_LOGO_COLORS
241 
242 #else  /* CONFIG_VIDEO_BMP_LOGO */
243 #define LINUX_LOGO_WIDTH	80
244 #define LINUX_LOGO_HEIGHT	80
245 #define LINUX_LOGO_COLORS	214
246 #define LINUX_LOGO_LUT_OFFSET	0x20
247 #define __initdata
248 #include <linux_logo.h>
249 #define VIDEO_LOGO_WIDTH	LINUX_LOGO_WIDTH
250 #define VIDEO_LOGO_HEIGHT	LINUX_LOGO_HEIGHT
251 #define VIDEO_LOGO_LUT_OFFSET	LINUX_LOGO_LUT_OFFSET
252 #define VIDEO_LOGO_COLORS	LINUX_LOGO_COLORS
253 #endif /* CONFIG_VIDEO_BMP_LOGO */
254 #define VIDEO_INFO_X		(VIDEO_LOGO_WIDTH)
255 #define VIDEO_INFO_Y		(VIDEO_FONT_HEIGHT/2)
256 #else  /* CONFIG_VIDEO_LOGO */
257 #define VIDEO_LOGO_WIDTH	0
258 #define VIDEO_LOGO_HEIGHT	0
259 #endif /* CONFIG_VIDEO_LOGO */
260 
261 #define VIDEO_COLS		VIDEO_VISIBLE_COLS
262 #define VIDEO_ROWS		VIDEO_VISIBLE_ROWS
263 #ifndef VIDEO_LINE_LEN
264 #define VIDEO_LINE_LEN		(VIDEO_COLS * VIDEO_PIXEL_SIZE)
265 #endif
266 #define VIDEO_SIZE		(VIDEO_ROWS * VIDEO_LINE_LEN)
267 #define VIDEO_BURST_LEN		(VIDEO_COLS/8)
268 
269 #ifdef	CONFIG_VIDEO_LOGO
270 #define CONSOLE_ROWS		((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT)
271 #else
272 #define CONSOLE_ROWS		(VIDEO_ROWS / VIDEO_FONT_HEIGHT)
273 #endif
274 
275 #define CONSOLE_COLS		(VIDEO_COLS / VIDEO_FONT_WIDTH)
276 #define CONSOLE_ROW_SIZE	(VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
277 #define CONSOLE_ROW_FIRST	(video_console_address)
278 #define CONSOLE_ROW_SECOND	(video_console_address + CONSOLE_ROW_SIZE)
279 #define CONSOLE_ROW_LAST	(video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
280 #define CONSOLE_SIZE		(CONSOLE_ROW_SIZE * CONSOLE_ROWS)
281 
282 /* By default we scroll by a single line */
283 #ifndef CONFIG_CONSOLE_SCROLL_LINES
284 #define CONFIG_CONSOLE_SCROLL_LINES 1
285 #endif
286 
287 /* Macros */
288 #ifdef	VIDEO_FB_LITTLE_ENDIAN
289 #define SWAP16(x)		((((x) & 0x00ff) << 8) | \
290 				  ((x) >> 8) \
291 				)
292 #define SWAP32(x)		((((x) & 0x000000ff) << 24) | \
293 				 (((x) & 0x0000ff00) <<  8) | \
294 				 (((x) & 0x00ff0000) >>  8) | \
295 				 (((x) & 0xff000000) >> 24)   \
296 				)
297 #define SHORTSWAP32(x)		((((x) & 0x000000ff) <<  8) | \
298 				 (((x) & 0x0000ff00) >>  8) | \
299 				 (((x) & 0x00ff0000) <<  8) | \
300 				 (((x) & 0xff000000) >>  8)   \
301 				)
302 #else
303 #define SWAP16(x)		(x)
304 #define SWAP32(x)		(x)
305 #if defined(VIDEO_FB_16BPP_WORD_SWAP)
306 #define SHORTSWAP32(x)		(((x) >> 16) | ((x) << 16))
307 #else
308 #define SHORTSWAP32(x)		(x)
309 #endif
310 #endif
311 
312 #ifdef CONFIG_CONSOLE_EXTRA_INFO
313 /*
314  * setup a board string: type, speed, etc.
315  *
316  * line_number:	location to place info string beside logo
317  * info:	buffer for info string
318  */
319 extern void video_get_info_str(int line_number,	char *info);
320 #endif
321 
322 DECLARE_GLOBAL_DATA_PTR;
323 
324 /* Locals */
325 static GraphicDevice *pGD;	/* Pointer to Graphic array */
326 
327 static void *video_fb_address;	/* frame buffer address */
328 static void *video_console_address;	/* console buffer start address */
329 
330 static int video_logo_height = VIDEO_LOGO_HEIGHT;
331 
332 static int __maybe_unused cursor_state;
333 static int __maybe_unused old_col;
334 static int __maybe_unused old_row;
335 
336 static int console_col;		/* cursor col */
337 static int console_row;		/* cursor row */
338 
339 static u32 eorx, fgx, bgx;	/* color pats */
340 
341 static int cfb_do_flush_cache;
342 
343 #ifdef CONFIG_CFB_CONSOLE_ANSI
344 static char ansi_buf[10];
345 static int ansi_buf_size;
346 static int ansi_colors_need_revert;
347 static int ansi_cursor_hidden;
348 #endif
349 
350 static const int video_font_draw_table8[] = {
351 	0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
352 	0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
353 	0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
354 	0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
355 };
356 
357 static const int video_font_draw_table15[] = {
358 	0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff
359 };
360 
361 static const int video_font_draw_table16[] = {
362 	0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
363 };
364 
365 static const int video_font_draw_table24[16][3] = {
366 	{0x00000000, 0x00000000, 0x00000000},
367 	{0x00000000, 0x00000000, 0x00ffffff},
368 	{0x00000000, 0x0000ffff, 0xff000000},
369 	{0x00000000, 0x0000ffff, 0xffffffff},
370 	{0x000000ff, 0xffff0000, 0x00000000},
371 	{0x000000ff, 0xffff0000, 0x00ffffff},
372 	{0x000000ff, 0xffffffff, 0xff000000},
373 	{0x000000ff, 0xffffffff, 0xffffffff},
374 	{0xffffff00, 0x00000000, 0x00000000},
375 	{0xffffff00, 0x00000000, 0x00ffffff},
376 	{0xffffff00, 0x0000ffff, 0xff000000},
377 	{0xffffff00, 0x0000ffff, 0xffffffff},
378 	{0xffffffff, 0xffff0000, 0x00000000},
379 	{0xffffffff, 0xffff0000, 0x00ffffff},
380 	{0xffffffff, 0xffffffff, 0xff000000},
381 	{0xffffffff, 0xffffffff, 0xffffffff}
382 };
383 
384 static const int video_font_draw_table32[16][4] = {
385 	{0x00000000, 0x00000000, 0x00000000, 0x00000000},
386 	{0x00000000, 0x00000000, 0x00000000, 0x00ffffff},
387 	{0x00000000, 0x00000000, 0x00ffffff, 0x00000000},
388 	{0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff},
389 	{0x00000000, 0x00ffffff, 0x00000000, 0x00000000},
390 	{0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff},
391 	{0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000},
392 	{0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff},
393 	{0x00ffffff, 0x00000000, 0x00000000, 0x00000000},
394 	{0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff},
395 	{0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000},
396 	{0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff},
397 	{0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000},
398 	{0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff},
399 	{0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000},
400 	{0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff}
401 };
402 
403 /*
404  * Implement a weak default function for boards that optionally
405  * need to skip the cfb initialization.
406  */
407 __weak int board_cfb_skip(void)
408 {
409 	/* As default, don't skip cfb init */
410 	return 0;
411 }
412 
413 static void video_drawchars(int xx, int yy, unsigned char *s, int count)
414 {
415 	u8 *cdat, *dest, *dest0;
416 	int rows, offset, c;
417 
418 	offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE;
419 	dest0 = video_fb_address + offset;
420 
421 	switch (VIDEO_DATA_FORMAT) {
422 	case GDF__8BIT_INDEX:
423 	case GDF__8BIT_332RGB:
424 		while (count--) {
425 			c = *s;
426 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
427 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
428 			     rows--; dest += VIDEO_LINE_LEN) {
429 				u8 bits = *cdat++;
430 
431 				((u32 *) dest)[0] =
432 					(video_font_draw_table8[bits >> 4] &
433 					 eorx) ^ bgx;
434 
435 				if (VIDEO_FONT_WIDTH == 4)
436 					continue;
437 
438 				((u32 *) dest)[1] =
439 					(video_font_draw_table8[bits & 15] &
440 					 eorx) ^ bgx;
441 			}
442 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
443 			s++;
444 		}
445 		break;
446 
447 	case GDF_15BIT_555RGB:
448 		while (count--) {
449 			c = *s;
450 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
451 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
452 			     rows--; dest += VIDEO_LINE_LEN) {
453 				u8 bits = *cdat++;
454 
455 				((u32 *) dest)[0] =
456 					SHORTSWAP32((video_font_draw_table15
457 						     [bits >> 6] & eorx) ^
458 						    bgx);
459 				((u32 *) dest)[1] =
460 					SHORTSWAP32((video_font_draw_table15
461 						     [bits >> 4 & 3] & eorx) ^
462 						    bgx);
463 
464 				if (VIDEO_FONT_WIDTH == 4)
465 					continue;
466 
467 				((u32 *) dest)[2] =
468 					SHORTSWAP32((video_font_draw_table15
469 						     [bits >> 2 & 3] & eorx) ^
470 						    bgx);
471 				((u32 *) dest)[3] =
472 					SHORTSWAP32((video_font_draw_table15
473 						     [bits & 3] & eorx) ^
474 						    bgx);
475 			}
476 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
477 			s++;
478 		}
479 		break;
480 
481 	case GDF_16BIT_565RGB:
482 		while (count--) {
483 			c = *s;
484 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
485 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
486 			     rows--; dest += VIDEO_LINE_LEN) {
487 				u8 bits = *cdat++;
488 
489 				((u32 *) dest)[0] =
490 					SHORTSWAP32((video_font_draw_table16
491 						     [bits >> 6] & eorx) ^
492 						    bgx);
493 				((u32 *) dest)[1] =
494 					SHORTSWAP32((video_font_draw_table16
495 						     [bits >> 4 & 3] & eorx) ^
496 						    bgx);
497 
498 				if (VIDEO_FONT_WIDTH == 4)
499 					continue;
500 
501 				((u32 *) dest)[2] =
502 					SHORTSWAP32((video_font_draw_table16
503 						     [bits >> 2 & 3] & eorx) ^
504 						    bgx);
505 				((u32 *) dest)[3] =
506 					SHORTSWAP32((video_font_draw_table16
507 						     [bits & 3] & eorx) ^
508 						    bgx);
509 			}
510 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
511 			s++;
512 		}
513 		break;
514 
515 	case GDF_32BIT_X888RGB:
516 		while (count--) {
517 			c = *s;
518 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
519 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
520 			     rows--; dest += VIDEO_LINE_LEN) {
521 				u8 bits = *cdat++;
522 
523 				((u32 *) dest)[0] =
524 					SWAP32((video_font_draw_table32
525 						[bits >> 4][0] & eorx) ^ bgx);
526 				((u32 *) dest)[1] =
527 					SWAP32((video_font_draw_table32
528 						[bits >> 4][1] & eorx) ^ bgx);
529 				((u32 *) dest)[2] =
530 					SWAP32((video_font_draw_table32
531 						[bits >> 4][2] & eorx) ^ bgx);
532 				((u32 *) dest)[3] =
533 					SWAP32((video_font_draw_table32
534 						[bits >> 4][3] & eorx) ^ bgx);
535 
536 
537 				if (VIDEO_FONT_WIDTH == 4)
538 					continue;
539 
540 				((u32 *) dest)[4] =
541 					SWAP32((video_font_draw_table32
542 						[bits & 15][0] & eorx) ^ bgx);
543 				((u32 *) dest)[5] =
544 					SWAP32((video_font_draw_table32
545 						[bits & 15][1] & eorx) ^ bgx);
546 				((u32 *) dest)[6] =
547 					SWAP32((video_font_draw_table32
548 						[bits & 15][2] & eorx) ^ bgx);
549 				((u32 *) dest)[7] =
550 					SWAP32((video_font_draw_table32
551 						[bits & 15][3] & eorx) ^ bgx);
552 			}
553 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
554 			s++;
555 		}
556 		break;
557 
558 	case GDF_24BIT_888RGB:
559 		while (count--) {
560 			c = *s;
561 			cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
562 			for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
563 			     rows--; dest += VIDEO_LINE_LEN) {
564 				u8 bits = *cdat++;
565 
566 				((u32 *) dest)[0] =
567 					(video_font_draw_table24[bits >> 4][0]
568 					 & eorx) ^ bgx;
569 				((u32 *) dest)[1] =
570 					(video_font_draw_table24[bits >> 4][1]
571 					 & eorx) ^ bgx;
572 				((u32 *) dest)[2] =
573 					(video_font_draw_table24[bits >> 4][2]
574 					 & eorx) ^ bgx;
575 
576 				if (VIDEO_FONT_WIDTH == 4)
577 					continue;
578 
579 				((u32 *) dest)[3] =
580 					(video_font_draw_table24[bits & 15][0]
581 					 & eorx) ^ bgx;
582 				((u32 *) dest)[4] =
583 					(video_font_draw_table24[bits & 15][1]
584 					 & eorx) ^ bgx;
585 				((u32 *) dest)[5] =
586 					(video_font_draw_table24[bits & 15][2]
587 					 & eorx) ^ bgx;
588 			}
589 			dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
590 			s++;
591 		}
592 		break;
593 	}
594 }
595 
596 static inline void video_drawstring(int xx, int yy, unsigned char *s)
597 {
598 	video_drawchars(xx, yy, s, strlen((char *) s));
599 }
600 
601 static void video_putchar(int xx, int yy, unsigned char c)
602 {
603 	video_drawchars(xx, yy + video_logo_height, &c, 1);
604 }
605 
606 #if defined(CONFIG_VIDEO_SW_CURSOR)
607 static void video_set_cursor(void)
608 {
609 	if (cursor_state)
610 		console_cursor(0);
611 	console_cursor(1);
612 }
613 
614 static void video_invertchar(int xx, int yy)
615 {
616 	int firstx = xx * VIDEO_PIXEL_SIZE;
617 	int lastx = (xx + VIDEO_FONT_WIDTH) * VIDEO_PIXEL_SIZE;
618 	int firsty = yy * VIDEO_LINE_LEN;
619 	int lasty = (yy + VIDEO_FONT_HEIGHT) * VIDEO_LINE_LEN;
620 	int x, y;
621 	for (y = firsty; y < lasty; y += VIDEO_LINE_LEN) {
622 		for (x = firstx; x < lastx; x++) {
623 			u8 *dest = (u8 *)(video_fb_address) + x + y;
624 			*dest = ~*dest;
625 		}
626 	}
627 }
628 
629 void console_cursor(int state)
630 {
631 	if (cursor_state != state) {
632 		if (cursor_state) {
633 			/* turn off the cursor */
634 			video_invertchar(old_col * VIDEO_FONT_WIDTH,
635 					 old_row * VIDEO_FONT_HEIGHT +
636 					 video_logo_height);
637 		} else {
638 			/* turn off the cursor and record where it is */
639 			video_invertchar(console_col * VIDEO_FONT_WIDTH,
640 					 console_row * VIDEO_FONT_HEIGHT +
641 					 video_logo_height);
642 			old_col = console_col;
643 			old_row = console_row;
644 		}
645 		cursor_state = state;
646 	}
647 	if (cfb_do_flush_cache)
648 		flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
649 }
650 #endif
651 
652 #ifndef VIDEO_HW_RECTFILL
653 static void memsetl(int *p, int c, int v)
654 {
655 	while (c--)
656 		*(p++) = v;
657 }
658 #endif
659 
660 #ifndef VIDEO_HW_BITBLT
661 static void memcpyl(int *d, int *s, int c)
662 {
663 	while (c--)
664 		*(d++) = *(s++);
665 }
666 #endif
667 
668 static void console_clear_line(int line, int begin, int end)
669 {
670 #ifdef VIDEO_HW_RECTFILL
671 	video_hw_rectfill(VIDEO_PIXEL_SIZE,		/* bytes per pixel */
672 			  VIDEO_FONT_WIDTH * begin,	/* dest pos x */
673 			  video_logo_height +
674 			  VIDEO_FONT_HEIGHT * line,	/* dest pos y */
675 			  VIDEO_FONT_WIDTH * (end - begin + 1), /* fr. width */
676 			  VIDEO_FONT_HEIGHT,		/* frame height */
677 			  bgx				/* fill color */
678 		);
679 #else
680 	if (begin == 0 && (end + 1) == CONSOLE_COLS) {
681 		memsetl(CONSOLE_ROW_FIRST +
682 			CONSOLE_ROW_SIZE * line,	/* offset of row */
683 			CONSOLE_ROW_SIZE >> 2,		/* length of row */
684 			bgx				/* fill color */
685 		);
686 	} else {
687 		void *offset;
688 		int i, size;
689 
690 		offset = CONSOLE_ROW_FIRST +
691 			 CONSOLE_ROW_SIZE * line +	/* offset of row */
692 			 VIDEO_FONT_WIDTH *
693 			 VIDEO_PIXEL_SIZE * begin;	/* offset of col */
694 		size = VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE * (end - begin + 1);
695 		size >>= 2; /* length to end for memsetl() */
696 		/* fill at col offset of i'th line using bgx as fill color */
697 		for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
698 			memsetl(offset + i * VIDEO_LINE_LEN, size, bgx);
699 	}
700 #endif
701 }
702 
703 static void console_scrollup(void)
704 {
705 	const int rows = CONFIG_CONSOLE_SCROLL_LINES;
706 	int i;
707 
708 	/* copy up rows ignoring the first one */
709 
710 #ifdef VIDEO_HW_BITBLT
711 	video_hw_bitblt(VIDEO_PIXEL_SIZE,	/* bytes per pixel */
712 			0,			/* source pos x */
713 			video_logo_height +
714 				VIDEO_FONT_HEIGHT * rows, /* source pos y */
715 			0,			/* dest pos x */
716 			video_logo_height,	/* dest pos y */
717 			VIDEO_VISIBLE_COLS,	/* frame width */
718 			VIDEO_VISIBLE_ROWS
719 			- video_logo_height
720 			- VIDEO_FONT_HEIGHT * rows	/* frame height */
721 		);
722 #else
723 	memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_FIRST + rows * CONSOLE_ROW_SIZE,
724 		(CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows) >> 2);
725 #endif
726 	/* clear the last one */
727 	for (i = 1; i <= rows; i++)
728 		console_clear_line(CONSOLE_ROWS - i, 0, CONSOLE_COLS - 1);
729 
730 	/* Decrement row number */
731 	console_row -= rows;
732 }
733 
734 static void console_back(void)
735 {
736 	console_col--;
737 
738 	if (console_col < 0) {
739 		console_col = CONSOLE_COLS - 1;
740 		console_row--;
741 		if (console_row < 0)
742 			console_row = 0;
743 	}
744 }
745 
746 #ifdef CONFIG_CFB_CONSOLE_ANSI
747 
748 static void console_clear(void)
749 {
750 #ifdef VIDEO_HW_RECTFILL
751 	video_hw_rectfill(VIDEO_PIXEL_SIZE,	/* bytes per pixel */
752 			  0,			/* dest pos x */
753 			  video_logo_height,	/* dest pos y */
754 			  VIDEO_VISIBLE_COLS,	/* frame width */
755 			  VIDEO_VISIBLE_ROWS,	/* frame height */
756 			  bgx			/* fill color */
757 	);
758 #else
759 	memsetl(CONSOLE_ROW_FIRST, CONSOLE_SIZE, bgx);
760 #endif
761 }
762 
763 static void console_cursor_fix(void)
764 {
765 	if (console_row < 0)
766 		console_row = 0;
767 	if (console_row >= CONSOLE_ROWS)
768 		console_row = CONSOLE_ROWS - 1;
769 	if (console_col < 0)
770 		console_col = 0;
771 	if (console_col >= CONSOLE_COLS)
772 		console_col = CONSOLE_COLS - 1;
773 }
774 
775 static void console_cursor_up(int n)
776 {
777 	console_row -= n;
778 	console_cursor_fix();
779 }
780 
781 static void console_cursor_down(int n)
782 {
783 	console_row += n;
784 	console_cursor_fix();
785 }
786 
787 static void console_cursor_left(int n)
788 {
789 	console_col -= n;
790 	console_cursor_fix();
791 }
792 
793 static void console_cursor_right(int n)
794 {
795 	console_col += n;
796 	console_cursor_fix();
797 }
798 
799 static void console_cursor_set_position(int row, int col)
800 {
801 	if (console_row != -1)
802 		console_row = row;
803 	if (console_col != -1)
804 		console_col = col;
805 	console_cursor_fix();
806 }
807 
808 static void console_previousline(int n)
809 {
810 	/* FIXME: also scroll terminal ? */
811 	console_row -= n;
812 	console_cursor_fix();
813 }
814 
815 static void console_swap_colors(void)
816 {
817 	eorx = fgx;
818 	fgx = bgx;
819 	bgx = eorx;
820 	eorx = fgx ^ bgx;
821 }
822 
823 static inline int console_cursor_is_visible(void)
824 {
825 	return !ansi_cursor_hidden;
826 }
827 #else
828 static inline int console_cursor_is_visible(void)
829 {
830 	return 1;
831 }
832 #endif
833 
834 static void console_newline(int n)
835 {
836 	console_row += n;
837 	console_col = 0;
838 
839 	/* Check if we need to scroll the terminal */
840 	if (console_row >= CONSOLE_ROWS) {
841 		/* Scroll everything up */
842 		console_scrollup();
843 	}
844 }
845 
846 static void console_cr(void)
847 {
848 	console_col = 0;
849 }
850 
851 static void parse_putc(const char c)
852 {
853 	static int nl = 1;
854 
855 	if (console_cursor_is_visible())
856 		CURSOR_OFF;
857 
858 	switch (c) {
859 	case 13:		/* back to first column */
860 		console_cr();
861 		break;
862 
863 	case '\n':		/* next line */
864 		if (console_col || (!console_col && nl))
865 			console_newline(1);
866 		nl = 1;
867 		break;
868 
869 	case 9:		/* tab 8 */
870 		console_col |= 0x0008;
871 		console_col &= ~0x0007;
872 
873 		if (console_col >= CONSOLE_COLS)
874 			console_newline(1);
875 		break;
876 
877 	case 8:		/* backspace */
878 		console_back();
879 		break;
880 
881 	case 7:		/* bell */
882 		break;	/* ignored */
883 
884 	default:		/* draw the char */
885 		video_putchar(console_col * VIDEO_FONT_WIDTH,
886 			      console_row * VIDEO_FONT_HEIGHT, c);
887 		console_col++;
888 
889 		/* check for newline */
890 		if (console_col >= CONSOLE_COLS) {
891 			console_newline(1);
892 			nl = 0;
893 		}
894 	}
895 
896 	if (console_cursor_is_visible())
897 		CURSOR_SET;
898 }
899 
900 static void video_putc(struct stdio_dev *dev, const char c)
901 {
902 #ifdef CONFIG_CFB_CONSOLE_ANSI
903 	int i;
904 
905 	if (c == 27) {
906 		for (i = 0; i < ansi_buf_size; ++i)
907 			parse_putc(ansi_buf[i]);
908 		ansi_buf[0] = 27;
909 		ansi_buf_size = 1;
910 		return;
911 	}
912 
913 	if (ansi_buf_size > 0) {
914 		/*
915 		 * 0 - ESC
916 		 * 1 - [
917 		 * 2 - num1
918 		 * 3 - ..
919 		 * 4 - ;
920 		 * 5 - num2
921 		 * 6 - ..
922 		 * - cchar
923 		 */
924 		int next = 0;
925 
926 		int flush = 0;
927 		int fail = 0;
928 
929 		int num1 = 0;
930 		int num2 = 0;
931 		int cchar = 0;
932 
933 		ansi_buf[ansi_buf_size++] = c;
934 
935 		if (ansi_buf_size >= sizeof(ansi_buf))
936 			fail = 1;
937 
938 		for (i = 0; i < ansi_buf_size; ++i) {
939 			if (fail)
940 				break;
941 
942 			switch (next) {
943 			case 0:
944 				if (ansi_buf[i] == 27)
945 					next = 1;
946 				else
947 					fail = 1;
948 				break;
949 
950 			case 1:
951 				if (ansi_buf[i] == '[')
952 					next = 2;
953 				else
954 					fail = 1;
955 				break;
956 
957 			case 2:
958 				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
959 					num1 = ansi_buf[i]-'0';
960 					next = 3;
961 				} else if (ansi_buf[i] != '?') {
962 					--i;
963 					num1 = 1;
964 					next = 4;
965 				}
966 				break;
967 
968 			case 3:
969 				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
970 					num1 *= 10;
971 					num1 += ansi_buf[i]-'0';
972 				} else {
973 					--i;
974 					next = 4;
975 				}
976 				break;
977 
978 			case 4:
979 				if (ansi_buf[i] != ';') {
980 					--i;
981 					next = 7;
982 				} else
983 					next = 5;
984 				break;
985 
986 			case 5:
987 				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
988 					num2 = ansi_buf[i]-'0';
989 					next = 6;
990 				} else
991 					fail = 1;
992 				break;
993 
994 			case 6:
995 				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
996 					num2 *= 10;
997 					num2 += ansi_buf[i]-'0';
998 				} else {
999 					--i;
1000 					next = 7;
1001 				}
1002 				break;
1003 
1004 			case 7:
1005 				if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H')
1006 					|| ansi_buf[i] == 'J'
1007 					|| ansi_buf[i] == 'K'
1008 					|| ansi_buf[i] == 'h'
1009 					|| ansi_buf[i] == 'l'
1010 					|| ansi_buf[i] == 'm') {
1011 					cchar = ansi_buf[i];
1012 					flush = 1;
1013 				} else
1014 					fail = 1;
1015 				break;
1016 			}
1017 		}
1018 
1019 		if (fail) {
1020 			for (i = 0; i < ansi_buf_size; ++i)
1021 				parse_putc(ansi_buf[i]);
1022 			ansi_buf_size = 0;
1023 			return;
1024 		}
1025 
1026 		if (flush) {
1027 			if (!ansi_cursor_hidden)
1028 				CURSOR_OFF;
1029 			ansi_buf_size = 0;
1030 			switch (cchar) {
1031 			case 'A':
1032 				/* move cursor num1 rows up */
1033 				console_cursor_up(num1);
1034 				break;
1035 			case 'B':
1036 				/* move cursor num1 rows down */
1037 				console_cursor_down(num1);
1038 				break;
1039 			case 'C':
1040 				/* move cursor num1 columns forward */
1041 				console_cursor_right(num1);
1042 				break;
1043 			case 'D':
1044 				/* move cursor num1 columns back */
1045 				console_cursor_left(num1);
1046 				break;
1047 			case 'E':
1048 				/* move cursor num1 rows up at begin of row */
1049 				console_previousline(num1);
1050 				break;
1051 			case 'F':
1052 				/* move cursor num1 rows down at begin of row */
1053 				console_newline(num1);
1054 				break;
1055 			case 'G':
1056 				/* move cursor to column num1 */
1057 				console_cursor_set_position(-1, num1-1);
1058 				break;
1059 			case 'H':
1060 				/* move cursor to row num1, column num2 */
1061 				console_cursor_set_position(num1-1, num2-1);
1062 				break;
1063 			case 'J':
1064 				/* clear console and move cursor to 0, 0 */
1065 				console_clear();
1066 				console_cursor_set_position(0, 0);
1067 				break;
1068 			case 'K':
1069 				/* clear line */
1070 				if (num1 == 0)
1071 					console_clear_line(console_row,
1072 							console_col,
1073 							CONSOLE_COLS-1);
1074 				else if (num1 == 1)
1075 					console_clear_line(console_row,
1076 							0, console_col);
1077 				else
1078 					console_clear_line(console_row,
1079 							0, CONSOLE_COLS-1);
1080 				break;
1081 			case 'h':
1082 				ansi_cursor_hidden = 0;
1083 				break;
1084 			case 'l':
1085 				ansi_cursor_hidden = 1;
1086 				break;
1087 			case 'm':
1088 				if (num1 == 0) { /* reset swapped colors */
1089 					if (ansi_colors_need_revert) {
1090 						console_swap_colors();
1091 						ansi_colors_need_revert = 0;
1092 					}
1093 				} else if (num1 == 7) { /* once swap colors */
1094 					if (!ansi_colors_need_revert) {
1095 						console_swap_colors();
1096 						ansi_colors_need_revert = 1;
1097 					}
1098 				}
1099 				break;
1100 			}
1101 			if (!ansi_cursor_hidden)
1102 				CURSOR_SET;
1103 		}
1104 	} else {
1105 		parse_putc(c);
1106 	}
1107 #else
1108 	parse_putc(c);
1109 #endif
1110 	if (cfb_do_flush_cache)
1111 		flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
1112 }
1113 
1114 static void video_puts(struct stdio_dev *dev, const char *s)
1115 {
1116 	int flush = cfb_do_flush_cache;
1117 	int count = strlen(s);
1118 
1119 	/* temporarily disable cache flush */
1120 	cfb_do_flush_cache = 0;
1121 
1122 	while (count--)
1123 		video_putc(dev, *s++);
1124 
1125 	if (flush) {
1126 		cfb_do_flush_cache = flush;
1127 		flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
1128 	}
1129 }
1130 
1131 /*
1132  * Do not enforce drivers (or board code) to provide empty
1133  * video_set_lut() if they do not support 8 bpp format.
1134  * Implement weak default function instead.
1135  */
1136 __weak void video_set_lut(unsigned int index, unsigned char r,
1137 		     unsigned char g, unsigned char b)
1138 {
1139 }
1140 
1141 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
1142 
1143 #define FILL_8BIT_332RGB(r,g,b)	{			\
1144 	*fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6);	\
1145 	fb ++;						\
1146 }
1147 
1148 #define FILL_15BIT_555RGB(r,g,b) {			\
1149 	*(unsigned short *)fb =				\
1150 		SWAP16((unsigned short)(((r>>3)<<10) |	\
1151 					((g>>3)<<5)  |	\
1152 					 (b>>3)));	\
1153 	fb += 2;					\
1154 }
1155 
1156 #define FILL_16BIT_565RGB(r,g,b) {			\
1157 	*(unsigned short *)fb =				\
1158 		SWAP16((unsigned short)((((r)>>3)<<11)| \
1159 					(((g)>>2)<<5) | \
1160 					 ((b)>>3)));	\
1161 	fb += 2;					\
1162 }
1163 
1164 #define FILL_32BIT_X888RGB(r,g,b) {			\
1165 	*(unsigned long *)fb =				\
1166 		SWAP32((unsigned long)(((r<<16) |	\
1167 					(g<<8)  |	\
1168 					 b)));		\
1169 	fb += 4;					\
1170 }
1171 
1172 #ifdef VIDEO_FB_LITTLE_ENDIAN
1173 #define FILL_24BIT_888RGB(r,g,b) {			\
1174 	fb[0] = b;					\
1175 	fb[1] = g;					\
1176 	fb[2] = r;					\
1177 	fb += 3;					\
1178 }
1179 #else
1180 #define FILL_24BIT_888RGB(r,g,b) {			\
1181 	fb[0] = r;					\
1182 	fb[1] = g;					\
1183 	fb[2] = b;					\
1184 	fb += 3;					\
1185 }
1186 #endif
1187 
1188 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1189 static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b)
1190 {
1191 	ushort *dst = (ushort *) fb;
1192 	ushort color = (ushort) (((r >> 3) << 10) |
1193 				 ((g >> 3) <<  5) |
1194 				  (b >> 3));
1195 	if (x & 1)
1196 		*(--dst) = color;
1197 	else
1198 		*(++dst) = color;
1199 }
1200 #endif
1201 
1202 /*
1203  * RLE8 bitmap support
1204  */
1205 
1206 #ifdef CONFIG_VIDEO_BMP_RLE8
1207 /* Pre-calculated color table entry */
1208 struct palette {
1209 	union {
1210 		unsigned short w;	/* word */
1211 		unsigned int dw;	/* double word */
1212 	} ce;				/* color entry */
1213 };
1214 
1215 /*
1216  * Helper to draw encoded/unencoded run.
1217  */
1218 static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p,
1219 			int cnt, int enc)
1220 {
1221 	ulong addr = (ulong) *fb;
1222 	int *off;
1223 	int enc_off = 1;
1224 	int i;
1225 
1226 	/*
1227 	 * Setup offset of the color index in the bitmap.
1228 	 * Color index of encoded run is at offset 1.
1229 	 */
1230 	off = enc ? &enc_off : &i;
1231 
1232 	switch (VIDEO_DATA_FORMAT) {
1233 	case GDF__8BIT_INDEX:
1234 		for (i = 0; i < cnt; i++)
1235 			*(unsigned char *) addr++ = bm[*off];
1236 		break;
1237 	case GDF_15BIT_555RGB:
1238 	case GDF_16BIT_565RGB:
1239 		/* differences handled while pre-calculating palette */
1240 		for (i = 0; i < cnt; i++) {
1241 			*(unsigned short *) addr = p[bm[*off]].ce.w;
1242 			addr += 2;
1243 		}
1244 		break;
1245 	case GDF_32BIT_X888RGB:
1246 		for (i = 0; i < cnt; i++) {
1247 			*(unsigned long *) addr = p[bm[*off]].ce.dw;
1248 			addr += 4;
1249 		}
1250 		break;
1251 	}
1252 	*fb = (uchar *) addr;	/* return modified address */
1253 }
1254 
1255 static int display_rle8_bitmap(struct bmp_image *img, int xoff, int yoff,
1256 			       int width, int height)
1257 {
1258 	unsigned char *bm;
1259 	unsigned char *fbp;
1260 	unsigned int cnt, runlen;
1261 	int decode = 1;
1262 	int x, y, bpp, i, ncolors;
1263 	struct palette p[256];
1264 	struct bmp_color_table_entry cte;
1265 	int green_shift, red_off;
1266 	int limit = (VIDEO_LINE_LEN / VIDEO_PIXEL_SIZE) * VIDEO_ROWS;
1267 	int pixels = 0;
1268 
1269 	x = 0;
1270 	y = __le32_to_cpu(img->header.height) - 1;
1271 	ncolors = __le32_to_cpu(img->header.colors_used);
1272 	bpp = VIDEO_PIXEL_SIZE;
1273 	fbp = (unsigned char *) ((unsigned int) video_fb_address +
1274 				 (y + yoff) * VIDEO_LINE_LEN +
1275 				 xoff * bpp);
1276 
1277 	bm = (uchar *) img + __le32_to_cpu(img->header.data_offset);
1278 
1279 	/* pre-calculate and setup palette */
1280 	switch (VIDEO_DATA_FORMAT) {
1281 	case GDF__8BIT_INDEX:
1282 		for (i = 0; i < ncolors; i++) {
1283 			cte = img->color_table[i];
1284 			video_set_lut(i, cte.red, cte.green, cte.blue);
1285 		}
1286 		break;
1287 	case GDF_15BIT_555RGB:
1288 	case GDF_16BIT_565RGB:
1289 		if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) {
1290 			green_shift = 3;
1291 			red_off = 10;
1292 		} else {
1293 			green_shift = 2;
1294 			red_off = 11;
1295 		}
1296 		for (i = 0; i < ncolors; i++) {
1297 			cte = img->color_table[i];
1298 			p[i].ce.w = SWAP16((unsigned short)
1299 					   (((cte.red >> 3) << red_off) |
1300 					    ((cte.green >> green_shift) << 5) |
1301 					    cte.blue >> 3));
1302 		}
1303 		break;
1304 	case GDF_32BIT_X888RGB:
1305 		for (i = 0; i < ncolors; i++) {
1306 			cte = img->color_table[i];
1307 			p[i].ce.dw = SWAP32((cte.red << 16) |
1308 					    (cte.green << 8) |
1309 					     cte.blue);
1310 		}
1311 		break;
1312 	default:
1313 		printf("RLE Bitmap unsupported in video mode 0x%x\n",
1314 		       VIDEO_DATA_FORMAT);
1315 		return -1;
1316 	}
1317 
1318 	while (decode) {
1319 		switch (bm[0]) {
1320 		case 0:
1321 			switch (bm[1]) {
1322 			case 0:
1323 				/* scan line end marker */
1324 				bm += 2;
1325 				x = 0;
1326 				y--;
1327 				fbp = (unsigned char *)
1328 					((unsigned int) video_fb_address +
1329 					 (y + yoff) * VIDEO_LINE_LEN +
1330 					 xoff * bpp);
1331 				continue;
1332 			case 1:
1333 				/* end of bitmap data marker */
1334 				decode = 0;
1335 				break;
1336 			case 2:
1337 				/* run offset marker */
1338 				x += bm[2];
1339 				y -= bm[3];
1340 				fbp = (unsigned char *)
1341 					((unsigned int) video_fb_address +
1342 					 (y + yoff) * VIDEO_LINE_LEN +
1343 					 xoff * bpp);
1344 				bm += 4;
1345 				break;
1346 			default:
1347 				/* unencoded run */
1348 				cnt = bm[1];
1349 				runlen = cnt;
1350 				pixels += cnt;
1351 				if (pixels > limit)
1352 					goto error;
1353 
1354 				bm += 2;
1355 				if (y < height) {
1356 					if (x >= width) {
1357 						x += runlen;
1358 						goto next_run;
1359 					}
1360 					if (x + runlen > width)
1361 						cnt = width - x;
1362 					draw_bitmap(&fbp, bm, p, cnt, 0);
1363 					x += runlen;
1364 				}
1365 next_run:
1366 				bm += runlen;
1367 				if (runlen & 1)
1368 					bm++;	/* 0 padding if length is odd */
1369 			}
1370 			break;
1371 		default:
1372 			/* encoded run */
1373 			cnt = bm[0];
1374 			runlen = cnt;
1375 			pixels += cnt;
1376 			if (pixels > limit)
1377 				goto error;
1378 
1379 			if (y < height) {     /* only draw into visible area */
1380 				if (x >= width) {
1381 					x += runlen;
1382 					bm += 2;
1383 					continue;
1384 				}
1385 				if (x + runlen > width)
1386 					cnt = width - x;
1387 				draw_bitmap(&fbp, bm, p, cnt, 1);
1388 				x += runlen;
1389 			}
1390 			bm += 2;
1391 			break;
1392 		}
1393 	}
1394 	return 0;
1395 error:
1396 	printf("Error: Too much encoded pixel data, validate your bitmap\n");
1397 	return -1;
1398 }
1399 #endif
1400 
1401 /*
1402  * Display the BMP file located at address bmp_image.
1403  */
1404 int video_display_bitmap(ulong bmp_image, int x, int y)
1405 {
1406 	ushort xcount, ycount;
1407 	uchar *fb;
1408 	struct bmp_image *bmp = (struct bmp_image *)bmp_image;
1409 	uchar *bmap;
1410 	ushort padded_line;
1411 	unsigned long width, height, bpp;
1412 	unsigned colors;
1413 	unsigned long compression;
1414 	struct bmp_color_table_entry cte;
1415 
1416 #ifdef CONFIG_VIDEO_BMP_GZIP
1417 	unsigned char *dst = NULL;
1418 	ulong len;
1419 #endif
1420 
1421 	WATCHDOG_RESET();
1422 
1423 	if (!((bmp->header.signature[0] == 'B') &&
1424 	      (bmp->header.signature[1] == 'M'))) {
1425 
1426 #ifdef CONFIG_VIDEO_BMP_GZIP
1427 		/*
1428 		 * Could be a gzipped bmp image, try to decrompress...
1429 		 */
1430 		len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
1431 		dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
1432 		if (dst == NULL) {
1433 			printf("Error: malloc in gunzip failed!\n");
1434 			return 1;
1435 		}
1436 		/*
1437 		 * NB: we need to force offset of +2
1438 		 * See doc/README.displaying-bmps
1439 		 */
1440 		if (gunzip(dst+2, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE-2,
1441 			   (uchar *) bmp_image,
1442 			   &len) != 0) {
1443 			printf("Error: no valid bmp or bmp.gz image at %lx\n",
1444 			       bmp_image);
1445 			free(dst);
1446 			return 1;
1447 		}
1448 		if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
1449 			printf("Image could be truncated "
1450 				"(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
1451 		}
1452 
1453 		/*
1454 		 * Set addr to decompressed image
1455 		 */
1456 		bmp = (struct bmp_image *)(dst+2);
1457 
1458 		if (!((bmp->header.signature[0] == 'B') &&
1459 		      (bmp->header.signature[1] == 'M'))) {
1460 			printf("Error: no valid bmp.gz image at %lx\n",
1461 			       bmp_image);
1462 			free(dst);
1463 			return 1;
1464 		}
1465 #else
1466 		printf("Error: no valid bmp image at %lx\n", bmp_image);
1467 		return 1;
1468 #endif /* CONFIG_VIDEO_BMP_GZIP */
1469 	}
1470 
1471 	width = le32_to_cpu(bmp->header.width);
1472 	height = le32_to_cpu(bmp->header.height);
1473 	bpp = le16_to_cpu(bmp->header.bit_count);
1474 	colors = le32_to_cpu(bmp->header.colors_used);
1475 	compression = le32_to_cpu(bmp->header.compression);
1476 
1477 	debug("Display-bmp: %ld x %ld  with %d colors\n",
1478 	      width, height, colors);
1479 
1480 	if (compression != BMP_BI_RGB
1481 #ifdef CONFIG_VIDEO_BMP_RLE8
1482 	    && compression != BMP_BI_RLE8
1483 #endif
1484 		) {
1485 		printf("Error: compression type %ld not supported\n",
1486 		       compression);
1487 #ifdef CONFIG_VIDEO_BMP_GZIP
1488 		if (dst)
1489 			free(dst);
1490 #endif
1491 		return 1;
1492 	}
1493 
1494 	padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
1495 
1496 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1497 	if (x == BMP_ALIGN_CENTER)
1498 		x = max(0, (int)(VIDEO_VISIBLE_COLS - width) / 2);
1499 	else if (x < 0)
1500 		x = max(0, (int)(VIDEO_VISIBLE_COLS - width + x + 1));
1501 
1502 	if (y == BMP_ALIGN_CENTER)
1503 		y = max(0, (int)(VIDEO_VISIBLE_ROWS - height) / 2);
1504 	else if (y < 0)
1505 		y = max(0, (int)(VIDEO_VISIBLE_ROWS - height + y + 1));
1506 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1507 
1508 	/*
1509 	 * Just ignore elements which are completely beyond screen
1510 	 * dimensions.
1511 	 */
1512 	if ((x >= VIDEO_VISIBLE_COLS) || (y >= VIDEO_VISIBLE_ROWS))
1513 		return 0;
1514 
1515 	if ((x + width) > VIDEO_VISIBLE_COLS)
1516 		width = VIDEO_VISIBLE_COLS - x;
1517 	if ((y + height) > VIDEO_VISIBLE_ROWS)
1518 		height = VIDEO_VISIBLE_ROWS - y;
1519 
1520 	bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
1521 	fb = (uchar *) (video_fb_address +
1522 			((y + height - 1) * VIDEO_LINE_LEN) +
1523 			x * VIDEO_PIXEL_SIZE);
1524 
1525 #ifdef CONFIG_VIDEO_BMP_RLE8
1526 	if (compression == BMP_BI_RLE8) {
1527 		return display_rle8_bitmap(bmp, x, y, width, height);
1528 	}
1529 #endif
1530 
1531 	/* We handle only 4, 8, or 24 bpp bitmaps */
1532 	switch (le16_to_cpu(bmp->header.bit_count)) {
1533 	case 4:
1534 		padded_line -= width / 2;
1535 		ycount = height;
1536 
1537 		switch (VIDEO_DATA_FORMAT) {
1538 		case GDF_32BIT_X888RGB:
1539 			while (ycount--) {
1540 				WATCHDOG_RESET();
1541 				/*
1542 				 * Don't assume that 'width' is an
1543 				 * even number
1544 				 */
1545 				for (xcount = 0; xcount < width; xcount++) {
1546 					uchar idx;
1547 
1548 					if (xcount & 1) {
1549 						idx = *bmap & 0xF;
1550 						bmap++;
1551 					} else
1552 						idx = *bmap >> 4;
1553 					cte = bmp->color_table[idx];
1554 					FILL_32BIT_X888RGB(cte.red, cte.green,
1555 							   cte.blue);
1556 				}
1557 				bmap += padded_line;
1558 				fb -= VIDEO_LINE_LEN + width *
1559 					VIDEO_PIXEL_SIZE;
1560 			}
1561 			break;
1562 		default:
1563 			puts("4bpp bitmap unsupported with current "
1564 			     "video mode\n");
1565 			break;
1566 		}
1567 		break;
1568 
1569 	case 8:
1570 		padded_line -= width;
1571 		if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1572 			/* Copy colormap */
1573 			for (xcount = 0; xcount < colors; ++xcount) {
1574 				cte = bmp->color_table[xcount];
1575 				video_set_lut(xcount, cte.red, cte.green,
1576 					      cte.blue);
1577 			}
1578 		}
1579 		ycount = height;
1580 		switch (VIDEO_DATA_FORMAT) {
1581 		case GDF__8BIT_INDEX:
1582 			while (ycount--) {
1583 				WATCHDOG_RESET();
1584 				xcount = width;
1585 				while (xcount--) {
1586 					*fb++ = *bmap++;
1587 				}
1588 				bmap += padded_line;
1589 				fb -= VIDEO_LINE_LEN + width *
1590 					VIDEO_PIXEL_SIZE;
1591 			}
1592 			break;
1593 		case GDF__8BIT_332RGB:
1594 			while (ycount--) {
1595 				WATCHDOG_RESET();
1596 				xcount = width;
1597 				while (xcount--) {
1598 					cte = bmp->color_table[*bmap++];
1599 					FILL_8BIT_332RGB(cte.red, cte.green,
1600 							 cte.blue);
1601 				}
1602 				bmap += padded_line;
1603 				fb -= VIDEO_LINE_LEN + width *
1604 					VIDEO_PIXEL_SIZE;
1605 			}
1606 			break;
1607 		case GDF_15BIT_555RGB:
1608 			while (ycount--) {
1609 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1610 				int xpos = x;
1611 #endif
1612 				WATCHDOG_RESET();
1613 				xcount = width;
1614 				while (xcount--) {
1615 					cte = bmp->color_table[*bmap++];
1616 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1617 					fill_555rgb_pswap(fb, xpos++, cte.red,
1618 							  cte.green,
1619 							  cte.blue);
1620 					fb += 2;
1621 #else
1622 					FILL_15BIT_555RGB(cte.red, cte.green,
1623 							  cte.blue);
1624 #endif
1625 				}
1626 				bmap += padded_line;
1627 				fb -= VIDEO_LINE_LEN + width *
1628 					VIDEO_PIXEL_SIZE;
1629 			}
1630 			break;
1631 		case GDF_16BIT_565RGB:
1632 			while (ycount--) {
1633 				WATCHDOG_RESET();
1634 				xcount = width;
1635 				while (xcount--) {
1636 					cte = bmp->color_table[*bmap++];
1637 					FILL_16BIT_565RGB(cte.red, cte.green,
1638 							  cte.blue);
1639 				}
1640 				bmap += padded_line;
1641 				fb -= VIDEO_LINE_LEN + width *
1642 					VIDEO_PIXEL_SIZE;
1643 			}
1644 			break;
1645 		case GDF_32BIT_X888RGB:
1646 			while (ycount--) {
1647 				WATCHDOG_RESET();
1648 				xcount = width;
1649 				while (xcount--) {
1650 					cte = bmp->color_table[*bmap++];
1651 					FILL_32BIT_X888RGB(cte.red, cte.green,
1652 							   cte.blue);
1653 				}
1654 				bmap += padded_line;
1655 				fb -= VIDEO_LINE_LEN + width *
1656 					VIDEO_PIXEL_SIZE;
1657 			}
1658 			break;
1659 		case GDF_24BIT_888RGB:
1660 			while (ycount--) {
1661 				WATCHDOG_RESET();
1662 				xcount = width;
1663 				while (xcount--) {
1664 					cte = bmp->color_table[*bmap++];
1665 					FILL_24BIT_888RGB(cte.red, cte.green,
1666 							  cte.blue);
1667 				}
1668 				bmap += padded_line;
1669 				fb -= VIDEO_LINE_LEN + width *
1670 					VIDEO_PIXEL_SIZE;
1671 			}
1672 			break;
1673 		}
1674 		break;
1675 	case 24:
1676 		padded_line -= 3 * width;
1677 		ycount = height;
1678 		switch (VIDEO_DATA_FORMAT) {
1679 		case GDF__8BIT_332RGB:
1680 			while (ycount--) {
1681 				WATCHDOG_RESET();
1682 				xcount = width;
1683 				while (xcount--) {
1684 					FILL_8BIT_332RGB(bmap[2], bmap[1],
1685 							 bmap[0]);
1686 					bmap += 3;
1687 				}
1688 				bmap += padded_line;
1689 				fb -= VIDEO_LINE_LEN + width *
1690 					VIDEO_PIXEL_SIZE;
1691 			}
1692 			break;
1693 		case GDF_15BIT_555RGB:
1694 			while (ycount--) {
1695 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1696 				int xpos = x;
1697 #endif
1698 				WATCHDOG_RESET();
1699 				xcount = width;
1700 				while (xcount--) {
1701 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1702 					fill_555rgb_pswap(fb, xpos++, bmap[2],
1703 							  bmap[1], bmap[0]);
1704 					fb += 2;
1705 #else
1706 					FILL_15BIT_555RGB(bmap[2], bmap[1],
1707 							  bmap[0]);
1708 #endif
1709 					bmap += 3;
1710 				}
1711 				bmap += padded_line;
1712 				fb -= VIDEO_LINE_LEN + width *
1713 					VIDEO_PIXEL_SIZE;
1714 			}
1715 			break;
1716 		case GDF_16BIT_565RGB:
1717 			while (ycount--) {
1718 				WATCHDOG_RESET();
1719 				xcount = width;
1720 				while (xcount--) {
1721 					FILL_16BIT_565RGB(bmap[2], bmap[1],
1722 							  bmap[0]);
1723 					bmap += 3;
1724 				}
1725 				bmap += padded_line;
1726 				fb -= VIDEO_LINE_LEN + width *
1727 					VIDEO_PIXEL_SIZE;
1728 			}
1729 			break;
1730 		case GDF_32BIT_X888RGB:
1731 			while (ycount--) {
1732 				WATCHDOG_RESET();
1733 				xcount = width;
1734 				while (xcount--) {
1735 					FILL_32BIT_X888RGB(bmap[2], bmap[1],
1736 							   bmap[0]);
1737 					bmap += 3;
1738 				}
1739 				bmap += padded_line;
1740 				fb -= VIDEO_LINE_LEN + width *
1741 					VIDEO_PIXEL_SIZE;
1742 			}
1743 			break;
1744 		case GDF_24BIT_888RGB:
1745 			while (ycount--) {
1746 				WATCHDOG_RESET();
1747 				xcount = width;
1748 				while (xcount--) {
1749 					FILL_24BIT_888RGB(bmap[2], bmap[1],
1750 							  bmap[0]);
1751 					bmap += 3;
1752 				}
1753 				bmap += padded_line;
1754 				fb -= VIDEO_LINE_LEN + width *
1755 					VIDEO_PIXEL_SIZE;
1756 			}
1757 			break;
1758 		default:
1759 			printf("Error: 24 bits/pixel bitmap incompatible "
1760 				"with current video mode\n");
1761 			break;
1762 		}
1763 		break;
1764 	default:
1765 		printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
1766 			le16_to_cpu(bmp->header.bit_count));
1767 		break;
1768 	}
1769 
1770 #ifdef CONFIG_VIDEO_BMP_GZIP
1771 	if (dst) {
1772 		free(dst);
1773 	}
1774 #endif
1775 
1776 	if (cfb_do_flush_cache)
1777 		flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
1778 	return (0);
1779 }
1780 #endif
1781 
1782 
1783 #ifdef CONFIG_VIDEO_LOGO
1784 static int video_logo_xpos;
1785 static int video_logo_ypos;
1786 
1787 static void plot_logo_or_black(void *screen, int x, int y, int black);
1788 
1789 static void logo_plot(void *screen, int x, int y)
1790 {
1791 	plot_logo_or_black(screen, x, y, 0);
1792 }
1793 
1794 static void logo_black(void)
1795 {
1796 	plot_logo_or_black(video_fb_address, video_logo_xpos, video_logo_ypos,
1797 			1);
1798 }
1799 
1800 static int do_clrlogo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1801 {
1802 	if (argc != 1)
1803 		return cmd_usage(cmdtp);
1804 
1805 	logo_black();
1806 	return 0;
1807 }
1808 
1809 U_BOOT_CMD(
1810 	   clrlogo, 1, 0, do_clrlogo,
1811 	   "fill the boot logo area with black",
1812 	   " "
1813 	   );
1814 
1815 static void plot_logo_or_black(void *screen, int x, int y, int black)
1816 {
1817 
1818 	int xcount, i;
1819 	int skip = VIDEO_LINE_LEN - VIDEO_LOGO_WIDTH * VIDEO_PIXEL_SIZE;
1820 	int ycount = video_logo_height;
1821 	unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
1822 	unsigned char *source;
1823 	unsigned char *dest;
1824 
1825 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1826 	if (x == BMP_ALIGN_CENTER)
1827 		x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2);
1828 	else if (x < 0)
1829 		x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1));
1830 
1831 	if (y == BMP_ALIGN_CENTER)
1832 		y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2);
1833 	else if (y < 0)
1834 		y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1));
1835 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1836 
1837 	dest = (unsigned char *)screen + y * VIDEO_LINE_LEN + x * VIDEO_PIXEL_SIZE;
1838 
1839 #ifdef CONFIG_VIDEO_BMP_LOGO
1840 	source = bmp_logo_bitmap;
1841 
1842 	/* Allocate temporary space for computing colormap */
1843 	logo_red = malloc(BMP_LOGO_COLORS);
1844 	logo_green = malloc(BMP_LOGO_COLORS);
1845 	logo_blue = malloc(BMP_LOGO_COLORS);
1846 	/* Compute color map */
1847 	for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1848 		logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
1849 		logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
1850 		logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
1851 	}
1852 #else
1853 	source = linux_logo;
1854 	logo_red = linux_logo_red;
1855 	logo_green = linux_logo_green;
1856 	logo_blue = linux_logo_blue;
1857 #endif
1858 
1859 	if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1860 		for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1861 			video_set_lut(i + VIDEO_LOGO_LUT_OFFSET,
1862 				      logo_red[i], logo_green[i],
1863 				      logo_blue[i]);
1864 		}
1865 	}
1866 
1867 	while (ycount--) {
1868 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1869 		int xpos = x;
1870 #endif
1871 		xcount = VIDEO_LOGO_WIDTH;
1872 		while (xcount--) {
1873 			if (black) {
1874 				r = 0x00;
1875 				g = 0x00;
1876 				b = 0x00;
1877 			} else {
1878 				r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
1879 				g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
1880 				b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
1881 			}
1882 
1883 			switch (VIDEO_DATA_FORMAT) {
1884 			case GDF__8BIT_INDEX:
1885 				*dest = *source;
1886 				break;
1887 			case GDF__8BIT_332RGB:
1888 				*dest = ((r >> 5) << 5) |
1889 					((g >> 5) << 2) |
1890 					 (b >> 6);
1891 				break;
1892 			case GDF_15BIT_555RGB:
1893 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1894 				fill_555rgb_pswap(dest, xpos++, r, g, b);
1895 #else
1896 				*(unsigned short *) dest =
1897 					SWAP16((unsigned short) (
1898 							((r >> 3) << 10) |
1899 							((g >> 3) <<  5) |
1900 							 (b >> 3)));
1901 #endif
1902 				break;
1903 			case GDF_16BIT_565RGB:
1904 				*(unsigned short *) dest =
1905 					SWAP16((unsigned short) (
1906 							((r >> 3) << 11) |
1907 							((g >> 2) <<  5) |
1908 							 (b >> 3)));
1909 				break;
1910 			case GDF_32BIT_X888RGB:
1911 				*(unsigned long *) dest =
1912 					SWAP32((unsigned long) (
1913 							(r << 16) |
1914 							(g <<  8) |
1915 							 b));
1916 				break;
1917 			case GDF_24BIT_888RGB:
1918 #ifdef VIDEO_FB_LITTLE_ENDIAN
1919 				dest[0] = b;
1920 				dest[1] = g;
1921 				dest[2] = r;
1922 #else
1923 				dest[0] = r;
1924 				dest[1] = g;
1925 				dest[2] = b;
1926 #endif
1927 				break;
1928 			}
1929 			source++;
1930 			dest += VIDEO_PIXEL_SIZE;
1931 		}
1932 		dest += skip;
1933 	}
1934 #ifdef CONFIG_VIDEO_BMP_LOGO
1935 	free(logo_red);
1936 	free(logo_green);
1937 	free(logo_blue);
1938 #endif
1939 }
1940 
1941 static void *video_logo(void)
1942 {
1943 	char info[128];
1944 	int space, len;
1945 	__maybe_unused int y_off = 0;
1946 	__maybe_unused ulong addr;
1947 	__maybe_unused char *s;
1948 
1949 	splash_get_pos(&video_logo_xpos, &video_logo_ypos);
1950 
1951 #ifdef CONFIG_SPLASH_SCREEN
1952 	s = getenv("splashimage");
1953 	if (s != NULL) {
1954 		splash_screen_prepare();
1955 		addr = simple_strtoul(s, NULL, 16);
1956 
1957 		if (video_display_bitmap(addr,
1958 					video_logo_xpos,
1959 					video_logo_ypos) == 0) {
1960 			video_logo_height = 0;
1961 			return ((void *) (video_fb_address));
1962 		}
1963 	}
1964 #endif /* CONFIG_SPLASH_SCREEN */
1965 
1966 	logo_plot(video_fb_address, video_logo_xpos, video_logo_ypos);
1967 
1968 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1969 	/*
1970 	 * when using splashpos for video_logo, skip any info
1971 	 * output on video console if the logo is not at 0,0
1972 	 */
1973 	if (video_logo_xpos || video_logo_ypos) {
1974 		/*
1975 		 * video_logo_height is used in text and cursor offset
1976 		 * calculations. Since the console is below the logo,
1977 		 * we need to adjust the logo height
1978 		 */
1979 		if (video_logo_ypos == BMP_ALIGN_CENTER)
1980 			video_logo_height += max(0, (int)(VIDEO_VISIBLE_ROWS -
1981 						     VIDEO_LOGO_HEIGHT) / 2);
1982 		else if (video_logo_ypos > 0)
1983 			video_logo_height += video_logo_ypos;
1984 
1985 		return video_fb_address + video_logo_height * VIDEO_LINE_LEN;
1986 	}
1987 #endif
1988 	if (board_cfb_skip())
1989 		return 0;
1990 
1991 	sprintf(info, " %s", version_string);
1992 
1993 	space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
1994 	len = strlen(info);
1995 
1996 	if (len > space) {
1997 		video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y,
1998 				(uchar *) info, space);
1999 		video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH,
2000 				VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
2001 				(uchar *) info + space, len - space);
2002 		y_off = 1;
2003 	} else
2004 		video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);
2005 
2006 #ifdef CONFIG_CONSOLE_EXTRA_INFO
2007 	{
2008 		int i, n =
2009 			((video_logo_height -
2010 			  VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
2011 
2012 		for (i = 1; i < n; i++) {
2013 			video_get_info_str(i, info);
2014 			if (!*info)
2015 				continue;
2016 
2017 			len = strlen(info);
2018 			if (len > space) {
2019 				video_drawchars(VIDEO_INFO_X,
2020 						VIDEO_INFO_Y +
2021 						(i + y_off) *
2022 							VIDEO_FONT_HEIGHT,
2023 						(uchar *) info, space);
2024 				y_off++;
2025 				video_drawchars(VIDEO_INFO_X +
2026 						VIDEO_FONT_WIDTH,
2027 						VIDEO_INFO_Y +
2028 							(i + y_off) *
2029 							VIDEO_FONT_HEIGHT,
2030 						(uchar *) info + space,
2031 						len - space);
2032 			} else {
2033 				video_drawstring(VIDEO_INFO_X,
2034 						 VIDEO_INFO_Y +
2035 						 (i + y_off) *
2036 							VIDEO_FONT_HEIGHT,
2037 						 (uchar *) info);
2038 			}
2039 		}
2040 	}
2041 #endif
2042 
2043 	return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
2044 }
2045 #endif
2046 
2047 static int cfb_fb_is_in_dram(void)
2048 {
2049 	bd_t *bd = gd->bd;
2050 #if defined(CONFIG_ARM) || defined(CONFIG_AVR32) || defined(COFNIG_NDS32) || \
2051 defined(CONFIG_SANDBOX) || defined(CONFIG_X86)
2052 	ulong start, end;
2053 	int i;
2054 
2055 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
2056 		start = bd->bi_dram[i].start;
2057 		end = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
2058 		if ((ulong)video_fb_address >= start &&
2059 		    (ulong)video_fb_address < end)
2060 			return 1;
2061 	}
2062 #else
2063 	if ((ulong)video_fb_address >= bd->bi_memstart &&
2064 	    (ulong)video_fb_address < bd->bi_memstart + bd->bi_memsize)
2065 		return 1;
2066 #endif
2067 	return 0;
2068 }
2069 
2070 void video_clear(void)
2071 {
2072 	if (!video_fb_address)
2073 		return;
2074 #ifdef VIDEO_HW_RECTFILL
2075 	video_hw_rectfill(VIDEO_PIXEL_SIZE,	/* bytes per pixel */
2076 			  0,			/* dest pos x */
2077 			  0,			/* dest pos y */
2078 			  VIDEO_VISIBLE_COLS,	/* frame width */
2079 			  VIDEO_VISIBLE_ROWS,	/* frame height */
2080 			  bgx			/* fill color */
2081 	);
2082 #else
2083 	memsetl(video_fb_address,
2084 		(VIDEO_VISIBLE_ROWS * VIDEO_LINE_LEN) / sizeof(int), bgx);
2085 #endif
2086 }
2087 
2088 static int video_init(void)
2089 {
2090 	unsigned char color8;
2091 
2092 	pGD = video_hw_init();
2093 	if (pGD == NULL)
2094 		return -1;
2095 
2096 	video_fb_address = (void *) VIDEO_FB_ADRS;
2097 #ifdef CONFIG_VIDEO_HW_CURSOR
2098 	video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
2099 #endif
2100 
2101 	cfb_do_flush_cache = cfb_fb_is_in_dram() && dcache_status();
2102 
2103 	/* Init drawing pats */
2104 	switch (VIDEO_DATA_FORMAT) {
2105 	case GDF__8BIT_INDEX:
2106 		video_set_lut(0x01, CONSOLE_FG_COL, CONSOLE_FG_COL,
2107 			      CONSOLE_FG_COL);
2108 		video_set_lut(0x00, CONSOLE_BG_COL, CONSOLE_BG_COL,
2109 			      CONSOLE_BG_COL);
2110 		fgx = 0x01010101;
2111 		bgx = 0x00000000;
2112 		break;
2113 	case GDF__8BIT_332RGB:
2114 		color8 = ((CONSOLE_FG_COL & 0xe0) |
2115 			  ((CONSOLE_FG_COL >> 3) & 0x1c) |
2116 			  CONSOLE_FG_COL >> 6);
2117 		fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
2118 			color8;
2119 		color8 = ((CONSOLE_BG_COL & 0xe0) |
2120 			  ((CONSOLE_BG_COL >> 3) & 0x1c) |
2121 			  CONSOLE_BG_COL >> 6);
2122 		bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
2123 			color8;
2124 		break;
2125 	case GDF_15BIT_555RGB:
2126 		fgx = (((CONSOLE_FG_COL >> 3) << 26) |
2127 		       ((CONSOLE_FG_COL >> 3) << 21) |
2128 		       ((CONSOLE_FG_COL >> 3) << 16) |
2129 		       ((CONSOLE_FG_COL >> 3) << 10) |
2130 		       ((CONSOLE_FG_COL >> 3) <<  5) |
2131 			(CONSOLE_FG_COL >> 3));
2132 		bgx = (((CONSOLE_BG_COL >> 3) << 26) |
2133 		       ((CONSOLE_BG_COL >> 3) << 21) |
2134 		       ((CONSOLE_BG_COL >> 3) << 16) |
2135 		       ((CONSOLE_BG_COL >> 3) << 10) |
2136 		       ((CONSOLE_BG_COL >> 3) <<  5) |
2137 			(CONSOLE_BG_COL >> 3));
2138 		break;
2139 	case GDF_16BIT_565RGB:
2140 		fgx = (((CONSOLE_FG_COL >> 3) << 27) |
2141 		       ((CONSOLE_FG_COL >> 2) << 21) |
2142 		       ((CONSOLE_FG_COL >> 3) << 16) |
2143 		       ((CONSOLE_FG_COL >> 3) << 11) |
2144 		       ((CONSOLE_FG_COL >> 2) <<  5) |
2145 			(CONSOLE_FG_COL >> 3));
2146 		bgx = (((CONSOLE_BG_COL >> 3) << 27) |
2147 		       ((CONSOLE_BG_COL >> 2) << 21) |
2148 		       ((CONSOLE_BG_COL >> 3) << 16) |
2149 		       ((CONSOLE_BG_COL >> 3) << 11) |
2150 		       ((CONSOLE_BG_COL >> 2) <<  5) |
2151 			(CONSOLE_BG_COL >> 3));
2152 		break;
2153 	case GDF_32BIT_X888RGB:
2154 		fgx =	(CONSOLE_FG_COL << 16) |
2155 			(CONSOLE_FG_COL <<  8) |
2156 			 CONSOLE_FG_COL;
2157 		bgx =	(CONSOLE_BG_COL << 16) |
2158 			(CONSOLE_BG_COL <<  8) |
2159 			 CONSOLE_BG_COL;
2160 		break;
2161 	case GDF_24BIT_888RGB:
2162 		fgx =	(CONSOLE_FG_COL << 24) |
2163 			(CONSOLE_FG_COL << 16) |
2164 			(CONSOLE_FG_COL <<  8) |
2165 			 CONSOLE_FG_COL;
2166 		bgx =	(CONSOLE_BG_COL << 24) |
2167 			(CONSOLE_BG_COL << 16) |
2168 			(CONSOLE_BG_COL <<  8) |
2169 			 CONSOLE_BG_COL;
2170 		break;
2171 	}
2172 	eorx = fgx ^ bgx;
2173 
2174 	video_clear();
2175 
2176 #ifdef CONFIG_VIDEO_LOGO
2177 	/* Plot the logo and get start point of console */
2178 	debug("Video: Drawing the logo ...\n");
2179 	video_console_address = video_logo();
2180 #else
2181 	video_console_address = video_fb_address;
2182 #endif
2183 
2184 	/* Initialize the console */
2185 	console_col = 0;
2186 	console_row = 0;
2187 
2188 	if (cfb_do_flush_cache)
2189 		flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
2190 
2191 	return 0;
2192 }
2193 
2194 /*
2195  * Implement a weak default function for boards that optionally
2196  * need to skip the video initialization.
2197  */
2198 __weak int board_video_skip(void)
2199 {
2200 	/* As default, don't skip test */
2201 	return 0;
2202 }
2203 
2204 int drv_video_init(void)
2205 {
2206 	struct stdio_dev console_dev;
2207 	bool have_keyboard;
2208 	bool __maybe_unused keyboard_ok = false;
2209 
2210 	/* Check if video initialization should be skipped */
2211 	if (board_video_skip())
2212 		return 0;
2213 
2214 	/* Init video chip - returns with framebuffer cleared */
2215 	if (video_init() == -1)
2216 		return 0;
2217 
2218 	if (board_cfb_skip())
2219 		return 0;
2220 
2221 #if defined(CONFIG_VGA_AS_SINGLE_DEVICE)
2222 	have_keyboard = false;
2223 #elif defined(CONFIG_OF_CONTROL)
2224 	have_keyboard = !fdtdec_get_config_bool(gd->fdt_blob,
2225 						"u-boot,no-keyboard");
2226 #else
2227 	have_keyboard = true;
2228 #endif
2229 	if (have_keyboard) {
2230 		debug("KBD: Keyboard init ...\n");
2231 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
2232 		keyboard_ok = !(VIDEO_KBD_INIT_FCT == -1);
2233 #endif
2234 	}
2235 
2236 	/* Init vga device */
2237 	memset(&console_dev, 0, sizeof(console_dev));
2238 	strcpy(console_dev.name, "vga");
2239 	console_dev.flags = DEV_FLAGS_OUTPUT;
2240 	console_dev.putc = video_putc;	/* 'putc' function */
2241 	console_dev.puts = video_puts;	/* 'puts' function */
2242 
2243 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
2244 	if (have_keyboard && keyboard_ok) {
2245 		/* Also init console device */
2246 		console_dev.flags |= DEV_FLAGS_INPUT;
2247 		console_dev.tstc = VIDEO_TSTC_FCT;	/* 'tstc' function */
2248 		console_dev.getc = VIDEO_GETC_FCT;	/* 'getc' function */
2249 	}
2250 #endif
2251 
2252 	if (stdio_register(&console_dev) != 0)
2253 		return 0;
2254 
2255 	/* Return success */
2256 	return 1;
2257 }
2258 
2259 void video_position_cursor(unsigned col, unsigned row)
2260 {
2261 	console_col = min(col, CONSOLE_COLS - 1);
2262 	console_row = min(row, CONSOLE_ROWS - 1);
2263 }
2264 
2265 int video_get_pixel_width(void)
2266 {
2267 	return VIDEO_VISIBLE_COLS;
2268 }
2269 
2270 int video_get_pixel_height(void)
2271 {
2272 	return VIDEO_VISIBLE_ROWS;
2273 }
2274 
2275 int video_get_screen_rows(void)
2276 {
2277 	return CONSOLE_ROWS;
2278 }
2279 
2280 int video_get_screen_columns(void)
2281 {
2282 	return CONSOLE_COLS;
2283 }
2284