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