uboot/common/lcd.c
<<
>>
Prefs
   1/*
   2 * Common LCD routines for supported CPUs
   3 *
   4 * (C) Copyright 2001-2002
   5 * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
   6 *
   7 * See file CREDITS for list of people who contributed to this
   8 * project.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation; either version 2 of
  13 * the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23 * MA 02111-1307 USA
  24 */
  25
  26/************************************************************************/
  27/* ** HEADER FILES                                                      */
  28/************************************************************************/
  29
  30/* #define DEBUG */
  31
  32#include <config.h>
  33#include <common.h>
  34#include <command.h>
  35#include <stdarg.h>
  36#include <linux/types.h>
  37#include <stdio_dev.h>
  38#if defined(CONFIG_POST)
  39#include <post.h>
  40#endif
  41#include <lcd.h>
  42#include <watchdog.h>
  43
  44#if defined(CONFIG_CPU_PXA25X) || defined(CONFIG_CPU_PXA27X) || \
  45        defined(CONFIG_CPU_MONAHANS)
  46#define CONFIG_CPU_PXA
  47#include <asm/byteorder.h>
  48#endif
  49
  50#if defined(CONFIG_MPC823)
  51#include <lcdvideo.h>
  52#endif
  53
  54#if defined(CONFIG_ATMEL_LCD)
  55#include <atmel_lcdc.h>
  56#endif
  57
  58/************************************************************************/
  59/* ** FONT DATA                                                         */
  60/************************************************************************/
  61#include <video_font.h>         /* Get font data, width and height      */
  62#include <video_font_data.h>
  63
  64/************************************************************************/
  65/* ** LOGO DATA                                                         */
  66/************************************************************************/
  67#ifdef CONFIG_LCD_LOGO
  68# include <bmp_logo.h>          /* Get logo data, width and height      */
  69# include <bmp_logo_data.h>
  70# if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)
  71#  error Default Color Map overlaps with Logo Color Map
  72# endif
  73#endif
  74
  75#ifndef CONFIG_LCD_ALIGNMENT
  76#define CONFIG_LCD_ALIGNMENT PAGE_SIZE
  77#endif
  78
  79/* By default we scroll by a single line */
  80#ifndef CONFIG_CONSOLE_SCROLL_LINES
  81#define CONFIG_CONSOLE_SCROLL_LINES 1
  82#endif
  83
  84DECLARE_GLOBAL_DATA_PTR;
  85
  86ulong lcd_setmem (ulong addr);
  87
  88static void lcd_drawchars(ushort x, ushort y, uchar *str, int count);
  89static inline void lcd_puts_xy(ushort x, ushort y, uchar *s);
  90static inline void lcd_putc_xy(ushort x, ushort y, uchar  c);
  91
  92static int lcd_init(void *lcdbase);
  93
  94static void *lcd_logo (void);
  95
  96static int lcd_getbgcolor(void);
  97static void lcd_setfgcolor(int color);
  98static void lcd_setbgcolor(int color);
  99
 100char lcd_is_enabled = 0;
 101
 102static char lcd_flush_dcache;   /* 1 to flush dcache after each lcd update */
 103
 104
 105#ifdef  NOT_USED_SO_FAR
 106static void lcd_getcolreg(ushort regno,
 107                                ushort *red, ushort *green, ushort *blue);
 108static int lcd_getfgcolor(void);
 109#endif  /* NOT_USED_SO_FAR */
 110
 111/************************************************************************/
 112
 113/* Flush LCD activity to the caches */
 114void lcd_sync(void)
 115{
 116        /*
 117         * flush_dcache_range() is declared in common.h but it seems that some
 118         * architectures do not actually implement it. Is there a way to find
 119         * out whether it exists? For now, ARM is safe.
 120         */
 121#if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF)
 122        int line_length;
 123
 124        if (lcd_flush_dcache)
 125                flush_dcache_range((u32)lcd_base,
 126                        (u32)(lcd_base + lcd_get_size(&line_length)));
 127#endif
 128}
 129
 130void lcd_set_flush_dcache(int flush)
 131{
 132        lcd_flush_dcache = (flush != 0);
 133}
 134
 135/*----------------------------------------------------------------------*/
 136
 137static void console_scrollup(void)
 138{
 139        const int rows = CONFIG_CONSOLE_SCROLL_LINES;
 140
 141        /* Copy up rows ignoring those that will be overwritten */
 142        memcpy(CONSOLE_ROW_FIRST,
 143               lcd_console_address + CONSOLE_ROW_SIZE * rows,
 144               CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows);
 145
 146        /* Clear the last rows */
 147        memset(lcd_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows,
 148                COLOR_MASK(lcd_color_bg),
 149               CONSOLE_ROW_SIZE * rows);
 150
 151        lcd_sync();
 152        console_row -= rows;
 153}
 154
 155/*----------------------------------------------------------------------*/
 156
 157static inline void console_back(void)
 158{
 159        if (--console_col < 0) {
 160                console_col = CONSOLE_COLS-1 ;
 161                if (--console_row < 0) {
 162                        console_row = 0;
 163                }
 164        }
 165
 166        lcd_putc_xy(console_col * VIDEO_FONT_WIDTH,
 167                console_row * VIDEO_FONT_HEIGHT, ' ');
 168}
 169
 170/*----------------------------------------------------------------------*/
 171
 172static inline void console_newline(void)
 173{
 174        ++console_row;
 175        console_col = 0;
 176
 177        /* Check if we need to scroll the terminal */
 178        if (console_row >= CONSOLE_ROWS) {
 179                /* Scroll everything up */
 180                console_scrollup();
 181        } else {
 182                lcd_sync();
 183        }
 184}
 185
 186/*----------------------------------------------------------------------*/
 187
 188void lcd_putc(const char c)
 189{
 190        if (!lcd_is_enabled) {
 191                serial_putc(c);
 192
 193                return;
 194        }
 195
 196        switch (c) {
 197        case '\r':
 198                console_col = 0;
 199
 200                return;
 201        case '\n':
 202                console_newline();
 203
 204                return;
 205        case '\t':      /* Tab (8 chars alignment) */
 206                console_col +=  8;
 207                console_col &= ~7;
 208
 209                if (console_col >= CONSOLE_COLS)
 210                        console_newline();
 211
 212                return;
 213        case '\b':
 214                console_back();
 215
 216                return;
 217        default:
 218                lcd_putc_xy(console_col * VIDEO_FONT_WIDTH,
 219                        console_row * VIDEO_FONT_HEIGHT, c);
 220                if (++console_col >= CONSOLE_COLS)
 221                        console_newline();
 222        }
 223}
 224
 225/*----------------------------------------------------------------------*/
 226
 227void lcd_puts(const char *s)
 228{
 229        if (!lcd_is_enabled) {
 230                serial_puts(s);
 231
 232                return;
 233        }
 234
 235        while (*s) {
 236                lcd_putc(*s++);
 237        }
 238        lcd_sync();
 239}
 240
 241/*----------------------------------------------------------------------*/
 242
 243void lcd_printf(const char *fmt, ...)
 244{
 245        va_list args;
 246        char buf[CONFIG_SYS_PBSIZE];
 247
 248        va_start(args, fmt);
 249        vsprintf(buf, fmt, args);
 250        va_end(args);
 251
 252        lcd_puts(buf);
 253}
 254
 255/************************************************************************/
 256/* ** Low-Level Graphics Routines                                       */
 257/************************************************************************/
 258
 259static void lcd_drawchars(ushort x, ushort y, uchar *str, int count)
 260{
 261        uchar *dest;
 262        ushort row;
 263
 264#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
 265        y += BMP_LOGO_HEIGHT;
 266#endif
 267
 268#if LCD_BPP == LCD_MONOCHROME
 269        ushort off  = x * (1 << LCD_BPP) % 8;
 270#endif
 271
 272        dest = (uchar *)(lcd_base + y * lcd_line_length + x * (1 << LCD_BPP) / 8);
 273
 274        for (row = 0; row < VIDEO_FONT_HEIGHT; ++row, dest += lcd_line_length) {
 275                uchar *s = str;
 276                int i;
 277#if LCD_BPP == LCD_COLOR16
 278                ushort *d = (ushort *)dest;
 279#else
 280                uchar *d = dest;
 281#endif
 282
 283#if LCD_BPP == LCD_MONOCHROME
 284                uchar rest = *d & -(1 << (8-off));
 285                uchar sym;
 286#endif
 287                for (i = 0; i < count; ++i) {
 288                        uchar c, bits;
 289
 290                        c = *s++;
 291                        bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
 292
 293#if LCD_BPP == LCD_MONOCHROME
 294                        sym  = (COLOR_MASK(lcd_color_fg) & bits) |
 295                                (COLOR_MASK(lcd_color_bg) & ~bits);
 296
 297                        *d++ = rest | (sym >> off);
 298                        rest = sym << (8-off);
 299#elif LCD_BPP == LCD_COLOR8
 300                        for (c = 0; c < 8; ++c) {
 301                                *d++ = (bits & 0x80) ?
 302                                                lcd_color_fg : lcd_color_bg;
 303                                bits <<= 1;
 304                        }
 305#elif LCD_BPP == LCD_COLOR16
 306                        for (c = 0; c < 8; ++c) {
 307                                *d++ = (bits & 0x80) ?
 308                                                lcd_color_fg : lcd_color_bg;
 309                                bits <<= 1;
 310                        }
 311#endif
 312                }
 313#if LCD_BPP == LCD_MONOCHROME
 314                *d  = rest | (*d & ((1 << (8-off)) - 1));
 315#endif
 316        }
 317}
 318
 319/*----------------------------------------------------------------------*/
 320
 321static inline void lcd_puts_xy(ushort x, ushort y, uchar *s)
 322{
 323        lcd_drawchars(x, y, s, strlen((char *)s));
 324}
 325
 326/*----------------------------------------------------------------------*/
 327
 328static inline void lcd_putc_xy(ushort x, ushort y, uchar c)
 329{
 330        lcd_drawchars(x, y, &c, 1);
 331}
 332
 333/************************************************************************/
 334/**  Small utility to check that you got the colours right              */
 335/************************************************************************/
 336#ifdef LCD_TEST_PATTERN
 337
 338#define N_BLK_VERT      2
 339#define N_BLK_HOR       3
 340
 341static int test_colors[N_BLK_HOR*N_BLK_VERT] = {
 342        CONSOLE_COLOR_RED,      CONSOLE_COLOR_GREEN,    CONSOLE_COLOR_YELLOW,
 343        CONSOLE_COLOR_BLUE,     CONSOLE_COLOR_MAGENTA,  CONSOLE_COLOR_CYAN,
 344};
 345
 346static void test_pattern(void)
 347{
 348        ushort v_max  = panel_info.vl_row;
 349        ushort h_max  = panel_info.vl_col;
 350        ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT;
 351        ushort h_step = (h_max + N_BLK_HOR  - 1) / N_BLK_HOR;
 352        ushort v, h;
 353        uchar *pix = (uchar *)lcd_base;
 354
 355        printf("[LCD] Test Pattern: %d x %d [%d x %d]\n",
 356                h_max, v_max, h_step, v_step);
 357
 358        /* WARNING: Code silently assumes 8bit/pixel */
 359        for (v = 0; v < v_max; ++v) {
 360                uchar iy = v / v_step;
 361                for (h = 0; h < h_max; ++h) {
 362                        uchar ix = N_BLK_HOR * iy + (h/h_step);
 363                        *pix++ = test_colors[ix];
 364                }
 365        }
 366}
 367#endif /* LCD_TEST_PATTERN */
 368
 369
 370/************************************************************************/
 371/* ** GENERIC Initialization Routines                                   */
 372/************************************************************************/
 373
 374int lcd_get_size(int *line_length)
 375{
 376        *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
 377        return *line_length * panel_info.vl_row;
 378}
 379
 380int drv_lcd_init (void)
 381{
 382        struct stdio_dev lcddev;
 383        int rc;
 384
 385        lcd_base = (void *)(gd->fb_base);
 386
 387        lcd_get_size(&lcd_line_length);
 388
 389        lcd_init(lcd_base);             /* LCD initialization */
 390
 391        /* Device initialization */
 392        memset(&lcddev, 0, sizeof(lcddev));
 393
 394        strcpy(lcddev.name, "lcd");
 395        lcddev.ext   = 0;                       /* No extensions */
 396        lcddev.flags = DEV_FLAGS_OUTPUT;        /* Output only */
 397        lcddev.putc  = lcd_putc;                /* 'putc' function */
 398        lcddev.puts  = lcd_puts;                /* 'puts' function */
 399
 400        rc = stdio_register (&lcddev);
 401
 402        return (rc == 0) ? 1 : rc;
 403}
 404
 405/*----------------------------------------------------------------------*/
 406void lcd_clear(void)
 407{
 408#if LCD_BPP == LCD_MONOCHROME
 409        /* Setting the palette */
 410        lcd_initcolregs();
 411
 412#elif LCD_BPP == LCD_COLOR8
 413        /* Setting the palette */
 414        lcd_setcolreg(CONSOLE_COLOR_BLACK, 0, 0, 0);
 415        lcd_setcolreg(CONSOLE_COLOR_RED, 0xFF, 0, 0);
 416        lcd_setcolreg(CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
 417        lcd_setcolreg(CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
 418        lcd_setcolreg(CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
 419        lcd_setcolreg(CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
 420        lcd_setcolreg(CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
 421        lcd_setcolreg(CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
 422        lcd_setcolreg(CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
 423#endif
 424
 425#ifndef CONFIG_SYS_WHITE_ON_BLACK
 426        lcd_setfgcolor(CONSOLE_COLOR_BLACK);
 427        lcd_setbgcolor(CONSOLE_COLOR_WHITE);
 428#else
 429        lcd_setfgcolor(CONSOLE_COLOR_WHITE);
 430        lcd_setbgcolor(CONSOLE_COLOR_BLACK);
 431#endif  /* CONFIG_SYS_WHITE_ON_BLACK */
 432
 433#ifdef  LCD_TEST_PATTERN
 434        test_pattern();
 435#else
 436        /* set framebuffer to background color */
 437        memset((char *)lcd_base,
 438                COLOR_MASK(lcd_getbgcolor()),
 439                lcd_line_length*panel_info.vl_row);
 440#endif
 441        /* Paint the logo and retrieve LCD base address */
 442        debug("[LCD] Drawing the logo...\n");
 443        lcd_console_address = lcd_logo ();
 444
 445        console_col = 0;
 446        console_row = 0;
 447        lcd_sync();
 448}
 449
 450static int do_lcd_clear(cmd_tbl_t *cmdtp, int flag, int argc,
 451                        char *const argv[])
 452{
 453        lcd_clear();
 454        return 0;
 455}
 456
 457U_BOOT_CMD(
 458        cls,    1,      1,      do_lcd_clear,
 459        "clear screen",
 460        ""
 461);
 462
 463/*----------------------------------------------------------------------*/
 464
 465static int lcd_init(void *lcdbase)
 466{
 467        /* Initialize the lcd controller */
 468        debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
 469
 470        lcd_ctrl_init(lcdbase);
 471        lcd_is_enabled = 1;
 472        lcd_clear();
 473        lcd_enable ();
 474
 475        /* Initialize the console */
 476        console_col = 0;
 477#ifdef CONFIG_LCD_INFO_BELOW_LOGO
 478        console_row = 7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT;
 479#else
 480        console_row = 1;        /* leave 1 blank line below logo */
 481#endif
 482
 483        return 0;
 484}
 485
 486
 487/************************************************************************/
 488/* ** ROM capable initialization part - needed to reserve FB memory     */
 489/************************************************************************/
 490/*
 491 * This is called early in the system initialization to grab memory
 492 * for the LCD controller.
 493 * Returns new address for monitor, after reserving LCD buffer memory
 494 *
 495 * Note that this is running from ROM, so no write access to global data.
 496 */
 497ulong lcd_setmem(ulong addr)
 498{
 499        ulong size;
 500        int line_length;
 501
 502        debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col,
 503                panel_info.vl_row, NBITS(panel_info.vl_bpix));
 504
 505        size = lcd_get_size(&line_length);
 506
 507        /* Round up to nearest full page, or MMU section if defined */
 508        size = ALIGN(size, CONFIG_LCD_ALIGNMENT);
 509        addr = ALIGN(addr - CONFIG_LCD_ALIGNMENT + 1, CONFIG_LCD_ALIGNMENT);
 510
 511        /* Allocate pages for the frame buffer. */
 512        addr -= size;
 513
 514        debug("Reserving %ldk for LCD Framebuffer at: %08lx\n", size>>10, addr);
 515
 516        return addr;
 517}
 518
 519/*----------------------------------------------------------------------*/
 520
 521static void lcd_setfgcolor(int color)
 522{
 523        lcd_color_fg = color;
 524}
 525
 526/*----------------------------------------------------------------------*/
 527
 528static void lcd_setbgcolor(int color)
 529{
 530        lcd_color_bg = color;
 531}
 532
 533/*----------------------------------------------------------------------*/
 534
 535#ifdef  NOT_USED_SO_FAR
 536static int lcd_getfgcolor(void)
 537{
 538        return lcd_color_fg;
 539}
 540#endif  /* NOT_USED_SO_FAR */
 541
 542/*----------------------------------------------------------------------*/
 543
 544static int lcd_getbgcolor(void)
 545{
 546        return lcd_color_bg;
 547}
 548
 549/*----------------------------------------------------------------------*/
 550
 551/************************************************************************/
 552/* ** Chipset depending Bitmap / Logo stuff...                          */
 553/************************************************************************/
 554static inline ushort *configuration_get_cmap(void)
 555{
 556#if defined CONFIG_CPU_PXA
 557        struct pxafb_info *fbi = &panel_info.pxa;
 558        return (ushort *)fbi->palette;
 559#elif defined(CONFIG_MPC823)
 560        immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 561        cpm8xx_t *cp = &(immr->im_cpm);
 562        return (ushort *)&(cp->lcd_cmap[255 * sizeof(ushort)]);
 563#elif defined(CONFIG_ATMEL_LCD)
 564        return (ushort *)(panel_info.mmio + ATMEL_LCDC_LUT(0));
 565#elif !defined(CONFIG_ATMEL_HLCD) && !defined(CONFIG_EXYNOS_FB)
 566        return panel_info.cmap;
 567#else
 568#if defined(CONFIG_LCD_LOGO)
 569        return bmp_logo_palette;
 570#else
 571        return NULL;
 572#endif
 573#endif
 574}
 575
 576#ifdef CONFIG_LCD_LOGO
 577void bitmap_plot(int x, int y)
 578{
 579#ifdef CONFIG_ATMEL_LCD
 580        uint *cmap = (uint *)bmp_logo_palette;
 581#else
 582        ushort *cmap = (ushort *)bmp_logo_palette;
 583#endif
 584        ushort i, j;
 585        uchar *bmap;
 586        uchar *fb;
 587        ushort *fb16;
 588#if defined(CONFIG_MPC823)
 589        immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 590        cpm8xx_t *cp = &(immr->im_cpm);
 591#endif
 592
 593        debug("Logo: width %d  height %d  colors %d  cmap %d\n",
 594                BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS,
 595                ARRAY_SIZE(bmp_logo_palette));
 596
 597        bmap = &bmp_logo_bitmap[0];
 598        fb   = (uchar *)(lcd_base + y * lcd_line_length + x);
 599
 600        if (NBITS(panel_info.vl_bpix) < 12) {
 601                /* Leave room for default color map
 602                 * default case: generic system with no cmap (most likely 16bpp)
 603                 * cmap was set to the source palette, so no change is done.
 604                 * This avoids even more ifdefs in the next stanza
 605                 */
 606#if defined(CONFIG_MPC823)
 607                cmap = (ushort *) &(cp->lcd_cmap[BMP_LOGO_OFFSET * sizeof(ushort)]);
 608#elif defined(CONFIG_ATMEL_LCD)
 609                cmap = (uint *)configuration_get_cmap();
 610#else
 611                cmap = configuration_get_cmap();
 612#endif
 613
 614                WATCHDOG_RESET();
 615
 616                /* Set color map */
 617                for (i = 0; i < ARRAY_SIZE(bmp_logo_palette); ++i) {
 618                        ushort colreg = bmp_logo_palette[i];
 619#ifdef CONFIG_ATMEL_LCD
 620                        uint lut_entry;
 621#ifdef CONFIG_ATMEL_LCD_BGR555
 622                        lut_entry = ((colreg & 0x000F) << 11) |
 623                                        ((colreg & 0x00F0) <<  2) |
 624                                        ((colreg & 0x0F00) >>  7);
 625#else /* CONFIG_ATMEL_LCD_RGB565 */
 626                        lut_entry = ((colreg & 0x000F) << 1) |
 627                                        ((colreg & 0x00F0) << 3) |
 628                                        ((colreg & 0x0F00) << 4);
 629#endif
 630                        *(cmap + BMP_LOGO_OFFSET) = lut_entry;
 631                        cmap++;
 632#else /* !CONFIG_ATMEL_LCD */
 633#ifdef  CONFIG_SYS_INVERT_COLORS
 634                        *cmap++ = 0xffff - colreg;
 635#else
 636                        *cmap++ = colreg;
 637#endif
 638#endif /* CONFIG_ATMEL_LCD */
 639                }
 640
 641                WATCHDOG_RESET();
 642
 643                for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
 644                        memcpy(fb, bmap, BMP_LOGO_WIDTH);
 645                        bmap += BMP_LOGO_WIDTH;
 646                        fb   += panel_info.vl_col;
 647                }
 648        }
 649        else { /* true color mode */
 650                u16 col16;
 651                fb16 = (ushort *)(lcd_base + y * lcd_line_length + x);
 652                for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
 653                        for (j = 0; j < BMP_LOGO_WIDTH; j++) {
 654                                col16 = bmp_logo_palette[(bmap[j]-16)];
 655                                fb16[j] =
 656                                        ((col16 & 0x000F) << 1) |
 657                                        ((col16 & 0x00F0) << 3) |
 658                                        ((col16 & 0x0F00) << 4);
 659                                }
 660                        bmap += BMP_LOGO_WIDTH;
 661                        fb16 += panel_info.vl_col;
 662                }
 663        }
 664
 665        WATCHDOG_RESET();
 666        lcd_sync();
 667}
 668#else
 669static inline void bitmap_plot(int x, int y) {}
 670#endif /* CONFIG_LCD_LOGO */
 671
 672/*----------------------------------------------------------------------*/
 673#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
 674/*
 675 * Display the BMP file located at address bmp_image.
 676 * Only uncompressed.
 677 */
 678
 679#ifdef CONFIG_SPLASH_SCREEN_ALIGN
 680#define BMP_ALIGN_CENTER        0x7FFF
 681
 682static void splash_align_axis(int *axis, unsigned long panel_size,
 683                                        unsigned long picture_size)
 684{
 685        unsigned long panel_picture_delta = panel_size - picture_size;
 686        unsigned long axis_alignment;
 687
 688        if (*axis == BMP_ALIGN_CENTER)
 689                axis_alignment = panel_picture_delta / 2;
 690        else if (*axis < 0)
 691                axis_alignment = panel_picture_delta + *axis + 1;
 692        else
 693                return;
 694
 695        *axis = max(0, axis_alignment);
 696}
 697#endif
 698
 699
 700#ifdef CONFIG_LCD_BMP_RLE8
 701
 702#define BMP_RLE8_ESCAPE         0
 703#define BMP_RLE8_EOL            0
 704#define BMP_RLE8_EOBMP          1
 705#define BMP_RLE8_DELTA          2
 706
 707static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap,
 708                                  int cnt)
 709{
 710        while (cnt > 0) {
 711                *(*fbp)++ = cmap[*bmap++];
 712                cnt--;
 713        }
 714}
 715
 716static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt)
 717{
 718        ushort *fb = *fbp;
 719        int cnt_8copy = cnt >> 3;
 720
 721        cnt -= cnt_8copy << 3;
 722        while (cnt_8copy > 0) {
 723                *fb++ = c;
 724                *fb++ = c;
 725                *fb++ = c;
 726                *fb++ = c;
 727                *fb++ = c;
 728                *fb++ = c;
 729                *fb++ = c;
 730                *fb++ = c;
 731                cnt_8copy--;
 732        }
 733        while (cnt > 0) {
 734                *fb++ = c;
 735                cnt--;
 736        }
 737        (*fbp) = fb;
 738}
 739
 740/*
 741 * Do not call this function directly, must be called from
 742 * lcd_display_bitmap.
 743 */
 744static void lcd_display_rle8_bitmap(bmp_image_t *bmp, ushort *cmap, uchar *fb,
 745                                    int x_off, int y_off)
 746{
 747        uchar *bmap;
 748        ulong width, height;
 749        ulong cnt, runlen;
 750        int x, y;
 751        int decode = 1;
 752
 753        width = le32_to_cpu(bmp->header.width);
 754        height = le32_to_cpu(bmp->header.height);
 755        bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset);
 756
 757        x = 0;
 758        y = height - 1;
 759
 760        while (decode) {
 761                if (bmap[0] == BMP_RLE8_ESCAPE) {
 762                        switch (bmap[1]) {
 763                        case BMP_RLE8_EOL:
 764                                /* end of line */
 765                                bmap += 2;
 766                                x = 0;
 767                                y--;
 768                                /* 16bpix, 2-byte per pixel, width should *2 */
 769                                fb -= (width * 2 + lcd_line_length);
 770                                break;
 771                        case BMP_RLE8_EOBMP:
 772                                /* end of bitmap */
 773                                decode = 0;
 774                                break;
 775                        case BMP_RLE8_DELTA:
 776                                /* delta run */
 777                                x += bmap[2];
 778                                y -= bmap[3];
 779                                /* 16bpix, 2-byte per pixel, x should *2 */
 780                                fb = (uchar *) (lcd_base + (y + y_off - 1)
 781                                        * lcd_line_length + (x + x_off) * 2);
 782                                bmap += 4;
 783                                break;
 784                        default:
 785                                /* unencoded run */
 786                                runlen = bmap[1];
 787                                bmap += 2;
 788                                if (y < height) {
 789                                        if (x < width) {
 790                                                if (x + runlen > width)
 791                                                        cnt = width - x;
 792                                                else
 793                                                        cnt = runlen;
 794                                                draw_unencoded_bitmap(
 795                                                        (ushort **)&fb,
 796                                                        bmap, cmap, cnt);
 797                                        }
 798                                        x += runlen;
 799                                }
 800                                bmap += runlen;
 801                                if (runlen & 1)
 802                                        bmap++;
 803                        }
 804                } else {
 805                        /* encoded run */
 806                        if (y < height) {
 807                                runlen = bmap[0];
 808                                if (x < width) {
 809                                        /* aggregate the same code */
 810                                        while (bmap[0] == 0xff &&
 811                                               bmap[2] != BMP_RLE8_ESCAPE &&
 812                                               bmap[1] == bmap[3]) {
 813                                                runlen += bmap[2];
 814                                                bmap += 2;
 815                                        }
 816                                        if (x + runlen > width)
 817                                                cnt = width - x;
 818                                        else
 819                                                cnt = runlen;
 820                                        draw_encoded_bitmap((ushort **)&fb,
 821                                                cmap[bmap[1]], cnt);
 822                                }
 823                                x += runlen;
 824                        }
 825                        bmap += 2;
 826                }
 827        }
 828}
 829#endif
 830
 831#if defined(CONFIG_MPC823) || defined(CONFIG_MCC200)
 832#define FB_PUT_BYTE(fb, from) *(fb)++ = (255 - *(from)++)
 833#else
 834#define FB_PUT_BYTE(fb, from) *(fb)++ = *(from)++
 835#endif
 836
 837#if defined(CONFIG_BMP_16BPP)
 838#if defined(CONFIG_ATMEL_LCD_BGR555)
 839static inline void fb_put_word(uchar **fb, uchar **from)
 840{
 841        *(*fb)++ = (((*from)[0] & 0x1f) << 2) | ((*from)[1] & 0x03);
 842        *(*fb)++ = ((*from)[0] & 0xe0) | (((*from)[1] & 0x7c) >> 2);
 843        *from += 2;
 844}
 845#else
 846static inline void fb_put_word(uchar **fb, uchar **from)
 847{
 848        *(*fb)++ = *(*from)++;
 849        *(*fb)++ = *(*from)++;
 850}
 851#endif
 852#endif /* CONFIG_BMP_16BPP */
 853
 854int lcd_display_bitmap(ulong bmp_image, int x, int y)
 855{
 856#if !defined(CONFIG_MCC200)
 857        ushort *cmap = NULL;
 858#endif
 859        ushort *cmap_base = NULL;
 860        ushort i, j;
 861        uchar *fb;
 862        bmp_image_t *bmp=(bmp_image_t *)bmp_image;
 863        uchar *bmap;
 864        ushort padded_width;
 865        unsigned long width, height, byte_width;
 866        unsigned long pwidth = panel_info.vl_col;
 867        unsigned colors, bpix, bmp_bpix;
 868
 869        if (!bmp || !((bmp->header.signature[0] == 'B') &&
 870                (bmp->header.signature[1] == 'M'))) {
 871                printf("Error: no valid bmp image at %lx\n", bmp_image);
 872
 873                return 1;
 874        }
 875
 876        width = le32_to_cpu(bmp->header.width);
 877        height = le32_to_cpu(bmp->header.height);
 878        bmp_bpix = le16_to_cpu(bmp->header.bit_count);
 879        colors = 1 << bmp_bpix;
 880
 881        bpix = NBITS(panel_info.vl_bpix);
 882
 883        if ((bpix != 1) && (bpix != 8) && (bpix != 16) && (bpix != 32)) {
 884                printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
 885                        bpix, bmp_bpix);
 886
 887                return 1;
 888        }
 889
 890        /* We support displaying 8bpp BMPs on 16bpp LCDs */
 891        if (bpix != bmp_bpix && !(bmp_bpix == 8 && bpix == 16)) {
 892                printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
 893                        bpix,
 894                        le16_to_cpu(bmp->header.bit_count));
 895
 896                return 1;
 897        }
 898
 899        debug("Display-bmp: %d x %d  with %d colors\n",
 900                (int)width, (int)height, (int)colors);
 901
 902#if !defined(CONFIG_MCC200)
 903        /* MCC200 LCD doesn't need CMAP, supports 1bpp b&w only */
 904        if (bmp_bpix == 8) {
 905                cmap = configuration_get_cmap();
 906                cmap_base = cmap;
 907
 908                /* Set color map */
 909                for (i = 0; i < colors; ++i) {
 910                        bmp_color_table_entry_t cte = bmp->color_table[i];
 911#if !defined(CONFIG_ATMEL_LCD)
 912                        ushort colreg =
 913                                ( ((cte.red)   << 8) & 0xf800) |
 914                                ( ((cte.green) << 3) & 0x07e0) |
 915                                ( ((cte.blue)  >> 3) & 0x001f) ;
 916#ifdef CONFIG_SYS_INVERT_COLORS
 917                        *cmap = 0xffff - colreg;
 918#else
 919                        *cmap = colreg;
 920#endif
 921#if defined(CONFIG_MPC823)
 922                        cmap--;
 923#else
 924                        cmap++;
 925#endif
 926#else /* CONFIG_ATMEL_LCD */
 927                        lcd_setcolreg(i, cte.red, cte.green, cte.blue);
 928#endif
 929                }
 930        }
 931#endif
 932
 933        /*
 934         *  BMP format for Monochrome assumes that the state of a
 935         * pixel is described on a per Bit basis, not per Byte.
 936         *  So, in case of Monochrome BMP we should align widths
 937         * on a byte boundary and convert them from Bit to Byte
 938         * units.
 939         *  Probably, PXA250 and MPC823 process 1bpp BMP images in
 940         * their own ways, so make the converting to be MCC200
 941         * specific.
 942         */
 943#if defined(CONFIG_MCC200)
 944        if (bpix == 1) {
 945                width = ((width + 7) & ~7) >> 3;
 946                x     = ((x + 7) & ~7) >> 3;
 947                pwidth= ((pwidth + 7) & ~7) >> 3;
 948        }
 949#endif
 950
 951        padded_width = (width&0x3) ? ((width&~0x3)+4) : (width);
 952
 953#ifdef CONFIG_SPLASH_SCREEN_ALIGN
 954        splash_align_axis(&x, pwidth, width);
 955        splash_align_axis(&y, panel_info.vl_row, height);
 956#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
 957
 958        if ((x + width) > pwidth)
 959                width = pwidth - x;
 960        if ((y + height) > panel_info.vl_row)
 961                height = panel_info.vl_row - y;
 962
 963        bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset);
 964        fb   = (uchar *) (lcd_base +
 965                (y + height - 1) * lcd_line_length + x * bpix / 8);
 966
 967        switch (bmp_bpix) {
 968        case 1: /* pass through */
 969        case 8:
 970#ifdef CONFIG_LCD_BMP_RLE8
 971                if (le32_to_cpu(bmp->header.compression) == BMP_BI_RLE8) {
 972                        if (bpix != 16) {
 973                                /* TODO implement render code for bpix != 16 */
 974                                printf("Error: only support 16 bpix");
 975                                return 1;
 976                        }
 977                        lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y);
 978                        break;
 979                }
 980#endif
 981
 982                if (bpix != 16)
 983                        byte_width = width;
 984                else
 985                        byte_width = width * 2;
 986
 987                for (i = 0; i < height; ++i) {
 988                        WATCHDOG_RESET();
 989                        for (j = 0; j < width; j++) {
 990                                if (bpix != 16) {
 991                                        FB_PUT_BYTE(fb, bmap);
 992                                } else {
 993                                        *(uint16_t *)fb = cmap_base[*(bmap++)];
 994                                        fb += sizeof(uint16_t) / sizeof(*fb);
 995                                }
 996                        }
 997                        bmap += (padded_width - width);
 998                        fb   -= (byte_width + lcd_line_length);
 999                }
1000                break;
1001
1002#if defined(CONFIG_BMP_16BPP)
1003        case 16:
1004                for (i = 0; i < height; ++i) {
1005                        WATCHDOG_RESET();
1006                        for (j = 0; j < width; j++)
1007                                fb_put_word(&fb, &bmap);
1008
1009                        bmap += (padded_width - width) * 2;
1010                        fb   -= (width * 2 + lcd_line_length);
1011                }
1012                break;
1013#endif /* CONFIG_BMP_16BPP */
1014
1015#if defined(CONFIG_BMP_32BPP)
1016        case 32:
1017                for (i = 0; i < height; ++i) {
1018                        for (j = 0; j < width; j++) {
1019                                *(fb++) = *(bmap++);
1020                                *(fb++) = *(bmap++);
1021                                *(fb++) = *(bmap++);
1022                                *(fb++) = *(bmap++);
1023                        }
1024                        fb  -= (lcd_line_length + width * (bpix / 8));
1025                }
1026                break;
1027#endif /* CONFIG_BMP_32BPP */
1028        default:
1029                break;
1030        };
1031
1032        lcd_sync();
1033        return 0;
1034}
1035#endif
1036
1037static void *lcd_logo(void)
1038{
1039#ifdef CONFIG_SPLASH_SCREEN
1040        char *s;
1041        ulong addr;
1042        static int do_splash = 1;
1043
1044        if (do_splash && (s = getenv("splashimage")) != NULL) {
1045                int x = 0, y = 0;
1046                do_splash = 0;
1047
1048                addr = simple_strtoul (s, NULL, 16);
1049#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1050                s = getenv("splashpos");
1051                if (s != NULL) {
1052                        if (s[0] == 'm')
1053                                x = BMP_ALIGN_CENTER;
1054                        else
1055                                x = simple_strtol(s, NULL, 0);
1056
1057                        s = strchr(s + 1, ',');
1058                        if (s != NULL) {
1059                                if (s[1] == 'm')
1060                                        y = BMP_ALIGN_CENTER;
1061                                else
1062                                        y = simple_strtol (s + 1, NULL, 0);
1063                        }
1064                }
1065#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1066
1067                if (bmp_display(addr, x, y) == 0)
1068                        return (void *)lcd_base;
1069        }
1070#endif /* CONFIG_SPLASH_SCREEN */
1071
1072        bitmap_plot(0, 0);
1073
1074#ifdef CONFIG_LCD_INFO
1075        console_col = LCD_INFO_X / VIDEO_FONT_WIDTH;
1076        console_row = LCD_INFO_Y / VIDEO_FONT_HEIGHT;
1077        lcd_show_board_info();
1078#endif /* CONFIG_LCD_INFO */
1079
1080#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
1081        return (void *)((ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length);
1082#else
1083        return (void *)lcd_base;
1084#endif /* CONFIG_LCD_LOGO && !CONFIG_LCD_INFO_BELOW_LOGO */
1085}
1086
1087void lcd_position_cursor(unsigned col, unsigned row)
1088{
1089        console_col = min(col, CONSOLE_COLS - 1);
1090        console_row = min(row, CONSOLE_ROWS - 1);
1091}
1092
1093int lcd_get_pixel_width(void)
1094{
1095        return panel_info.vl_col;
1096}
1097
1098int lcd_get_pixel_height(void)
1099{
1100        return panel_info.vl_row;
1101}
1102
1103int lcd_get_screen_rows(void)
1104{
1105        return CONSOLE_ROWS;
1106}
1107
1108int lcd_get_screen_columns(void)
1109{
1110        return CONSOLE_COLS;
1111}
1112
1113/************************************************************************/
1114/************************************************************************/
1115