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