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