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