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