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