]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/video/cfb_console.c
tools: logo: split bmp arrays from bmp_logo.h
[karo-tx-uboot.git] / drivers / video / cfb_console.c
1 /*
2  * (C) Copyright 2002 ELTEC Elektronik AG
3  * Frank Gottschling <fgottschling@eltec.de>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /*
25  * cfb_console.c
26  *
27  * Color Framebuffer Console driver for 8/15/16/24/32 bits per pixel.
28  *
29  * At the moment only the 8x16 font is tested and the font fore- and
30  * background color is limited to black/white/gray colors. The Linux
31  * logo can be placed in the upper left corner and additional board
32  * information strings (that normally goes to serial port) can be drawn.
33  *
34  * The console driver can use the standard PC keyboard interface (i8042)
35  * for character input. Character output goes to a memory mapped video
36  * framebuffer with little or big-endian organisation.
37  * With environment setting 'console=serial' the console i/o can be
38  * forced to serial port.
39  *
40  * The driver uses graphic specific defines/parameters/functions:
41  *
42  * (for SMI LynxE graphic chip)
43  *
44  * CONFIG_VIDEO_SMI_LYNXEM    - use graphic driver for SMI 710,712,810
45  * VIDEO_FB_LITTLE_ENDIAN     - framebuffer organisation default: big endian
46  * VIDEO_HW_RECTFILL          - graphic driver supports hardware rectangle fill
47  * VIDEO_HW_BITBLT            - graphic driver supports hardware bit blt
48  *
49  * Console Parameters are set by graphic drivers global struct:
50  *
51  * VIDEO_VISIBLE_COLS         - x resolution
52  * VIDEO_VISIBLE_ROWS         - y resolution
53  * VIDEO_PIXEL_SIZE           - storage size in byte per pixel
54  * VIDEO_DATA_FORMAT          - graphical data format GDF
55  * VIDEO_FB_ADRS              - start of video memory
56  *
57  * CONFIG_I8042_KBD           - AT Keyboard driver for i8042
58  * VIDEO_KBD_INIT_FCT         - init function for keyboard
59  * VIDEO_TSTC_FCT             - keyboard_tstc function
60  * VIDEO_GETC_FCT             - keyboard_getc function
61  *
62  * CONFIG_CONSOLE_CURSOR      - on/off drawing cursor is done with
63  *                              delay loop in VIDEO_TSTC_FCT (i8042)
64  *
65  * CONFIG_SYS_CONSOLE_BLINK_COUNT - value for delay loop - blink rate
66  * CONFIG_CONSOLE_TIME        - display time/date in upper right
67  *                              corner, needs CONFIG_CMD_DATE and
68  *                              CONFIG_CONSOLE_CURSOR
69  * CONFIG_VIDEO_LOGO          - display Linux Logo in upper left corner
70  * CONFIG_VIDEO_BMP_LOGO      - use bmp_logo instead of linux_logo
71  * CONFIG_CONSOLE_EXTRA_INFO  - display additional board information
72  *                              strings that normaly goes to serial
73  *                              port.  This define requires a board
74  *                              specific function:
75  *                              video_drawstring (VIDEO_INFO_X,
76  *                                      VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT,
77  *                                      info);
78  *                              that fills a info buffer at i=row.
79  *                              s.a: board/eltec/bab7xx.
80  * CONFIG_VGA_AS_SINGLE_DEVICE - If set the framebuffer device will be
81  *                              initialized as an output only device.
82  *                              The Keyboard driver will not be
83  *                              set-up.  This may be used, if you have
84  *                              no or more than one Keyboard devices
85  *                              (USB Keyboard, AT Keyboard).
86  *
87  * CONFIG_VIDEO_SW_CURSOR:    - Draws a cursor after the last
88  *                              character. No blinking is provided.
89  *                              Uses the macros CURSOR_SET and
90  *                              CURSOR_OFF.
91  *
92  * CONFIG_VIDEO_HW_CURSOR:    - Uses the hardware cursor capability
93  *                              of the graphic chip. Uses the macro
94  *                              CURSOR_SET. ATTENTION: If booting an
95  *                              OS, the display driver must disable
96  *                              the hardware register of the graphic
97  *                              chip. Otherwise a blinking field is
98  *                              displayed.
99  */
100
101 #include <common.h>
102 #include <version.h>
103 #include <malloc.h>
104 #include <linux/compiler.h>
105
106 /*
107  * Console device defines with SMI graphic
108  * Any other graphic must change this section
109  */
110
111 #ifdef  CONFIG_VIDEO_SMI_LYNXEM
112
113 #define VIDEO_FB_LITTLE_ENDIAN
114 #define VIDEO_HW_RECTFILL
115 #define VIDEO_HW_BITBLT
116 #endif
117
118 /*
119  * Defines for the CT69000 driver
120  */
121 #ifdef  CONFIG_VIDEO_CT69000
122
123 #define VIDEO_FB_LITTLE_ENDIAN
124 #define VIDEO_HW_RECTFILL
125 #define VIDEO_HW_BITBLT
126 #endif
127
128 /*
129  * Defines for the SED13806 driver
130  */
131 #ifdef CONFIG_VIDEO_SED13806
132
133 #ifndef CONFIG_TOTAL5200
134 #define VIDEO_FB_LITTLE_ENDIAN
135 #endif
136 #define VIDEO_HW_RECTFILL
137 #define VIDEO_HW_BITBLT
138 #endif
139
140 /*
141  * Defines for the SED13806 driver
142  */
143 #ifdef CONFIG_VIDEO_SM501
144
145 #ifdef CONFIG_HH405
146 #define VIDEO_FB_LITTLE_ENDIAN
147 #endif
148 #endif
149
150 /*
151  * Defines for the MB862xx driver
152  */
153 #ifdef CONFIG_VIDEO_MB862xx
154
155 #ifdef CONFIG_VIDEO_CORALP
156 #define VIDEO_FB_LITTLE_ENDIAN
157 #endif
158 #ifdef CONFIG_VIDEO_MB862xx_ACCEL
159 #define VIDEO_HW_RECTFILL
160 #define VIDEO_HW_BITBLT
161 #endif
162 #endif
163
164 /*
165  * Defines for the i.MX31 driver (mx3fb.c)
166  */
167 #ifdef CONFIG_VIDEO_MX3
168 #define VIDEO_FB_16BPP_WORD_SWAP
169 #endif
170
171 /*
172  * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc.
173  */
174 #include <video_fb.h>
175
176 /*
177  * some Macros
178  */
179 #define VIDEO_VISIBLE_COLS      (pGD->winSizeX)
180 #define VIDEO_VISIBLE_ROWS      (pGD->winSizeY)
181 #define VIDEO_PIXEL_SIZE        (pGD->gdfBytesPP)
182 #define VIDEO_DATA_FORMAT       (pGD->gdfIndex)
183 #define VIDEO_FB_ADRS           (pGD->frameAdrs)
184
185 /*
186  * Console device defines with i8042 keyboard controller
187  * Any other keyboard controller must change this section
188  */
189
190 #ifdef  CONFIG_I8042_KBD
191 #include <i8042.h>
192
193 #define VIDEO_KBD_INIT_FCT      i8042_kbd_init()
194 #define VIDEO_TSTC_FCT          i8042_tstc
195 #define VIDEO_GETC_FCT          i8042_getc
196 #endif
197
198 /*
199  * Console device
200  */
201
202 #include <version.h>
203 #include <linux/types.h>
204 #include <stdio_dev.h>
205 #include <video_font.h>
206
207 #if defined(CONFIG_CMD_DATE)
208 #include <rtc.h>
209 #endif
210
211 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
212 #include <watchdog.h>
213 #include <bmp_layout.h>
214
215 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
216 #define BMP_ALIGN_CENTER        0x7FFF
217 #endif
218
219 #endif
220
221 /*
222  * Cursor definition:
223  * CONFIG_CONSOLE_CURSOR:  Uses a timer function (see drivers/input/i8042.c)
224  *                         to let the cursor blink. Uses the macros
225  *                         CURSOR_OFF and CURSOR_ON.
226  * CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No
227  *                         blinking is provided. Uses the macros CURSOR_SET
228  *                         and CURSOR_OFF.
229  * CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the
230  *                         graphic chip. Uses the macro CURSOR_SET.
231  *                         ATTENTION: If booting an OS, the display driver
232  *                         must disable the hardware register of the graphic
233  *                         chip. Otherwise a blinking field is displayed
234  */
235 #if !defined(CONFIG_CONSOLE_CURSOR) && \
236     !defined(CONFIG_VIDEO_SW_CURSOR) && \
237     !defined(CONFIG_VIDEO_HW_CURSOR)
238 /* no Cursor defined */
239 #define CURSOR_ON
240 #define CURSOR_OFF
241 #define CURSOR_SET
242 #endif
243
244 #ifdef  CONFIG_CONSOLE_CURSOR
245 #ifdef  CURSOR_ON
246 #error  only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
247         or CONFIG_VIDEO_HW_CURSOR can be defined
248 #endif
249 void console_cursor(int state);
250
251 #define CURSOR_ON  console_cursor(1)
252 #define CURSOR_OFF console_cursor(0)
253 #define CURSOR_SET
254 #ifndef CONFIG_I8042_KBD
255 #warning Cursor drawing on/off needs timer function s.a. drivers/input/i8042.c
256 #endif
257 #else
258 #ifdef  CONFIG_CONSOLE_TIME
259 #error  CONFIG_CONSOLE_CURSOR must be defined for CONFIG_CONSOLE_TIME
260 #endif
261 #endif /* CONFIG_CONSOLE_CURSOR */
262
263 #ifdef  CONFIG_VIDEO_SW_CURSOR
264 #ifdef  CURSOR_ON
265 #error  only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
266         or CONFIG_VIDEO_HW_CURSOR can be defined
267 #endif
268 #define CURSOR_ON
269 #define CURSOR_OFF video_putchar(console_col * VIDEO_FONT_WIDTH,\
270                                  console_row * VIDEO_FONT_HEIGHT, ' ')
271 #define CURSOR_SET video_set_cursor()
272 #endif /* CONFIG_VIDEO_SW_CURSOR */
273
274
275 #ifdef CONFIG_VIDEO_HW_CURSOR
276 #ifdef  CURSOR_ON
277 #error  only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
278         or CONFIG_VIDEO_HW_CURSOR can be defined
279 #endif
280 #define CURSOR_ON
281 #define CURSOR_OFF
282 #define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \
283                   (console_row * VIDEO_FONT_HEIGHT) + video_logo_height)
284 #endif /* CONFIG_VIDEO_HW_CURSOR */
285
286 #ifdef  CONFIG_VIDEO_LOGO
287 #ifdef  CONFIG_VIDEO_BMP_LOGO
288 #include <bmp_logo.h>
289 #include <bmp_logo_data.h>
290 #define VIDEO_LOGO_WIDTH        BMP_LOGO_WIDTH
291 #define VIDEO_LOGO_HEIGHT       BMP_LOGO_HEIGHT
292 #define VIDEO_LOGO_LUT_OFFSET   BMP_LOGO_OFFSET
293 #define VIDEO_LOGO_COLORS       BMP_LOGO_COLORS
294
295 #else  /* CONFIG_VIDEO_BMP_LOGO */
296 #define LINUX_LOGO_WIDTH        80
297 #define LINUX_LOGO_HEIGHT       80
298 #define LINUX_LOGO_COLORS       214
299 #define LINUX_LOGO_LUT_OFFSET   0x20
300 #define __initdata
301 #include <linux_logo.h>
302 #define VIDEO_LOGO_WIDTH        LINUX_LOGO_WIDTH
303 #define VIDEO_LOGO_HEIGHT       LINUX_LOGO_HEIGHT
304 #define VIDEO_LOGO_LUT_OFFSET   LINUX_LOGO_LUT_OFFSET
305 #define VIDEO_LOGO_COLORS       LINUX_LOGO_COLORS
306 #endif /* CONFIG_VIDEO_BMP_LOGO */
307 #define VIDEO_INFO_X            (VIDEO_LOGO_WIDTH)
308 #define VIDEO_INFO_Y            (VIDEO_FONT_HEIGHT/2)
309 #else  /* CONFIG_VIDEO_LOGO */
310 #define VIDEO_LOGO_WIDTH        0
311 #define VIDEO_LOGO_HEIGHT       0
312 #endif /* CONFIG_VIDEO_LOGO */
313
314 #define VIDEO_COLS              VIDEO_VISIBLE_COLS
315 #define VIDEO_ROWS              VIDEO_VISIBLE_ROWS
316 #define VIDEO_SIZE              (VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE)
317 #define VIDEO_PIX_BLOCKS        (VIDEO_SIZE >> 2)
318 #define VIDEO_LINE_LEN          (VIDEO_COLS*VIDEO_PIXEL_SIZE)
319 #define VIDEO_BURST_LEN         (VIDEO_COLS/8)
320
321 #ifdef  CONFIG_VIDEO_LOGO
322 #define CONSOLE_ROWS            ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT)
323 #else
324 #define CONSOLE_ROWS            (VIDEO_ROWS / VIDEO_FONT_HEIGHT)
325 #endif
326
327 #define CONSOLE_COLS            (VIDEO_COLS / VIDEO_FONT_WIDTH)
328 #define CONSOLE_ROW_SIZE        (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
329 #define CONSOLE_ROW_FIRST       (video_console_address)
330 #define CONSOLE_ROW_SECOND      (video_console_address + CONSOLE_ROW_SIZE)
331 #define CONSOLE_ROW_LAST        (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
332 #define CONSOLE_SIZE            (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
333 #define CONSOLE_SCROLL_SIZE     (CONSOLE_SIZE - CONSOLE_ROW_SIZE)
334
335 /* Macros */
336 #ifdef  VIDEO_FB_LITTLE_ENDIAN
337 #define SWAP16(x)               ((((x) & 0x00ff) << 8) | \
338                                   ((x) >> 8) \
339                                 )
340 #define SWAP32(x)               ((((x) & 0x000000ff) << 24) | \
341                                  (((x) & 0x0000ff00) <<  8) | \
342                                  (((x) & 0x00ff0000) >>  8) | \
343                                  (((x) & 0xff000000) >> 24)   \
344                                 )
345 #define SHORTSWAP32(x)          ((((x) & 0x000000ff) <<  8) | \
346                                  (((x) & 0x0000ff00) >>  8) | \
347                                  (((x) & 0x00ff0000) <<  8) | \
348                                  (((x) & 0xff000000) >>  8)   \
349                                 )
350 #else
351 #define SWAP16(x)               (x)
352 #define SWAP32(x)               (x)
353 #if defined(VIDEO_FB_16BPP_WORD_SWAP)
354 #define SHORTSWAP32(x)          (((x) >> 16) | ((x) << 16))
355 #else
356 #define SHORTSWAP32(x)          (x)
357 #endif
358 #endif
359
360 #ifdef CONFIG_CONSOLE_EXTRA_INFO
361 /*
362  * setup a board string: type, speed, etc.
363  *
364  * line_number: location to place info string beside logo
365  * info:        buffer for info string
366  */
367 extern void video_get_info_str(int line_number, char *info);
368 #endif
369
370 /* Locals */
371 static GraphicDevice *pGD;      /* Pointer to Graphic array */
372
373 static void *video_fb_address;  /* frame buffer address */
374 static void *video_console_address;     /* console buffer start address */
375
376 static int video_logo_height = VIDEO_LOGO_HEIGHT;
377
378 static int console_col;         /* cursor col */
379 static int console_row;         /* cursor row */
380
381 static u32 eorx, fgx, bgx;      /* color pats */
382
383 static const int video_font_draw_table8[] = {
384         0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
385         0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
386         0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
387         0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
388 };
389
390 static const int video_font_draw_table15[] = {
391         0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff
392 };
393
394 static const int video_font_draw_table16[] = {
395         0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
396 };
397
398 static const int video_font_draw_table24[16][3] = {
399         {0x00000000, 0x00000000, 0x00000000},
400         {0x00000000, 0x00000000, 0x00ffffff},
401         {0x00000000, 0x0000ffff, 0xff000000},
402         {0x00000000, 0x0000ffff, 0xffffffff},
403         {0x000000ff, 0xffff0000, 0x00000000},
404         {0x000000ff, 0xffff0000, 0x00ffffff},
405         {0x000000ff, 0xffffffff, 0xff000000},
406         {0x000000ff, 0xffffffff, 0xffffffff},
407         {0xffffff00, 0x00000000, 0x00000000},
408         {0xffffff00, 0x00000000, 0x00ffffff},
409         {0xffffff00, 0x0000ffff, 0xff000000},
410         {0xffffff00, 0x0000ffff, 0xffffffff},
411         {0xffffffff, 0xffff0000, 0x00000000},
412         {0xffffffff, 0xffff0000, 0x00ffffff},
413         {0xffffffff, 0xffffffff, 0xff000000},
414         {0xffffffff, 0xffffffff, 0xffffffff}
415 };
416
417 static const int video_font_draw_table32[16][4] = {
418         {0x00000000, 0x00000000, 0x00000000, 0x00000000},
419         {0x00000000, 0x00000000, 0x00000000, 0x00ffffff},
420         {0x00000000, 0x00000000, 0x00ffffff, 0x00000000},
421         {0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff},
422         {0x00000000, 0x00ffffff, 0x00000000, 0x00000000},
423         {0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff},
424         {0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000},
425         {0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff},
426         {0x00ffffff, 0x00000000, 0x00000000, 0x00000000},
427         {0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff},
428         {0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000},
429         {0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff},
430         {0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000},
431         {0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff},
432         {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000},
433         {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff}
434 };
435
436
437 static void video_drawchars(int xx, int yy, unsigned char *s, int count)
438 {
439         u8 *cdat, *dest, *dest0;
440         int rows, offset, c;
441
442         offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE;
443         dest0 = video_fb_address + offset;
444
445         switch (VIDEO_DATA_FORMAT) {
446         case GDF__8BIT_INDEX:
447         case GDF__8BIT_332RGB:
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                                         (video_font_draw_table8[bits >> 4] &
457                                          eorx) ^ bgx;
458                                 ((u32 *) dest)[1] =
459                                         (video_font_draw_table8[bits & 15] &
460                                          eorx) ^ bgx;
461                         }
462                         dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
463                         s++;
464                 }
465                 break;
466
467         case GDF_15BIT_555RGB:
468                 while (count--) {
469                         c = *s;
470                         cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
471                         for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
472                              rows--; dest += VIDEO_LINE_LEN) {
473                                 u8 bits = *cdat++;
474
475                                 ((u32 *) dest)[0] =
476                                         SHORTSWAP32((video_font_draw_table15
477                                                      [bits >> 6] & eorx) ^
478                                                     bgx);
479                                 ((u32 *) dest)[1] =
480                                         SHORTSWAP32((video_font_draw_table15
481                                                      [bits >> 4 & 3] & eorx) ^
482                                                     bgx);
483                                 ((u32 *) dest)[2] =
484                                         SHORTSWAP32((video_font_draw_table15
485                                                      [bits >> 2 & 3] & eorx) ^
486                                                     bgx);
487                                 ((u32 *) dest)[3] =
488                                         SHORTSWAP32((video_font_draw_table15
489                                                      [bits & 3] & eorx) ^
490                                                     bgx);
491                         }
492                         dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
493                         s++;
494                 }
495                 break;
496
497         case GDF_16BIT_565RGB:
498                 while (count--) {
499                         c = *s;
500                         cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
501                         for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
502                              rows--; dest += VIDEO_LINE_LEN) {
503                                 u8 bits = *cdat++;
504
505                                 ((u32 *) dest)[0] =
506                                         SHORTSWAP32((video_font_draw_table16
507                                                      [bits >> 6] & eorx) ^
508                                                     bgx);
509                                 ((u32 *) dest)[1] =
510                                         SHORTSWAP32((video_font_draw_table16
511                                                      [bits >> 4 & 3] & eorx) ^
512                                                     bgx);
513                                 ((u32 *) dest)[2] =
514                                         SHORTSWAP32((video_font_draw_table16
515                                                      [bits >> 2 & 3] & eorx) ^
516                                                     bgx);
517                                 ((u32 *) dest)[3] =
518                                         SHORTSWAP32((video_font_draw_table16
519                                                      [bits & 3] & eorx) ^
520                                                     bgx);
521                         }
522                         dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
523                         s++;
524                 }
525                 break;
526
527         case GDF_32BIT_X888RGB:
528                 while (count--) {
529                         c = *s;
530                         cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
531                         for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
532                              rows--; dest += VIDEO_LINE_LEN) {
533                                 u8 bits = *cdat++;
534
535                                 ((u32 *) dest)[0] =
536                                         SWAP32((video_font_draw_table32
537                                                 [bits >> 4][0] & eorx) ^ bgx);
538                                 ((u32 *) dest)[1] =
539                                         SWAP32((video_font_draw_table32
540                                                 [bits >> 4][1] & eorx) ^ bgx);
541                                 ((u32 *) dest)[2] =
542                                         SWAP32((video_font_draw_table32
543                                                 [bits >> 4][2] & eorx) ^ bgx);
544                                 ((u32 *) dest)[3] =
545                                         SWAP32((video_font_draw_table32
546                                                 [bits >> 4][3] & eorx) ^ bgx);
547                                 ((u32 *) dest)[4] =
548                                         SWAP32((video_font_draw_table32
549                                                 [bits & 15][0] & eorx) ^ bgx);
550                                 ((u32 *) dest)[5] =
551                                         SWAP32((video_font_draw_table32
552                                                 [bits & 15][1] & eorx) ^ bgx);
553                                 ((u32 *) dest)[6] =
554                                         SWAP32((video_font_draw_table32
555                                                 [bits & 15][2] & eorx) ^ bgx);
556                                 ((u32 *) dest)[7] =
557                                         SWAP32((video_font_draw_table32
558                                                 [bits & 15][3] & eorx) ^ bgx);
559                         }
560                         dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
561                         s++;
562                 }
563                 break;
564
565         case GDF_24BIT_888RGB:
566                 while (count--) {
567                         c = *s;
568                         cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
569                         for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
570                              rows--; dest += VIDEO_LINE_LEN) {
571                                 u8 bits = *cdat++;
572
573                                 ((u32 *) dest)[0] =
574                                         (video_font_draw_table24[bits >> 4][0]
575                                          & eorx) ^ bgx;
576                                 ((u32 *) dest)[1] =
577                                         (video_font_draw_table24[bits >> 4][1]
578                                          & eorx) ^ bgx;
579                                 ((u32 *) dest)[2] =
580                                         (video_font_draw_table24[bits >> 4][2]
581                                          & eorx) ^ bgx;
582                                 ((u32 *) dest)[3] =
583                                         (video_font_draw_table24[bits & 15][0]
584                                          & eorx) ^ bgx;
585                                 ((u32 *) dest)[4] =
586                                         (video_font_draw_table24[bits & 15][1]
587                                          & eorx) ^ bgx;
588                                 ((u32 *) dest)[5] =
589                                         (video_font_draw_table24[bits & 15][2]
590                                          & eorx) ^ bgx;
591                         }
592                         dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
593                         s++;
594                 }
595                 break;
596         }
597 }
598
599 static inline void video_drawstring(int xx, int yy, unsigned char *s)
600 {
601         video_drawchars(xx, yy, s, strlen((char *) s));
602 }
603
604 static void video_putchar(int xx, int yy, unsigned char c)
605 {
606         video_drawchars(xx, yy + video_logo_height, &c, 1);
607 }
608
609 #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR)
610 static void video_set_cursor(void)
611 {
612         /* swap drawing colors */
613         eorx = fgx;
614         fgx = bgx;
615         bgx = eorx;
616         eorx = fgx ^ bgx;
617         /* draw cursor */
618         video_putchar(console_col * VIDEO_FONT_WIDTH,
619                       console_row * VIDEO_FONT_HEIGHT, ' ');
620         /* restore drawing colors */
621         eorx = fgx;
622         fgx = bgx;
623         bgx = eorx;
624         eorx = fgx ^ bgx;
625 }
626 #endif
627
628 #ifdef CONFIG_CONSOLE_CURSOR
629 void console_cursor(int state)
630 {
631         static int last_state = 0;
632
633 #ifdef CONFIG_CONSOLE_TIME
634         struct rtc_time tm;
635         char info[16];
636
637         /* time update only if cursor is on (faster scroll) */
638         if (state) {
639                 rtc_get(&tm);
640
641                 sprintf(info, " %02d:%02d:%02d ", tm.tm_hour, tm.tm_min,
642                         tm.tm_sec);
643                 video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH,
644                                  VIDEO_INFO_Y, (uchar *) info);
645
646                 sprintf(info, "%02d.%02d.%04d", tm.tm_mday, tm.tm_mon,
647                         tm.tm_year);
648                 video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH,
649                                  VIDEO_INFO_Y + 1 * VIDEO_FONT_HEIGHT,
650                                  (uchar *) info);
651         }
652 #endif
653
654         if (state && (last_state != state)) {
655                 video_set_cursor();
656         }
657
658         if (!state && (last_state != state)) {
659                 /* clear cursor */
660                 video_putchar(console_col * VIDEO_FONT_WIDTH,
661                               console_row * VIDEO_FONT_HEIGHT, ' ');
662         }
663
664         last_state = state;
665 }
666 #endif
667
668 #ifndef VIDEO_HW_RECTFILL
669 static void memsetl(int *p, int c, int v)
670 {
671         while (c--)
672                 *(p++) = v;
673 }
674 #endif
675
676 #ifndef VIDEO_HW_BITBLT
677 static void memcpyl(int *d, int *s, int c)
678 {
679         while (c--)
680                 *(d++) = *(s++);
681 }
682 #endif
683
684 static void console_scrollup(void)
685 {
686         /* copy up rows ignoring the first one */
687
688 #ifdef VIDEO_HW_BITBLT
689         video_hw_bitblt(VIDEO_PIXEL_SIZE,       /* bytes per pixel */
690                         0,                      /* source pos x */
691                         video_logo_height +
692                                 VIDEO_FONT_HEIGHT, /* source pos y */
693                         0,                      /* dest pos x */
694                         video_logo_height,      /* dest pos y */
695                         VIDEO_VISIBLE_COLS,     /* frame width */
696                         VIDEO_VISIBLE_ROWS
697                         - video_logo_height
698                         - VIDEO_FONT_HEIGHT     /* frame height */
699                 );
700 #else
701         memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND,
702                 CONSOLE_SCROLL_SIZE >> 2);
703 #endif
704
705         /* clear the last one */
706 #ifdef VIDEO_HW_RECTFILL
707         video_hw_rectfill(VIDEO_PIXEL_SIZE,     /* bytes per pixel */
708                           0,                    /* dest pos x */
709                           VIDEO_VISIBLE_ROWS
710                           - VIDEO_FONT_HEIGHT,  /* dest pos y */
711                           VIDEO_VISIBLE_COLS,   /* frame width */
712                           VIDEO_FONT_HEIGHT,    /* frame height */
713                           CONSOLE_BG_COL        /* fill color */
714                 );
715 #else
716         memsetl(CONSOLE_ROW_LAST, CONSOLE_ROW_SIZE >> 2, CONSOLE_BG_COL);
717 #endif
718 }
719
720 static void console_back(void)
721 {
722         CURSOR_OFF;
723         console_col--;
724
725         if (console_col < 0) {
726                 console_col = CONSOLE_COLS - 1;
727                 console_row--;
728                 if (console_row < 0)
729                         console_row = 0;
730         }
731         video_putchar(console_col * VIDEO_FONT_WIDTH,
732                       console_row * VIDEO_FONT_HEIGHT, ' ');
733 }
734
735 static void console_newline(void)
736 {
737         /* Check if last character in the line was just drawn. If so, cursor was
738            overwriten and need not to be cleared. Cursor clearing without this
739            check causes overwriting the 1st character of the line if line lenght
740            is >= CONSOLE_COLS
741          */
742         if (console_col < CONSOLE_COLS)
743                 CURSOR_OFF;
744         console_row++;
745         console_col = 0;
746
747         /* Check if we need to scroll the terminal */
748         if (console_row >= CONSOLE_ROWS) {
749                 /* Scroll everything up */
750                 console_scrollup();
751
752                 /* Decrement row number */
753                 console_row--;
754         }
755 }
756
757 static void console_cr(void)
758 {
759         CURSOR_OFF;
760         console_col = 0;
761 }
762
763 void video_putc(const char c)
764 {
765         static int nl = 1;
766
767         switch (c) {
768         case 13:                /* back to first column */
769                 console_cr();
770                 break;
771
772         case '\n':              /* next line */
773                 if (console_col || (!console_col && nl))
774                         console_newline();
775                 nl = 1;
776                 break;
777
778         case 9:         /* tab 8 */
779                 CURSOR_OFF;
780                 console_col |= 0x0008;
781                 console_col &= ~0x0007;
782
783                 if (console_col >= CONSOLE_COLS)
784                         console_newline();
785                 break;
786
787         case 8:         /* backspace */
788                 console_back();
789                 break;
790
791         default:                /* draw the char */
792                 video_putchar(console_col * VIDEO_FONT_WIDTH,
793                               console_row * VIDEO_FONT_HEIGHT, c);
794                 console_col++;
795
796                 /* check for newline */
797                 if (console_col >= CONSOLE_COLS) {
798                         console_newline();
799                         nl = 0;
800                 }
801         }
802         CURSOR_SET;
803 }
804
805 void video_puts(const char *s)
806 {
807         int count = strlen(s);
808
809         while (count--)
810                 video_putc(*s++);
811 }
812
813 /*
814  * Do not enforce drivers (or board code) to provide empty
815  * video_set_lut() if they do not support 8 bpp format.
816  * Implement weak default function instead.
817  */
818 void __video_set_lut(unsigned int index, unsigned char r,
819                      unsigned char g, unsigned char b)
820 {
821 }
822
823 void video_set_lut(unsigned int, unsigned char, unsigned char, unsigned char)
824         __attribute__ ((weak, alias("__video_set_lut")));
825
826 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
827
828 #define FILL_8BIT_332RGB(r,g,b) {                       \
829         *fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6);       \
830         fb ++;                                          \
831 }
832
833 #define FILL_15BIT_555RGB(r,g,b) {                      \
834         *(unsigned short *)fb =                         \
835                 SWAP16((unsigned short)(((r>>3)<<10) |  \
836                                         ((g>>3)<<5)  |  \
837                                          (b>>3)));      \
838         fb += 2;                                        \
839 }
840
841 #define FILL_16BIT_565RGB(r,g,b) {                      \
842         *(unsigned short *)fb =                         \
843                 SWAP16((unsigned short)((((r)>>3)<<11)| \
844                                         (((g)>>2)<<5) | \
845                                          ((b)>>3)));    \
846         fb += 2;                                        \
847 }
848
849 #define FILL_32BIT_X888RGB(r,g,b) {                     \
850         *(unsigned long *)fb =                          \
851                 SWAP32((unsigned long)(((r<<16) |       \
852                                         (g<<8)  |       \
853                                          b)));          \
854         fb += 4;                                        \
855 }
856
857 #ifdef VIDEO_FB_LITTLE_ENDIAN
858 #define FILL_24BIT_888RGB(r,g,b) {                      \
859         fb[0] = b;                                      \
860         fb[1] = g;                                      \
861         fb[2] = r;                                      \
862         fb += 3;                                        \
863 }
864 #else
865 #define FILL_24BIT_888RGB(r,g,b) {                      \
866         fb[0] = r;                                      \
867         fb[1] = g;                                      \
868         fb[2] = b;                                      \
869         fb += 3;                                        \
870 }
871 #endif
872
873 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
874 static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b)
875 {
876         ushort *dst = (ushort *) fb;
877         ushort color = (ushort) (((r >> 3) << 10) |
878                                  ((g >> 3) <<  5) |
879                                   (b >> 3));
880         if (x & 1)
881                 *(--dst) = color;
882         else
883                 *(++dst) = color;
884 }
885 #endif
886
887 /*
888  * RLE8 bitmap support
889  */
890
891 #ifdef CONFIG_VIDEO_BMP_RLE8
892 /* Pre-calculated color table entry */
893 struct palette {
894         union {
895                 unsigned short w;       /* word */
896                 unsigned int dw;        /* double word */
897         } ce;                           /* color entry */
898 };
899
900 /*
901  * Helper to draw encoded/unencoded run.
902  */
903 static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p,
904                         int cnt, int enc)
905 {
906         ulong addr = (ulong) *fb;
907         int *off;
908         int enc_off = 1;
909         int i;
910
911         /*
912          * Setup offset of the color index in the bitmap.
913          * Color index of encoded run is at offset 1.
914          */
915         off = enc ? &enc_off : &i;
916
917         switch (VIDEO_DATA_FORMAT) {
918         case GDF__8BIT_INDEX:
919                 for (i = 0; i < cnt; i++)
920                         *(unsigned char *) addr++ = bm[*off];
921                 break;
922         case GDF_15BIT_555RGB:
923         case GDF_16BIT_565RGB:
924                 /* differences handled while pre-calculating palette */
925                 for (i = 0; i < cnt; i++) {
926                         *(unsigned short *) addr = p[bm[*off]].ce.w;
927                         addr += 2;
928                 }
929                 break;
930         case GDF_32BIT_X888RGB:
931                 for (i = 0; i < cnt; i++) {
932                         *(unsigned long *) addr = p[bm[*off]].ce.dw;
933                         addr += 4;
934                 }
935                 break;
936         }
937         *fb = (uchar *) addr;   /* return modified address */
938 }
939
940 static int display_rle8_bitmap(bmp_image_t *img, int xoff, int yoff,
941                                int width, int height)
942 {
943         unsigned char *bm;
944         unsigned char *fbp;
945         unsigned int cnt, runlen;
946         int decode = 1;
947         int x, y, bpp, i, ncolors;
948         struct palette p[256];
949         bmp_color_table_entry_t cte;
950         int green_shift, red_off;
951         int limit = VIDEO_COLS * VIDEO_ROWS;
952         int pixels = 0;
953
954         x = 0;
955         y = __le32_to_cpu(img->header.height) - 1;
956         ncolors = __le32_to_cpu(img->header.colors_used);
957         bpp = VIDEO_PIXEL_SIZE;
958         fbp = (unsigned char *) ((unsigned int) video_fb_address +
959                                  (((y + yoff) * VIDEO_COLS) + xoff) * bpp);
960
961         bm = (uchar *) img + __le32_to_cpu(img->header.data_offset);
962
963         /* pre-calculate and setup palette */
964         switch (VIDEO_DATA_FORMAT) {
965         case GDF__8BIT_INDEX:
966                 for (i = 0; i < ncolors; i++) {
967                         cte = img->color_table[i];
968                         video_set_lut(i, cte.red, cte.green, cte.blue);
969                 }
970                 break;
971         case GDF_15BIT_555RGB:
972         case GDF_16BIT_565RGB:
973                 if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) {
974                         green_shift = 3;
975                         red_off = 10;
976                 } else {
977                         green_shift = 2;
978                         red_off = 11;
979                 }
980                 for (i = 0; i < ncolors; i++) {
981                         cte = img->color_table[i];
982                         p[i].ce.w = SWAP16((unsigned short)
983                                            (((cte.red >> 3) << red_off) |
984                                             ((cte.green >> green_shift) << 5) |
985                                             cte.blue >> 3));
986                 }
987                 break;
988         case GDF_32BIT_X888RGB:
989                 for (i = 0; i < ncolors; i++) {
990                         cte = img->color_table[i];
991                         p[i].ce.dw = SWAP32((cte.red << 16) |
992                                             (cte.green << 8) |
993                                              cte.blue);
994                 }
995                 break;
996         default:
997                 printf("RLE Bitmap unsupported in video mode 0x%x\n",
998                        VIDEO_DATA_FORMAT);
999                 return -1;
1000         }
1001
1002         while (decode) {
1003                 switch (bm[0]) {
1004                 case 0:
1005                         switch (bm[1]) {
1006                         case 0:
1007                                 /* scan line end marker */
1008                                 bm += 2;
1009                                 x = 0;
1010                                 y--;
1011                                 fbp = (unsigned char *)
1012                                         ((unsigned int) video_fb_address +
1013                                          (((y + yoff) * VIDEO_COLS) +
1014                                           xoff) * bpp);
1015                                 continue;
1016                         case 1:
1017                                 /* end of bitmap data marker */
1018                                 decode = 0;
1019                                 break;
1020                         case 2:
1021                                 /* run offset marker */
1022                                 x += bm[2];
1023                                 y -= bm[3];
1024                                 fbp = (unsigned char *)
1025                                         ((unsigned int) video_fb_address +
1026                                          (((y + yoff) * VIDEO_COLS) +
1027                                           x + xoff) * bpp);
1028                                 bm += 4;
1029                                 break;
1030                         default:
1031                                 /* unencoded run */
1032                                 cnt = bm[1];
1033                                 runlen = cnt;
1034                                 pixels += cnt;
1035                                 if (pixels > limit)
1036                                         goto error;
1037
1038                                 bm += 2;
1039                                 if (y < height) {
1040                                         if (x >= width) {
1041                                                 x += runlen;
1042                                                 goto next_run;
1043                                         }
1044                                         if (x + runlen > width)
1045                                                 cnt = width - x;
1046                                         draw_bitmap(&fbp, bm, p, cnt, 0);
1047                                         x += runlen;
1048                                 }
1049 next_run:
1050                                 bm += runlen;
1051                                 if (runlen & 1)
1052                                         bm++;   /* 0 padding if length is odd */
1053                         }
1054                         break;
1055                 default:
1056                         /* encoded run */
1057                         cnt = bm[0];
1058                         runlen = cnt;
1059                         pixels += cnt;
1060                         if (pixels > limit)
1061                                 goto error;
1062
1063                         if (y < height) {     /* only draw into visible area */
1064                                 if (x >= width) {
1065                                         x += runlen;
1066                                         bm += 2;
1067                                         continue;
1068                                 }
1069                                 if (x + runlen > width)
1070                                         cnt = width - x;
1071                                 draw_bitmap(&fbp, bm, p, cnt, 1);
1072                                 x += runlen;
1073                         }
1074                         bm += 2;
1075                         break;
1076                 }
1077         }
1078         return 0;
1079 error:
1080         printf("Error: Too much encoded pixel data, validate your bitmap\n");
1081         return -1;
1082 }
1083 #endif
1084
1085 /*
1086  * Display the BMP file located at address bmp_image.
1087  */
1088 int video_display_bitmap(ulong bmp_image, int x, int y)
1089 {
1090         ushort xcount, ycount;
1091         uchar *fb;
1092         bmp_image_t *bmp = (bmp_image_t *) bmp_image;
1093         uchar *bmap;
1094         ushort padded_line;
1095         unsigned long width, height, bpp;
1096         unsigned colors;
1097         unsigned long compression;
1098         bmp_color_table_entry_t cte;
1099
1100 #ifdef CONFIG_VIDEO_BMP_GZIP
1101         unsigned char *dst = NULL;
1102         ulong len;
1103 #endif
1104
1105         WATCHDOG_RESET();
1106
1107         if (!((bmp->header.signature[0] == 'B') &&
1108               (bmp->header.signature[1] == 'M'))) {
1109
1110 #ifdef CONFIG_VIDEO_BMP_GZIP
1111                 /*
1112                  * Could be a gzipped bmp image, try to decrompress...
1113                  */
1114                 len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
1115                 dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
1116                 if (dst == NULL) {
1117                         printf("Error: malloc in gunzip failed!\n");
1118                         return 1;
1119                 }
1120                 if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE,
1121                            (uchar *) bmp_image,
1122                            &len) != 0) {
1123                         printf("Error: no valid bmp or bmp.gz image at %lx\n",
1124                                bmp_image);
1125                         free(dst);
1126                         return 1;
1127                 }
1128                 if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
1129                         printf("Image could be truncated "
1130                                 "(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
1131                 }
1132
1133                 /*
1134                  * Set addr to decompressed image
1135                  */
1136                 bmp = (bmp_image_t *) dst;
1137
1138                 if (!((bmp->header.signature[0] == 'B') &&
1139                       (bmp->header.signature[1] == 'M'))) {
1140                         printf("Error: no valid bmp.gz image at %lx\n",
1141                                bmp_image);
1142                         free(dst);
1143                         return 1;
1144                 }
1145 #else
1146                 printf("Error: no valid bmp image at %lx\n", bmp_image);
1147                 return 1;
1148 #endif /* CONFIG_VIDEO_BMP_GZIP */
1149         }
1150
1151         width = le32_to_cpu(bmp->header.width);
1152         height = le32_to_cpu(bmp->header.height);
1153         bpp = le16_to_cpu(bmp->header.bit_count);
1154         colors = le32_to_cpu(bmp->header.colors_used);
1155         compression = le32_to_cpu(bmp->header.compression);
1156
1157         debug("Display-bmp: %ld x %ld  with %d colors\n",
1158               width, height, colors);
1159
1160         if (compression != BMP_BI_RGB
1161 #ifdef CONFIG_VIDEO_BMP_RLE8
1162             && compression != BMP_BI_RLE8
1163 #endif
1164                 ) {
1165                 printf("Error: compression type %ld not supported\n",
1166                        compression);
1167 #ifdef CONFIG_VIDEO_BMP_GZIP
1168                 if (dst)
1169                         free(dst);
1170 #endif
1171                 return 1;
1172         }
1173
1174         padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
1175
1176 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1177         if (x == BMP_ALIGN_CENTER)
1178                 x = max(0, (VIDEO_VISIBLE_COLS - width) / 2);
1179         else if (x < 0)
1180                 x = max(0, VIDEO_VISIBLE_COLS - width + x + 1);
1181
1182         if (y == BMP_ALIGN_CENTER)
1183                 y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2);
1184         else if (y < 0)
1185                 y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1);
1186 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1187
1188         if ((x + width) > VIDEO_VISIBLE_COLS)
1189                 width = VIDEO_VISIBLE_COLS - x;
1190         if ((y + height) > VIDEO_VISIBLE_ROWS)
1191                 height = VIDEO_VISIBLE_ROWS - y;
1192
1193         bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
1194         fb = (uchar *) (video_fb_address +
1195                         ((y + height - 1) * VIDEO_COLS * VIDEO_PIXEL_SIZE) +
1196                         x * VIDEO_PIXEL_SIZE);
1197
1198 #ifdef CONFIG_VIDEO_BMP_RLE8
1199         if (compression == BMP_BI_RLE8) {
1200                 return display_rle8_bitmap(bmp, x, y, width, height);
1201         }
1202 #endif
1203
1204         /* We handle only 4, 8, or 24 bpp bitmaps */
1205         switch (le16_to_cpu(bmp->header.bit_count)) {
1206         case 4:
1207                 padded_line -= width / 2;
1208                 ycount = height;
1209
1210                 switch (VIDEO_DATA_FORMAT) {
1211                 case GDF_32BIT_X888RGB:
1212                         while (ycount--) {
1213                                 WATCHDOG_RESET();
1214                                 /*
1215                                  * Don't assume that 'width' is an
1216                                  * even number
1217                                  */
1218                                 for (xcount = 0; xcount < width; xcount++) {
1219                                         uchar idx;
1220
1221                                         if (xcount & 1) {
1222                                                 idx = *bmap & 0xF;
1223                                                 bmap++;
1224                                         } else
1225                                                 idx = *bmap >> 4;
1226                                         cte = bmp->color_table[idx];
1227                                         FILL_32BIT_X888RGB(cte.red, cte.green,
1228                                                            cte.blue);
1229                                 }
1230                                 bmap += padded_line;
1231                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1232                                         VIDEO_PIXEL_SIZE;
1233                         }
1234                         break;
1235                 default:
1236                         puts("4bpp bitmap unsupported with current "
1237                              "video mode\n");
1238                         break;
1239                 }
1240                 break;
1241
1242         case 8:
1243                 padded_line -= width;
1244                 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1245                         /* Copy colormap */
1246                         for (xcount = 0; xcount < colors; ++xcount) {
1247                                 cte = bmp->color_table[xcount];
1248                                 video_set_lut(xcount, cte.red, cte.green,
1249                                               cte.blue);
1250                         }
1251                 }
1252                 ycount = height;
1253                 switch (VIDEO_DATA_FORMAT) {
1254                 case GDF__8BIT_INDEX:
1255                         while (ycount--) {
1256                                 WATCHDOG_RESET();
1257                                 xcount = width;
1258                                 while (xcount--) {
1259                                         *fb++ = *bmap++;
1260                                 }
1261                                 bmap += padded_line;
1262                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1263                                                         VIDEO_PIXEL_SIZE;
1264                         }
1265                         break;
1266                 case GDF__8BIT_332RGB:
1267                         while (ycount--) {
1268                                 WATCHDOG_RESET();
1269                                 xcount = width;
1270                                 while (xcount--) {
1271                                         cte = bmp->color_table[*bmap++];
1272                                         FILL_8BIT_332RGB(cte.red, cte.green,
1273                                                          cte.blue);
1274                                 }
1275                                 bmap += padded_line;
1276                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1277                                                         VIDEO_PIXEL_SIZE;
1278                         }
1279                         break;
1280                 case GDF_15BIT_555RGB:
1281                         while (ycount--) {
1282 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1283                                 int xpos = x;
1284 #endif
1285                                 WATCHDOG_RESET();
1286                                 xcount = width;
1287                                 while (xcount--) {
1288                                         cte = bmp->color_table[*bmap++];
1289 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1290                                         fill_555rgb_pswap(fb, xpos++, cte.red,
1291                                                           cte.green,
1292                                                           cte.blue);
1293                                         fb += 2;
1294 #else
1295                                         FILL_15BIT_555RGB(cte.red, cte.green,
1296                                                           cte.blue);
1297 #endif
1298                                 }
1299                                 bmap += padded_line;
1300                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1301                                                         VIDEO_PIXEL_SIZE;
1302                         }
1303                         break;
1304                 case GDF_16BIT_565RGB:
1305                         while (ycount--) {
1306                                 WATCHDOG_RESET();
1307                                 xcount = width;
1308                                 while (xcount--) {
1309                                         cte = bmp->color_table[*bmap++];
1310                                         FILL_16BIT_565RGB(cte.red, cte.green,
1311                                                           cte.blue);
1312                                 }
1313                                 bmap += padded_line;
1314                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1315                                                         VIDEO_PIXEL_SIZE;
1316                         }
1317                         break;
1318                 case GDF_32BIT_X888RGB:
1319                         while (ycount--) {
1320                                 WATCHDOG_RESET();
1321                                 xcount = width;
1322                                 while (xcount--) {
1323                                         cte = bmp->color_table[*bmap++];
1324                                         FILL_32BIT_X888RGB(cte.red, cte.green,
1325                                                            cte.blue);
1326                                 }
1327                                 bmap += padded_line;
1328                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1329                                                         VIDEO_PIXEL_SIZE;
1330                         }
1331                         break;
1332                 case GDF_24BIT_888RGB:
1333                         while (ycount--) {
1334                                 WATCHDOG_RESET();
1335                                 xcount = width;
1336                                 while (xcount--) {
1337                                         cte = bmp->color_table[*bmap++];
1338                                         FILL_24BIT_888RGB(cte.red, cte.green,
1339                                                           cte.blue);
1340                                 }
1341                                 bmap += padded_line;
1342                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1343                                                         VIDEO_PIXEL_SIZE;
1344                         }
1345                         break;
1346                 }
1347                 break;
1348         case 24:
1349                 padded_line -= 3 * width;
1350                 ycount = height;
1351                 switch (VIDEO_DATA_FORMAT) {
1352                 case GDF__8BIT_332RGB:
1353                         while (ycount--) {
1354                                 WATCHDOG_RESET();
1355                                 xcount = width;
1356                                 while (xcount--) {
1357                                         FILL_8BIT_332RGB(bmap[2], bmap[1],
1358                                                          bmap[0]);
1359                                         bmap += 3;
1360                                 }
1361                                 bmap += padded_line;
1362                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1363                                                         VIDEO_PIXEL_SIZE;
1364                         }
1365                         break;
1366                 case GDF_15BIT_555RGB:
1367                         while (ycount--) {
1368 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1369                                 int xpos = x;
1370 #endif
1371                                 WATCHDOG_RESET();
1372                                 xcount = width;
1373                                 while (xcount--) {
1374 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1375                                         fill_555rgb_pswap(fb, xpos++, bmap[2],
1376                                                           bmap[1], bmap[0]);
1377                                         fb += 2;
1378 #else
1379                                         FILL_15BIT_555RGB(bmap[2], bmap[1],
1380                                                           bmap[0]);
1381 #endif
1382                                         bmap += 3;
1383                                 }
1384                                 bmap += padded_line;
1385                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1386                                                         VIDEO_PIXEL_SIZE;
1387                         }
1388                         break;
1389                 case GDF_16BIT_565RGB:
1390                         while (ycount--) {
1391                                 WATCHDOG_RESET();
1392                                 xcount = width;
1393                                 while (xcount--) {
1394                                         FILL_16BIT_565RGB(bmap[2], bmap[1],
1395                                                           bmap[0]);
1396                                         bmap += 3;
1397                                 }
1398                                 bmap += padded_line;
1399                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1400                                                         VIDEO_PIXEL_SIZE;
1401                         }
1402                         break;
1403                 case GDF_32BIT_X888RGB:
1404                         while (ycount--) {
1405                                 WATCHDOG_RESET();
1406                                 xcount = width;
1407                                 while (xcount--) {
1408                                         FILL_32BIT_X888RGB(bmap[2], bmap[1],
1409                                                            bmap[0]);
1410                                         bmap += 3;
1411                                 }
1412                                 bmap += padded_line;
1413                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1414                                                         VIDEO_PIXEL_SIZE;
1415                         }
1416                         break;
1417                 case GDF_24BIT_888RGB:
1418                         while (ycount--) {
1419                                 WATCHDOG_RESET();
1420                                 xcount = width;
1421                                 while (xcount--) {
1422                                         FILL_24BIT_888RGB(bmap[2], bmap[1],
1423                                                           bmap[0]);
1424                                         bmap += 3;
1425                                 }
1426                                 bmap += padded_line;
1427                                 fb -= (VIDEO_VISIBLE_COLS + width) *
1428                                                         VIDEO_PIXEL_SIZE;
1429                         }
1430                         break;
1431                 default:
1432                         printf("Error: 24 bits/pixel bitmap incompatible "
1433                                 "with current video mode\n");
1434                         break;
1435                 }
1436                 break;
1437         default:
1438                 printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
1439                         le16_to_cpu(bmp->header.bit_count));
1440                 break;
1441         }
1442
1443 #ifdef CONFIG_VIDEO_BMP_GZIP
1444         if (dst) {
1445                 free(dst);
1446         }
1447 #endif
1448
1449         return (0);
1450 }
1451 #endif
1452
1453
1454 #ifdef CONFIG_VIDEO_LOGO
1455 void logo_plot(void *screen, int width, int x, int y)
1456 {
1457
1458         int xcount, i;
1459         int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE;
1460         int ycount = video_logo_height;
1461         unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
1462         unsigned char *source;
1463         unsigned char *dest = (unsigned char *) screen +
1464                 ((y * width * VIDEO_PIXEL_SIZE) + x * VIDEO_PIXEL_SIZE);
1465
1466 #ifdef CONFIG_VIDEO_BMP_LOGO
1467         source = bmp_logo_bitmap;
1468
1469         /* Allocate temporary space for computing colormap */
1470         logo_red = malloc(BMP_LOGO_COLORS);
1471         logo_green = malloc(BMP_LOGO_COLORS);
1472         logo_blue = malloc(BMP_LOGO_COLORS);
1473         /* Compute color map */
1474         for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1475                 logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
1476                 logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
1477                 logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
1478         }
1479 #else
1480         source = linux_logo;
1481         logo_red = linux_logo_red;
1482         logo_green = linux_logo_green;
1483         logo_blue = linux_logo_blue;
1484 #endif
1485
1486         if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1487                 for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1488                         video_set_lut(i + VIDEO_LOGO_LUT_OFFSET,
1489                                       logo_red[i], logo_green[i],
1490                                       logo_blue[i]);
1491                 }
1492         }
1493
1494         while (ycount--) {
1495 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1496                 int xpos = x;
1497 #endif
1498                 xcount = VIDEO_LOGO_WIDTH;
1499                 while (xcount--) {
1500                         r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
1501                         g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
1502                         b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
1503
1504                         switch (VIDEO_DATA_FORMAT) {
1505                         case GDF__8BIT_INDEX:
1506                                 *dest = *source;
1507                                 break;
1508                         case GDF__8BIT_332RGB:
1509                                 *dest = ((r >> 5) << 5) |
1510                                         ((g >> 5) << 2) |
1511                                          (b >> 6);
1512                                 break;
1513                         case GDF_15BIT_555RGB:
1514 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1515                                 fill_555rgb_pswap(dest, xpos++, r, g, b);
1516 #else
1517                                 *(unsigned short *) dest =
1518                                         SWAP16((unsigned short) (
1519                                                         ((r >> 3) << 10) |
1520                                                         ((g >> 3) <<  5) |
1521                                                          (b >> 3)));
1522 #endif
1523                                 break;
1524                         case GDF_16BIT_565RGB:
1525                                 *(unsigned short *) dest =
1526                                         SWAP16((unsigned short) (
1527                                                         ((r >> 3) << 11) |
1528                                                         ((g >> 2) <<  5) |
1529                                                          (b >> 3)));
1530                                 break;
1531                         case GDF_32BIT_X888RGB:
1532                                 *(unsigned long *) dest =
1533                                         SWAP32((unsigned long) (
1534                                                         (r << 16) |
1535                                                         (g <<  8) |
1536                                                          b));
1537                                 break;
1538                         case GDF_24BIT_888RGB:
1539 #ifdef VIDEO_FB_LITTLE_ENDIAN
1540                                 dest[0] = b;
1541                                 dest[1] = g;
1542                                 dest[2] = r;
1543 #else
1544                                 dest[0] = r;
1545                                 dest[1] = g;
1546                                 dest[2] = b;
1547 #endif
1548                                 break;
1549                         }
1550                         source++;
1551                         dest += VIDEO_PIXEL_SIZE;
1552                 }
1553                 dest += skip;
1554         }
1555 #ifdef CONFIG_VIDEO_BMP_LOGO
1556         free(logo_red);
1557         free(logo_green);
1558         free(logo_blue);
1559 #endif
1560 }
1561
1562 static void *video_logo(void)
1563 {
1564         char info[128];
1565         int space, len;
1566         __maybe_unused int y_off = 0;
1567
1568 #ifdef CONFIG_SPLASH_SCREEN
1569         char *s;
1570         ulong addr;
1571
1572         s = getenv("splashimage");
1573         if (s != NULL) {
1574                 int x = 0, y = 0;
1575
1576                 addr = simple_strtoul(s, NULL, 16);
1577 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1578                 s = getenv("splashpos");
1579                 if (s != NULL) {
1580                         if (s[0] == 'm')
1581                                 x = BMP_ALIGN_CENTER;
1582                         else
1583                                 x = simple_strtol(s, NULL, 0);
1584
1585                         s = strchr(s + 1, ',');
1586                         if (s != NULL) {
1587                                 if (s[1] == 'm')
1588                                         y = BMP_ALIGN_CENTER;
1589                                 else
1590                                         y = simple_strtol(s + 1, NULL, 0);
1591                         }
1592                 }
1593 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1594
1595                 if (video_display_bitmap(addr, x, y) == 0) {
1596                         video_logo_height = 0;
1597                         return ((void *) (video_fb_address));
1598                 }
1599         }
1600 #endif /* CONFIG_SPLASH_SCREEN */
1601
1602         logo_plot(video_fb_address, VIDEO_COLS, 0, 0);
1603
1604         sprintf(info, " %s", version_string);
1605
1606         space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
1607         len = strlen(info);
1608
1609         if (len > space) {
1610                 video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y,
1611                                 (uchar *) info, space);
1612                 video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH,
1613                                 VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
1614                                 (uchar *) info + space, len - space);
1615                 y_off = 1;
1616         } else
1617                 video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);
1618
1619 #ifdef CONFIG_CONSOLE_EXTRA_INFO
1620         {
1621                 int i, n =
1622                         ((video_logo_height -
1623                           VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
1624
1625                 for (i = 1; i < n; i++) {
1626                         video_get_info_str(i, info);
1627                         if (!*info)
1628                                 continue;
1629
1630                         len = strlen(info);
1631                         if (len > space) {
1632                                 video_drawchars(VIDEO_INFO_X,
1633                                                 VIDEO_INFO_Y +
1634                                                 (i + y_off) *
1635                                                         VIDEO_FONT_HEIGHT,
1636                                                 (uchar *) info, space);
1637                                 y_off++;
1638                                 video_drawchars(VIDEO_INFO_X +
1639                                                 VIDEO_FONT_WIDTH,
1640                                                 VIDEO_INFO_Y +
1641                                                         (i + y_off) *
1642                                                         VIDEO_FONT_HEIGHT,
1643                                                 (uchar *) info + space,
1644                                                 len - space);
1645                         } else {
1646                                 video_drawstring(VIDEO_INFO_X,
1647                                                  VIDEO_INFO_Y +
1648                                                  (i + y_off) *
1649                                                         VIDEO_FONT_HEIGHT,
1650                                                  (uchar *) info);
1651                         }
1652                 }
1653         }
1654 #endif
1655
1656         return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
1657 }
1658 #endif
1659
1660 static int video_init(void)
1661 {
1662         unsigned char color8;
1663
1664         pGD = video_hw_init();
1665         if (pGD == NULL)
1666                 return -1;
1667
1668         video_fb_address = (void *) VIDEO_FB_ADRS;
1669 #ifdef CONFIG_VIDEO_HW_CURSOR
1670         video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
1671 #endif
1672
1673         /* Init drawing pats */
1674         switch (VIDEO_DATA_FORMAT) {
1675         case GDF__8BIT_INDEX:
1676                 video_set_lut(0x01, CONSOLE_FG_COL, CONSOLE_FG_COL,
1677                               CONSOLE_FG_COL);
1678                 video_set_lut(0x00, CONSOLE_BG_COL, CONSOLE_BG_COL,
1679                               CONSOLE_BG_COL);
1680                 fgx = 0x01010101;
1681                 bgx = 0x00000000;
1682                 break;
1683         case GDF__8BIT_332RGB:
1684                 color8 = ((CONSOLE_FG_COL & 0xe0) |
1685                           ((CONSOLE_FG_COL >> 3) & 0x1c) |
1686                           CONSOLE_FG_COL >> 6);
1687                 fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
1688                         color8;
1689                 color8 = ((CONSOLE_BG_COL & 0xe0) |
1690                           ((CONSOLE_BG_COL >> 3) & 0x1c) |
1691                           CONSOLE_BG_COL >> 6);
1692                 bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
1693                         color8;
1694                 break;
1695         case GDF_15BIT_555RGB:
1696                 fgx = (((CONSOLE_FG_COL >> 3) << 26) |
1697                        ((CONSOLE_FG_COL >> 3) << 21) |
1698                        ((CONSOLE_FG_COL >> 3) << 16) |
1699                        ((CONSOLE_FG_COL >> 3) << 10) |
1700                        ((CONSOLE_FG_COL >> 3) <<  5) |
1701                         (CONSOLE_FG_COL >> 3));
1702                 bgx = (((CONSOLE_BG_COL >> 3) << 26) |
1703                        ((CONSOLE_BG_COL >> 3) << 21) |
1704                        ((CONSOLE_BG_COL >> 3) << 16) |
1705                        ((CONSOLE_BG_COL >> 3) << 10) |
1706                        ((CONSOLE_BG_COL >> 3) <<  5) |
1707                         (CONSOLE_BG_COL >> 3));
1708                 break;
1709         case GDF_16BIT_565RGB:
1710                 fgx = (((CONSOLE_FG_COL >> 3) << 27) |
1711                        ((CONSOLE_FG_COL >> 2) << 21) |
1712                        ((CONSOLE_FG_COL >> 3) << 16) |
1713                        ((CONSOLE_FG_COL >> 3) << 11) |
1714                        ((CONSOLE_FG_COL >> 2) <<  5) |
1715                         (CONSOLE_FG_COL >> 3));
1716                 bgx = (((CONSOLE_BG_COL >> 3) << 27) |
1717                        ((CONSOLE_BG_COL >> 2) << 21) |
1718                        ((CONSOLE_BG_COL >> 3) << 16) |
1719                        ((CONSOLE_BG_COL >> 3) << 11) |
1720                        ((CONSOLE_BG_COL >> 2) <<  5) |
1721                         (CONSOLE_BG_COL >> 3));
1722                 break;
1723         case GDF_32BIT_X888RGB:
1724                 fgx =   (CONSOLE_FG_COL << 16) |
1725                         (CONSOLE_FG_COL <<  8) |
1726                          CONSOLE_FG_COL;
1727                 bgx =   (CONSOLE_BG_COL << 16) |
1728                         (CONSOLE_BG_COL <<  8) |
1729                          CONSOLE_BG_COL;
1730                 break;
1731         case GDF_24BIT_888RGB:
1732                 fgx =   (CONSOLE_FG_COL << 24) |
1733                         (CONSOLE_FG_COL << 16) |
1734                         (CONSOLE_FG_COL <<  8) |
1735                          CONSOLE_FG_COL;
1736                 bgx =   (CONSOLE_BG_COL << 24) |
1737                         (CONSOLE_BG_COL << 16) |
1738                         (CONSOLE_BG_COL <<  8) |
1739                          CONSOLE_BG_COL;
1740                 break;
1741         }
1742         eorx = fgx ^ bgx;
1743
1744 #ifdef CONFIG_VIDEO_LOGO
1745         /* Plot the logo and get start point of console */
1746         debug("Video: Drawing the logo ...\n");
1747         video_console_address = video_logo();
1748 #else
1749         video_console_address = video_fb_address;
1750 #endif
1751
1752         /* Initialize the console */
1753         console_col = 0;
1754         console_row = 0;
1755
1756         return 0;
1757 }
1758
1759 /*
1760  * Implement a weak default function for boards that optionally
1761  * need to skip the video initialization.
1762  */
1763 int __board_video_skip(void)
1764 {
1765         /* As default, don't skip test */
1766         return 0;
1767 }
1768
1769 int board_video_skip(void)
1770         __attribute__ ((weak, alias("__board_video_skip")));
1771
1772 int drv_video_init(void)
1773 {
1774         int skip_dev_init;
1775         struct stdio_dev console_dev;
1776
1777         /* Check if video initialization should be skipped */
1778         if (board_video_skip())
1779                 return 0;
1780
1781         /* Init video chip - returns with framebuffer cleared */
1782         skip_dev_init = (video_init() == -1);
1783
1784 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
1785         debug("KBD: Keyboard init ...\n");
1786         skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
1787 #endif
1788
1789         if (skip_dev_init)
1790                 return 0;
1791
1792         /* Init vga device */
1793         memset(&console_dev, 0, sizeof(console_dev));
1794         strcpy(console_dev.name, "vga");
1795         console_dev.ext = DEV_EXT_VIDEO;        /* Video extensions */
1796         console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
1797         console_dev.putc = video_putc;  /* 'putc' function */
1798         console_dev.puts = video_puts;  /* 'puts' function */
1799         console_dev.tstc = NULL;        /* 'tstc' function */
1800         console_dev.getc = NULL;        /* 'getc' function */
1801
1802 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
1803         /* Also init console device */
1804         console_dev.flags |= DEV_FLAGS_INPUT;
1805         console_dev.tstc = VIDEO_TSTC_FCT;      /* 'tstc' function */
1806         console_dev.getc = VIDEO_GETC_FCT;      /* 'getc' function */
1807 #endif /* CONFIG_VGA_AS_SINGLE_DEVICE */
1808
1809         if (stdio_register(&console_dev) != 0)
1810                 return 0;
1811
1812         /* Return success */
1813         return 1;
1814 }