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