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