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