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