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