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