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 <env_callback.h> 14 #include <linux/types.h> 15 #include <stdio_dev.h> 16 #include <lcd.h> 17 #include <mapmem.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 #ifndef CONFIG_LCD_ALIGNMENT 34 #define CONFIG_LCD_ALIGNMENT PAGE_SIZE 35 #endif 36 37 #if (LCD_BPP != LCD_COLOR8) && (LCD_BPP != LCD_COLOR16) && \ 38 (LCD_BPP != LCD_COLOR32) 39 #error Unsupported LCD BPP. 40 #endif 41 42 DECLARE_GLOBAL_DATA_PTR; 43 44 static int lcd_init(void *lcdbase); 45 static void lcd_logo(void); 46 static void lcd_setfgcolor(int color); 47 static void lcd_setbgcolor(int color); 48 49 static int lcd_color_fg; 50 static int lcd_color_bg; 51 int lcd_line_length; 52 char lcd_is_enabled = 0; 53 static void *lcd_base; /* Start of framebuffer memory */ 54 static char lcd_flush_dcache; /* 1 to flush dcache after each lcd update */ 55 56 /* Flush LCD activity to the caches */ 57 void lcd_sync(void) 58 { 59 /* 60 * flush_dcache_range() is declared in common.h but it seems that some 61 * architectures do not actually implement it. Is there a way to find 62 * out whether it exists? For now, ARM is safe. 63 */ 64 #if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF) 65 int line_length; 66 67 if (lcd_flush_dcache) 68 flush_dcache_range((ulong)lcd_base, 69 (ulong)(lcd_base + lcd_get_size(&line_length))); 70 #endif 71 } 72 73 void lcd_set_flush_dcache(int flush) 74 { 75 lcd_flush_dcache = (flush != 0); 76 } 77 78 static void lcd_stub_putc(struct stdio_dev *dev, const char c) 79 { 80 lcd_putc(c); 81 } 82 83 static void lcd_stub_puts(struct stdio_dev *dev, const char *s) 84 { 85 lcd_puts(s); 86 } 87 88 /* Small utility to check that you got the colours right */ 89 #ifdef LCD_TEST_PATTERN 90 91 #if LCD_BPP == LCD_COLOR8 92 #define N_BLK_VERT 2 93 #define N_BLK_HOR 3 94 95 static int test_colors[N_BLK_HOR * N_BLK_VERT] = { 96 CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW, 97 CONSOLE_COLOR_BLUE, CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN, 98 }; /*LCD_BPP == LCD_COLOR8 */ 99 100 #elif LCD_BPP == LCD_COLOR16 101 #define N_BLK_VERT 2 102 #define N_BLK_HOR 4 103 104 static int test_colors[N_BLK_HOR * N_BLK_VERT] = { 105 CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW, CONSOLE_COLOR_BLUE, 106 CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN, CONSOLE_COLOR_GREY, CONSOLE_COLOR_WHITE, 107 }; 108 #endif /*LCD_BPP == LCD_COLOR16 */ 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 #if LCD_BPP == LCD_COLOR8 118 uchar *pix = (uchar *)lcd_base; 119 #elif LCD_BPP == LCD_COLOR16 120 ushort *pix = (ushort *)lcd_base; 121 #endif 122 123 printf("[LCD] Test Pattern: %d x %d [%d x %d]\n", 124 h_max, v_max, h_step, v_step); 125 126 for (v = 0; v < v_max; ++v) { 127 uchar iy = v / v_step; 128 for (h = 0; h < h_max; ++h) { 129 uchar ix = N_BLK_HOR * iy + h / h_step; 130 *pix++ = test_colors[ix]; 131 } 132 } 133 } 134 #endif /* LCD_TEST_PATTERN */ 135 136 /* 137 * With most lcd drivers the line length is set up 138 * by calculating it from panel_info parameters. Some 139 * drivers need to calculate the line length differently, 140 * so make the function weak to allow overriding it. 141 */ 142 __weak int lcd_get_size(int *line_length) 143 { 144 *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8; 145 return *line_length * panel_info.vl_row; 146 } 147 148 int drv_lcd_init(void) 149 { 150 struct stdio_dev lcddev; 151 int rc; 152 153 lcd_base = map_sysmem(gd->fb_base, 0); 154 155 lcd_init(lcd_base); 156 157 /* Device initialization */ 158 memset(&lcddev, 0, sizeof(lcddev)); 159 160 strcpy(lcddev.name, "lcd"); 161 lcddev.ext = 0; /* No extensions */ 162 lcddev.flags = DEV_FLAGS_OUTPUT; /* Output only */ 163 lcddev.putc = lcd_stub_putc; /* 'putc' function */ 164 lcddev.puts = lcd_stub_puts; /* 'puts' function */ 165 166 rc = stdio_register(&lcddev); 167 168 return (rc == 0) ? 1 : rc; 169 } 170 171 void lcd_clear(void) 172 { 173 int bg_color; 174 char *s; 175 ulong addr; 176 static int do_splash = 1; 177 #if LCD_BPP == LCD_COLOR8 178 /* Setting the palette */ 179 lcd_setcolreg(CONSOLE_COLOR_BLACK, 0, 0, 0); 180 lcd_setcolreg(CONSOLE_COLOR_RED, 0xFF, 0, 0); 181 lcd_setcolreg(CONSOLE_COLOR_GREEN, 0, 0xFF, 0); 182 lcd_setcolreg(CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0); 183 lcd_setcolreg(CONSOLE_COLOR_BLUE, 0, 0, 0xFF); 184 lcd_setcolreg(CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF); 185 lcd_setcolreg(CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF); 186 lcd_setcolreg(CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA); 187 lcd_setcolreg(CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF); 188 #endif 189 190 #ifndef CONFIG_SYS_WHITE_ON_BLACK 191 lcd_setfgcolor(CONSOLE_COLOR_BLACK); 192 lcd_setbgcolor(CONSOLE_COLOR_WHITE); 193 bg_color = CONSOLE_COLOR_WHITE; 194 #else 195 lcd_setfgcolor(CONSOLE_COLOR_WHITE); 196 lcd_setbgcolor(CONSOLE_COLOR_BLACK); 197 bg_color = CONSOLE_COLOR_BLACK; 198 #endif /* CONFIG_SYS_WHITE_ON_BLACK */ 199 200 #ifdef LCD_TEST_PATTERN 201 test_pattern(); 202 #else 203 /* set framebuffer to background color */ 204 #if (LCD_BPP != LCD_COLOR32) 205 memset((char *)lcd_base, bg_color, lcd_line_length * panel_info.vl_row); 206 #else 207 u32 *ppix = lcd_base; 208 u32 i; 209 for (i = 0; 210 i < (lcd_line_length * panel_info.vl_row)/NBYTES(panel_info.vl_bpix); 211 i++) { 212 *ppix++ = bg_color; 213 } 214 #endif 215 #endif 216 /* setup text-console */ 217 debug("[LCD] setting up console...\n"); 218 lcd_init_console(lcd_base, 219 panel_info.vl_col, 220 panel_info.vl_row, 221 panel_info.vl_rot); 222 /* Paint the logo and retrieve LCD base address */ 223 debug("[LCD] Drawing the logo...\n"); 224 if (do_splash) { 225 s = env_get("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, panel_info.vl_col, 240 panel_info.vl_row, panel_info.vl_rot); 241 #endif 242 lcd_sync(); 243 } 244 245 static 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 */ 284 ulong 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 307 static void lcd_setfgcolor(int color) 308 { 309 lcd_color_fg = color; 310 } 311 312 int lcd_getfgcolor(void) 313 { 314 return lcd_color_fg; 315 } 316 317 static void lcd_setbgcolor(int color) 318 { 319 lcd_color_bg = color; 320 } 321 322 int 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 337 void 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 379 static 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 385 static 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 408 static 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 417 static 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 */ 444 static 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 559 int 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 729 static 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 741 static 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 = simple_strtoul(value, NULL, 16); 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 761 U_BOOT_ENV_CALLBACK(splashimage, on_splashimage); 762 #endif 763 764 int lcd_get_pixel_width(void) 765 { 766 return panel_info.vl_col; 767 } 768 769 int lcd_get_pixel_height(void) 770 { 771 return panel_info.vl_row; 772 } 773