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