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