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