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