uboot/drivers/video/cfb_console.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2002 ELTEC Elektronik AG
   3 * Frank Gottschling <fgottschling@eltec.de>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8/*
   9 * cfb_console.c
  10 *
  11 * Color Framebuffer Console driver for 8/15/16/24/32 bits per pixel.
  12 *
  13 * At the moment only the 8x16 font is tested and the font fore- and
  14 * background color is limited to black/white/gray colors. The Linux
  15 * logo can be placed in the upper left corner and additional board
  16 * information strings (that normally goes to serial port) can be drawn.
  17 *
  18 * The console driver can use a keyboard interface for character input
  19 * but this is deprecated. Only rk51 uses it.
  20 *
  21 * Character output goes to a memory-mapped video
  22 * framebuffer with little or big-endian organisation.
  23 * With environment setting 'console=serial' the console i/o can be
  24 * forced to serial port.
  25 *
  26 * The driver uses graphic specific defines/parameters/functions:
  27 *
  28 * (for SMI LynxE graphic chip)
  29 *
  30 * VIDEO_FB_LITTLE_ENDIAN     - framebuffer organisation default: big endian
  31 * VIDEO_HW_RECTFILL          - graphic driver supports hardware rectangle fill
  32 * VIDEO_HW_BITBLT            - graphic driver supports hardware bit blt
  33 *
  34 * Console Parameters are set by graphic drivers global struct:
  35 *
  36 * VIDEO_VISIBLE_COLS         - x resolution
  37 * VIDEO_VISIBLE_ROWS         - y resolution
  38 * VIDEO_PIXEL_SIZE           - storage size in byte per pixel
  39 * VIDEO_DATA_FORMAT          - graphical data format GDF
  40 * VIDEO_FB_ADRS              - start of video memory
  41 *
  42 * VIDEO_KBD_INIT_FCT         - init function for keyboard
  43 * VIDEO_TSTC_FCT             - keyboard_tstc function
  44 * VIDEO_GETC_FCT             - keyboard_getc function
  45 *
  46 * CONFIG_VIDEO_LOGO          - display Linux Logo in upper left corner.
  47 *                              Use CONFIG_SPLASH_SCREEN_ALIGN with
  48 *                              environment variable "splashpos" to place
  49 *                              the logo on other position. In this case
  50 *                              no CONSOLE_EXTRA_INFO is possible.
  51 * CONFIG_VIDEO_BMP_LOGO      - use bmp_logo instead of linux_logo
  52 * CONFIG_CONSOLE_EXTRA_INFO  - display additional board information
  53 *                              strings that normaly goes to serial
  54 *                              port.  This define requires a board
  55 *                              specific function:
  56 *                              video_drawstring (VIDEO_INFO_X,
  57 *                                      VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT,
  58 *                                      info);
  59 *                              that fills a info buffer at i=row.
  60 *                              s.a: board/eltec/bab7xx.
  61 *
  62 * CONFIG_VIDEO_SW_CURSOR:    - Draws a cursor after the last
  63 *                              character. No blinking is provided.
  64 *                              Uses the macros CURSOR_SET and
  65 *                              CURSOR_OFF.
  66 */
  67
  68#include <common.h>
  69#include <fdtdec.h>
  70#include <version.h>
  71#include <malloc.h>
  72#include <video.h>
  73#include <linux/compiler.h>
  74
  75/*
  76 * Defines for the CT69000 driver
  77 */
  78#ifdef  CONFIG_VIDEO_CT69000
  79
  80#define VIDEO_FB_LITTLE_ENDIAN
  81#define VIDEO_HW_RECTFILL
  82#define VIDEO_HW_BITBLT
  83#endif
  84
  85#if defined(CONFIG_VIDEO_MXS)
  86#define VIDEO_FB_16BPP_WORD_SWAP
  87#endif
  88
  89/*
  90 * Defines for the MB862xx driver
  91 */
  92#ifdef CONFIG_VIDEO_MB862xx
  93
  94#ifdef CONFIG_VIDEO_CORALP
  95#define VIDEO_FB_LITTLE_ENDIAN
  96#endif
  97#ifdef CONFIG_VIDEO_MB862xx_ACCEL
  98#define VIDEO_HW_RECTFILL
  99#define VIDEO_HW_BITBLT
 100#endif
 101#endif
 102
 103/*
 104 * Defines for the i.MX31 driver (mx3fb.c)
 105 */
 106#if defined(CONFIG_VIDEO_MX3) || defined(CONFIG_VIDEO_IPUV3)
 107#define VIDEO_FB_16BPP_WORD_SWAP
 108#endif
 109
 110/*
 111 * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc.
 112 */
 113#include <video_fb.h>
 114
 115#include <splash.h>
 116
 117/*
 118 * some Macros
 119 */
 120#define VIDEO_VISIBLE_COLS      (pGD->winSizeX)
 121#define VIDEO_VISIBLE_ROWS      (pGD->winSizeY)
 122#define VIDEO_PIXEL_SIZE        (pGD->gdfBytesPP)
 123#define VIDEO_DATA_FORMAT       (pGD->gdfIndex)
 124#define VIDEO_FB_ADRS           (pGD->frameAdrs)
 125
 126/*
 127 * Console device
 128 */
 129
 130#include <version.h>
 131#include <linux/types.h>
 132#include <stdio_dev.h>
 133#include <video_font.h>
 134
 135#if defined(CONFIG_CMD_DATE)
 136#include <rtc.h>
 137#endif
 138
 139#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
 140#include <watchdog.h>
 141#include <bmp_layout.h>
 142#include <splash.h>
 143#endif
 144
 145#if !defined(CONFIG_VIDEO_SW_CURSOR)
 146/* no Cursor defined */
 147#define CURSOR_ON
 148#define CURSOR_OFF
 149#define CURSOR_SET
 150#endif
 151
 152#if defined(CONFIG_VIDEO_SW_CURSOR)
 153void console_cursor(int state);
 154
 155#define CURSOR_ON  console_cursor(1)
 156#define CURSOR_OFF console_cursor(0)
 157#define CURSOR_SET video_set_cursor()
 158#endif /* CONFIG_VIDEO_SW_CURSOR */
 159
 160#ifdef  CONFIG_VIDEO_LOGO
 161#ifdef  CONFIG_VIDEO_BMP_LOGO
 162#include <bmp_logo.h>
 163#include <bmp_logo_data.h>
 164#define VIDEO_LOGO_WIDTH        BMP_LOGO_WIDTH
 165#define VIDEO_LOGO_HEIGHT       BMP_LOGO_HEIGHT
 166#define VIDEO_LOGO_LUT_OFFSET   BMP_LOGO_OFFSET
 167#define VIDEO_LOGO_COLORS       BMP_LOGO_COLORS
 168
 169#else  /* CONFIG_VIDEO_BMP_LOGO */
 170#define LINUX_LOGO_WIDTH        80
 171#define LINUX_LOGO_HEIGHT       80
 172#define LINUX_LOGO_COLORS       214
 173#define LINUX_LOGO_LUT_OFFSET   0x20
 174#define __initdata
 175#include <linux_logo.h>
 176#define VIDEO_LOGO_WIDTH        LINUX_LOGO_WIDTH
 177#define VIDEO_LOGO_HEIGHT       LINUX_LOGO_HEIGHT
 178#define VIDEO_LOGO_LUT_OFFSET   LINUX_LOGO_LUT_OFFSET
 179#define VIDEO_LOGO_COLORS       LINUX_LOGO_COLORS
 180#endif /* CONFIG_VIDEO_BMP_LOGO */
 181#define VIDEO_INFO_X            (VIDEO_LOGO_WIDTH)
 182#define VIDEO_INFO_Y            (VIDEO_FONT_HEIGHT/2)
 183#else  /* CONFIG_VIDEO_LOGO */
 184#define VIDEO_LOGO_WIDTH        0
 185#define VIDEO_LOGO_HEIGHT       0
 186#endif /* CONFIG_VIDEO_LOGO */
 187
 188#define VIDEO_COLS              VIDEO_VISIBLE_COLS
 189#define VIDEO_ROWS              VIDEO_VISIBLE_ROWS
 190#ifndef VIDEO_LINE_LEN
 191#define VIDEO_LINE_LEN          (VIDEO_COLS * VIDEO_PIXEL_SIZE)
 192#endif
 193#define VIDEO_SIZE              (VIDEO_ROWS * VIDEO_LINE_LEN)
 194#define VIDEO_BURST_LEN         (VIDEO_COLS/8)
 195
 196#ifdef  CONFIG_VIDEO_LOGO
 197#define CONSOLE_ROWS            ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT)
 198#else
 199#define CONSOLE_ROWS            (VIDEO_ROWS / VIDEO_FONT_HEIGHT)
 200#endif
 201
 202#define CONSOLE_COLS            (VIDEO_COLS / VIDEO_FONT_WIDTH)
 203#define CONSOLE_ROW_SIZE        (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
 204#define CONSOLE_ROW_FIRST       (video_console_address)
 205#define CONSOLE_ROW_SECOND      (video_console_address + CONSOLE_ROW_SIZE)
 206#define CONSOLE_ROW_LAST        (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
 207#define CONSOLE_SIZE            (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
 208
 209/* By default we scroll by a single line */
 210#ifndef CONFIG_CONSOLE_SCROLL_LINES
 211#define CONFIG_CONSOLE_SCROLL_LINES 1
 212#endif
 213
 214/* Macros */
 215#ifdef  VIDEO_FB_LITTLE_ENDIAN
 216#define SWAP16(x)               ((((x) & 0x00ff) << 8) | \
 217                                  ((x) >> 8) \
 218                                )
 219#define SWAP32(x)               ((((x) & 0x000000ff) << 24) | \
 220                                 (((x) & 0x0000ff00) <<  8) | \
 221                                 (((x) & 0x00ff0000) >>  8) | \
 222                                 (((x) & 0xff000000) >> 24)   \
 223                                )
 224#define SHORTSWAP32(x)          ((((x) & 0x000000ff) <<  8) | \
 225                                 (((x) & 0x0000ff00) >>  8) | \
 226                                 (((x) & 0x00ff0000) <<  8) | \
 227                                 (((x) & 0xff000000) >>  8)   \
 228                                )
 229#else
 230#define SWAP16(x)               (x)
 231#define SWAP32(x)               (x)
 232#if defined(VIDEO_FB_16BPP_WORD_SWAP)
 233#define SHORTSWAP32(x)          (((x) >> 16) | ((x) << 16))
 234#else
 235#define SHORTSWAP32(x)          (x)
 236#endif
 237#endif
 238
 239DECLARE_GLOBAL_DATA_PTR;
 240
 241/* Locals */
 242static GraphicDevice *pGD;      /* Pointer to Graphic array */
 243
 244static void *video_fb_address;  /* frame buffer address */
 245static void *video_console_address;     /* console buffer start address */
 246
 247static int video_logo_height = VIDEO_LOGO_HEIGHT;
 248
 249static int __maybe_unused cursor_state;
 250static int __maybe_unused old_col;
 251static int __maybe_unused old_row;
 252
 253static int console_col;         /* cursor col */
 254static int console_row;         /* cursor row */
 255
 256static u32 eorx, fgx, bgx;      /* color pats */
 257
 258static int cfb_do_flush_cache;
 259
 260#ifdef CONFIG_CFB_CONSOLE_ANSI
 261static char ansi_buf[10];
 262static int ansi_buf_size;
 263static int ansi_colors_need_revert;
 264static int ansi_cursor_hidden;
 265#endif
 266
 267static const int video_font_draw_table8[] = {
 268        0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
 269        0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
 270        0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
 271        0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
 272};
 273
 274static const int video_font_draw_table15[] = {
 275        0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff
 276};
 277
 278static const int video_font_draw_table16[] = {
 279        0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
 280};
 281
 282static const int video_font_draw_table24[16][3] = {
 283        {0x00000000, 0x00000000, 0x00000000},
 284        {0x00000000, 0x00000000, 0x00ffffff},
 285        {0x00000000, 0x0000ffff, 0xff000000},
 286        {0x00000000, 0x0000ffff, 0xffffffff},
 287        {0x000000ff, 0xffff0000, 0x00000000},
 288        {0x000000ff, 0xffff0000, 0x00ffffff},
 289        {0x000000ff, 0xffffffff, 0xff000000},
 290        {0x000000ff, 0xffffffff, 0xffffffff},
 291        {0xffffff00, 0x00000000, 0x00000000},
 292        {0xffffff00, 0x00000000, 0x00ffffff},
 293        {0xffffff00, 0x0000ffff, 0xff000000},
 294        {0xffffff00, 0x0000ffff, 0xffffffff},
 295        {0xffffffff, 0xffff0000, 0x00000000},
 296        {0xffffffff, 0xffff0000, 0x00ffffff},
 297        {0xffffffff, 0xffffffff, 0xff000000},
 298        {0xffffffff, 0xffffffff, 0xffffffff}
 299};
 300
 301static const int video_font_draw_table32[16][4] = {
 302        {0x00000000, 0x00000000, 0x00000000, 0x00000000},
 303        {0x00000000, 0x00000000, 0x00000000, 0x00ffffff},
 304        {0x00000000, 0x00000000, 0x00ffffff, 0x00000000},
 305        {0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff},
 306        {0x00000000, 0x00ffffff, 0x00000000, 0x00000000},
 307        {0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff},
 308        {0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000},
 309        {0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff},
 310        {0x00ffffff, 0x00000000, 0x00000000, 0x00000000},
 311        {0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff},
 312        {0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000},
 313        {0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff},
 314        {0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000},
 315        {0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff},
 316        {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000},
 317        {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff}
 318};
 319
 320/*
 321 * Implement a weak default function for boards that optionally
 322 * need to skip the cfb initialization.
 323 */
 324__weak int board_cfb_skip(void)
 325{
 326        /* As default, don't skip cfb init */
 327        return 0;
 328}
 329
 330static void video_drawchars(int xx, int yy, unsigned char *s, int count)
 331{
 332        u8 *cdat, *dest, *dest0;
 333        int rows, offset, c;
 334
 335        offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE;
 336        dest0 = video_fb_address + offset;
 337
 338        switch (VIDEO_DATA_FORMAT) {
 339        case GDF__8BIT_INDEX:
 340        case GDF__8BIT_332RGB:
 341                while (count--) {
 342                        c = *s;
 343                        cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
 344                        for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
 345                             rows--; dest += VIDEO_LINE_LEN) {
 346                                u8 bits = *cdat++;
 347
 348                                ((u32 *) dest)[0] =
 349                                        (video_font_draw_table8[bits >> 4] &
 350                                         eorx) ^ bgx;
 351
 352                                if (VIDEO_FONT_WIDTH == 4)
 353                                        continue;
 354
 355                                ((u32 *) dest)[1] =
 356                                        (video_font_draw_table8[bits & 15] &
 357                                         eorx) ^ bgx;
 358                        }
 359                        dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
 360                        s++;
 361                }
 362                break;
 363
 364        case GDF_15BIT_555RGB:
 365                while (count--) {
 366                        c = *s;
 367                        cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
 368                        for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
 369                             rows--; dest += VIDEO_LINE_LEN) {
 370                                u8 bits = *cdat++;
 371
 372                                ((u32 *) dest)[0] =
 373                                        SHORTSWAP32((video_font_draw_table15
 374                                                     [bits >> 6] & eorx) ^
 375                                                    bgx);
 376                                ((u32 *) dest)[1] =
 377                                        SHORTSWAP32((video_font_draw_table15
 378                                                     [bits >> 4 & 3] & eorx) ^
 379                                                    bgx);
 380
 381                                if (VIDEO_FONT_WIDTH == 4)
 382                                        continue;
 383
 384                                ((u32 *) dest)[2] =
 385                                        SHORTSWAP32((video_font_draw_table15
 386                                                     [bits >> 2 & 3] & eorx) ^
 387                                                    bgx);
 388                                ((u32 *) dest)[3] =
 389                                        SHORTSWAP32((video_font_draw_table15
 390                                                     [bits & 3] & eorx) ^
 391                                                    bgx);
 392                        }
 393                        dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
 394                        s++;
 395                }
 396                break;
 397
 398        case GDF_16BIT_565RGB:
 399                while (count--) {
 400                        c = *s;
 401                        cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
 402                        for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
 403                             rows--; dest += VIDEO_LINE_LEN) {
 404                                u8 bits = *cdat++;
 405
 406                                ((u32 *) dest)[0] =
 407                                        SHORTSWAP32((video_font_draw_table16
 408                                                     [bits >> 6] & eorx) ^
 409                                                    bgx);
 410                                ((u32 *) dest)[1] =
 411                                        SHORTSWAP32((video_font_draw_table16
 412                                                     [bits >> 4 & 3] & eorx) ^
 413                                                    bgx);
 414
 415                                if (VIDEO_FONT_WIDTH == 4)
 416                                        continue;
 417
 418                                ((u32 *) dest)[2] =
 419                                        SHORTSWAP32((video_font_draw_table16
 420                                                     [bits >> 2 & 3] & eorx) ^
 421                                                    bgx);
 422                                ((u32 *) dest)[3] =
 423                                        SHORTSWAP32((video_font_draw_table16
 424                                                     [bits & 3] & eorx) ^
 425                                                    bgx);
 426                        }
 427                        dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
 428                        s++;
 429                }
 430                break;
 431
 432        case GDF_32BIT_X888RGB:
 433                while (count--) {
 434                        c = *s;
 435                        cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
 436                        for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
 437                             rows--; dest += VIDEO_LINE_LEN) {
 438                                u8 bits = *cdat++;
 439
 440                                ((u32 *) dest)[0] =
 441                                        SWAP32((video_font_draw_table32
 442                                                [bits >> 4][0] & eorx) ^ bgx);
 443                                ((u32 *) dest)[1] =
 444                                        SWAP32((video_font_draw_table32
 445                                                [bits >> 4][1] & eorx) ^ bgx);
 446                                ((u32 *) dest)[2] =
 447                                        SWAP32((video_font_draw_table32
 448                                                [bits >> 4][2] & eorx) ^ bgx);
 449                                ((u32 *) dest)[3] =
 450                                        SWAP32((video_font_draw_table32
 451                                                [bits >> 4][3] & eorx) ^ bgx);
 452
 453
 454                                if (VIDEO_FONT_WIDTH == 4)
 455                                        continue;
 456
 457                                ((u32 *) dest)[4] =
 458                                        SWAP32((video_font_draw_table32
 459                                                [bits & 15][0] & eorx) ^ bgx);
 460                                ((u32 *) dest)[5] =
 461                                        SWAP32((video_font_draw_table32
 462                                                [bits & 15][1] & eorx) ^ bgx);
 463                                ((u32 *) dest)[6] =
 464                                        SWAP32((video_font_draw_table32
 465                                                [bits & 15][2] & eorx) ^ bgx);
 466                                ((u32 *) dest)[7] =
 467                                        SWAP32((video_font_draw_table32
 468                                                [bits & 15][3] & eorx) ^ bgx);
 469                        }
 470                        dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
 471                        s++;
 472                }
 473                break;
 474
 475        case GDF_24BIT_888RGB:
 476                while (count--) {
 477                        c = *s;
 478                        cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
 479                        for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
 480                             rows--; dest += VIDEO_LINE_LEN) {
 481                                u8 bits = *cdat++;
 482
 483                                ((u32 *) dest)[0] =
 484                                        (video_font_draw_table24[bits >> 4][0]
 485                                         & eorx) ^ bgx;
 486                                ((u32 *) dest)[1] =
 487                                        (video_font_draw_table24[bits >> 4][1]
 488                                         & eorx) ^ bgx;
 489                                ((u32 *) dest)[2] =
 490                                        (video_font_draw_table24[bits >> 4][2]
 491                                         & eorx) ^ bgx;
 492
 493                                if (VIDEO_FONT_WIDTH == 4)
 494                                        continue;
 495
 496                                ((u32 *) dest)[3] =
 497                                        (video_font_draw_table24[bits & 15][0]
 498                                         & eorx) ^ bgx;
 499                                ((u32 *) dest)[4] =
 500                                        (video_font_draw_table24[bits & 15][1]
 501                                         & eorx) ^ bgx;
 502                                ((u32 *) dest)[5] =
 503                                        (video_font_draw_table24[bits & 15][2]
 504                                         & eorx) ^ bgx;
 505                        }
 506                        dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
 507                        s++;
 508                }
 509                break;
 510        }
 511}
 512
 513static inline void video_drawstring(int xx, int yy, unsigned char *s)
 514{
 515        video_drawchars(xx, yy, s, strlen((char *) s));
 516}
 517
 518static void video_putchar(int xx, int yy, unsigned char c)
 519{
 520        video_drawchars(xx, yy + video_logo_height, &c, 1);
 521}
 522
 523#if defined(CONFIG_VIDEO_SW_CURSOR)
 524static void video_set_cursor(void)
 525{
 526        if (cursor_state)
 527                console_cursor(0);
 528        console_cursor(1);
 529}
 530
 531static void video_invertchar(int xx, int yy)
 532{
 533        int firstx = xx * VIDEO_PIXEL_SIZE;
 534        int lastx = (xx + VIDEO_FONT_WIDTH) * VIDEO_PIXEL_SIZE;
 535        int firsty = yy * VIDEO_LINE_LEN;
 536        int lasty = (yy + VIDEO_FONT_HEIGHT) * VIDEO_LINE_LEN;
 537        int x, y;
 538        for (y = firsty; y < lasty; y += VIDEO_LINE_LEN) {
 539                for (x = firstx; x < lastx; x++) {
 540                        u8 *dest = (u8 *)(video_fb_address) + x + y;
 541                        *dest = ~*dest;
 542                }
 543        }
 544}
 545
 546void console_cursor(int state)
 547{
 548        if (cursor_state != state) {
 549                if (cursor_state) {
 550                        /* turn off the cursor */
 551                        video_invertchar(old_col * VIDEO_FONT_WIDTH,
 552                                         old_row * VIDEO_FONT_HEIGHT +
 553                                         video_logo_height);
 554                } else {
 555                        /* turn off the cursor and record where it is */
 556                        video_invertchar(console_col * VIDEO_FONT_WIDTH,
 557                                         console_row * VIDEO_FONT_HEIGHT +
 558                                         video_logo_height);
 559                        old_col = console_col;
 560                        old_row = console_row;
 561                }
 562                cursor_state = state;
 563        }
 564        if (cfb_do_flush_cache)
 565                flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
 566}
 567#endif
 568
 569#ifndef VIDEO_HW_RECTFILL
 570static void memsetl(int *p, int c, int v)
 571{
 572        while (c--)
 573                *(p++) = v;
 574}
 575#endif
 576
 577#ifndef VIDEO_HW_BITBLT
 578static void memcpyl(int *d, int *s, int c)
 579{
 580        while (c--)
 581                *(d++) = *(s++);
 582}
 583#endif
 584
 585static void console_clear_line(int line, int begin, int end)
 586{
 587#ifdef VIDEO_HW_RECTFILL
 588        video_hw_rectfill(VIDEO_PIXEL_SIZE,             /* bytes per pixel */
 589                          VIDEO_FONT_WIDTH * begin,     /* dest pos x */
 590                          video_logo_height +
 591                          VIDEO_FONT_HEIGHT * line,     /* dest pos y */
 592                          VIDEO_FONT_WIDTH * (end - begin + 1), /* fr. width */
 593                          VIDEO_FONT_HEIGHT,            /* frame height */
 594                          bgx                           /* fill color */
 595                );
 596#else
 597        if (begin == 0 && (end + 1) == CONSOLE_COLS) {
 598                memsetl(CONSOLE_ROW_FIRST +
 599                        CONSOLE_ROW_SIZE * line,        /* offset of row */
 600                        CONSOLE_ROW_SIZE >> 2,          /* length of row */
 601                        bgx                             /* fill color */
 602                );
 603        } else {
 604                void *offset;
 605                int i, size;
 606
 607                offset = CONSOLE_ROW_FIRST +
 608                         CONSOLE_ROW_SIZE * line +      /* offset of row */
 609                         VIDEO_FONT_WIDTH *
 610                         VIDEO_PIXEL_SIZE * begin;      /* offset of col */
 611                size = VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE * (end - begin + 1);
 612                size >>= 2; /* length to end for memsetl() */
 613                /* fill at col offset of i'th line using bgx as fill color */
 614                for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
 615                        memsetl(offset + i * VIDEO_LINE_LEN, size, bgx);
 616        }
 617#endif
 618}
 619
 620static void console_scrollup(void)
 621{
 622        const int rows = CONFIG_CONSOLE_SCROLL_LINES;
 623        int i;
 624
 625        /* copy up rows ignoring the first one */
 626
 627#ifdef VIDEO_HW_BITBLT
 628        video_hw_bitblt(VIDEO_PIXEL_SIZE,       /* bytes per pixel */
 629                        0,                      /* source pos x */
 630                        video_logo_height +
 631                                VIDEO_FONT_HEIGHT * rows, /* source pos y */
 632                        0,                      /* dest pos x */
 633                        video_logo_height,      /* dest pos y */
 634                        VIDEO_VISIBLE_COLS,     /* frame width */
 635                        VIDEO_VISIBLE_ROWS
 636                        - video_logo_height
 637                        - VIDEO_FONT_HEIGHT * rows      /* frame height */
 638                );
 639#else
 640        memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_FIRST + rows * CONSOLE_ROW_SIZE,
 641                (CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows) >> 2);
 642#endif
 643        /* clear the last one */
 644        for (i = 1; i <= rows; i++)
 645                console_clear_line(CONSOLE_ROWS - i, 0, CONSOLE_COLS - 1);
 646
 647        /* Decrement row number */
 648        console_row -= rows;
 649}
 650
 651static void console_back(void)
 652{
 653        console_col--;
 654
 655        if (console_col < 0) {
 656                console_col = CONSOLE_COLS - 1;
 657                console_row--;
 658                if (console_row < 0)
 659                        console_row = 0;
 660        }
 661}
 662
 663#ifdef CONFIG_CFB_CONSOLE_ANSI
 664
 665static void console_clear(void)
 666{
 667#ifdef VIDEO_HW_RECTFILL
 668        video_hw_rectfill(VIDEO_PIXEL_SIZE,     /* bytes per pixel */
 669                          0,                    /* dest pos x */
 670                          video_logo_height,    /* dest pos y */
 671                          VIDEO_VISIBLE_COLS,   /* frame width */
 672                          VIDEO_VISIBLE_ROWS,   /* frame height */
 673                          bgx                   /* fill color */
 674        );
 675#else
 676        memsetl(CONSOLE_ROW_FIRST, CONSOLE_SIZE, bgx);
 677#endif
 678}
 679
 680static void console_cursor_fix(void)
 681{
 682        if (console_row < 0)
 683                console_row = 0;
 684        if (console_row >= CONSOLE_ROWS)
 685                console_row = CONSOLE_ROWS - 1;
 686        if (console_col < 0)
 687                console_col = 0;
 688        if (console_col >= CONSOLE_COLS)
 689                console_col = CONSOLE_COLS - 1;
 690}
 691
 692static void console_cursor_up(int n)
 693{
 694        console_row -= n;
 695        console_cursor_fix();
 696}
 697
 698static void console_cursor_down(int n)
 699{
 700        console_row += n;
 701        console_cursor_fix();
 702}
 703
 704static void console_cursor_left(int n)
 705{
 706        console_col -= n;
 707        console_cursor_fix();
 708}
 709
 710static void console_cursor_right(int n)
 711{
 712        console_col += n;
 713        console_cursor_fix();
 714}
 715
 716static void console_cursor_set_position(int row, int col)
 717{
 718        if (console_row != -1)
 719                console_row = row;
 720        if (console_col != -1)
 721                console_col = col;
 722        console_cursor_fix();
 723}
 724
 725static void console_previousline(int n)
 726{
 727        /* FIXME: also scroll terminal ? */
 728        console_row -= n;
 729        console_cursor_fix();
 730}
 731
 732static void console_swap_colors(void)
 733{
 734        eorx = fgx;
 735        fgx = bgx;
 736        bgx = eorx;
 737        eorx = fgx ^ bgx;
 738}
 739
 740static inline int console_cursor_is_visible(void)
 741{
 742        return !ansi_cursor_hidden;
 743}
 744#else
 745static inline int console_cursor_is_visible(void)
 746{
 747        return 1;
 748}
 749#endif
 750
 751static void console_newline(int n)
 752{
 753        console_row += n;
 754        console_col = 0;
 755
 756        /* Check if we need to scroll the terminal */
 757        if (console_row >= CONSOLE_ROWS) {
 758                /* Scroll everything up */
 759                console_scrollup();
 760        }
 761}
 762
 763static void console_cr(void)
 764{
 765        console_col = 0;
 766}
 767
 768static void parse_putc(const char c)
 769{
 770        static int nl = 1;
 771
 772        if (console_cursor_is_visible())
 773                CURSOR_OFF;
 774
 775        switch (c) {
 776        case 13:                /* back to first column */
 777                console_cr();
 778                break;
 779
 780        case '\n':              /* next line */
 781                if (console_col || (!console_col && nl))
 782                        console_newline(1);
 783                nl = 1;
 784                break;
 785
 786        case 9:         /* tab 8 */
 787                console_col |= 0x0008;
 788                console_col &= ~0x0007;
 789
 790                if (console_col >= CONSOLE_COLS)
 791                        console_newline(1);
 792                break;
 793
 794        case 8:         /* backspace */
 795                console_back();
 796                break;
 797
 798        case 7:         /* bell */
 799                break;  /* ignored */
 800
 801        default:                /* draw the char */
 802                video_putchar(console_col * VIDEO_FONT_WIDTH,
 803                              console_row * VIDEO_FONT_HEIGHT, c);
 804                console_col++;
 805
 806                /* check for newline */
 807                if (console_col >= CONSOLE_COLS) {
 808                        console_newline(1);
 809                        nl = 0;
 810                }
 811        }
 812
 813        if (console_cursor_is_visible())
 814                CURSOR_SET;
 815}
 816
 817static void cfb_video_putc(struct stdio_dev *dev, const char c)
 818{
 819#ifdef CONFIG_CFB_CONSOLE_ANSI
 820        int i;
 821
 822        if (c == 27) {
 823                for (i = 0; i < ansi_buf_size; ++i)
 824                        parse_putc(ansi_buf[i]);
 825                ansi_buf[0] = 27;
 826                ansi_buf_size = 1;
 827                return;
 828        }
 829
 830        if (ansi_buf_size > 0) {
 831                /*
 832                 * 0 - ESC
 833                 * 1 - [
 834                 * 2 - num1
 835                 * 3 - ..
 836                 * 4 - ;
 837                 * 5 - num2
 838                 * 6 - ..
 839                 * - cchar
 840                 */
 841                int next = 0;
 842
 843                int flush = 0;
 844                int fail = 0;
 845
 846                int num1 = 0;
 847                int num2 = 0;
 848                int cchar = 0;
 849
 850                ansi_buf[ansi_buf_size++] = c;
 851
 852                if (ansi_buf_size >= sizeof(ansi_buf))
 853                        fail = 1;
 854
 855                for (i = 0; i < ansi_buf_size; ++i) {
 856                        if (fail)
 857                                break;
 858
 859                        switch (next) {
 860                        case 0:
 861                                if (ansi_buf[i] == 27)
 862                                        next = 1;
 863                                else
 864                                        fail = 1;
 865                                break;
 866
 867                        case 1:
 868                                if (ansi_buf[i] == '[')
 869                                        next = 2;
 870                                else
 871                                        fail = 1;
 872                                break;
 873
 874                        case 2:
 875                                if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
 876                                        num1 = ansi_buf[i]-'0';
 877                                        next = 3;
 878                                } else if (ansi_buf[i] != '?') {
 879                                        --i;
 880                                        num1 = 1;
 881                                        next = 4;
 882                                }
 883                                break;
 884
 885                        case 3:
 886                                if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
 887                                        num1 *= 10;
 888                                        num1 += ansi_buf[i]-'0';
 889                                } else {
 890                                        --i;
 891                                        next = 4;
 892                                }
 893                                break;
 894
 895                        case 4:
 896                                if (ansi_buf[i] != ';') {
 897                                        --i;
 898                                        next = 7;
 899                                } else
 900                                        next = 5;
 901                                break;
 902
 903                        case 5:
 904                                if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
 905                                        num2 = ansi_buf[i]-'0';
 906                                        next = 6;
 907                                } else
 908                                        fail = 1;
 909                                break;
 910
 911                        case 6:
 912                                if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
 913                                        num2 *= 10;
 914                                        num2 += ansi_buf[i]-'0';
 915                                } else {
 916                                        --i;
 917                                        next = 7;
 918                                }
 919                                break;
 920
 921                        case 7:
 922                                if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H')
 923                                        || ansi_buf[i] == 'J'
 924                                        || ansi_buf[i] == 'K'
 925                                        || ansi_buf[i] == 'h'
 926                                        || ansi_buf[i] == 'l'
 927                                        || ansi_buf[i] == 'm') {
 928                                        cchar = ansi_buf[i];
 929                                        flush = 1;
 930                                } else
 931                                        fail = 1;
 932                                break;
 933                        }
 934                }
 935
 936                if (fail) {
 937                        for (i = 0; i < ansi_buf_size; ++i)
 938                                parse_putc(ansi_buf[i]);
 939                        ansi_buf_size = 0;
 940                        return;
 941                }
 942
 943                if (flush) {
 944                        if (!ansi_cursor_hidden)
 945                                CURSOR_OFF;
 946                        ansi_buf_size = 0;
 947                        switch (cchar) {
 948                        case 'A':
 949                                /* move cursor num1 rows up */
 950                                console_cursor_up(num1);
 951                                break;
 952                        case 'B':
 953                                /* move cursor num1 rows down */
 954                                console_cursor_down(num1);
 955                                break;
 956                        case 'C':
 957                                /* move cursor num1 columns forward */
 958                                console_cursor_right(num1);
 959                                break;
 960                        case 'D':
 961                                /* move cursor num1 columns back */
 962                                console_cursor_left(num1);
 963                                break;
 964                        case 'E':
 965                                /* move cursor num1 rows up at begin of row */
 966                                console_previousline(num1);
 967                                break;
 968                        case 'F':
 969                                /* move cursor num1 rows down at begin of row */
 970                                console_newline(num1);
 971                                break;
 972                        case 'G':
 973                                /* move cursor to column num1 */
 974                                console_cursor_set_position(-1, num1-1);
 975                                break;
 976                        case 'H':
 977                                /* move cursor to row num1, column num2 */
 978                                console_cursor_set_position(num1-1, num2-1);
 979                                break;
 980                        case 'J':
 981                                /* clear console and move cursor to 0, 0 */
 982                                console_clear();
 983                                console_cursor_set_position(0, 0);
 984                                break;
 985                        case 'K':
 986                                /* clear line */
 987                                if (num1 == 0)
 988                                        console_clear_line(console_row,
 989                                                        console_col,
 990                                                        CONSOLE_COLS-1);
 991                                else if (num1 == 1)
 992                                        console_clear_line(console_row,
 993                                                        0, console_col);
 994                                else
 995                                        console_clear_line(console_row,
 996                                                        0, CONSOLE_COLS-1);
 997                                break;
 998                        case 'h':
 999                                ansi_cursor_hidden = 0;
1000                                break;
1001                        case 'l':
1002                                ansi_cursor_hidden = 1;
1003                                break;
1004                        case 'm':
1005                                if (num1 == 0) { /* reset swapped colors */
1006                                        if (ansi_colors_need_revert) {
1007                                                console_swap_colors();
1008                                                ansi_colors_need_revert = 0;
1009                                        }
1010                                } else if (num1 == 7) { /* once swap colors */
1011                                        if (!ansi_colors_need_revert) {
1012                                                console_swap_colors();
1013                                                ansi_colors_need_revert = 1;
1014                                        }
1015                                }
1016                                break;
1017                        }
1018                        if (!ansi_cursor_hidden)
1019                                CURSOR_SET;
1020                }
1021        } else {
1022                parse_putc(c);
1023        }
1024#else
1025        parse_putc(c);
1026#endif
1027        if (cfb_do_flush_cache)
1028                flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
1029}
1030
1031static void cfb_video_puts(struct stdio_dev *dev, const char *s)
1032{
1033        int flush = cfb_do_flush_cache;
1034        int count = strlen(s);
1035
1036        /* temporarily disable cache flush */
1037        cfb_do_flush_cache = 0;
1038
1039        while (count--)
1040                cfb_video_putc(dev, *s++);
1041
1042        if (flush) {
1043                cfb_do_flush_cache = flush;
1044                flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
1045        }
1046}
1047
1048/*
1049 * Do not enforce drivers (or board code) to provide empty
1050 * video_set_lut() if they do not support 8 bpp format.
1051 * Implement weak default function instead.
1052 */
1053__weak void video_set_lut(unsigned int index, unsigned char r,
1054                     unsigned char g, unsigned char b)
1055{
1056}
1057
1058#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
1059
1060#define FILL_8BIT_332RGB(r,g,b) {                       \
1061        *fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6);       \
1062        fb ++;                                          \
1063}
1064
1065#define FILL_15BIT_555RGB(r,g,b) {                      \
1066        *(unsigned short *)fb =                         \
1067                SWAP16((unsigned short)(((r>>3)<<10) |  \
1068                                        ((g>>3)<<5)  |  \
1069                                         (b>>3)));      \
1070        fb += 2;                                        \
1071}
1072
1073#define FILL_16BIT_565RGB(r,g,b) {                      \
1074        *(unsigned short *)fb =                         \
1075                SWAP16((unsigned short)((((r)>>3)<<11)| \
1076                                        (((g)>>2)<<5) | \
1077                                         ((b)>>3)));    \
1078        fb += 2;                                        \
1079}
1080
1081#define FILL_32BIT_X888RGB(r,g,b) {                     \
1082        *(u32 *)fb =                            \
1083                SWAP32((unsigned int)(((r<<16) |        \
1084                                        (g<<8)  |       \
1085                                         b)));          \
1086        fb += 4;                                        \
1087}
1088
1089#ifdef VIDEO_FB_LITTLE_ENDIAN
1090#define FILL_24BIT_888RGB(r,g,b) {                      \
1091        fb[0] = b;                                      \
1092        fb[1] = g;                                      \
1093        fb[2] = r;                                      \
1094        fb += 3;                                        \
1095}
1096#else
1097#define FILL_24BIT_888RGB(r,g,b) {                      \
1098        fb[0] = r;                                      \
1099        fb[1] = g;                                      \
1100        fb[2] = b;                                      \
1101        fb += 3;                                        \
1102}
1103#endif
1104
1105#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1106static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b)
1107{
1108        ushort *dst = (ushort *) fb;
1109        ushort color = (ushort) (((r >> 3) << 10) |
1110                                 ((g >> 3) <<  5) |
1111                                  (b >> 3));
1112        if (x & 1)
1113                *(--dst) = color;
1114        else
1115                *(++dst) = color;
1116}
1117#endif
1118
1119/*
1120 * RLE8 bitmap support
1121 */
1122
1123#ifdef CONFIG_VIDEO_BMP_RLE8
1124/* Pre-calculated color table entry */
1125struct palette {
1126        union {
1127                unsigned short w;       /* word */
1128                unsigned int dw;        /* double word */
1129        } ce;                           /* color entry */
1130};
1131
1132/*
1133 * Helper to draw encoded/unencoded run.
1134 */
1135static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p,
1136                        int cnt, int enc)
1137{
1138        ulong addr = (ulong) *fb;
1139        int *off;
1140        int enc_off = 1;
1141        int i;
1142
1143        /*
1144         * Setup offset of the color index in the bitmap.
1145         * Color index of encoded run is at offset 1.
1146         */
1147        off = enc ? &enc_off : &i;
1148
1149        switch (VIDEO_DATA_FORMAT) {
1150        case GDF__8BIT_INDEX:
1151                for (i = 0; i < cnt; i++)
1152                        *(unsigned char *) addr++ = bm[*off];
1153                break;
1154        case GDF_15BIT_555RGB:
1155        case GDF_16BIT_565RGB:
1156                /* differences handled while pre-calculating palette */
1157                for (i = 0; i < cnt; i++) {
1158                        *(unsigned short *) addr = p[bm[*off]].ce.w;
1159                        addr += 2;
1160                }
1161                break;
1162        case GDF_32BIT_X888RGB:
1163                for (i = 0; i < cnt; i++) {
1164                        *(u32 *) addr = p[bm[*off]].ce.dw;
1165                        addr += 4;
1166                }
1167                break;
1168        }
1169        *fb = (uchar *) addr;   /* return modified address */
1170}
1171
1172static int display_rle8_bitmap(struct bmp_image *img, int xoff, int yoff,
1173                               int width, int height)
1174{
1175        unsigned char *bm;
1176        unsigned char *fbp;
1177        unsigned int cnt, runlen;
1178        int decode = 1;
1179        int x, y, bpp, i, ncolors;
1180        struct palette p[256];
1181        struct bmp_color_table_entry cte;
1182        int green_shift, red_off;
1183        int limit = (VIDEO_LINE_LEN / VIDEO_PIXEL_SIZE) * VIDEO_ROWS;
1184        int pixels = 0;
1185
1186        x = 0;
1187        y = __le32_to_cpu(img->header.height) - 1;
1188        ncolors = __le32_to_cpu(img->header.colors_used);
1189        bpp = VIDEO_PIXEL_SIZE;
1190        fbp = (unsigned char *) ((unsigned int) video_fb_address +
1191                                 (y + yoff) * VIDEO_LINE_LEN +
1192                                 xoff * bpp);
1193
1194        bm = (uchar *) img + __le32_to_cpu(img->header.data_offset);
1195
1196        /* pre-calculate and setup palette */
1197        switch (VIDEO_DATA_FORMAT) {
1198        case GDF__8BIT_INDEX:
1199                for (i = 0; i < ncolors; i++) {
1200                        cte = img->color_table[i];
1201                        video_set_lut(i, cte.red, cte.green, cte.blue);
1202                }
1203                break;
1204        case GDF_15BIT_555RGB:
1205        case GDF_16BIT_565RGB:
1206                if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) {
1207                        green_shift = 3;
1208                        red_off = 10;
1209                } else {
1210                        green_shift = 2;
1211                        red_off = 11;
1212                }
1213                for (i = 0; i < ncolors; i++) {
1214                        cte = img->color_table[i];
1215                        p[i].ce.w = SWAP16((unsigned short)
1216                                           (((cte.red >> 3) << red_off) |
1217                                            ((cte.green >> green_shift) << 5) |
1218                                            cte.blue >> 3));
1219                }
1220                break;
1221        case GDF_32BIT_X888RGB:
1222                for (i = 0; i < ncolors; i++) {
1223                        cte = img->color_table[i];
1224                        p[i].ce.dw = SWAP32((cte.red << 16) |
1225                                            (cte.green << 8) |
1226                                             cte.blue);
1227                }
1228                break;
1229        default:
1230                printf("RLE Bitmap unsupported in video mode 0x%x\n",
1231                       VIDEO_DATA_FORMAT);
1232                return -1;
1233        }
1234
1235        while (decode) {
1236                switch (bm[0]) {
1237                case 0:
1238                        switch (bm[1]) {
1239                        case 0:
1240                                /* scan line end marker */
1241                                bm += 2;
1242                                x = 0;
1243                                y--;
1244                                fbp = (unsigned char *)
1245                                        ((unsigned int) video_fb_address +
1246                                         (y + yoff) * VIDEO_LINE_LEN +
1247                                         xoff * bpp);
1248                                continue;
1249                        case 1:
1250                                /* end of bitmap data marker */
1251                                decode = 0;
1252                                break;
1253                        case 2:
1254                                /* run offset marker */
1255                                x += bm[2];
1256                                y -= bm[3];
1257                                fbp = (unsigned char *)
1258                                        ((unsigned int) video_fb_address +
1259                                         (y + yoff) * VIDEO_LINE_LEN +
1260                                         xoff * bpp);
1261                                bm += 4;
1262                                break;
1263                        default:
1264                                /* unencoded run */
1265                                cnt = bm[1];
1266                                runlen = cnt;
1267                                pixels += cnt;
1268                                if (pixels > limit)
1269                                        goto error;
1270
1271                                bm += 2;
1272                                if (y < height) {
1273                                        if (x >= width) {
1274                                                x += runlen;
1275                                                goto next_run;
1276                                        }
1277                                        if (x + runlen > width)
1278                                                cnt = width - x;
1279                                        draw_bitmap(&fbp, bm, p, cnt, 0);
1280                                        x += runlen;
1281                                }
1282next_run:
1283                                bm += runlen;
1284                                if (runlen & 1)
1285                                        bm++;   /* 0 padding if length is odd */
1286                        }
1287                        break;
1288                default:
1289                        /* encoded run */
1290                        cnt = bm[0];
1291                        runlen = cnt;
1292                        pixels += cnt;
1293                        if (pixels > limit)
1294                                goto error;
1295
1296                        if (y < height) {     /* only draw into visible area */
1297                                if (x >= width) {
1298                                        x += runlen;
1299                                        bm += 2;
1300                                        continue;
1301                                }
1302                                if (x + runlen > width)
1303                                        cnt = width - x;
1304                                draw_bitmap(&fbp, bm, p, cnt, 1);
1305                                x += runlen;
1306                        }
1307                        bm += 2;
1308                        break;
1309                }
1310        }
1311        return 0;
1312error:
1313        printf("Error: Too much encoded pixel data, validate your bitmap\n");
1314        return -1;
1315}
1316#endif
1317
1318/*
1319 * Display the BMP file located at address bmp_image.
1320 */
1321int video_display_bitmap(ulong bmp_image, int x, int y)
1322{
1323        ushort xcount, ycount;
1324        uchar *fb;
1325        struct bmp_image *bmp = (struct bmp_image *)bmp_image;
1326        uchar *bmap;
1327        ushort padded_line;
1328        unsigned long width, height, bpp;
1329        unsigned colors;
1330        unsigned long compression;
1331        struct bmp_color_table_entry cte;
1332
1333#ifdef CONFIG_VIDEO_BMP_GZIP
1334        unsigned char *dst = NULL;
1335        ulong len;
1336#endif
1337
1338        WATCHDOG_RESET();
1339
1340        if (!((bmp->header.signature[0] == 'B') &&
1341              (bmp->header.signature[1] == 'M'))) {
1342
1343#ifdef CONFIG_VIDEO_BMP_GZIP
1344                /*
1345                 * Could be a gzipped bmp image, try to decrompress...
1346                 */
1347                len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
1348                dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
1349                if (dst == NULL) {
1350                        printf("Error: malloc in gunzip failed!\n");
1351                        return 1;
1352                }
1353                /*
1354                 * NB: we need to force offset of +2
1355                 * See doc/README.displaying-bmps
1356                 */
1357                if (gunzip(dst+2, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE-2,
1358                           (uchar *) bmp_image,
1359                           &len) != 0) {
1360                        printf("Error: no valid bmp or bmp.gz image at %lx\n",
1361                               bmp_image);
1362                        free(dst);
1363                        return 1;
1364                }
1365                if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
1366                        printf("Image could be truncated "
1367                                "(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
1368                }
1369
1370                /*
1371                 * Set addr to decompressed image
1372                 */
1373                bmp = (struct bmp_image *)(dst+2);
1374
1375                if (!((bmp->header.signature[0] == 'B') &&
1376                      (bmp->header.signature[1] == 'M'))) {
1377                        printf("Error: no valid bmp.gz image at %lx\n",
1378                               bmp_image);
1379                        free(dst);
1380                        return 1;
1381                }
1382#else
1383                printf("Error: no valid bmp image at %lx\n", bmp_image);
1384                return 1;
1385#endif /* CONFIG_VIDEO_BMP_GZIP */
1386        }
1387
1388        width = le32_to_cpu(bmp->header.width);
1389        height = le32_to_cpu(bmp->header.height);
1390        bpp = le16_to_cpu(bmp->header.bit_count);
1391        colors = le32_to_cpu(bmp->header.colors_used);
1392        compression = le32_to_cpu(bmp->header.compression);
1393
1394        debug("Display-bmp: %ld x %ld  with %d colors\n",
1395              width, height, colors);
1396
1397        if (compression != BMP_BI_RGB
1398#ifdef CONFIG_VIDEO_BMP_RLE8
1399            && compression != BMP_BI_RLE8
1400#endif
1401                ) {
1402                printf("Error: compression type %ld not supported\n",
1403                       compression);
1404#ifdef CONFIG_VIDEO_BMP_GZIP
1405                if (dst)
1406                        free(dst);
1407#endif
1408                return 1;
1409        }
1410
1411        padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
1412
1413#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1414        if (x == BMP_ALIGN_CENTER)
1415                x = max(0, (int)(VIDEO_VISIBLE_COLS - width) / 2);
1416        else if (x < 0)
1417                x = max(0, (int)(VIDEO_VISIBLE_COLS - width + x + 1));
1418
1419        if (y == BMP_ALIGN_CENTER)
1420                y = max(0, (int)(VIDEO_VISIBLE_ROWS - height) / 2);
1421        else if (y < 0)
1422                y = max(0, (int)(VIDEO_VISIBLE_ROWS - height + y + 1));
1423#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1424
1425        /*
1426         * Just ignore elements which are completely beyond screen
1427         * dimensions.
1428         */
1429        if ((x >= VIDEO_VISIBLE_COLS) || (y >= VIDEO_VISIBLE_ROWS))
1430                return 0;
1431
1432        if ((x + width) > VIDEO_VISIBLE_COLS)
1433                width = VIDEO_VISIBLE_COLS - x;
1434        if ((y + height) > VIDEO_VISIBLE_ROWS)
1435                height = VIDEO_VISIBLE_ROWS - y;
1436
1437        bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
1438        fb = (uchar *) (video_fb_address +
1439                        ((y + height - 1) * VIDEO_LINE_LEN) +
1440                        x * VIDEO_PIXEL_SIZE);
1441
1442#ifdef CONFIG_VIDEO_BMP_RLE8
1443        if (compression == BMP_BI_RLE8) {
1444                return display_rle8_bitmap(bmp, x, y, width, height);
1445        }
1446#endif
1447
1448        /* We handle only 4, 8, or 24 bpp bitmaps */
1449        switch (le16_to_cpu(bmp->header.bit_count)) {
1450        case 4:
1451                padded_line -= width / 2;
1452                ycount = height;
1453
1454                switch (VIDEO_DATA_FORMAT) {
1455                case GDF_32BIT_X888RGB:
1456                        while (ycount--) {
1457                                WATCHDOG_RESET();
1458                                /*
1459                                 * Don't assume that 'width' is an
1460                                 * even number
1461                                 */
1462                                for (xcount = 0; xcount < width; xcount++) {
1463                                        uchar idx;
1464
1465                                        if (xcount & 1) {
1466                                                idx = *bmap & 0xF;
1467                                                bmap++;
1468                                        } else
1469                                                idx = *bmap >> 4;
1470                                        cte = bmp->color_table[idx];
1471                                        FILL_32BIT_X888RGB(cte.red, cte.green,
1472                                                           cte.blue);
1473                                }
1474                                bmap += padded_line;
1475                                fb -= VIDEO_LINE_LEN + width *
1476                                        VIDEO_PIXEL_SIZE;
1477                        }
1478                        break;
1479                default:
1480                        puts("4bpp bitmap unsupported with current "
1481                             "video mode\n");
1482                        break;
1483                }
1484                break;
1485
1486        case 8:
1487                padded_line -= width;
1488                if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1489                        /* Copy colormap */
1490                        for (xcount = 0; xcount < colors; ++xcount) {
1491                                cte = bmp->color_table[xcount];
1492                                video_set_lut(xcount, cte.red, cte.green,
1493                                              cte.blue);
1494                        }
1495                }
1496                ycount = height;
1497                switch (VIDEO_DATA_FORMAT) {
1498                case GDF__8BIT_INDEX:
1499                        while (ycount--) {
1500                                WATCHDOG_RESET();
1501                                xcount = width;
1502                                while (xcount--) {
1503                                        *fb++ = *bmap++;
1504                                }
1505                                bmap += padded_line;
1506                                fb -= VIDEO_LINE_LEN + width *
1507                                        VIDEO_PIXEL_SIZE;
1508                        }
1509                        break;
1510                case GDF__8BIT_332RGB:
1511                        while (ycount--) {
1512                                WATCHDOG_RESET();
1513                                xcount = width;
1514                                while (xcount--) {
1515                                        cte = bmp->color_table[*bmap++];
1516                                        FILL_8BIT_332RGB(cte.red, cte.green,
1517                                                         cte.blue);
1518                                }
1519                                bmap += padded_line;
1520                                fb -= VIDEO_LINE_LEN + width *
1521                                        VIDEO_PIXEL_SIZE;
1522                        }
1523                        break;
1524                case GDF_15BIT_555RGB:
1525                        while (ycount--) {
1526#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1527                                int xpos = x;
1528#endif
1529                                WATCHDOG_RESET();
1530                                xcount = width;
1531                                while (xcount--) {
1532                                        cte = bmp->color_table[*bmap++];
1533#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1534                                        fill_555rgb_pswap(fb, xpos++, cte.red,
1535                                                          cte.green,
1536                                                          cte.blue);
1537                                        fb += 2;
1538#else
1539                                        FILL_15BIT_555RGB(cte.red, cte.green,
1540                                                          cte.blue);
1541#endif
1542                                }
1543                                bmap += padded_line;
1544                                fb -= VIDEO_LINE_LEN + width *
1545                                        VIDEO_PIXEL_SIZE;
1546                        }
1547                        break;
1548                case GDF_16BIT_565RGB:
1549                        while (ycount--) {
1550                                WATCHDOG_RESET();
1551                                xcount = width;
1552                                while (xcount--) {
1553                                        cte = bmp->color_table[*bmap++];
1554                                        FILL_16BIT_565RGB(cte.red, cte.green,
1555                                                          cte.blue);
1556                                }
1557                                bmap += padded_line;
1558                                fb -= VIDEO_LINE_LEN + width *
1559                                        VIDEO_PIXEL_SIZE;
1560                        }
1561                        break;
1562                case GDF_32BIT_X888RGB:
1563                        while (ycount--) {
1564                                WATCHDOG_RESET();
1565                                xcount = width;
1566                                while (xcount--) {
1567                                        cte = bmp->color_table[*bmap++];
1568                                        FILL_32BIT_X888RGB(cte.red, cte.green,
1569                                                           cte.blue);
1570                                }
1571                                bmap += padded_line;
1572                                fb -= VIDEO_LINE_LEN + width *
1573                                        VIDEO_PIXEL_SIZE;
1574                        }
1575                        break;
1576                case GDF_24BIT_888RGB:
1577                        while (ycount--) {
1578                                WATCHDOG_RESET();
1579                                xcount = width;
1580                                while (xcount--) {
1581                                        cte = bmp->color_table[*bmap++];
1582                                        FILL_24BIT_888RGB(cte.red, cte.green,
1583                                                          cte.blue);
1584                                }
1585                                bmap += padded_line;
1586                                fb -= VIDEO_LINE_LEN + width *
1587                                        VIDEO_PIXEL_SIZE;
1588                        }
1589                        break;
1590                }
1591                break;
1592        case 24:
1593                padded_line -= 3 * width;
1594                ycount = height;
1595                switch (VIDEO_DATA_FORMAT) {
1596                case GDF__8BIT_332RGB:
1597                        while (ycount--) {
1598                                WATCHDOG_RESET();
1599                                xcount = width;
1600                                while (xcount--) {
1601                                        FILL_8BIT_332RGB(bmap[2], bmap[1],
1602                                                         bmap[0]);
1603                                        bmap += 3;
1604                                }
1605                                bmap += padded_line;
1606                                fb -= VIDEO_LINE_LEN + width *
1607                                        VIDEO_PIXEL_SIZE;
1608                        }
1609                        break;
1610                case GDF_15BIT_555RGB:
1611                        while (ycount--) {
1612#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1613                                int xpos = x;
1614#endif
1615                                WATCHDOG_RESET();
1616                                xcount = width;
1617                                while (xcount--) {
1618#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1619                                        fill_555rgb_pswap(fb, xpos++, bmap[2],
1620                                                          bmap[1], bmap[0]);
1621                                        fb += 2;
1622#else
1623                                        FILL_15BIT_555RGB(bmap[2], bmap[1],
1624                                                          bmap[0]);
1625#endif
1626                                        bmap += 3;
1627                                }
1628                                bmap += padded_line;
1629                                fb -= VIDEO_LINE_LEN + width *
1630                                        VIDEO_PIXEL_SIZE;
1631                        }
1632                        break;
1633                case GDF_16BIT_565RGB:
1634                        while (ycount--) {
1635                                WATCHDOG_RESET();
1636                                xcount = width;
1637                                while (xcount--) {
1638                                        FILL_16BIT_565RGB(bmap[2], bmap[1],
1639                                                          bmap[0]);
1640                                        bmap += 3;
1641                                }
1642                                bmap += padded_line;
1643                                fb -= VIDEO_LINE_LEN + width *
1644                                        VIDEO_PIXEL_SIZE;
1645                        }
1646                        break;
1647                case GDF_32BIT_X888RGB:
1648                        while (ycount--) {
1649                                WATCHDOG_RESET();
1650                                xcount = width;
1651                                while (xcount--) {
1652                                        FILL_32BIT_X888RGB(bmap[2], bmap[1],
1653                                                           bmap[0]);
1654                                        bmap += 3;
1655                                }
1656                                bmap += padded_line;
1657                                fb -= VIDEO_LINE_LEN + width *
1658                                        VIDEO_PIXEL_SIZE;
1659                        }
1660                        break;
1661                case GDF_24BIT_888RGB:
1662                        while (ycount--) {
1663                                WATCHDOG_RESET();
1664                                xcount = width;
1665                                while (xcount--) {
1666                                        FILL_24BIT_888RGB(bmap[2], bmap[1],
1667                                                          bmap[0]);
1668                                        bmap += 3;
1669                                }
1670                                bmap += padded_line;
1671                                fb -= VIDEO_LINE_LEN + width *
1672                                        VIDEO_PIXEL_SIZE;
1673                        }
1674                        break;
1675                default:
1676                        printf("Error: 24 bits/pixel bitmap incompatible "
1677                                "with current video mode\n");
1678                        break;
1679                }
1680                break;
1681        default:
1682                printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
1683                        le16_to_cpu(bmp->header.bit_count));
1684                break;
1685        }
1686
1687#ifdef CONFIG_VIDEO_BMP_GZIP
1688        if (dst) {
1689                free(dst);
1690        }
1691#endif
1692
1693        if (cfb_do_flush_cache)
1694                flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
1695        return (0);
1696}
1697#endif
1698
1699
1700#ifdef CONFIG_VIDEO_LOGO
1701static int video_logo_xpos;
1702static int video_logo_ypos;
1703
1704static void plot_logo_or_black(void *screen, int x, int y, int black);
1705
1706static void logo_plot(void *screen, int x, int y)
1707{
1708        plot_logo_or_black(screen, x, y, 0);
1709}
1710
1711static void logo_black(void)
1712{
1713        plot_logo_or_black(video_fb_address, video_logo_xpos, video_logo_ypos,
1714                        1);
1715}
1716
1717static int do_clrlogo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1718{
1719        if (argc != 1)
1720                return cmd_usage(cmdtp);
1721
1722        logo_black();
1723        return 0;
1724}
1725
1726U_BOOT_CMD(
1727           clrlogo, 1, 0, do_clrlogo,
1728           "fill the boot logo area with black",
1729           " "
1730           );
1731
1732static void plot_logo_or_black(void *screen, int x, int y, int black)
1733{
1734
1735        int xcount, i;
1736        int skip = VIDEO_LINE_LEN - VIDEO_LOGO_WIDTH * VIDEO_PIXEL_SIZE;
1737        int ycount = video_logo_height;
1738        unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
1739        unsigned char *source;
1740        unsigned char *dest;
1741
1742#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1743        if (x == BMP_ALIGN_CENTER)
1744                x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2);
1745        else if (x < 0)
1746                x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1));
1747
1748        if (y == BMP_ALIGN_CENTER)
1749                y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2);
1750        else if (y < 0)
1751                y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1));
1752#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1753
1754        dest = (unsigned char *)screen + y * VIDEO_LINE_LEN + x * VIDEO_PIXEL_SIZE;
1755
1756#ifdef CONFIG_VIDEO_BMP_LOGO
1757        source = bmp_logo_bitmap;
1758
1759        /* Allocate temporary space for computing colormap */
1760        logo_red = malloc(BMP_LOGO_COLORS);
1761        logo_green = malloc(BMP_LOGO_COLORS);
1762        logo_blue = malloc(BMP_LOGO_COLORS);
1763        /* Compute color map */
1764        for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1765                logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
1766                logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
1767                logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
1768        }
1769#else
1770        source = linux_logo;
1771        logo_red = linux_logo_red;
1772        logo_green = linux_logo_green;
1773        logo_blue = linux_logo_blue;
1774#endif
1775
1776        if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1777                for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1778                        video_set_lut(i + VIDEO_LOGO_LUT_OFFSET,
1779                                      logo_red[i], logo_green[i],
1780                                      logo_blue[i]);
1781                }
1782        }
1783
1784        while (ycount--) {
1785#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1786                int xpos = x;
1787#endif
1788                xcount = VIDEO_LOGO_WIDTH;
1789                while (xcount--) {
1790                        if (black) {
1791                                r = 0x00;
1792                                g = 0x00;
1793                                b = 0x00;
1794                        } else {
1795                                r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
1796                                g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
1797                                b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
1798                        }
1799
1800                        switch (VIDEO_DATA_FORMAT) {
1801                        case GDF__8BIT_INDEX:
1802                                *dest = *source;
1803                                break;
1804                        case GDF__8BIT_332RGB:
1805                                *dest = ((r >> 5) << 5) |
1806                                        ((g >> 5) << 2) |
1807                                         (b >> 6);
1808                                break;
1809                        case GDF_15BIT_555RGB:
1810#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1811                                fill_555rgb_pswap(dest, xpos++, r, g, b);
1812#else
1813                                *(unsigned short *) dest =
1814                                        SWAP16((unsigned short) (
1815                                                        ((r >> 3) << 10) |
1816                                                        ((g >> 3) <<  5) |
1817                                                         (b >> 3)));
1818#endif
1819                                break;
1820                        case GDF_16BIT_565RGB:
1821                                *(unsigned short *) dest =
1822                                        SWAP16((unsigned short) (
1823                                                        ((r >> 3) << 11) |
1824                                                        ((g >> 2) <<  5) |
1825                                                         (b >> 3)));
1826                                break;
1827                        case GDF_32BIT_X888RGB:
1828                                *(u32 *) dest =
1829                                        SWAP32((u32) (
1830                                                        (r << 16) |
1831                                                        (g <<  8) |
1832                                                         b));
1833                                break;
1834                        case GDF_24BIT_888RGB:
1835#ifdef VIDEO_FB_LITTLE_ENDIAN
1836                                dest[0] = b;
1837                                dest[1] = g;
1838                                dest[2] = r;
1839#else
1840                                dest[0] = r;
1841                                dest[1] = g;
1842                                dest[2] = b;
1843#endif
1844                                break;
1845                        }
1846                        source++;
1847                        dest += VIDEO_PIXEL_SIZE;
1848                }
1849                dest += skip;
1850        }
1851#ifdef CONFIG_VIDEO_BMP_LOGO
1852        free(logo_red);
1853        free(logo_green);
1854        free(logo_blue);
1855#endif
1856}
1857
1858static void *video_logo(void)
1859{
1860        char info[128];
1861        __maybe_unused int y_off = 0;
1862        __maybe_unused ulong addr;
1863        __maybe_unused char *s;
1864        __maybe_unused int len, ret, space;
1865
1866        splash_get_pos(&video_logo_xpos, &video_logo_ypos);
1867
1868#ifdef CONFIG_SPLASH_SCREEN
1869        s = getenv("splashimage");
1870        if (s != NULL) {
1871                ret = splash_screen_prepare();
1872                if (ret < 0)
1873                        return video_fb_address;
1874                addr = simple_strtoul(s, NULL, 16);
1875
1876                if (video_display_bitmap(addr,
1877                                        video_logo_xpos,
1878                                        video_logo_ypos) == 0) {
1879                        video_logo_height = 0;
1880                        return ((void *) (video_fb_address));
1881                }
1882        }
1883#endif /* CONFIG_SPLASH_SCREEN */
1884
1885        logo_plot(video_fb_address, video_logo_xpos, video_logo_ypos);
1886
1887#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1888        /*
1889         * when using splashpos for video_logo, skip any info
1890         * output on video console if the logo is not at 0,0
1891         */
1892        if (video_logo_xpos || video_logo_ypos) {
1893                /*
1894                 * video_logo_height is used in text and cursor offset
1895                 * calculations. Since the console is below the logo,
1896                 * we need to adjust the logo height
1897                 */
1898                if (video_logo_ypos == BMP_ALIGN_CENTER)
1899                        video_logo_height += max(0, (int)(VIDEO_VISIBLE_ROWS -
1900                                                     VIDEO_LOGO_HEIGHT) / 2);
1901                else if (video_logo_ypos > 0)
1902                        video_logo_height += video_logo_ypos;
1903
1904                return video_fb_address + video_logo_height * VIDEO_LINE_LEN;
1905        }
1906#endif
1907        if (board_cfb_skip())
1908                return 0;
1909
1910        sprintf(info, " %s", version_string);
1911
1912#ifndef CONFIG_HIDE_LOGO_VERSION
1913        space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
1914        len = strlen(info);
1915
1916        if (len > space) {
1917                video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y,
1918                                (uchar *) info, space);
1919                video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH,
1920                                VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
1921                                (uchar *) info + space, len - space);
1922                y_off = 1;
1923        } else
1924                video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);
1925
1926#ifdef CONFIG_CONSOLE_EXTRA_INFO
1927        {
1928                int i, n =
1929                        ((video_logo_height -
1930                          VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
1931
1932                for (i = 1; i < n; i++) {
1933                        video_get_info_str(i, info);
1934                        if (!*info)
1935                                continue;
1936
1937                        len = strlen(info);
1938                        if (len > space) {
1939                                video_drawchars(VIDEO_INFO_X,
1940                                                VIDEO_INFO_Y +
1941                                                (i + y_off) *
1942                                                        VIDEO_FONT_HEIGHT,
1943                                                (uchar *) info, space);
1944                                y_off++;
1945                                video_drawchars(VIDEO_INFO_X +
1946                                                VIDEO_FONT_WIDTH,
1947                                                VIDEO_INFO_Y +
1948                                                        (i + y_off) *
1949                                                        VIDEO_FONT_HEIGHT,
1950                                                (uchar *) info + space,
1951                                                len - space);
1952                        } else {
1953                                video_drawstring(VIDEO_INFO_X,
1954                                                 VIDEO_INFO_Y +
1955                                                 (i + y_off) *
1956                                                        VIDEO_FONT_HEIGHT,
1957                                                 (uchar *) info);
1958                        }
1959                }
1960        }
1961#endif
1962#endif
1963
1964        return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
1965}
1966#endif
1967
1968static int cfb_fb_is_in_dram(void)
1969{
1970        bd_t *bd = gd->bd;
1971#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || \
1972defined(CONFIG_SANDBOX) || defined(CONFIG_X86)
1973        ulong start, end;
1974        int i;
1975
1976        for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
1977                start = bd->bi_dram[i].start;
1978                end = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
1979                if ((ulong)video_fb_address >= start &&
1980                    (ulong)video_fb_address < end)
1981                        return 1;
1982        }
1983#else
1984        if ((ulong)video_fb_address >= bd->bi_memstart &&
1985            (ulong)video_fb_address < bd->bi_memstart + bd->bi_memsize)
1986                return 1;
1987#endif
1988        return 0;
1989}
1990
1991void video_clear(void)
1992{
1993        if (!video_fb_address)
1994                return;
1995#ifdef VIDEO_HW_RECTFILL
1996        video_hw_rectfill(VIDEO_PIXEL_SIZE,     /* bytes per pixel */
1997                          0,                    /* dest pos x */
1998                          0,                    /* dest pos y */
1999                          VIDEO_VISIBLE_COLS,   /* frame width */
2000                          VIDEO_VISIBLE_ROWS,   /* frame height */
2001                          bgx                   /* fill color */
2002        );
2003#else
2004        memsetl(video_fb_address,
2005                (VIDEO_VISIBLE_ROWS * VIDEO_LINE_LEN) / sizeof(int), bgx);
2006#endif
2007}
2008
2009static int cfg_video_init(void)
2010{
2011        unsigned char color8;
2012
2013        pGD = video_hw_init();
2014        if (pGD == NULL)
2015                return -1;
2016
2017        video_fb_address = (void *) VIDEO_FB_ADRS;
2018
2019        cfb_do_flush_cache = cfb_fb_is_in_dram() && dcache_status();
2020
2021        /* Init drawing pats */
2022        switch (VIDEO_DATA_FORMAT) {
2023        case GDF__8BIT_INDEX:
2024                video_set_lut(0x01, CONFIG_SYS_CONSOLE_FG_COL,
2025                              CONFIG_SYS_CONSOLE_FG_COL,
2026                              CONFIG_SYS_CONSOLE_FG_COL);
2027                video_set_lut(0x00, CONFIG_SYS_CONSOLE_BG_COL,
2028                              CONFIG_SYS_CONSOLE_BG_COL,
2029                              CONFIG_SYS_CONSOLE_BG_COL);
2030                fgx = 0x01010101;
2031                bgx = 0x00000000;
2032                break;
2033        case GDF__8BIT_332RGB:
2034                color8 = ((CONFIG_SYS_CONSOLE_FG_COL & 0xe0) |
2035                          ((CONFIG_SYS_CONSOLE_FG_COL >> 3) & 0x1c) |
2036                          CONFIG_SYS_CONSOLE_FG_COL >> 6);
2037                fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
2038                        color8;
2039                color8 = ((CONFIG_SYS_CONSOLE_BG_COL & 0xe0) |
2040                          ((CONFIG_SYS_CONSOLE_BG_COL >> 3) & 0x1c) |
2041                          CONFIG_SYS_CONSOLE_BG_COL >> 6);
2042                bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
2043                        color8;
2044                break;
2045        case GDF_15BIT_555RGB:
2046                fgx = (((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 26) |
2047                       ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 21) |
2048                       ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 16) |
2049                       ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 10) |
2050                       ((CONFIG_SYS_CONSOLE_FG_COL >> 3) <<  5) |
2051                        (CONFIG_SYS_CONSOLE_FG_COL >> 3));
2052                bgx = (((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 26) |
2053                       ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 21) |
2054                       ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 16) |
2055                       ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 10) |
2056                       ((CONFIG_SYS_CONSOLE_BG_COL >> 3) <<  5) |
2057                        (CONFIG_SYS_CONSOLE_BG_COL >> 3));
2058                break;
2059        case GDF_16BIT_565RGB:
2060                fgx = (((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 27) |
2061                       ((CONFIG_SYS_CONSOLE_FG_COL >> 2) << 21) |
2062                       ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 16) |
2063                       ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 11) |
2064                       ((CONFIG_SYS_CONSOLE_FG_COL >> 2) <<  5) |
2065                        (CONFIG_SYS_CONSOLE_FG_COL >> 3));
2066                bgx = (((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 27) |
2067                       ((CONFIG_SYS_CONSOLE_BG_COL >> 2) << 21) |
2068                       ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 16) |
2069                       ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 11) |
2070                       ((CONFIG_SYS_CONSOLE_BG_COL >> 2) <<  5) |
2071                        (CONFIG_SYS_CONSOLE_BG_COL >> 3));
2072                break;
2073        case GDF_32BIT_X888RGB:
2074                fgx =   (CONFIG_SYS_CONSOLE_FG_COL << 16) |
2075                        (CONFIG_SYS_CONSOLE_FG_COL <<  8) |
2076                         CONFIG_SYS_CONSOLE_FG_COL;
2077                bgx =   (CONFIG_SYS_CONSOLE_BG_COL << 16) |
2078                        (CONFIG_SYS_CONSOLE_BG_COL <<  8) |
2079                         CONFIG_SYS_CONSOLE_BG_COL;
2080                break;
2081        case GDF_24BIT_888RGB:
2082                fgx =   (CONFIG_SYS_CONSOLE_FG_COL << 24) |
2083                        (CONFIG_SYS_CONSOLE_FG_COL << 16) |
2084                        (CONFIG_SYS_CONSOLE_FG_COL <<  8) |
2085                         CONFIG_SYS_CONSOLE_FG_COL;
2086                bgx =   (CONFIG_SYS_CONSOLE_BG_COL << 24) |
2087                        (CONFIG_SYS_CONSOLE_BG_COL << 16) |
2088                        (CONFIG_SYS_CONSOLE_BG_COL <<  8) |
2089                         CONFIG_SYS_CONSOLE_BG_COL;
2090                break;
2091        }
2092        eorx = fgx ^ bgx;
2093
2094        video_clear();
2095
2096#ifdef CONFIG_VIDEO_LOGO
2097        /* Plot the logo and get start point of console */
2098        debug("Video: Drawing the logo ...\n");
2099        video_console_address = video_logo();
2100#else
2101        video_console_address = video_fb_address;
2102#endif
2103
2104        /* Initialize the console */
2105        console_col = 0;
2106        console_row = 0;
2107
2108        if (cfb_do_flush_cache)
2109                flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
2110
2111        return 0;
2112}
2113
2114/*
2115 * Implement a weak default function for boards that optionally
2116 * need to skip the video initialization.
2117 */
2118__weak int board_video_skip(void)
2119{
2120        /* As default, don't skip test */
2121        return 0;
2122}
2123
2124int drv_video_init(void)
2125{
2126        struct stdio_dev console_dev;
2127        bool have_keyboard;
2128        bool __maybe_unused keyboard_ok = false;
2129
2130        /* Check if video initialization should be skipped */
2131        if (board_video_skip())
2132                return 0;
2133
2134        /* Init video chip - returns with framebuffer cleared */
2135        if (cfg_video_init() == -1)
2136                return 0;
2137
2138        if (board_cfb_skip())
2139                return 0;
2140
2141#if defined(CONFIG_VGA_AS_SINGLE_DEVICE)
2142        have_keyboard = false;
2143#elif defined(CONFIG_OF_CONTROL)
2144        have_keyboard = !fdtdec_get_config_bool(gd->fdt_blob,
2145                                                "u-boot,no-keyboard");
2146#else
2147        have_keyboard = true;
2148#endif
2149        if (have_keyboard) {
2150                debug("KBD: Keyboard init ...\n");
2151#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
2152                keyboard_ok = !(VIDEO_KBD_INIT_FCT == -1);
2153#endif
2154        }
2155
2156        /* Init vga device */
2157        memset(&console_dev, 0, sizeof(console_dev));
2158        strcpy(console_dev.name, "vga");
2159        console_dev.flags = DEV_FLAGS_OUTPUT;
2160        console_dev.putc = cfb_video_putc;      /* 'putc' function */
2161        console_dev.puts = cfb_video_puts;      /* 'puts' function */
2162
2163#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
2164        if (have_keyboard && keyboard_ok) {
2165                /* Also init console device */
2166                console_dev.flags |= DEV_FLAGS_INPUT;
2167                console_dev.tstc = VIDEO_TSTC_FCT;      /* 'tstc' function */
2168                console_dev.getc = VIDEO_GETC_FCT;      /* 'getc' function */
2169        }
2170#endif
2171
2172        if (stdio_register(&console_dev) != 0)
2173                return 0;
2174
2175        /* Return success */
2176        return 1;
2177}
2178
2179void video_position_cursor(unsigned col, unsigned row)
2180{
2181        console_col = min(col, CONSOLE_COLS - 1);
2182        console_row = min(row, CONSOLE_ROWS - 1);
2183}
2184
2185int video_get_pixel_width(void)
2186{
2187        return VIDEO_VISIBLE_COLS;
2188}
2189
2190int video_get_pixel_height(void)
2191{
2192        return VIDEO_VISIBLE_ROWS;
2193}
2194
2195int video_get_screen_rows(void)
2196{
2197        return CONSOLE_ROWS;
2198}
2199
2200int video_get_screen_columns(void)
2201{
2202        return CONSOLE_COLS;
2203}
2204