1 /* 2 * (C) Copyright 2002 ELTEC Elektronik AG 3 * Frank Gottschling <fgottschling@eltec.de> 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 /* 25 * cfb_console.c 26 * 27 * Color Framebuffer Console driver for 8/15/16/24/32 bits per pixel. 28 * 29 * At the moment only the 8x16 font is tested and the font fore- and 30 * background color is limited to black/white/gray colors. The Linux 31 * logo can be placed in the upper left corner and additional board 32 * information strings (that normally goes to serial port) can be drawn. 33 * 34 * The console driver can use the standard PC keyboard interface (i8042) 35 * for character input. Character output goes to a memory mapped video 36 * framebuffer with little or big-endian organisation. 37 * With environment setting 'console=serial' the console i/o can be 38 * forced to serial port. 39 * 40 * The driver uses graphic specific defines/parameters/functions: 41 * 42 * (for SMI LynxE graphic chip) 43 * 44 * CONFIG_VIDEO_SMI_LYNXEM - use graphic driver for SMI 710,712,810 45 * VIDEO_FB_LITTLE_ENDIAN - framebuffer organisation default: big endian 46 * VIDEO_HW_RECTFILL - graphic driver supports hardware rectangle fill 47 * VIDEO_HW_BITBLT - graphic driver supports hardware bit blt 48 * 49 * Console Parameters are set by graphic drivers global struct: 50 * 51 * VIDEO_VISIBLE_COLS - x resolution 52 * VIDEO_VISIBLE_ROWS - y resolution 53 * VIDEO_PIXEL_SIZE - storage size in byte per pixel 54 * VIDEO_DATA_FORMAT - graphical data format GDF 55 * VIDEO_FB_ADRS - start of video memory 56 * 57 * CONFIG_I8042_KBD - AT Keyboard driver for i8042 58 * VIDEO_KBD_INIT_FCT - init function for keyboard 59 * VIDEO_TSTC_FCT - keyboard_tstc function 60 * VIDEO_GETC_FCT - keyboard_getc function 61 * 62 * CONFIG_CONSOLE_CURSOR - on/off drawing cursor is done with 63 * delay loop in VIDEO_TSTC_FCT (i8042) 64 * 65 * CONFIG_SYS_CONSOLE_BLINK_COUNT - value for delay loop - blink rate 66 * CONFIG_CONSOLE_TIME - display time/date in upper right 67 * corner, needs CONFIG_CMD_DATE and 68 * CONFIG_CONSOLE_CURSOR 69 * CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner 70 * CONFIG_VIDEO_BMP_LOGO - use bmp_logo instead of linux_logo 71 * CONFIG_CONSOLE_EXTRA_INFO - display additional board information 72 * strings that normaly goes to serial 73 * port. This define requires a board 74 * specific function: 75 * video_drawstring (VIDEO_INFO_X, 76 * VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT, 77 * info); 78 * that fills a info buffer at i=row. 79 * s.a: board/eltec/bab7xx. 80 * CONFIG_VGA_AS_SINGLE_DEVICE - If set the framebuffer device will be 81 * initialized as an output only device. 82 * The Keyboard driver will not be 83 * set-up. This may be used, if you have 84 * no or more than one Keyboard devices 85 * (USB Keyboard, AT Keyboard). 86 * 87 * CONFIG_VIDEO_SW_CURSOR: - Draws a cursor after the last 88 * character. No blinking is provided. 89 * Uses the macros CURSOR_SET and 90 * CURSOR_OFF. 91 * 92 * CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability 93 * of the graphic chip. Uses the macro 94 * CURSOR_SET. ATTENTION: If booting an 95 * OS, the display driver must disable 96 * the hardware register of the graphic 97 * chip. Otherwise a blinking field is 98 * displayed. 99 */ 100 101 #include <common.h> 102 #include <version.h> 103 #include <malloc.h> 104 105 /* 106 * Console device defines with SMI graphic 107 * Any other graphic must change this section 108 */ 109 110 #ifdef CONFIG_VIDEO_SMI_LYNXEM 111 112 #define VIDEO_FB_LITTLE_ENDIAN 113 #define VIDEO_HW_RECTFILL 114 #define VIDEO_HW_BITBLT 115 #endif 116 117 /* 118 * Defines for the CT69000 driver 119 */ 120 #ifdef CONFIG_VIDEO_CT69000 121 122 #define VIDEO_FB_LITTLE_ENDIAN 123 #define VIDEO_HW_RECTFILL 124 #define VIDEO_HW_BITBLT 125 #endif 126 127 /* 128 * Defines for the SED13806 driver 129 */ 130 #ifdef CONFIG_VIDEO_SED13806 131 132 #ifndef CONFIG_TOTAL5200 133 #define VIDEO_FB_LITTLE_ENDIAN 134 #endif 135 #define VIDEO_HW_RECTFILL 136 #define VIDEO_HW_BITBLT 137 #endif 138 139 /* 140 * Defines for the SED13806 driver 141 */ 142 #ifdef CONFIG_VIDEO_SM501 143 144 #ifdef CONFIG_HH405 145 #define VIDEO_FB_LITTLE_ENDIAN 146 #endif 147 #endif 148 149 /* 150 * Defines for the MB862xx driver 151 */ 152 #ifdef CONFIG_VIDEO_MB862xx 153 154 #ifdef CONFIG_VIDEO_CORALP 155 #define VIDEO_FB_LITTLE_ENDIAN 156 #endif 157 #ifdef CONFIG_VIDEO_MB862xx_ACCEL 158 #define VIDEO_HW_RECTFILL 159 #define VIDEO_HW_BITBLT 160 #endif 161 #endif 162 163 /* 164 * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc. 165 */ 166 #include <video_fb.h> 167 168 /* 169 * some Macros 170 */ 171 #define VIDEO_VISIBLE_COLS (pGD->winSizeX) 172 #define VIDEO_VISIBLE_ROWS (pGD->winSizeY) 173 #define VIDEO_PIXEL_SIZE (pGD->gdfBytesPP) 174 #define VIDEO_DATA_FORMAT (pGD->gdfIndex) 175 #define VIDEO_FB_ADRS (pGD->frameAdrs) 176 177 /* 178 * Console device defines with i8042 keyboard controller 179 * Any other keyboard controller must change this section 180 */ 181 182 #ifdef CONFIG_I8042_KBD 183 #include <i8042.h> 184 185 #define VIDEO_KBD_INIT_FCT i8042_kbd_init() 186 #define VIDEO_TSTC_FCT i8042_tstc 187 #define VIDEO_GETC_FCT i8042_getc 188 #endif 189 190 /* 191 * Console device 192 */ 193 194 #include <version.h> 195 #include <linux/types.h> 196 #include <stdio_dev.h> 197 #include <video_font.h> 198 199 #if defined(CONFIG_CMD_DATE) 200 #include <rtc.h> 201 #endif 202 203 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) 204 #include <watchdog.h> 205 #include <bmp_layout.h> 206 207 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 208 #define BMP_ALIGN_CENTER 0x7FFF 209 #endif 210 211 #endif 212 213 /* 214 * Cursor definition: 215 * CONFIG_CONSOLE_CURSOR: Uses a timer function (see drivers/input/i8042.c) 216 * to let the cursor blink. Uses the macros 217 * CURSOR_OFF and CURSOR_ON. 218 * CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No 219 * blinking is provided. Uses the macros CURSOR_SET 220 * and CURSOR_OFF. 221 * CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the 222 * graphic chip. Uses the macro CURSOR_SET. 223 * ATTENTION: If booting an OS, the display driver 224 * must disable the hardware register of the graphic 225 * chip. Otherwise a blinking field is displayed 226 */ 227 #if !defined(CONFIG_CONSOLE_CURSOR) && \ 228 !defined(CONFIG_VIDEO_SW_CURSOR) && \ 229 !defined(CONFIG_VIDEO_HW_CURSOR) 230 /* no Cursor defined */ 231 #define CURSOR_ON 232 #define CURSOR_OFF 233 #define CURSOR_SET 234 #endif 235 236 #ifdef CONFIG_CONSOLE_CURSOR 237 #ifdef CURSOR_ON 238 #error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \ 239 or CONFIG_VIDEO_HW_CURSOR can be defined 240 #endif 241 void console_cursor(int state); 242 243 #define CURSOR_ON console_cursor(1) 244 #define CURSOR_OFF console_cursor(0) 245 #define CURSOR_SET 246 #ifndef CONFIG_I8042_KBD 247 #warning Cursor drawing on/off needs timer function s.a. drivers/input/i8042.c 248 #endif 249 #else 250 #ifdef CONFIG_CONSOLE_TIME 251 #error CONFIG_CONSOLE_CURSOR must be defined for CONFIG_CONSOLE_TIME 252 #endif 253 #endif /* CONFIG_CONSOLE_CURSOR */ 254 255 #ifdef CONFIG_VIDEO_SW_CURSOR 256 #ifdef CURSOR_ON 257 #error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \ 258 or CONFIG_VIDEO_HW_CURSOR can be defined 259 #endif 260 #define CURSOR_ON 261 #define CURSOR_OFF video_putchar(console_col * VIDEO_FONT_WIDTH,\ 262 console_row * VIDEO_FONT_HEIGHT, ' ') 263 #define CURSOR_SET video_set_cursor() 264 #endif /* CONFIG_VIDEO_SW_CURSOR */ 265 266 267 #ifdef CONFIG_VIDEO_HW_CURSOR 268 #ifdef CURSOR_ON 269 #error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \ 270 or CONFIG_VIDEO_HW_CURSOR can be defined 271 #endif 272 #define CURSOR_ON 273 #define CURSOR_OFF 274 #define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \ 275 (console_row * VIDEO_FONT_HEIGHT) + video_logo_height) 276 #endif /* CONFIG_VIDEO_HW_CURSOR */ 277 278 #ifdef CONFIG_VIDEO_LOGO 279 #ifdef CONFIG_VIDEO_BMP_LOGO 280 #include <bmp_logo.h> 281 #define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH 282 #define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT 283 #define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET 284 #define VIDEO_LOGO_COLORS BMP_LOGO_COLORS 285 286 #else /* CONFIG_VIDEO_BMP_LOGO */ 287 #define LINUX_LOGO_WIDTH 80 288 #define LINUX_LOGO_HEIGHT 80 289 #define LINUX_LOGO_COLORS 214 290 #define LINUX_LOGO_LUT_OFFSET 0x20 291 #define __initdata 292 #include <linux_logo.h> 293 #define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH 294 #define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT 295 #define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET 296 #define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS 297 #endif /* CONFIG_VIDEO_BMP_LOGO */ 298 #define VIDEO_INFO_X (VIDEO_LOGO_WIDTH) 299 #define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2) 300 #else /* CONFIG_VIDEO_LOGO */ 301 #define VIDEO_LOGO_WIDTH 0 302 #define VIDEO_LOGO_HEIGHT 0 303 #endif /* CONFIG_VIDEO_LOGO */ 304 305 #define VIDEO_COLS VIDEO_VISIBLE_COLS 306 #define VIDEO_ROWS VIDEO_VISIBLE_ROWS 307 #define VIDEO_SIZE (VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE) 308 #define VIDEO_PIX_BLOCKS (VIDEO_SIZE >> 2) 309 #define VIDEO_LINE_LEN (VIDEO_COLS*VIDEO_PIXEL_SIZE) 310 #define VIDEO_BURST_LEN (VIDEO_COLS/8) 311 312 #ifdef CONFIG_VIDEO_LOGO 313 #define CONSOLE_ROWS ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT) 314 #else 315 #define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT) 316 #endif 317 318 #define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH) 319 #define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN) 320 #define CONSOLE_ROW_FIRST (video_console_address) 321 #define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE) 322 #define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE) 323 #define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS) 324 #define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE) 325 326 /* Macros */ 327 #ifdef VIDEO_FB_LITTLE_ENDIAN 328 #define SWAP16(x) ((((x) & 0x00ff) << 8) | \ 329 ((x) >> 8) \ 330 ) 331 #define SWAP32(x) ((((x) & 0x000000ff) << 24) | \ 332 (((x) & 0x0000ff00) << 8) | \ 333 (((x) & 0x00ff0000) >> 8) | \ 334 (((x) & 0xff000000) >> 24) \ 335 ) 336 #define SHORTSWAP32(x) ((((x) & 0x000000ff) << 8) | \ 337 (((x) & 0x0000ff00) >> 8) | \ 338 (((x) & 0x00ff0000) << 8) | \ 339 (((x) & 0xff000000) >> 8) \ 340 ) 341 #else 342 #define SWAP16(x) (x) 343 #define SWAP32(x) (x) 344 #if defined(VIDEO_FB_16BPP_WORD_SWAP) 345 #define SHORTSWAP32(x) (((x) >> 16) | ((x) << 16)) 346 #else 347 #define SHORTSWAP32(x) (x) 348 #endif 349 #endif 350 351 #ifdef CONFIG_CONSOLE_EXTRA_INFO 352 /* 353 * setup a board string: type, speed, etc. 354 * 355 * line_number: location to place info string beside logo 356 * info: buffer for info string 357 */ 358 extern void video_get_info_str(int line_number, char *info); 359 #endif 360 361 /* Locals */ 362 static GraphicDevice *pGD; /* Pointer to Graphic array */ 363 364 static void *video_fb_address; /* frame buffer address */ 365 static void *video_console_address; /* console buffer start address */ 366 367 static int video_logo_height = VIDEO_LOGO_HEIGHT; 368 369 static int console_col; /* cursor col */ 370 static int console_row; /* cursor row */ 371 372 static u32 eorx, fgx, bgx; /* color pats */ 373 374 static const int video_font_draw_table8[] = { 375 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, 376 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, 377 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, 378 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff 379 }; 380 381 static const int video_font_draw_table15[] = { 382 0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff 383 }; 384 385 static const int video_font_draw_table16[] = { 386 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff 387 }; 388 389 static const int video_font_draw_table24[16][3] = { 390 {0x00000000, 0x00000000, 0x00000000}, 391 {0x00000000, 0x00000000, 0x00ffffff}, 392 {0x00000000, 0x0000ffff, 0xff000000}, 393 {0x00000000, 0x0000ffff, 0xffffffff}, 394 {0x000000ff, 0xffff0000, 0x00000000}, 395 {0x000000ff, 0xffff0000, 0x00ffffff}, 396 {0x000000ff, 0xffffffff, 0xff000000}, 397 {0x000000ff, 0xffffffff, 0xffffffff}, 398 {0xffffff00, 0x00000000, 0x00000000}, 399 {0xffffff00, 0x00000000, 0x00ffffff}, 400 {0xffffff00, 0x0000ffff, 0xff000000}, 401 {0xffffff00, 0x0000ffff, 0xffffffff}, 402 {0xffffffff, 0xffff0000, 0x00000000}, 403 {0xffffffff, 0xffff0000, 0x00ffffff}, 404 {0xffffffff, 0xffffffff, 0xff000000}, 405 {0xffffffff, 0xffffffff, 0xffffffff} 406 }; 407 408 static const int video_font_draw_table32[16][4] = { 409 {0x00000000, 0x00000000, 0x00000000, 0x00000000}, 410 {0x00000000, 0x00000000, 0x00000000, 0x00ffffff}, 411 {0x00000000, 0x00000000, 0x00ffffff, 0x00000000}, 412 {0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff}, 413 {0x00000000, 0x00ffffff, 0x00000000, 0x00000000}, 414 {0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff}, 415 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000}, 416 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff}, 417 {0x00ffffff, 0x00000000, 0x00000000, 0x00000000}, 418 {0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff}, 419 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000}, 420 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff}, 421 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000}, 422 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff}, 423 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000}, 424 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff} 425 }; 426 427 428 static void video_drawchars(int xx, int yy, unsigned char *s, int count) 429 { 430 u8 *cdat, *dest, *dest0; 431 int rows, offset, c; 432 433 offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE; 434 dest0 = video_fb_address + offset; 435 436 switch (VIDEO_DATA_FORMAT) { 437 case GDF__8BIT_INDEX: 438 case GDF__8BIT_332RGB: 439 while (count--) { 440 c = *s; 441 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 442 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 443 rows--; dest += VIDEO_LINE_LEN) { 444 u8 bits = *cdat++; 445 446 ((u32 *) dest)[0] = 447 (video_font_draw_table8[bits >> 4] & 448 eorx) ^ bgx; 449 ((u32 *) dest)[1] = 450 (video_font_draw_table8[bits & 15] & 451 eorx) ^ bgx; 452 } 453 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 454 s++; 455 } 456 break; 457 458 case GDF_15BIT_555RGB: 459 while (count--) { 460 c = *s; 461 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 462 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 463 rows--; dest += VIDEO_LINE_LEN) { 464 u8 bits = *cdat++; 465 466 ((u32 *) dest)[0] = 467 SHORTSWAP32((video_font_draw_table15 468 [bits >> 6] & eorx) ^ 469 bgx); 470 ((u32 *) dest)[1] = 471 SHORTSWAP32((video_font_draw_table15 472 [bits >> 4 & 3] & eorx) ^ 473 bgx); 474 ((u32 *) dest)[2] = 475 SHORTSWAP32((video_font_draw_table15 476 [bits >> 2 & 3] & eorx) ^ 477 bgx); 478 ((u32 *) dest)[3] = 479 SHORTSWAP32((video_font_draw_table15 480 [bits & 3] & eorx) ^ 481 bgx); 482 } 483 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 484 s++; 485 } 486 break; 487 488 case GDF_16BIT_565RGB: 489 while (count--) { 490 c = *s; 491 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 492 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 493 rows--; dest += VIDEO_LINE_LEN) { 494 u8 bits = *cdat++; 495 496 ((u32 *) dest)[0] = 497 SHORTSWAP32((video_font_draw_table16 498 [bits >> 6] & eorx) ^ 499 bgx); 500 ((u32 *) dest)[1] = 501 SHORTSWAP32((video_font_draw_table16 502 [bits >> 4 & 3] & eorx) ^ 503 bgx); 504 ((u32 *) dest)[2] = 505 SHORTSWAP32((video_font_draw_table16 506 [bits >> 2 & 3] & eorx) ^ 507 bgx); 508 ((u32 *) dest)[3] = 509 SHORTSWAP32((video_font_draw_table16 510 [bits & 3] & eorx) ^ 511 bgx); 512 } 513 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 514 s++; 515 } 516 break; 517 518 case GDF_32BIT_X888RGB: 519 while (count--) { 520 c = *s; 521 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 522 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 523 rows--; dest += VIDEO_LINE_LEN) { 524 u8 bits = *cdat++; 525 526 ((u32 *) dest)[0] = 527 SWAP32((video_font_draw_table32 528 [bits >> 4][0] & eorx) ^ bgx); 529 ((u32 *) dest)[1] = 530 SWAP32((video_font_draw_table32 531 [bits >> 4][1] & eorx) ^ bgx); 532 ((u32 *) dest)[2] = 533 SWAP32((video_font_draw_table32 534 [bits >> 4][2] & eorx) ^ bgx); 535 ((u32 *) dest)[3] = 536 SWAP32((video_font_draw_table32 537 [bits >> 4][3] & eorx) ^ bgx); 538 ((u32 *) dest)[4] = 539 SWAP32((video_font_draw_table32 540 [bits & 15][0] & eorx) ^ bgx); 541 ((u32 *) dest)[5] = 542 SWAP32((video_font_draw_table32 543 [bits & 15][1] & eorx) ^ bgx); 544 ((u32 *) dest)[6] = 545 SWAP32((video_font_draw_table32 546 [bits & 15][2] & eorx) ^ bgx); 547 ((u32 *) dest)[7] = 548 SWAP32((video_font_draw_table32 549 [bits & 15][3] & eorx) ^ bgx); 550 } 551 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 552 s++; 553 } 554 break; 555 556 case GDF_24BIT_888RGB: 557 while (count--) { 558 c = *s; 559 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 560 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 561 rows--; dest += VIDEO_LINE_LEN) { 562 u8 bits = *cdat++; 563 564 ((u32 *) dest)[0] = 565 (video_font_draw_table24[bits >> 4][0] 566 & eorx) ^ bgx; 567 ((u32 *) dest)[1] = 568 (video_font_draw_table24[bits >> 4][1] 569 & eorx) ^ bgx; 570 ((u32 *) dest)[2] = 571 (video_font_draw_table24[bits >> 4][2] 572 & eorx) ^ bgx; 573 ((u32 *) dest)[3] = 574 (video_font_draw_table24[bits & 15][0] 575 & eorx) ^ bgx; 576 ((u32 *) dest)[4] = 577 (video_font_draw_table24[bits & 15][1] 578 & eorx) ^ bgx; 579 ((u32 *) dest)[5] = 580 (video_font_draw_table24[bits & 15][2] 581 & eorx) ^ bgx; 582 } 583 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 584 s++; 585 } 586 break; 587 } 588 } 589 590 static inline void video_drawstring(int xx, int yy, unsigned char *s) 591 { 592 video_drawchars(xx, yy, s, strlen((char *) s)); 593 } 594 595 static void video_putchar(int xx, int yy, unsigned char c) 596 { 597 video_drawchars(xx, yy + video_logo_height, &c, 1); 598 } 599 600 #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR) 601 static void video_set_cursor(void) 602 { 603 /* swap drawing colors */ 604 eorx = fgx; 605 fgx = bgx; 606 bgx = eorx; 607 eorx = fgx ^ bgx; 608 /* draw cursor */ 609 video_putchar(console_col * VIDEO_FONT_WIDTH, 610 console_row * VIDEO_FONT_HEIGHT, ' '); 611 /* restore drawing colors */ 612 eorx = fgx; 613 fgx = bgx; 614 bgx = eorx; 615 eorx = fgx ^ bgx; 616 } 617 #endif 618 619 #ifdef CONFIG_CONSOLE_CURSOR 620 void console_cursor(int state) 621 { 622 static int last_state = 0; 623 624 #ifdef CONFIG_CONSOLE_TIME 625 struct rtc_time tm; 626 char info[16]; 627 628 /* time update only if cursor is on (faster scroll) */ 629 if (state) { 630 rtc_get(&tm); 631 632 sprintf(info, " %02d:%02d:%02d ", tm.tm_hour, tm.tm_min, 633 tm.tm_sec); 634 video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH, 635 VIDEO_INFO_Y, (uchar *) info); 636 637 sprintf(info, "%02d.%02d.%04d", tm.tm_mday, tm.tm_mon, 638 tm.tm_year); 639 video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH, 640 VIDEO_INFO_Y + 1 * VIDEO_FONT_HEIGHT, 641 (uchar *) info); 642 } 643 #endif 644 645 if (state && (last_state != state)) { 646 video_set_cursor(); 647 } 648 649 if (!state && (last_state != state)) { 650 /* clear cursor */ 651 video_putchar(console_col * VIDEO_FONT_WIDTH, 652 console_row * VIDEO_FONT_HEIGHT, ' '); 653 } 654 655 last_state = state; 656 } 657 #endif 658 659 #ifndef VIDEO_HW_RECTFILL 660 static void memsetl(int *p, int c, int v) 661 { 662 while (c--) 663 *(p++) = v; 664 } 665 #endif 666 667 #ifndef VIDEO_HW_BITBLT 668 static void memcpyl(int *d, int *s, int c) 669 { 670 while (c--) 671 *(d++) = *(s++); 672 } 673 #endif 674 675 static void console_scrollup(void) 676 { 677 /* copy up rows ignoring the first one */ 678 679 #ifdef VIDEO_HW_BITBLT 680 video_hw_bitblt(VIDEO_PIXEL_SIZE, /* bytes per pixel */ 681 0, /* source pos x */ 682 video_logo_height + 683 VIDEO_FONT_HEIGHT, /* source pos y */ 684 0, /* dest pos x */ 685 video_logo_height, /* dest pos y */ 686 VIDEO_VISIBLE_COLS, /* frame width */ 687 VIDEO_VISIBLE_ROWS 688 - video_logo_height 689 - VIDEO_FONT_HEIGHT /* frame height */ 690 ); 691 #else 692 memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, 693 CONSOLE_SCROLL_SIZE >> 2); 694 #endif 695 696 /* clear the last one */ 697 #ifdef VIDEO_HW_RECTFILL 698 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */ 699 0, /* dest pos x */ 700 VIDEO_VISIBLE_ROWS 701 - VIDEO_FONT_HEIGHT, /* dest pos y */ 702 VIDEO_VISIBLE_COLS, /* frame width */ 703 VIDEO_FONT_HEIGHT, /* frame height */ 704 CONSOLE_BG_COL /* fill color */ 705 ); 706 #else 707 memsetl(CONSOLE_ROW_LAST, CONSOLE_ROW_SIZE >> 2, CONSOLE_BG_COL); 708 #endif 709 } 710 711 static void console_back(void) 712 { 713 CURSOR_OFF; 714 console_col--; 715 716 if (console_col < 0) { 717 console_col = CONSOLE_COLS - 1; 718 console_row--; 719 if (console_row < 0) 720 console_row = 0; 721 } 722 video_putchar(console_col * VIDEO_FONT_WIDTH, 723 console_row * VIDEO_FONT_HEIGHT, ' '); 724 } 725 726 static void console_newline(void) 727 { 728 /* Check if last character in the line was just drawn. If so, cursor was 729 overwriten and need not to be cleared. Cursor clearing without this 730 check causes overwriting the 1st character of the line if line lenght 731 is >= CONSOLE_COLS 732 */ 733 if (console_col < CONSOLE_COLS) 734 CURSOR_OFF; 735 console_row++; 736 console_col = 0; 737 738 /* Check if we need to scroll the terminal */ 739 if (console_row >= CONSOLE_ROWS) { 740 /* Scroll everything up */ 741 console_scrollup(); 742 743 /* Decrement row number */ 744 console_row--; 745 } 746 } 747 748 static void console_cr(void) 749 { 750 CURSOR_OFF; 751 console_col = 0; 752 } 753 754 void video_putc(const char c) 755 { 756 static int nl = 1; 757 758 switch (c) { 759 case 13: /* back to first column */ 760 console_cr(); 761 break; 762 763 case '\n': /* next line */ 764 if (console_col || (!console_col && nl)) 765 console_newline(); 766 nl = 1; 767 break; 768 769 case 9: /* tab 8 */ 770 CURSOR_OFF; 771 console_col |= 0x0008; 772 console_col &= ~0x0007; 773 774 if (console_col >= CONSOLE_COLS) 775 console_newline(); 776 break; 777 778 case 8: /* backspace */ 779 console_back(); 780 break; 781 782 default: /* draw the char */ 783 video_putchar(console_col * VIDEO_FONT_WIDTH, 784 console_row * VIDEO_FONT_HEIGHT, c); 785 console_col++; 786 787 /* check for newline */ 788 if (console_col >= CONSOLE_COLS) { 789 console_newline(); 790 nl = 0; 791 } 792 } 793 CURSOR_SET; 794 } 795 796 void video_puts(const char *s) 797 { 798 int count = strlen(s); 799 800 while (count--) 801 video_putc(*s++); 802 } 803 804 /* 805 * Do not enforce drivers (or board code) to provide empty 806 * video_set_lut() if they do not support 8 bpp format. 807 * Implement weak default function instead. 808 */ 809 void __video_set_lut(unsigned int index, unsigned char r, 810 unsigned char g, unsigned char b) 811 { 812 } 813 814 void video_set_lut(unsigned int, unsigned char, unsigned char, unsigned char) 815 __attribute__ ((weak, alias("__video_set_lut"))); 816 817 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) 818 819 #define FILL_8BIT_332RGB(r,g,b) { \ 820 *fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6); \ 821 fb ++; \ 822 } 823 824 #define FILL_15BIT_555RGB(r,g,b) { \ 825 *(unsigned short *)fb = \ 826 SWAP16((unsigned short)(((r>>3)<<10) | \ 827 ((g>>3)<<5) | \ 828 (b>>3))); \ 829 fb += 2; \ 830 } 831 832 #define FILL_16BIT_565RGB(r,g,b) { \ 833 *(unsigned short *)fb = \ 834 SWAP16((unsigned short)((((r)>>3)<<11)| \ 835 (((g)>>2)<<5) | \ 836 ((b)>>3))); \ 837 fb += 2; \ 838 } 839 840 #define FILL_32BIT_X888RGB(r,g,b) { \ 841 *(unsigned long *)fb = \ 842 SWAP32((unsigned long)(((r<<16) | \ 843 (g<<8) | \ 844 b))); \ 845 fb += 4; \ 846 } 847 848 #ifdef VIDEO_FB_LITTLE_ENDIAN 849 #define FILL_24BIT_888RGB(r,g,b) { \ 850 fb[0] = b; \ 851 fb[1] = g; \ 852 fb[2] = r; \ 853 fb += 3; \ 854 } 855 #else 856 #define FILL_24BIT_888RGB(r,g,b) { \ 857 fb[0] = r; \ 858 fb[1] = g; \ 859 fb[2] = b; \ 860 fb += 3; \ 861 } 862 #endif 863 864 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 865 static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b) 866 { 867 ushort *dst = (ushort *) fb; 868 ushort color = (ushort) (((r >> 3) << 10) | 869 ((g >> 3) << 5) | 870 (b >> 3)); 871 if (x & 1) 872 *(--dst) = color; 873 else 874 *(++dst) = color; 875 } 876 #endif 877 878 /* 879 * RLE8 bitmap support 880 */ 881 882 #ifdef CONFIG_VIDEO_BMP_RLE8 883 /* Pre-calculated color table entry */ 884 struct palette { 885 union { 886 unsigned short w; /* word */ 887 unsigned int dw; /* double word */ 888 } ce; /* color entry */ 889 }; 890 891 /* 892 * Helper to draw encoded/unencoded run. 893 */ 894 static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p, 895 int cnt, int enc) 896 { 897 ulong addr = (ulong) *fb; 898 int *off; 899 int enc_off = 1; 900 int i; 901 902 /* 903 * Setup offset of the color index in the bitmap. 904 * Color index of encoded run is at offset 1. 905 */ 906 off = enc ? &enc_off : &i; 907 908 switch (VIDEO_DATA_FORMAT) { 909 case GDF__8BIT_INDEX: 910 for (i = 0; i < cnt; i++) 911 *(unsigned char *) addr++ = bm[*off]; 912 break; 913 case GDF_15BIT_555RGB: 914 case GDF_16BIT_565RGB: 915 /* differences handled while pre-calculating palette */ 916 for (i = 0; i < cnt; i++) { 917 *(unsigned short *) addr = p[bm[*off]].ce.w; 918 addr += 2; 919 } 920 break; 921 case GDF_32BIT_X888RGB: 922 for (i = 0; i < cnt; i++) { 923 *(unsigned long *) addr = p[bm[*off]].ce.dw; 924 addr += 4; 925 } 926 break; 927 } 928 *fb = (uchar *) addr; /* return modified address */ 929 } 930 931 static int display_rle8_bitmap(bmp_image_t *img, int xoff, int yoff, 932 int width, int height) 933 { 934 unsigned char *bm; 935 unsigned char *fbp; 936 unsigned int cnt, runlen; 937 int decode = 1; 938 int x, y, bpp, i, ncolors; 939 struct palette p[256]; 940 bmp_color_table_entry_t cte; 941 int green_shift, red_off; 942 int limit = VIDEO_COLS * VIDEO_ROWS; 943 int pixels = 0; 944 945 x = 0; 946 y = __le32_to_cpu(img->header.height) - 1; 947 ncolors = __le32_to_cpu(img->header.colors_used); 948 bpp = VIDEO_PIXEL_SIZE; 949 fbp = (unsigned char *) ((unsigned int) video_fb_address + 950 (((y + yoff) * VIDEO_COLS) + xoff) * bpp); 951 952 bm = (uchar *) img + __le32_to_cpu(img->header.data_offset); 953 954 /* pre-calculate and setup palette */ 955 switch (VIDEO_DATA_FORMAT) { 956 case GDF__8BIT_INDEX: 957 for (i = 0; i < ncolors; i++) { 958 cte = img->color_table[i]; 959 video_set_lut(i, cte.red, cte.green, cte.blue); 960 } 961 break; 962 case GDF_15BIT_555RGB: 963 case GDF_16BIT_565RGB: 964 if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) { 965 green_shift = 3; 966 red_off = 10; 967 } else { 968 green_shift = 2; 969 red_off = 11; 970 } 971 for (i = 0; i < ncolors; i++) { 972 cte = img->color_table[i]; 973 p[i].ce.w = SWAP16((unsigned short) 974 (((cte.red >> 3) << red_off) | 975 ((cte.green >> green_shift) << 5) | 976 cte.blue >> 3)); 977 } 978 break; 979 case GDF_32BIT_X888RGB: 980 for (i = 0; i < ncolors; i++) { 981 cte = img->color_table[i]; 982 p[i].ce.dw = SWAP32((cte.red << 16) | 983 (cte.green << 8) | 984 cte.blue); 985 } 986 break; 987 default: 988 printf("RLE Bitmap unsupported in video mode 0x%x\n", 989 VIDEO_DATA_FORMAT); 990 return -1; 991 } 992 993 while (decode) { 994 switch (bm[0]) { 995 case 0: 996 switch (bm[1]) { 997 case 0: 998 /* scan line end marker */ 999 bm += 2; 1000 x = 0; 1001 y--; 1002 fbp = (unsigned char *) 1003 ((unsigned int) video_fb_address + 1004 (((y + yoff) * VIDEO_COLS) + 1005 xoff) * bpp); 1006 continue; 1007 case 1: 1008 /* end of bitmap data marker */ 1009 decode = 0; 1010 break; 1011 case 2: 1012 /* run offset marker */ 1013 x += bm[2]; 1014 y -= bm[3]; 1015 fbp = (unsigned char *) 1016 ((unsigned int) video_fb_address + 1017 (((y + yoff) * VIDEO_COLS) + 1018 x + xoff) * bpp); 1019 bm += 4; 1020 break; 1021 default: 1022 /* unencoded run */ 1023 cnt = bm[1]; 1024 runlen = cnt; 1025 pixels += cnt; 1026 if (pixels > limit) 1027 goto error; 1028 1029 bm += 2; 1030 if (y < height) { 1031 if (x >= width) { 1032 x += runlen; 1033 goto next_run; 1034 } 1035 if (x + runlen > width) 1036 cnt = width - x; 1037 draw_bitmap(&fbp, bm, p, cnt, 0); 1038 x += runlen; 1039 } 1040 next_run: 1041 bm += runlen; 1042 if (runlen & 1) 1043 bm++; /* 0 padding if length is odd */ 1044 } 1045 break; 1046 default: 1047 /* encoded run */ 1048 cnt = bm[0]; 1049 runlen = cnt; 1050 pixels += cnt; 1051 if (pixels > limit) 1052 goto error; 1053 1054 if (y < height) { /* only draw into visible area */ 1055 if (x >= width) { 1056 x += runlen; 1057 bm += 2; 1058 continue; 1059 } 1060 if (x + runlen > width) 1061 cnt = width - x; 1062 draw_bitmap(&fbp, bm, p, cnt, 1); 1063 x += runlen; 1064 } 1065 bm += 2; 1066 break; 1067 } 1068 } 1069 return 0; 1070 error: 1071 printf("Error: Too much encoded pixel data, validate your bitmap\n"); 1072 return -1; 1073 } 1074 #endif 1075 1076 /* 1077 * Display the BMP file located at address bmp_image. 1078 */ 1079 int video_display_bitmap(ulong bmp_image, int x, int y) 1080 { 1081 ushort xcount, ycount; 1082 uchar *fb; 1083 bmp_image_t *bmp = (bmp_image_t *) bmp_image; 1084 uchar *bmap; 1085 ushort padded_line; 1086 unsigned long width, height, bpp; 1087 unsigned colors; 1088 unsigned long compression; 1089 bmp_color_table_entry_t cte; 1090 1091 #ifdef CONFIG_VIDEO_BMP_GZIP 1092 unsigned char *dst = NULL; 1093 ulong len; 1094 #endif 1095 1096 WATCHDOG_RESET(); 1097 1098 if (!((bmp->header.signature[0] == 'B') && 1099 (bmp->header.signature[1] == 'M'))) { 1100 1101 #ifdef CONFIG_VIDEO_BMP_GZIP 1102 /* 1103 * Could be a gzipped bmp image, try to decrompress... 1104 */ 1105 len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE; 1106 dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE); 1107 if (dst == NULL) { 1108 printf("Error: malloc in gunzip failed!\n"); 1109 return 1; 1110 } 1111 if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, 1112 (uchar *) bmp_image, 1113 &len) != 0) { 1114 printf("Error: no valid bmp or bmp.gz image at %lx\n", 1115 bmp_image); 1116 free(dst); 1117 return 1; 1118 } 1119 if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) { 1120 printf("Image could be truncated " 1121 "(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n"); 1122 } 1123 1124 /* 1125 * Set addr to decompressed image 1126 */ 1127 bmp = (bmp_image_t *) dst; 1128 1129 if (!((bmp->header.signature[0] == 'B') && 1130 (bmp->header.signature[1] == 'M'))) { 1131 printf("Error: no valid bmp.gz image at %lx\n", 1132 bmp_image); 1133 free(dst); 1134 return 1; 1135 } 1136 #else 1137 printf("Error: no valid bmp image at %lx\n", bmp_image); 1138 return 1; 1139 #endif /* CONFIG_VIDEO_BMP_GZIP */ 1140 } 1141 1142 width = le32_to_cpu(bmp->header.width); 1143 height = le32_to_cpu(bmp->header.height); 1144 bpp = le16_to_cpu(bmp->header.bit_count); 1145 colors = le32_to_cpu(bmp->header.colors_used); 1146 compression = le32_to_cpu(bmp->header.compression); 1147 1148 debug("Display-bmp: %d x %d with %d colors\n", 1149 width, height, colors); 1150 1151 if (compression != BMP_BI_RGB 1152 #ifdef CONFIG_VIDEO_BMP_RLE8 1153 && compression != BMP_BI_RLE8 1154 #endif 1155 ) { 1156 printf("Error: compression type %ld not supported\n", 1157 compression); 1158 #ifdef CONFIG_VIDEO_BMP_GZIP 1159 if (dst) 1160 free(dst); 1161 #endif 1162 return 1; 1163 } 1164 1165 padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3; 1166 1167 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 1168 if (x == BMP_ALIGN_CENTER) 1169 x = max(0, (VIDEO_VISIBLE_COLS - width) / 2); 1170 else if (x < 0) 1171 x = max(0, VIDEO_VISIBLE_COLS - width + x + 1); 1172 1173 if (y == BMP_ALIGN_CENTER) 1174 y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2); 1175 else if (y < 0) 1176 y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1); 1177 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ 1178 1179 if ((x + width) > VIDEO_VISIBLE_COLS) 1180 width = VIDEO_VISIBLE_COLS - x; 1181 if ((y + height) > VIDEO_VISIBLE_ROWS) 1182 height = VIDEO_VISIBLE_ROWS - y; 1183 1184 bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset); 1185 fb = (uchar *) (video_fb_address + 1186 ((y + height - 1) * VIDEO_COLS * VIDEO_PIXEL_SIZE) + 1187 x * VIDEO_PIXEL_SIZE); 1188 1189 #ifdef CONFIG_VIDEO_BMP_RLE8 1190 if (compression == BMP_BI_RLE8) { 1191 return display_rle8_bitmap(bmp, x, y, width, height); 1192 } 1193 #endif 1194 1195 /* We handle only 4, 8, or 24 bpp bitmaps */ 1196 switch (le16_to_cpu(bmp->header.bit_count)) { 1197 case 4: 1198 padded_line -= width / 2; 1199 ycount = height; 1200 1201 switch (VIDEO_DATA_FORMAT) { 1202 case GDF_32BIT_X888RGB: 1203 while (ycount--) { 1204 WATCHDOG_RESET(); 1205 /* 1206 * Don't assume that 'width' is an 1207 * even number 1208 */ 1209 for (xcount = 0; xcount < width; xcount++) { 1210 uchar idx; 1211 1212 if (xcount & 1) { 1213 idx = *bmap & 0xF; 1214 bmap++; 1215 } else 1216 idx = *bmap >> 4; 1217 cte = bmp->color_table[idx]; 1218 FILL_32BIT_X888RGB(cte.red, cte.green, 1219 cte.blue); 1220 } 1221 bmap += padded_line; 1222 fb -= (VIDEO_VISIBLE_COLS + width) * 1223 VIDEO_PIXEL_SIZE; 1224 } 1225 break; 1226 default: 1227 puts("4bpp bitmap unsupported with current " 1228 "video mode\n"); 1229 break; 1230 } 1231 break; 1232 1233 case 8: 1234 padded_line -= width; 1235 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) { 1236 /* Copy colormap */ 1237 for (xcount = 0; xcount < colors; ++xcount) { 1238 cte = bmp->color_table[xcount]; 1239 video_set_lut(xcount, cte.red, cte.green, 1240 cte.blue); 1241 } 1242 } 1243 ycount = height; 1244 switch (VIDEO_DATA_FORMAT) { 1245 case GDF__8BIT_INDEX: 1246 while (ycount--) { 1247 WATCHDOG_RESET(); 1248 xcount = width; 1249 while (xcount--) { 1250 *fb++ = *bmap++; 1251 } 1252 bmap += padded_line; 1253 fb -= (VIDEO_VISIBLE_COLS + width) * 1254 VIDEO_PIXEL_SIZE; 1255 } 1256 break; 1257 case GDF__8BIT_332RGB: 1258 while (ycount--) { 1259 WATCHDOG_RESET(); 1260 xcount = width; 1261 while (xcount--) { 1262 cte = bmp->color_table[*bmap++]; 1263 FILL_8BIT_332RGB(cte.red, cte.green, 1264 cte.blue); 1265 } 1266 bmap += padded_line; 1267 fb -= (VIDEO_VISIBLE_COLS + width) * 1268 VIDEO_PIXEL_SIZE; 1269 } 1270 break; 1271 case GDF_15BIT_555RGB: 1272 while (ycount--) { 1273 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1274 int xpos = x; 1275 #endif 1276 WATCHDOG_RESET(); 1277 xcount = width; 1278 while (xcount--) { 1279 cte = bmp->color_table[*bmap++]; 1280 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1281 fill_555rgb_pswap(fb, xpos++, cte.red, 1282 cte.green, 1283 cte.blue); 1284 fb += 2; 1285 #else 1286 FILL_15BIT_555RGB(cte.red, cte.green, 1287 cte.blue); 1288 #endif 1289 } 1290 bmap += padded_line; 1291 fb -= (VIDEO_VISIBLE_COLS + width) * 1292 VIDEO_PIXEL_SIZE; 1293 } 1294 break; 1295 case GDF_16BIT_565RGB: 1296 while (ycount--) { 1297 WATCHDOG_RESET(); 1298 xcount = width; 1299 while (xcount--) { 1300 cte = bmp->color_table[*bmap++]; 1301 FILL_16BIT_565RGB(cte.red, cte.green, 1302 cte.blue); 1303 } 1304 bmap += padded_line; 1305 fb -= (VIDEO_VISIBLE_COLS + width) * 1306 VIDEO_PIXEL_SIZE; 1307 } 1308 break; 1309 case GDF_32BIT_X888RGB: 1310 while (ycount--) { 1311 WATCHDOG_RESET(); 1312 xcount = width; 1313 while (xcount--) { 1314 cte = bmp->color_table[*bmap++]; 1315 FILL_32BIT_X888RGB(cte.red, cte.green, 1316 cte.blue); 1317 } 1318 bmap += padded_line; 1319 fb -= (VIDEO_VISIBLE_COLS + width) * 1320 VIDEO_PIXEL_SIZE; 1321 } 1322 break; 1323 case GDF_24BIT_888RGB: 1324 while (ycount--) { 1325 WATCHDOG_RESET(); 1326 xcount = width; 1327 while (xcount--) { 1328 cte = bmp->color_table[*bmap++]; 1329 FILL_24BIT_888RGB(cte.red, cte.green, 1330 cte.blue); 1331 } 1332 bmap += padded_line; 1333 fb -= (VIDEO_VISIBLE_COLS + width) * 1334 VIDEO_PIXEL_SIZE; 1335 } 1336 break; 1337 } 1338 break; 1339 case 24: 1340 padded_line -= 3 * width; 1341 ycount = height; 1342 switch (VIDEO_DATA_FORMAT) { 1343 case GDF__8BIT_332RGB: 1344 while (ycount--) { 1345 WATCHDOG_RESET(); 1346 xcount = width; 1347 while (xcount--) { 1348 FILL_8BIT_332RGB(bmap[2], bmap[1], 1349 bmap[0]); 1350 bmap += 3; 1351 } 1352 bmap += padded_line; 1353 fb -= (VIDEO_VISIBLE_COLS + width) * 1354 VIDEO_PIXEL_SIZE; 1355 } 1356 break; 1357 case GDF_15BIT_555RGB: 1358 while (ycount--) { 1359 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1360 int xpos = x; 1361 #endif 1362 WATCHDOG_RESET(); 1363 xcount = width; 1364 while (xcount--) { 1365 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1366 fill_555rgb_pswap(fb, xpos++, bmap[2], 1367 bmap[1], bmap[0]); 1368 fb += 2; 1369 #else 1370 FILL_15BIT_555RGB(bmap[2], bmap[1], 1371 bmap[0]); 1372 #endif 1373 bmap += 3; 1374 } 1375 bmap += padded_line; 1376 fb -= (VIDEO_VISIBLE_COLS + width) * 1377 VIDEO_PIXEL_SIZE; 1378 } 1379 break; 1380 case GDF_16BIT_565RGB: 1381 while (ycount--) { 1382 WATCHDOG_RESET(); 1383 xcount = width; 1384 while (xcount--) { 1385 FILL_16BIT_565RGB(bmap[2], bmap[1], 1386 bmap[0]); 1387 bmap += 3; 1388 } 1389 bmap += padded_line; 1390 fb -= (VIDEO_VISIBLE_COLS + width) * 1391 VIDEO_PIXEL_SIZE; 1392 } 1393 break; 1394 case GDF_32BIT_X888RGB: 1395 while (ycount--) { 1396 WATCHDOG_RESET(); 1397 xcount = width; 1398 while (xcount--) { 1399 FILL_32BIT_X888RGB(bmap[2], bmap[1], 1400 bmap[0]); 1401 bmap += 3; 1402 } 1403 bmap += padded_line; 1404 fb -= (VIDEO_VISIBLE_COLS + width) * 1405 VIDEO_PIXEL_SIZE; 1406 } 1407 break; 1408 case GDF_24BIT_888RGB: 1409 while (ycount--) { 1410 WATCHDOG_RESET(); 1411 xcount = width; 1412 while (xcount--) { 1413 FILL_24BIT_888RGB(bmap[2], bmap[1], 1414 bmap[0]); 1415 bmap += 3; 1416 } 1417 bmap += padded_line; 1418 fb -= (VIDEO_VISIBLE_COLS + width) * 1419 VIDEO_PIXEL_SIZE; 1420 } 1421 break; 1422 default: 1423 printf("Error: 24 bits/pixel bitmap incompatible " 1424 "with current video mode\n"); 1425 break; 1426 } 1427 break; 1428 default: 1429 printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n", 1430 le16_to_cpu(bmp->header.bit_count)); 1431 break; 1432 } 1433 1434 #ifdef CONFIG_VIDEO_BMP_GZIP 1435 if (dst) { 1436 free(dst); 1437 } 1438 #endif 1439 1440 return (0); 1441 } 1442 #endif 1443 1444 1445 #ifdef CONFIG_VIDEO_LOGO 1446 void logo_plot(void *screen, int width, int x, int y) 1447 { 1448 1449 int xcount, i; 1450 int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE; 1451 int ycount = video_logo_height; 1452 unsigned char r, g, b, *logo_red, *logo_blue, *logo_green; 1453 unsigned char *source; 1454 unsigned char *dest = (unsigned char *) screen + 1455 ((y * width * VIDEO_PIXEL_SIZE) + x * VIDEO_PIXEL_SIZE); 1456 1457 #ifdef CONFIG_VIDEO_BMP_LOGO 1458 source = bmp_logo_bitmap; 1459 1460 /* Allocate temporary space for computing colormap */ 1461 logo_red = malloc(BMP_LOGO_COLORS); 1462 logo_green = malloc(BMP_LOGO_COLORS); 1463 logo_blue = malloc(BMP_LOGO_COLORS); 1464 /* Compute color map */ 1465 for (i = 0; i < VIDEO_LOGO_COLORS; i++) { 1466 logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4; 1467 logo_green[i] = (bmp_logo_palette[i] & 0x00f0); 1468 logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4; 1469 } 1470 #else 1471 source = linux_logo; 1472 logo_red = linux_logo_red; 1473 logo_green = linux_logo_green; 1474 logo_blue = linux_logo_blue; 1475 #endif 1476 1477 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) { 1478 for (i = 0; i < VIDEO_LOGO_COLORS; i++) { 1479 video_set_lut(i + VIDEO_LOGO_LUT_OFFSET, 1480 logo_red[i], logo_green[i], 1481 logo_blue[i]); 1482 } 1483 } 1484 1485 while (ycount--) { 1486 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1487 int xpos = x; 1488 #endif 1489 xcount = VIDEO_LOGO_WIDTH; 1490 while (xcount--) { 1491 r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET]; 1492 g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET]; 1493 b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET]; 1494 1495 switch (VIDEO_DATA_FORMAT) { 1496 case GDF__8BIT_INDEX: 1497 *dest = *source; 1498 break; 1499 case GDF__8BIT_332RGB: 1500 *dest = ((r >> 5) << 5) | 1501 ((g >> 5) << 2) | 1502 (b >> 6); 1503 break; 1504 case GDF_15BIT_555RGB: 1505 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1506 fill_555rgb_pswap(dest, xpos++, r, g, b); 1507 #else 1508 *(unsigned short *) dest = 1509 SWAP16((unsigned short) ( 1510 ((r >> 3) << 10) | 1511 ((g >> 3) << 5) | 1512 (b >> 3))); 1513 #endif 1514 break; 1515 case GDF_16BIT_565RGB: 1516 *(unsigned short *) dest = 1517 SWAP16((unsigned short) ( 1518 ((r >> 3) << 11) | 1519 ((g >> 2) << 5) | 1520 (b >> 3))); 1521 break; 1522 case GDF_32BIT_X888RGB: 1523 *(unsigned long *) dest = 1524 SWAP32((unsigned long) ( 1525 (r << 16) | 1526 (g << 8) | 1527 b)); 1528 break; 1529 case GDF_24BIT_888RGB: 1530 #ifdef VIDEO_FB_LITTLE_ENDIAN 1531 dest[0] = b; 1532 dest[1] = g; 1533 dest[2] = r; 1534 #else 1535 dest[0] = r; 1536 dest[1] = g; 1537 dest[2] = b; 1538 #endif 1539 break; 1540 } 1541 source++; 1542 dest += VIDEO_PIXEL_SIZE; 1543 } 1544 dest += skip; 1545 } 1546 #ifdef CONFIG_VIDEO_BMP_LOGO 1547 free(logo_red); 1548 free(logo_green); 1549 free(logo_blue); 1550 #endif 1551 } 1552 1553 static void *video_logo(void) 1554 { 1555 char info[128]; 1556 int space, len, y_off = 0; 1557 1558 #ifdef CONFIG_SPLASH_SCREEN 1559 char *s; 1560 ulong addr; 1561 1562 s = getenv("splashimage"); 1563 if (s != NULL) { 1564 int x = 0, y = 0; 1565 1566 addr = simple_strtoul(s, NULL, 16); 1567 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 1568 s = getenv("splashpos"); 1569 if (s != NULL) { 1570 if (s[0] == 'm') 1571 x = BMP_ALIGN_CENTER; 1572 else 1573 x = simple_strtol(s, NULL, 0); 1574 1575 s = strchr(s + 1, ','); 1576 if (s != NULL) { 1577 if (s[1] == 'm') 1578 y = BMP_ALIGN_CENTER; 1579 else 1580 y = simple_strtol(s + 1, NULL, 0); 1581 } 1582 } 1583 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ 1584 1585 if (video_display_bitmap(addr, x, y) == 0) { 1586 video_logo_height = 0; 1587 return ((void *) (video_fb_address)); 1588 } 1589 } 1590 #endif /* CONFIG_SPLASH_SCREEN */ 1591 1592 logo_plot(video_fb_address, VIDEO_COLS, 0, 0); 1593 1594 sprintf(info, " %s", version_string); 1595 1596 space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH; 1597 len = strlen(info); 1598 1599 if (len > space) { 1600 video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y, 1601 (uchar *) info, space); 1602 video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH, 1603 VIDEO_INFO_Y + VIDEO_FONT_HEIGHT, 1604 (uchar *) info + space, len - space); 1605 y_off = 1; 1606 } else 1607 video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info); 1608 1609 #ifdef CONFIG_CONSOLE_EXTRA_INFO 1610 { 1611 int i, n = 1612 ((video_logo_height - 1613 VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT); 1614 1615 for (i = 1; i < n; i++) { 1616 video_get_info_str(i, info); 1617 if (!*info) 1618 continue; 1619 1620 len = strlen(info); 1621 if (len > space) { 1622 video_drawchars(VIDEO_INFO_X, 1623 VIDEO_INFO_Y + 1624 (i + y_off) * 1625 VIDEO_FONT_HEIGHT, 1626 (uchar *) info, space); 1627 y_off++; 1628 video_drawchars(VIDEO_INFO_X + 1629 VIDEO_FONT_WIDTH, 1630 VIDEO_INFO_Y + 1631 (i + y_off) * 1632 VIDEO_FONT_HEIGHT, 1633 (uchar *) info + space, 1634 len - space); 1635 } else { 1636 video_drawstring(VIDEO_INFO_X, 1637 VIDEO_INFO_Y + 1638 (i + y_off) * 1639 VIDEO_FONT_HEIGHT, 1640 (uchar *) info); 1641 } 1642 } 1643 } 1644 #endif 1645 1646 return (video_fb_address + video_logo_height * VIDEO_LINE_LEN); 1647 } 1648 #endif 1649 1650 static int video_init(void) 1651 { 1652 unsigned char color8; 1653 1654 pGD = video_hw_init(); 1655 if (pGD == NULL) 1656 return -1; 1657 1658 video_fb_address = (void *) VIDEO_FB_ADRS; 1659 #ifdef CONFIG_VIDEO_HW_CURSOR 1660 video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT); 1661 #endif 1662 1663 /* Init drawing pats */ 1664 switch (VIDEO_DATA_FORMAT) { 1665 case GDF__8BIT_INDEX: 1666 video_set_lut(0x01, CONSOLE_FG_COL, CONSOLE_FG_COL, 1667 CONSOLE_FG_COL); 1668 video_set_lut(0x00, CONSOLE_BG_COL, CONSOLE_BG_COL, 1669 CONSOLE_BG_COL); 1670 fgx = 0x01010101; 1671 bgx = 0x00000000; 1672 break; 1673 case GDF__8BIT_332RGB: 1674 color8 = ((CONSOLE_FG_COL & 0xe0) | 1675 ((CONSOLE_FG_COL >> 3) & 0x1c) | 1676 CONSOLE_FG_COL >> 6); 1677 fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | 1678 color8; 1679 color8 = ((CONSOLE_BG_COL & 0xe0) | 1680 ((CONSOLE_BG_COL >> 3) & 0x1c) | 1681 CONSOLE_BG_COL >> 6); 1682 bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | 1683 color8; 1684 break; 1685 case GDF_15BIT_555RGB: 1686 fgx = (((CONSOLE_FG_COL >> 3) << 26) | 1687 ((CONSOLE_FG_COL >> 3) << 21) | 1688 ((CONSOLE_FG_COL >> 3) << 16) | 1689 ((CONSOLE_FG_COL >> 3) << 10) | 1690 ((CONSOLE_FG_COL >> 3) << 5) | 1691 (CONSOLE_FG_COL >> 3)); 1692 bgx = (((CONSOLE_BG_COL >> 3) << 26) | 1693 ((CONSOLE_BG_COL >> 3) << 21) | 1694 ((CONSOLE_BG_COL >> 3) << 16) | 1695 ((CONSOLE_BG_COL >> 3) << 10) | 1696 ((CONSOLE_BG_COL >> 3) << 5) | 1697 (CONSOLE_BG_COL >> 3)); 1698 break; 1699 case GDF_16BIT_565RGB: 1700 fgx = (((CONSOLE_FG_COL >> 3) << 27) | 1701 ((CONSOLE_FG_COL >> 2) << 21) | 1702 ((CONSOLE_FG_COL >> 3) << 16) | 1703 ((CONSOLE_FG_COL >> 3) << 11) | 1704 ((CONSOLE_FG_COL >> 2) << 5) | 1705 (CONSOLE_FG_COL >> 3)); 1706 bgx = (((CONSOLE_BG_COL >> 3) << 27) | 1707 ((CONSOLE_BG_COL >> 2) << 21) | 1708 ((CONSOLE_BG_COL >> 3) << 16) | 1709 ((CONSOLE_BG_COL >> 3) << 11) | 1710 ((CONSOLE_BG_COL >> 2) << 5) | 1711 (CONSOLE_BG_COL >> 3)); 1712 break; 1713 case GDF_32BIT_X888RGB: 1714 fgx = (CONSOLE_FG_COL << 16) | 1715 (CONSOLE_FG_COL << 8) | 1716 CONSOLE_FG_COL; 1717 bgx = (CONSOLE_BG_COL << 16) | 1718 (CONSOLE_BG_COL << 8) | 1719 CONSOLE_BG_COL; 1720 break; 1721 case GDF_24BIT_888RGB: 1722 fgx = (CONSOLE_FG_COL << 24) | 1723 (CONSOLE_FG_COL << 16) | 1724 (CONSOLE_FG_COL << 8) | 1725 CONSOLE_FG_COL; 1726 bgx = (CONSOLE_BG_COL << 24) | 1727 (CONSOLE_BG_COL << 16) | 1728 (CONSOLE_BG_COL << 8) | 1729 CONSOLE_BG_COL; 1730 break; 1731 } 1732 eorx = fgx ^ bgx; 1733 1734 #ifdef CONFIG_VIDEO_LOGO 1735 /* Plot the logo and get start point of console */ 1736 debug("Video: Drawing the logo ...\n"); 1737 video_console_address = video_logo(); 1738 #else 1739 video_console_address = video_fb_address; 1740 #endif 1741 1742 /* Initialize the console */ 1743 console_col = 0; 1744 console_row = 0; 1745 1746 return 0; 1747 } 1748 1749 /* 1750 * Implement a weak default function for boards that optionally 1751 * need to skip the video initialization. 1752 */ 1753 int __board_video_skip(void) 1754 { 1755 /* As default, don't skip test */ 1756 return 0; 1757 } 1758 1759 int board_video_skip(void) 1760 __attribute__ ((weak, alias("__board_video_skip"))); 1761 1762 int drv_video_init(void) 1763 { 1764 int skip_dev_init; 1765 struct stdio_dev console_dev; 1766 1767 /* Check if video initialization should be skipped */ 1768 if (board_video_skip()) 1769 return 0; 1770 1771 /* Init video chip - returns with framebuffer cleared */ 1772 skip_dev_init = (video_init() == -1); 1773 1774 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE) 1775 debug("KBD: Keyboard init ...\n"); 1776 skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1); 1777 #endif 1778 1779 if (skip_dev_init) 1780 return 0; 1781 1782 /* Init vga device */ 1783 memset(&console_dev, 0, sizeof(console_dev)); 1784 strcpy(console_dev.name, "vga"); 1785 console_dev.ext = DEV_EXT_VIDEO; /* Video extensions */ 1786 console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM; 1787 console_dev.putc = video_putc; /* 'putc' function */ 1788 console_dev.puts = video_puts; /* 'puts' function */ 1789 console_dev.tstc = NULL; /* 'tstc' function */ 1790 console_dev.getc = NULL; /* 'getc' function */ 1791 1792 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE) 1793 /* Also init console device */ 1794 console_dev.flags |= DEV_FLAGS_INPUT; 1795 console_dev.tstc = VIDEO_TSTC_FCT; /* 'tstc' function */ 1796 console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */ 1797 #endif /* CONFIG_VGA_AS_SINGLE_DEVICE */ 1798 1799 if (stdio_register(&console_dev) != 0) 1800 return 0; 1801 1802 /* Return success */ 1803 return 1; 1804 } 1805