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