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