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