uboot/common/lcd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Common LCD routines
   4 *
   5 * (C) Copyright 2001-2002
   6 * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
   7 */
   8
   9/* #define DEBUG */
  10#include <config.h>
  11#include <common.h>
  12#include <command.h>
  13#include <cpu_func.h>
  14#include <env_callback.h>
  15#include <log.h>
  16#include <asm/cache.h>
  17#include <init.h>
  18#include <asm/global_data.h>
  19#include <linux/types.h>
  20#include <stdio_dev.h>
  21#include <lcd.h>
  22#include <mapmem.h>
  23#include <watchdog.h>
  24#include <asm/unaligned.h>
  25#include <splash.h>
  26#include <asm/io.h>
  27#include <asm/unaligned.h>
  28#include <video_font.h>
  29
  30#ifdef CONFIG_LCD_LOGO
  31#include <bmp_logo.h>
  32#include <bmp_logo_data.h>
  33#if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)
  34#error Default Color Map overlaps with Logo Color Map
  35#endif
  36#endif
  37
  38#ifndef CONFIG_LCD_ALIGNMENT
  39#define CONFIG_LCD_ALIGNMENT PAGE_SIZE
  40#endif
  41
  42#if (LCD_BPP != LCD_COLOR8) && (LCD_BPP != LCD_COLOR16) && \
  43        (LCD_BPP != LCD_COLOR32)
  44#error Unsupported LCD BPP.
  45#endif
  46
  47DECLARE_GLOBAL_DATA_PTR;
  48
  49static int lcd_init(void *lcdbase);
  50static void lcd_logo(void);
  51static void lcd_setfgcolor(int color);
  52static void lcd_setbgcolor(int color);
  53
  54static int lcd_color_fg;
  55static int lcd_color_bg;
  56int lcd_line_length;
  57char lcd_is_enabled = 0;
  58static void *lcd_base;                  /* Start of framebuffer memory  */
  59static char lcd_flush_dcache;   /* 1 to flush dcache after each lcd update */
  60
  61/* Flush LCD activity to the caches */
  62void lcd_sync(void)
  63{
  64        /*
  65         * flush_dcache_range() is declared in common.h but it seems that some
  66         * architectures do not actually implement it. Is there a way to find
  67         * out whether it exists? For now, ARM is safe.
  68         */
  69#if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
  70        int line_length;
  71
  72        if (lcd_flush_dcache)
  73                flush_dcache_range((ulong)lcd_base,
  74                        (ulong)(lcd_base + lcd_get_size(&line_length)));
  75#endif
  76}
  77
  78void lcd_set_flush_dcache(int flush)
  79{
  80        lcd_flush_dcache = (flush != 0);
  81}
  82
  83static void lcd_stub_putc(struct stdio_dev *dev, const char c)
  84{
  85        lcd_putc(c);
  86}
  87
  88static void lcd_stub_puts(struct stdio_dev *dev, const char *s)
  89{
  90        lcd_puts(s);
  91}
  92
  93/* Small utility to check that you got the colours right */
  94#ifdef LCD_TEST_PATTERN
  95
  96#if LCD_BPP == LCD_COLOR8
  97#define N_BLK_VERT      2
  98#define N_BLK_HOR       3
  99
 100static int test_colors[N_BLK_HOR * N_BLK_VERT] = {
 101        CONSOLE_COLOR_RED,      CONSOLE_COLOR_GREEN,    CONSOLE_COLOR_YELLOW,
 102        CONSOLE_COLOR_BLUE,     CONSOLE_COLOR_MAGENTA,  CONSOLE_COLOR_CYAN,
 103}; /*LCD_BPP == LCD_COLOR8 */
 104
 105#elif LCD_BPP == LCD_COLOR16
 106#define N_BLK_VERT      2
 107#define N_BLK_HOR       4
 108
 109static int test_colors[N_BLK_HOR * N_BLK_VERT] = {
 110        CONSOLE_COLOR_RED,      CONSOLE_COLOR_GREEN,    CONSOLE_COLOR_YELLOW,   CONSOLE_COLOR_BLUE,
 111        CONSOLE_COLOR_MAGENTA,  CONSOLE_COLOR_CYAN,     CONSOLE_COLOR_GREY,     CONSOLE_COLOR_WHITE,
 112};
 113#endif /*LCD_BPP == LCD_COLOR16 */
 114
 115static void test_pattern(void)
 116{
 117        ushort v_max  = panel_info.vl_row;
 118        ushort h_max  = panel_info.vl_col;
 119        ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT;
 120        ushort h_step = (h_max + N_BLK_HOR  - 1) / N_BLK_HOR;
 121        ushort v, h;
 122#if LCD_BPP == LCD_COLOR8
 123        uchar *pix = (uchar *)lcd_base;
 124#elif LCD_BPP == LCD_COLOR16
 125        ushort *pix = (ushort *)lcd_base;
 126#endif
 127
 128        printf("[LCD] Test Pattern: %d x %d [%d x %d]\n",
 129                h_max, v_max, h_step, v_step);
 130
 131        for (v = 0; v < v_max; ++v) {
 132                uchar iy = v / v_step;
 133                for (h = 0; h < h_max; ++h) {
 134                        uchar ix = N_BLK_HOR * iy + h / h_step;
 135                        *pix++ = test_colors[ix];
 136                }
 137        }
 138}
 139#endif /* LCD_TEST_PATTERN */
 140
 141/*
 142 * With most lcd drivers the line length is set up
 143 * by calculating it from panel_info parameters. Some
 144 * drivers need to calculate the line length differently,
 145 * so make the function weak to allow overriding it.
 146 */
 147__weak int lcd_get_size(int *line_length)
 148{
 149        *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
 150        return *line_length * panel_info.vl_row;
 151}
 152
 153int drv_lcd_init(void)
 154{
 155        struct stdio_dev lcddev;
 156        int rc;
 157
 158        lcd_base = map_sysmem(gd->fb_base, 0);
 159
 160        lcd_init(lcd_base);
 161
 162        /* Device initialization */
 163        memset(&lcddev, 0, sizeof(lcddev));
 164
 165        strcpy(lcddev.name, "lcd");
 166        lcddev.ext   = 0;                       /* No extensions */
 167        lcddev.flags = DEV_FLAGS_OUTPUT;        /* Output only */
 168        lcddev.putc  = lcd_stub_putc;           /* 'putc' function */
 169        lcddev.puts  = lcd_stub_puts;           /* 'puts' function */
 170
 171        rc = stdio_register(&lcddev);
 172
 173        return (rc == 0) ? 1 : rc;
 174}
 175
 176void lcd_clear(void)
 177{
 178        int bg_color;
 179        __maybe_unused ulong addr;
 180        static int do_splash = 1;
 181#if LCD_BPP == LCD_COLOR8
 182        /* Setting the palette */
 183        lcd_setcolreg(CONSOLE_COLOR_BLACK, 0, 0, 0);
 184        lcd_setcolreg(CONSOLE_COLOR_RED, 0xFF, 0, 0);
 185        lcd_setcolreg(CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
 186        lcd_setcolreg(CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
 187        lcd_setcolreg(CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
 188        lcd_setcolreg(CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
 189        lcd_setcolreg(CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
 190        lcd_setcolreg(CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
 191        lcd_setcolreg(CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
 192#endif
 193
 194#ifndef CONFIG_SYS_WHITE_ON_BLACK
 195        lcd_setfgcolor(CONSOLE_COLOR_BLACK);
 196        lcd_setbgcolor(CONSOLE_COLOR_WHITE);
 197        bg_color = CONSOLE_COLOR_WHITE;
 198#else
 199        lcd_setfgcolor(CONSOLE_COLOR_WHITE);
 200        lcd_setbgcolor(CONSOLE_COLOR_BLACK);
 201        bg_color = CONSOLE_COLOR_BLACK;
 202#endif  /* CONFIG_SYS_WHITE_ON_BLACK */
 203
 204#ifdef  LCD_TEST_PATTERN
 205        test_pattern();
 206#else
 207        /* set framebuffer to background color */
 208#if (LCD_BPP != LCD_COLOR32)
 209        memset((char *)lcd_base, bg_color, lcd_line_length * panel_info.vl_row);
 210#else
 211        u32 *ppix = lcd_base;
 212        u32 i;
 213        for (i = 0;
 214           i < (lcd_line_length * panel_info.vl_row)/NBYTES(panel_info.vl_bpix);
 215           i++) {
 216                *ppix++ = bg_color;
 217        }
 218#endif
 219#endif
 220        /* setup text-console */
 221        debug("[LCD] setting up console...\n");
 222        lcd_init_console(lcd_base,
 223                         panel_info.vl_col,
 224                         panel_info.vl_row,
 225                         panel_info.vl_rot);
 226        /* Paint the logo and retrieve LCD base address */
 227        debug("[LCD] Drawing the logo...\n");
 228        if (do_splash) {
 229                if (splash_display() == 0) {
 230                        do_splash = 0;
 231                        lcd_sync();
 232                        return;
 233                }
 234        }
 235
 236        lcd_logo();
 237#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
 238        addr = (ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length;
 239        lcd_init_console((void *)addr, panel_info.vl_col,
 240                         panel_info.vl_row, panel_info.vl_rot);
 241#endif
 242        lcd_sync();
 243}
 244
 245static int lcd_init(void *lcdbase)
 246{
 247        debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
 248        lcd_ctrl_init(lcdbase);
 249
 250        /*
 251         * lcd_ctrl_init() of some drivers (i.e. bcm2835 on rpi) ignores
 252         * the 'lcdbase' argument and uses custom lcd base address
 253         * by setting up gd->fb_base. Check for this condition and fixup
 254         * 'lcd_base' address.
 255         */
 256        if (map_to_sysmem(lcdbase) != gd->fb_base)
 257                lcd_base = map_sysmem(gd->fb_base, 0);
 258
 259        debug("[LCD] Using LCD frambuffer at %p\n", lcd_base);
 260
 261        lcd_get_size(&lcd_line_length);
 262        lcd_is_enabled = 1;
 263        lcd_clear();
 264        lcd_enable();
 265
 266        /* Initialize the console */
 267        lcd_set_col(0);
 268#ifdef CONFIG_LCD_INFO_BELOW_LOGO
 269        lcd_set_row(7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT);
 270#else
 271        lcd_set_row(1); /* leave 1 blank line below logo */
 272#endif
 273
 274        return 0;
 275}
 276
 277/*
 278 * This is called early in the system initialization to grab memory
 279 * for the LCD controller.
 280 * Returns new address for monitor, after reserving LCD buffer memory
 281 *
 282 * Note that this is running from ROM, so no write access to global data.
 283 */
 284ulong lcd_setmem(ulong addr)
 285{
 286        ulong size;
 287        int line_length;
 288
 289        debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col,
 290                panel_info.vl_row, NBITS(panel_info.vl_bpix));
 291
 292        size = lcd_get_size(&line_length);
 293
 294        /* Round up to nearest full page, or MMU section if defined */
 295        size = ALIGN(size, CONFIG_LCD_ALIGNMENT);
 296        addr = ALIGN(addr - CONFIG_LCD_ALIGNMENT + 1, CONFIG_LCD_ALIGNMENT);
 297
 298        /* Allocate pages for the frame buffer. */
 299        addr -= size;
 300
 301        debug("Reserving %ldk for LCD Framebuffer at: %08lx\n",
 302              size >> 10, addr);
 303
 304        return addr;
 305}
 306
 307static void lcd_setfgcolor(int color)
 308{
 309        lcd_color_fg = color;
 310}
 311
 312int lcd_getfgcolor(void)
 313{
 314        return lcd_color_fg;
 315}
 316
 317static void lcd_setbgcolor(int color)
 318{
 319        lcd_color_bg = color;
 320}
 321
 322int lcd_getbgcolor(void)
 323{
 324        return lcd_color_bg;
 325}
 326
 327#ifdef CONFIG_LCD_LOGO
 328__weak void lcd_logo_set_cmap(void)
 329{
 330        int i;
 331        ushort *cmap = configuration_get_cmap();
 332
 333        for (i = 0; i < ARRAY_SIZE(bmp_logo_palette); ++i)
 334                *cmap++ = bmp_logo_palette[i];
 335}
 336
 337void lcd_logo_plot(int x, int y)
 338{
 339        ushort i, j;
 340        uchar *bmap = &bmp_logo_bitmap[0];
 341        unsigned bpix = NBITS(panel_info.vl_bpix);
 342        uchar *fb = (uchar *)(lcd_base + y * lcd_line_length + x * bpix / 8);
 343        ushort *fb16;
 344
 345        debug("Logo: width %d  height %d  colors %d\n",
 346              BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS);
 347
 348        if (bpix < 12) {
 349                WATCHDOG_RESET();
 350                lcd_logo_set_cmap();
 351                WATCHDOG_RESET();
 352
 353                for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
 354                        memcpy(fb, bmap, BMP_LOGO_WIDTH);
 355                        bmap += BMP_LOGO_WIDTH;
 356                        fb += panel_info.vl_col;
 357                }
 358        }
 359        else { /* true color mode */
 360                u16 col16;
 361                fb16 = (ushort *)fb;
 362                for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
 363                        for (j = 0; j < BMP_LOGO_WIDTH; j++) {
 364                                col16 = bmp_logo_palette[(bmap[j]-16)];
 365                                fb16[j] =
 366                                        ((col16 & 0x000F) << 1) |
 367                                        ((col16 & 0x00F0) << 3) |
 368                                        ((col16 & 0x0F00) << 4);
 369                                }
 370                        bmap += BMP_LOGO_WIDTH;
 371                        fb16 += panel_info.vl_col;
 372                }
 373        }
 374
 375        WATCHDOG_RESET();
 376        lcd_sync();
 377}
 378#else
 379static inline void lcd_logo_plot(int x, int y) {}
 380#endif /* CONFIG_LCD_LOGO */
 381
 382#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
 383#ifdef CONFIG_SPLASH_SCREEN_ALIGN
 384
 385static void splash_align_axis(int *axis, unsigned long panel_size,
 386                                        unsigned long picture_size)
 387{
 388        unsigned long panel_picture_delta = panel_size - picture_size;
 389        unsigned long axis_alignment;
 390
 391        if (*axis == BMP_ALIGN_CENTER)
 392                axis_alignment = panel_picture_delta / 2;
 393        else if (*axis < 0)
 394                axis_alignment = panel_picture_delta + *axis + 1;
 395        else
 396                return;
 397
 398        *axis = max(0, (int)axis_alignment);
 399}
 400#endif
 401
 402#ifdef CONFIG_LCD_BMP_RLE8
 403#define BMP_RLE8_ESCAPE         0
 404#define BMP_RLE8_EOL            0
 405#define BMP_RLE8_EOBMP          1
 406#define BMP_RLE8_DELTA          2
 407
 408static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap,
 409                                  int cnt)
 410{
 411        while (cnt > 0) {
 412                *(*fbp)++ = cmap[*bmap++];
 413                cnt--;
 414        }
 415}
 416
 417static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt)
 418{
 419        ushort *fb = *fbp;
 420        int cnt_8copy = cnt >> 3;
 421
 422        cnt -= cnt_8copy << 3;
 423        while (cnt_8copy > 0) {
 424                *fb++ = c;
 425                *fb++ = c;
 426                *fb++ = c;
 427                *fb++ = c;
 428                *fb++ = c;
 429                *fb++ = c;
 430                *fb++ = c;
 431                *fb++ = c;
 432                cnt_8copy--;
 433        }
 434        while (cnt > 0) {
 435                *fb++ = c;
 436                cnt--;
 437        }
 438        *fbp = fb;
 439}
 440
 441/*
 442 * Do not call this function directly, must be called from lcd_display_bitmap.
 443 */
 444static void lcd_display_rle8_bitmap(struct bmp_image *bmp, ushort *cmap,
 445                                    uchar *fb, int x_off, int y_off)
 446{
 447        uchar *bmap;
 448        ulong width, height;
 449        ulong cnt, runlen;
 450        int x, y;
 451        int decode = 1;
 452
 453        width = get_unaligned_le32(&bmp->header.width);
 454        height = get_unaligned_le32(&bmp->header.height);
 455        bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
 456
 457        x = 0;
 458        y = height - 1;
 459
 460        while (decode) {
 461                if (bmap[0] == BMP_RLE8_ESCAPE) {
 462                        switch (bmap[1]) {
 463                        case BMP_RLE8_EOL:
 464                                /* end of line */
 465                                bmap += 2;
 466                                x = 0;
 467                                y--;
 468                                /* 16bpix, 2-byte per pixel, width should *2 */
 469                                fb -= (width * 2 + lcd_line_length);
 470                                break;
 471                        case BMP_RLE8_EOBMP:
 472                                /* end of bitmap */
 473                                decode = 0;
 474                                break;
 475                        case BMP_RLE8_DELTA:
 476                                /* delta run */
 477                                x += bmap[2];
 478                                y -= bmap[3];
 479                                /* 16bpix, 2-byte per pixel, x should *2 */
 480                                fb = (uchar *) (lcd_base + (y + y_off - 1)
 481                                        * lcd_line_length + (x + x_off) * 2);
 482                                bmap += 4;
 483                                break;
 484                        default:
 485                                /* unencoded run */
 486                                runlen = bmap[1];
 487                                bmap += 2;
 488                                if (y < height) {
 489                                        if (x < width) {
 490                                                if (x + runlen > width)
 491                                                        cnt = width - x;
 492                                                else
 493                                                        cnt = runlen;
 494                                                draw_unencoded_bitmap(
 495                                                        (ushort **)&fb,
 496                                                        bmap, cmap, cnt);
 497                                        }
 498                                        x += runlen;
 499                                }
 500                                bmap += runlen;
 501                                if (runlen & 1)
 502                                        bmap++;
 503                        }
 504                } else {
 505                        /* encoded run */
 506                        if (y < height) {
 507                                runlen = bmap[0];
 508                                if (x < width) {
 509                                        /* aggregate the same code */
 510                                        while (bmap[0] == 0xff &&
 511                                               bmap[2] != BMP_RLE8_ESCAPE &&
 512                                               bmap[1] == bmap[3]) {
 513                                                runlen += bmap[2];
 514                                                bmap += 2;
 515                                        }
 516                                        if (x + runlen > width)
 517                                                cnt = width - x;
 518                                        else
 519                                                cnt = runlen;
 520                                        draw_encoded_bitmap((ushort **)&fb,
 521                                                cmap[bmap[1]], cnt);
 522                                }
 523                                x += runlen;
 524                        }
 525                        bmap += 2;
 526                }
 527        }
 528}
 529#endif
 530
 531__weak void fb_put_byte(uchar **fb, uchar **from)
 532{
 533        *(*fb)++ = *(*from)++;
 534}
 535
 536#if defined(CONFIG_BMP_16BPP)
 537__weak void fb_put_word(uchar **fb, uchar **from)
 538{
 539        *(*fb)++ = *(*from)++;
 540        *(*fb)++ = *(*from)++;
 541}
 542#endif /* CONFIG_BMP_16BPP */
 543
 544__weak void lcd_set_cmap(struct bmp_image *bmp, unsigned colors)
 545{
 546        int i;
 547        struct bmp_color_table_entry cte;
 548        ushort *cmap = configuration_get_cmap();
 549
 550        for (i = 0; i < colors; ++i) {
 551                cte = bmp->color_table[i];
 552                *cmap = (((cte.red)   << 8) & 0xf800) |
 553                        (((cte.green) << 3) & 0x07e0) |
 554                        (((cte.blue)  >> 3) & 0x001f);
 555                cmap++;
 556        }
 557}
 558
 559int lcd_display_bitmap(ulong bmp_image, int x, int y)
 560{
 561        ushort *cmap_base = NULL;
 562        ushort i, j;
 563        uchar *fb;
 564        struct bmp_image *bmp = (struct bmp_image *)map_sysmem(bmp_image, 0);
 565        uchar *bmap;
 566        ushort padded_width;
 567        unsigned long width, height, byte_width;
 568        unsigned long pwidth = panel_info.vl_col;
 569        unsigned colors, bpix, bmp_bpix;
 570        int hdr_size;
 571        struct bmp_color_table_entry *palette;
 572
 573        if (!bmp || !(bmp->header.signature[0] == 'B' &&
 574                bmp->header.signature[1] == 'M')) {
 575                printf("Error: no valid bmp image at %lx\n", bmp_image);
 576
 577                return 1;
 578        }
 579
 580        palette = bmp->color_table;
 581        width = get_unaligned_le32(&bmp->header.width);
 582        height = get_unaligned_le32(&bmp->header.height);
 583        bmp_bpix = get_unaligned_le16(&bmp->header.bit_count);
 584        hdr_size = get_unaligned_le16(&bmp->header.size);
 585        debug("hdr_size=%d, bmp_bpix=%d\n", hdr_size, bmp_bpix);
 586
 587        colors = 1 << bmp_bpix;
 588
 589        bpix = NBITS(panel_info.vl_bpix);
 590
 591        if (bpix != 1 && bpix != 8 && bpix != 16 && bpix != 32) {
 592                printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
 593                        bpix, bmp_bpix);
 594
 595                return 1;
 596        }
 597
 598        /*
 599         * We support displaying 8bpp BMPs on 16bpp LCDs
 600         * and displaying 24bpp BMPs on 32bpp LCDs
 601         * */
 602        if (bpix != bmp_bpix &&
 603            !(bmp_bpix == 8 && bpix == 16) &&
 604            !(bmp_bpix == 24 && bpix == 32)) {
 605                printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
 606                        bpix, get_unaligned_le16(&bmp->header.bit_count));
 607                return 1;
 608        }
 609
 610        debug("Display-bmp: %d x %d  with %d colors, display %d\n",
 611              (int)width, (int)height, (int)colors, 1 << bpix);
 612
 613        if (bmp_bpix == 8)
 614                lcd_set_cmap(bmp, colors);
 615
 616        padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width);
 617
 618#ifdef CONFIG_SPLASH_SCREEN_ALIGN
 619        splash_align_axis(&x, pwidth, width);
 620        splash_align_axis(&y, panel_info.vl_row, height);
 621#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
 622
 623        if ((x + width) > pwidth)
 624                width = pwidth - x;
 625        if ((y + height) > panel_info.vl_row)
 626                height = panel_info.vl_row - y;
 627
 628        bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
 629        fb   = (uchar *)(lcd_base +
 630                (y + height - 1) * lcd_line_length + x * bpix / 8);
 631
 632        switch (bmp_bpix) {
 633        case 1:
 634        case 8: {
 635                cmap_base = configuration_get_cmap();
 636#ifdef CONFIG_LCD_BMP_RLE8
 637                u32 compression = get_unaligned_le32(&bmp->header.compression);
 638                debug("compressed %d %d\n", compression, BMP_BI_RLE8);
 639                if (compression == BMP_BI_RLE8) {
 640                        if (bpix != 16) {
 641                                /* TODO implement render code for bpix != 16 */
 642                                printf("Error: only support 16 bpix");
 643                                return 1;
 644                        }
 645                        lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y);
 646                        break;
 647                }
 648#endif
 649
 650                if (bpix != 16)
 651                        byte_width = width;
 652                else
 653                        byte_width = width * 2;
 654
 655                for (i = 0; i < height; ++i) {
 656                        WATCHDOG_RESET();
 657                        for (j = 0; j < width; j++) {
 658                                if (bpix != 16) {
 659                                        fb_put_byte(&fb, &bmap);
 660                                } else {
 661                                        struct bmp_color_table_entry *entry;
 662                                        uint val;
 663
 664                                        if (cmap_base) {
 665                                                val = cmap_base[*bmap];
 666                                        } else {
 667                                                entry = &palette[*bmap];
 668                                                val = entry->blue >> 3 |
 669                                                        entry->green >> 2 << 5 |
 670                                                        entry->red >> 3 << 11;
 671                                        }
 672                                        *(uint16_t *)fb = val;
 673                                        bmap++;
 674                                        fb += sizeof(uint16_t) / sizeof(*fb);
 675                                }
 676                        }
 677                        bmap += (padded_width - width);
 678                        fb -= byte_width + lcd_line_length;
 679                }
 680                break;
 681        }
 682#if defined(CONFIG_BMP_16BPP)
 683        case 16:
 684                for (i = 0; i < height; ++i) {
 685                        WATCHDOG_RESET();
 686                        for (j = 0; j < width; j++)
 687                                fb_put_word(&fb, &bmap);
 688
 689                        bmap += (padded_width - width) * 2;
 690                        fb -= width * 2 + lcd_line_length;
 691                }
 692                break;
 693#endif /* CONFIG_BMP_16BPP */
 694#if defined(CONFIG_BMP_24BPP)
 695        case 24:
 696                for (i = 0; i < height; ++i) {
 697                        for (j = 0; j < width; j++) {
 698                                *(fb++) = *(bmap++);
 699                                *(fb++) = *(bmap++);
 700                                *(fb++) = *(bmap++);
 701                                *(fb++) = 0;
 702                        }
 703                        fb -= lcd_line_length + width * (bpix / 8);
 704                }
 705                break;
 706#endif /* CONFIG_BMP_24BPP */
 707#if defined(CONFIG_BMP_32BPP)
 708        case 32:
 709                for (i = 0; i < height; ++i) {
 710                        for (j = 0; j < width; j++) {
 711                                *(fb++) = *(bmap++);
 712                                *(fb++) = *(bmap++);
 713                                *(fb++) = *(bmap++);
 714                                *(fb++) = *(bmap++);
 715                        }
 716                        fb -= lcd_line_length + width * (bpix / 8);
 717                }
 718                break;
 719#endif /* CONFIG_BMP_32BPP */
 720        default:
 721                break;
 722        };
 723
 724        lcd_sync();
 725        return 0;
 726}
 727#endif
 728
 729static void lcd_logo(void)
 730{
 731        lcd_logo_plot(0, 0);
 732
 733#ifdef CONFIG_LCD_INFO
 734        lcd_set_col(LCD_INFO_X / VIDEO_FONT_WIDTH);
 735        lcd_set_row(LCD_INFO_Y / VIDEO_FONT_HEIGHT);
 736        lcd_show_board_info();
 737#endif /* CONFIG_LCD_INFO */
 738}
 739
 740#ifdef CONFIG_SPLASHIMAGE_GUARD
 741static int on_splashimage(const char *name, const char *value, enum env_op op,
 742        int flags)
 743{
 744        ulong addr;
 745        int aligned;
 746
 747        if (op == env_op_delete)
 748                return 0;
 749
 750        addr = hextoul(value, NULL);
 751        /* See README.displaying-bmps */
 752        aligned = (addr % 4 == 2);
 753        if (!aligned) {
 754                printf("Invalid splashimage value. Value must be 16 bit aligned, but not 32 bit aligned\n");
 755                return -1;
 756        }
 757
 758        return 0;
 759}
 760
 761U_BOOT_ENV_CALLBACK(splashimage, on_splashimage);
 762#endif
 763
 764int lcd_get_pixel_width(void)
 765{
 766        return panel_info.vl_col;
 767}
 768
 769int lcd_get_pixel_height(void)
 770{
 771        return panel_info.vl_row;
 772}
 773