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 #if LCD_BPP == LCD_COLOR8 173 /* Setting the palette */ 174 lcd_setcolreg(CONSOLE_COLOR_BLACK, 0, 0, 0); 175 lcd_setcolreg(CONSOLE_COLOR_RED, 0xFF, 0, 0); 176 lcd_setcolreg(CONSOLE_COLOR_GREEN, 0, 0xFF, 0); 177 lcd_setcolreg(CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0); 178 lcd_setcolreg(CONSOLE_COLOR_BLUE, 0, 0, 0xFF); 179 lcd_setcolreg(CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF); 180 lcd_setcolreg(CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF); 181 lcd_setcolreg(CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA); 182 lcd_setcolreg(CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF); 183 #endif 184 185 #ifndef CONFIG_SYS_WHITE_ON_BLACK 186 lcd_setfgcolor(CONSOLE_COLOR_BLACK); 187 lcd_setbgcolor(CONSOLE_COLOR_WHITE); 188 bg_color = CONSOLE_COLOR_WHITE; 189 #else 190 lcd_setfgcolor(CONSOLE_COLOR_WHITE); 191 lcd_setbgcolor(CONSOLE_COLOR_BLACK); 192 bg_color = CONSOLE_COLOR_BLACK; 193 #endif /* CONFIG_SYS_WHITE_ON_BLACK */ 194 195 #ifdef LCD_TEST_PATTERN 196 test_pattern(); 197 #else 198 /* set framebuffer to background color */ 199 #if (LCD_BPP != LCD_COLOR32) 200 memset((char *)lcd_base, bg_color, lcd_line_length * panel_info.vl_row); 201 #else 202 u32 *ppix = lcd_base; 203 u32 i; 204 for (i = 0; 205 i < (lcd_line_length * panel_info.vl_row)/NBYTES(panel_info.vl_bpix); 206 i++) { 207 *ppix++ = bg_color; 208 } 209 #endif 210 #endif 211 /* Paint the logo and retrieve LCD base address */ 212 debug("[LCD] Drawing the logo...\n"); 213 #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO) 214 console_rows = (panel_info.vl_row - BMP_LOGO_HEIGHT); 215 console_rows /= VIDEO_FONT_HEIGHT; 216 #else 217 console_rows = panel_info.vl_row / VIDEO_FONT_HEIGHT; 218 #endif 219 console_cols = panel_info.vl_col / VIDEO_FONT_WIDTH; 220 lcd_init_console(lcd_base, console_rows, console_cols); 221 lcd_init_console(lcd_logo(), console_rows, console_cols); 222 lcd_sync(); 223 } 224 225 static int do_lcd_clear(cmd_tbl_t *cmdtp, int flag, int argc, 226 char *const argv[]) 227 { 228 lcd_clear(); 229 return 0; 230 } 231 U_BOOT_CMD(cls, 1, 1, do_lcd_clear, "clear screen", ""); 232 233 static int lcd_init(void *lcdbase) 234 { 235 debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase); 236 lcd_ctrl_init(lcdbase); 237 238 /* 239 * lcd_ctrl_init() of some drivers (i.e. bcm2835 on rpi) ignores 240 * the 'lcdbase' argument and uses custom lcd base address 241 * by setting up gd->fb_base. Check for this condition and fixup 242 * 'lcd_base' address. 243 */ 244 if (map_to_sysmem(lcdbase) != gd->fb_base) 245 lcd_base = map_sysmem(gd->fb_base, 0); 246 247 debug("[LCD] Using LCD frambuffer at %p\n", lcd_base); 248 249 lcd_get_size(&lcd_line_length); 250 lcd_is_enabled = 1; 251 lcd_clear(); 252 lcd_enable(); 253 254 /* Initialize the console */ 255 lcd_set_col(0); 256 #ifdef CONFIG_LCD_INFO_BELOW_LOGO 257 lcd_set_row(7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT); 258 #else 259 lcd_set_row(1); /* leave 1 blank line below logo */ 260 #endif 261 262 return 0; 263 } 264 265 /* 266 * This is called early in the system initialization to grab memory 267 * for the LCD controller. 268 * Returns new address for monitor, after reserving LCD buffer memory 269 * 270 * Note that this is running from ROM, so no write access to global data. 271 */ 272 ulong lcd_setmem(ulong addr) 273 { 274 ulong size; 275 int line_length; 276 277 debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col, 278 panel_info.vl_row, NBITS(panel_info.vl_bpix)); 279 280 size = lcd_get_size(&line_length); 281 282 /* Round up to nearest full page, or MMU section if defined */ 283 size = ALIGN(size, CONFIG_LCD_ALIGNMENT); 284 addr = ALIGN(addr - CONFIG_LCD_ALIGNMENT + 1, CONFIG_LCD_ALIGNMENT); 285 286 /* Allocate pages for the frame buffer. */ 287 addr -= size; 288 289 debug("Reserving %ldk for LCD Framebuffer at: %08lx\n", 290 size >> 10, addr); 291 292 return addr; 293 } 294 295 static void lcd_setfgcolor(int color) 296 { 297 lcd_color_fg = color; 298 } 299 300 int lcd_getfgcolor(void) 301 { 302 return lcd_color_fg; 303 } 304 305 static void lcd_setbgcolor(int color) 306 { 307 lcd_color_bg = color; 308 } 309 310 int lcd_getbgcolor(void) 311 { 312 return lcd_color_bg; 313 } 314 315 #ifdef CONFIG_LCD_LOGO 316 __weak void lcd_logo_set_cmap(void) 317 { 318 int i; 319 ushort *cmap = configuration_get_cmap(); 320 321 for (i = 0; i < ARRAY_SIZE(bmp_logo_palette); ++i) 322 *cmap++ = bmp_logo_palette[i]; 323 } 324 325 void lcd_logo_plot(int x, int y) 326 { 327 ushort i, j; 328 uchar *bmap = &bmp_logo_bitmap[0]; 329 unsigned bpix = NBITS(panel_info.vl_bpix); 330 uchar *fb = (uchar *)(lcd_base + y * lcd_line_length + x * bpix / 8); 331 ushort *fb16; 332 333 debug("Logo: width %d height %d colors %d\n", 334 BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS); 335 336 if (bpix < 12) { 337 WATCHDOG_RESET(); 338 lcd_logo_set_cmap(); 339 WATCHDOG_RESET(); 340 341 for (i = 0; i < BMP_LOGO_HEIGHT; ++i) { 342 memcpy(fb, bmap, BMP_LOGO_WIDTH); 343 bmap += BMP_LOGO_WIDTH; 344 fb += panel_info.vl_col; 345 } 346 } 347 else { /* true color mode */ 348 u16 col16; 349 fb16 = (ushort *)fb; 350 for (i = 0; i < BMP_LOGO_HEIGHT; ++i) { 351 for (j = 0; j < BMP_LOGO_WIDTH; j++) { 352 col16 = bmp_logo_palette[(bmap[j]-16)]; 353 fb16[j] = 354 ((col16 & 0x000F) << 1) | 355 ((col16 & 0x00F0) << 3) | 356 ((col16 & 0x0F00) << 4); 357 } 358 bmap += BMP_LOGO_WIDTH; 359 fb16 += panel_info.vl_col; 360 } 361 } 362 363 WATCHDOG_RESET(); 364 lcd_sync(); 365 } 366 #else 367 static inline void lcd_logo_plot(int x, int y) {} 368 #endif /* CONFIG_LCD_LOGO */ 369 370 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) 371 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 372 #define BMP_ALIGN_CENTER 0x7FFF 373 374 static void splash_align_axis(int *axis, unsigned long panel_size, 375 unsigned long picture_size) 376 { 377 unsigned long panel_picture_delta = panel_size - picture_size; 378 unsigned long axis_alignment; 379 380 if (*axis == BMP_ALIGN_CENTER) 381 axis_alignment = panel_picture_delta / 2; 382 else if (*axis < 0) 383 axis_alignment = panel_picture_delta + *axis + 1; 384 else 385 return; 386 387 *axis = max(0, (int)axis_alignment); 388 } 389 #endif 390 391 #ifdef CONFIG_LCD_BMP_RLE8 392 #define BMP_RLE8_ESCAPE 0 393 #define BMP_RLE8_EOL 0 394 #define BMP_RLE8_EOBMP 1 395 #define BMP_RLE8_DELTA 2 396 397 static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap, 398 int cnt) 399 { 400 while (cnt > 0) { 401 *(*fbp)++ = cmap[*bmap++]; 402 cnt--; 403 } 404 } 405 406 static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt) 407 { 408 ushort *fb = *fbp; 409 int cnt_8copy = cnt >> 3; 410 411 cnt -= cnt_8copy << 3; 412 while (cnt_8copy > 0) { 413 *fb++ = c; 414 *fb++ = c; 415 *fb++ = c; 416 *fb++ = c; 417 *fb++ = c; 418 *fb++ = c; 419 *fb++ = c; 420 *fb++ = c; 421 cnt_8copy--; 422 } 423 while (cnt > 0) { 424 *fb++ = c; 425 cnt--; 426 } 427 *fbp = fb; 428 } 429 430 /* 431 * Do not call this function directly, must be called from lcd_display_bitmap. 432 */ 433 static void lcd_display_rle8_bitmap(bmp_image_t *bmp, ushort *cmap, uchar *fb, 434 int x_off, int y_off) 435 { 436 uchar *bmap; 437 ulong width, height; 438 ulong cnt, runlen; 439 int x, y; 440 int decode = 1; 441 442 width = get_unaligned_le32(&bmp->header.width); 443 height = get_unaligned_le32(&bmp->header.height); 444 bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset); 445 446 x = 0; 447 y = height - 1; 448 449 while (decode) { 450 if (bmap[0] == BMP_RLE8_ESCAPE) { 451 switch (bmap[1]) { 452 case BMP_RLE8_EOL: 453 /* end of line */ 454 bmap += 2; 455 x = 0; 456 y--; 457 /* 16bpix, 2-byte per pixel, width should *2 */ 458 fb -= (width * 2 + lcd_line_length); 459 break; 460 case BMP_RLE8_EOBMP: 461 /* end of bitmap */ 462 decode = 0; 463 break; 464 case BMP_RLE8_DELTA: 465 /* delta run */ 466 x += bmap[2]; 467 y -= bmap[3]; 468 /* 16bpix, 2-byte per pixel, x should *2 */ 469 fb = (uchar *) (lcd_base + (y + y_off - 1) 470 * lcd_line_length + (x + x_off) * 2); 471 bmap += 4; 472 break; 473 default: 474 /* unencoded run */ 475 runlen = bmap[1]; 476 bmap += 2; 477 if (y < height) { 478 if (x < width) { 479 if (x + runlen > width) 480 cnt = width - x; 481 else 482 cnt = runlen; 483 draw_unencoded_bitmap( 484 (ushort **)&fb, 485 bmap, cmap, cnt); 486 } 487 x += runlen; 488 } 489 bmap += runlen; 490 if (runlen & 1) 491 bmap++; 492 } 493 } else { 494 /* encoded run */ 495 if (y < height) { 496 runlen = bmap[0]; 497 if (x < width) { 498 /* aggregate the same code */ 499 while (bmap[0] == 0xff && 500 bmap[2] != BMP_RLE8_ESCAPE && 501 bmap[1] == bmap[3]) { 502 runlen += bmap[2]; 503 bmap += 2; 504 } 505 if (x + runlen > width) 506 cnt = width - x; 507 else 508 cnt = runlen; 509 draw_encoded_bitmap((ushort **)&fb, 510 cmap[bmap[1]], cnt); 511 } 512 x += runlen; 513 } 514 bmap += 2; 515 } 516 } 517 } 518 #endif 519 520 __weak void fb_put_byte(uchar **fb, uchar **from) 521 { 522 *(*fb)++ = *(*from)++; 523 } 524 525 #if defined(CONFIG_BMP_16BPP) 526 __weak void fb_put_word(uchar **fb, uchar **from) 527 { 528 *(*fb)++ = *(*from)++; 529 *(*fb)++ = *(*from)++; 530 } 531 #endif /* CONFIG_BMP_16BPP */ 532 533 __weak void lcd_set_cmap(bmp_image_t *bmp, unsigned colors) 534 { 535 int i; 536 bmp_color_table_entry_t cte; 537 ushort *cmap = configuration_get_cmap(); 538 539 for (i = 0; i < colors; ++i) { 540 cte = bmp->color_table[i]; 541 *cmap = (((cte.red) << 8) & 0xf800) | 542 (((cte.green) << 3) & 0x07e0) | 543 (((cte.blue) >> 3) & 0x001f); 544 #if defined(CONFIG_MPC823) 545 cmap--; 546 #else 547 cmap++; 548 #endif 549 } 550 } 551 552 int lcd_display_bitmap(ulong bmp_image, int x, int y) 553 { 554 ushort *cmap_base = NULL; 555 ushort i, j; 556 uchar *fb; 557 bmp_image_t *bmp = (bmp_image_t *)map_sysmem(bmp_image, 0); 558 uchar *bmap; 559 ushort padded_width; 560 unsigned long width, height, byte_width; 561 unsigned long pwidth = panel_info.vl_col; 562 unsigned colors, bpix, bmp_bpix; 563 564 if (!bmp || !(bmp->header.signature[0] == 'B' && 565 bmp->header.signature[1] == 'M')) { 566 printf("Error: no valid bmp image at %lx\n", bmp_image); 567 568 return 1; 569 } 570 571 width = get_unaligned_le32(&bmp->header.width); 572 height = get_unaligned_le32(&bmp->header.height); 573 bmp_bpix = get_unaligned_le16(&bmp->header.bit_count); 574 575 colors = 1 << bmp_bpix; 576 577 bpix = NBITS(panel_info.vl_bpix); 578 579 if (bpix != 1 && bpix != 8 && bpix != 16 && bpix != 32) { 580 printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n", 581 bpix, bmp_bpix); 582 583 return 1; 584 } 585 586 /* 587 * We support displaying 8bpp BMPs on 16bpp LCDs 588 * and displaying 24bpp BMPs on 32bpp LCDs 589 * */ 590 if (bpix != bmp_bpix && 591 !(bmp_bpix == 8 && bpix == 16) && 592 !(bmp_bpix == 24 && bpix == 32)) { 593 printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n", 594 bpix, get_unaligned_le16(&bmp->header.bit_count)); 595 return 1; 596 } 597 598 debug("Display-bmp: %d x %d with %d colors\n", 599 (int)width, (int)height, (int)colors); 600 601 if (bmp_bpix == 8) 602 lcd_set_cmap(bmp, colors); 603 604 padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width); 605 606 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 607 splash_align_axis(&x, pwidth, width); 608 splash_align_axis(&y, panel_info.vl_row, height); 609 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ 610 611 if ((x + width) > pwidth) 612 width = pwidth - x; 613 if ((y + height) > panel_info.vl_row) 614 height = panel_info.vl_row - y; 615 616 bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset); 617 fb = (uchar *)(lcd_base + 618 (y + height - 1) * lcd_line_length + x * bpix / 8); 619 620 switch (bmp_bpix) { 621 case 1: 622 case 8: { 623 cmap_base = configuration_get_cmap(); 624 #ifdef CONFIG_LCD_BMP_RLE8 625 u32 compression = get_unaligned_le32(&bmp->header.compression); 626 if (compression == BMP_BI_RLE8) { 627 if (bpix != 16) { 628 /* TODO implement render code for bpix != 16 */ 629 printf("Error: only support 16 bpix"); 630 return 1; 631 } 632 lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y); 633 break; 634 } 635 #endif 636 637 if (bpix != 16) 638 byte_width = width; 639 else 640 byte_width = width * 2; 641 642 for (i = 0; i < height; ++i) { 643 WATCHDOG_RESET(); 644 for (j = 0; j < width; j++) { 645 if (bpix != 16) { 646 fb_put_byte(&fb, &bmap); 647 } else { 648 *(uint16_t *)fb = cmap_base[*(bmap++)]; 649 fb += sizeof(uint16_t) / sizeof(*fb); 650 } 651 } 652 bmap += (padded_width - width); 653 fb -= byte_width + lcd_line_length; 654 } 655 break; 656 } 657 #if defined(CONFIG_BMP_16BPP) 658 case 16: 659 for (i = 0; i < height; ++i) { 660 WATCHDOG_RESET(); 661 for (j = 0; j < width; j++) 662 fb_put_word(&fb, &bmap); 663 664 bmap += (padded_width - width) * 2; 665 fb -= width * 2 + lcd_line_length; 666 } 667 break; 668 #endif /* CONFIG_BMP_16BPP */ 669 #if defined(CONFIG_BMP_24BMP) 670 case 24: 671 for (i = 0; i < height; ++i) { 672 for (j = 0; j < width; j++) { 673 *(fb++) = *(bmap++); 674 *(fb++) = *(bmap++); 675 *(fb++) = *(bmap++); 676 *(fb++) = 0; 677 } 678 fb -= lcd_line_length + width * (bpix / 8); 679 } 680 break; 681 #endif /* CONFIG_BMP_24BMP */ 682 #if defined(CONFIG_BMP_32BPP) 683 case 32: 684 for (i = 0; i < height; ++i) { 685 for (j = 0; j < width; j++) { 686 *(fb++) = *(bmap++); 687 *(fb++) = *(bmap++); 688 *(fb++) = *(bmap++); 689 *(fb++) = *(bmap++); 690 } 691 fb -= lcd_line_length + width * (bpix / 8); 692 } 693 break; 694 #endif /* CONFIG_BMP_32BPP */ 695 default: 696 break; 697 }; 698 699 lcd_sync(); 700 return 0; 701 } 702 #endif 703 704 static void *lcd_logo(void) 705 { 706 #ifdef CONFIG_SPLASH_SCREEN 707 char *s; 708 ulong addr; 709 static int do_splash = 1; 710 711 if (do_splash && (s = getenv("splashimage")) != NULL) { 712 int x = 0, y = 0; 713 do_splash = 0; 714 715 if (splash_screen_prepare()) 716 return (void *)lcd_base; 717 718 addr = simple_strtoul (s, NULL, 16); 719 720 splash_get_pos(&x, &y); 721 722 if (bmp_display(addr, x, y) == 0) 723 return (void *)lcd_base; 724 } 725 #endif /* CONFIG_SPLASH_SCREEN */ 726 727 lcd_logo_plot(0, 0); 728 729 #ifdef CONFIG_LCD_INFO 730 lcd_set_col(LCD_INFO_X / VIDEO_FONT_WIDTH); 731 lcd_set_row(LCD_INFO_Y / VIDEO_FONT_HEIGHT); 732 lcd_show_board_info(); 733 #endif /* CONFIG_LCD_INFO */ 734 735 #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO) 736 return (void *)((ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length); 737 #else 738 return (void *)lcd_base; 739 #endif /* CONFIG_LCD_LOGO && !defined(CONFIG_LCD_INFO_BELOW_LOGO) */ 740 } 741 742 #ifdef CONFIG_SPLASHIMAGE_GUARD 743 static int on_splashimage(const char *name, const char *value, enum env_op op, 744 int flags) 745 { 746 ulong addr; 747 int aligned; 748 749 if (op == env_op_delete) 750 return 0; 751 752 addr = simple_strtoul(value, NULL, 16); 753 /* See README.displaying-bmps */ 754 aligned = (addr % 4 == 2); 755 if (!aligned) { 756 printf("Invalid splashimage value. Value must be 16 bit aligned, but not 32 bit aligned\n"); 757 return -1; 758 } 759 760 return 0; 761 } 762 763 U_BOOT_ENV_CALLBACK(splashimage, on_splashimage); 764 #endif 765 766 int lcd_get_pixel_width(void) 767 { 768 return panel_info.vl_col; 769 } 770 771 int lcd_get_pixel_height(void) 772 { 773 return panel_info.vl_row; 774 } 775