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