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