1 /* 2 * (C) Copyright 2002 ELTEC Elektronik AG 3 * Frank Gottschling <fgottschling@eltec.de> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 /* 9 * cfb_console.c 10 * 11 * Color Framebuffer Console driver for 8/15/16/24/32 bits per pixel. 12 * 13 * At the moment only the 8x16 font is tested and the font fore- and 14 * background color is limited to black/white/gray colors. The Linux 15 * logo can be placed in the upper left corner and additional board 16 * information strings (that normally goes to serial port) can be drawn. 17 * 18 * The console driver can use the standard PC keyboard interface (i8042) 19 * for character input. Character output goes to a memory mapped video 20 * framebuffer with little or big-endian organisation. 21 * With environment setting 'console=serial' the console i/o can be 22 * forced to serial port. 23 * 24 * The driver uses graphic specific defines/parameters/functions: 25 * 26 * (for SMI LynxE graphic chip) 27 * 28 * CONFIG_VIDEO_SMI_LYNXEM - use graphic driver for SMI 710,712,810 29 * VIDEO_FB_LITTLE_ENDIAN - framebuffer organisation default: big endian 30 * VIDEO_HW_RECTFILL - graphic driver supports hardware rectangle fill 31 * VIDEO_HW_BITBLT - graphic driver supports hardware bit blt 32 * 33 * Console Parameters are set by graphic drivers global struct: 34 * 35 * VIDEO_VISIBLE_COLS - x resolution 36 * VIDEO_VISIBLE_ROWS - y resolution 37 * VIDEO_PIXEL_SIZE - storage size in byte per pixel 38 * VIDEO_DATA_FORMAT - graphical data format GDF 39 * VIDEO_FB_ADRS - start of video memory 40 * 41 * CONFIG_I8042_KBD - AT Keyboard driver for i8042 42 * VIDEO_KBD_INIT_FCT - init function for keyboard 43 * VIDEO_TSTC_FCT - keyboard_tstc function 44 * VIDEO_GETC_FCT - keyboard_getc function 45 * 46 * CONFIG_CONSOLE_CURSOR - on/off drawing cursor is done with 47 * delay loop in VIDEO_TSTC_FCT (i8042) 48 * 49 * CONFIG_SYS_CONSOLE_BLINK_COUNT - value for delay loop - blink rate 50 * CONFIG_CONSOLE_TIME - display time/date in upper right 51 * corner, needs CONFIG_CMD_DATE and 52 * CONFIG_CONSOLE_CURSOR 53 * CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner. 54 * Use CONFIG_SPLASH_SCREEN_ALIGN with 55 * environment variable "splashpos" to place 56 * the logo on other position. In this case 57 * no CONSOLE_EXTRA_INFO is possible. 58 * CONFIG_VIDEO_BMP_LOGO - use bmp_logo instead of linux_logo 59 * CONFIG_CONSOLE_EXTRA_INFO - display additional board information 60 * strings that normaly goes to serial 61 * port. This define requires a board 62 * specific function: 63 * video_drawstring (VIDEO_INFO_X, 64 * VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT, 65 * info); 66 * that fills a info buffer at i=row. 67 * s.a: board/eltec/bab7xx. 68 * CONFIG_VGA_AS_SINGLE_DEVICE - If set the framebuffer device will be 69 * initialized as an output only device. 70 * The Keyboard driver will not be 71 * set-up. This may be used, if you have 72 * no or more than one Keyboard devices 73 * (USB Keyboard, AT Keyboard). 74 * 75 * CONFIG_VIDEO_SW_CURSOR: - Draws a cursor after the last 76 * character. No blinking is provided. 77 * Uses the macros CURSOR_SET and 78 * CURSOR_OFF. 79 * 80 * CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability 81 * of the graphic chip. Uses the macro 82 * CURSOR_SET. ATTENTION: If booting an 83 * OS, the display driver must disable 84 * the hardware register of the graphic 85 * chip. Otherwise a blinking field is 86 * displayed. 87 */ 88 89 #include <common.h> 90 #include <version.h> 91 #include <malloc.h> 92 #include <linux/compiler.h> 93 94 /* 95 * Console device defines with SMI graphic 96 * Any other graphic must change this section 97 */ 98 99 #ifdef CONFIG_VIDEO_SMI_LYNXEM 100 101 #define VIDEO_FB_LITTLE_ENDIAN 102 #define VIDEO_HW_RECTFILL 103 #define VIDEO_HW_BITBLT 104 #endif 105 106 /* 107 * Defines for the CT69000 driver 108 */ 109 #ifdef CONFIG_VIDEO_CT69000 110 111 #define VIDEO_FB_LITTLE_ENDIAN 112 #define VIDEO_HW_RECTFILL 113 #define VIDEO_HW_BITBLT 114 #endif 115 116 /* 117 * Defines for the SED13806 driver 118 */ 119 #ifdef CONFIG_VIDEO_SED13806 120 121 #ifndef CONFIG_TOTAL5200 122 #define VIDEO_FB_LITTLE_ENDIAN 123 #endif 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_SM501 132 133 #ifdef CONFIG_HH405 134 #define VIDEO_FB_LITTLE_ENDIAN 135 #endif 136 #endif 137 138 #ifdef CONFIG_VIDEO_MXS 139 #define VIDEO_FB_16BPP_WORD_SWAP 140 #endif 141 142 /* 143 * Defines for the MB862xx driver 144 */ 145 #ifdef CONFIG_VIDEO_MB862xx 146 147 #ifdef CONFIG_VIDEO_CORALP 148 #define VIDEO_FB_LITTLE_ENDIAN 149 #endif 150 #ifdef CONFIG_VIDEO_MB862xx_ACCEL 151 #define VIDEO_HW_RECTFILL 152 #define VIDEO_HW_BITBLT 153 #endif 154 #endif 155 156 /* 157 * Defines for the i.MX31 driver (mx3fb.c) 158 */ 159 #if defined(CONFIG_VIDEO_MX3) || defined(CONFIG_VIDEO_IPUV3) 160 #define VIDEO_FB_16BPP_WORD_SWAP 161 #endif 162 163 /* 164 * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc. 165 */ 166 #include <video_fb.h> 167 168 #include <splash.h> 169 170 /* 171 * some Macros 172 */ 173 #define VIDEO_VISIBLE_COLS (pGD->winSizeX) 174 #define VIDEO_VISIBLE_ROWS (pGD->winSizeY) 175 #define VIDEO_PIXEL_SIZE (pGD->gdfBytesPP) 176 #define VIDEO_DATA_FORMAT (pGD->gdfIndex) 177 #define VIDEO_FB_ADRS (pGD->frameAdrs) 178 179 /* 180 * Console device defines with i8042 keyboard controller 181 * Any other keyboard controller must change this section 182 */ 183 184 #ifdef CONFIG_I8042_KBD 185 #include <i8042.h> 186 187 #define VIDEO_KBD_INIT_FCT i8042_kbd_init() 188 #define VIDEO_TSTC_FCT i8042_tstc 189 #define VIDEO_GETC_FCT i8042_getc 190 #endif 191 192 /* 193 * Console device 194 */ 195 196 #include <version.h> 197 #include <linux/types.h> 198 #include <stdio_dev.h> 199 #include <video_font.h> 200 #include <video_font_data.h> 201 202 #if defined(CONFIG_CMD_DATE) 203 #include <rtc.h> 204 #endif 205 206 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) 207 #include <watchdog.h> 208 #include <bmp_layout.h> 209 #include <splash.h> 210 #endif 211 212 /* 213 * Cursor definition: 214 * CONFIG_CONSOLE_CURSOR: Uses a timer function (see drivers/input/i8042.c) 215 * to let the cursor blink. Uses the macros 216 * CURSOR_OFF and CURSOR_ON. 217 * CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No 218 * blinking is provided. Uses the macros CURSOR_SET 219 * and CURSOR_OFF. 220 * CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the 221 * graphic chip. Uses the macro CURSOR_SET. 222 * ATTENTION: If booting an OS, the display driver 223 * must disable the hardware register of the graphic 224 * chip. Otherwise a blinking field is displayed 225 */ 226 #if !defined(CONFIG_CONSOLE_CURSOR) && \ 227 !defined(CONFIG_VIDEO_SW_CURSOR) && \ 228 !defined(CONFIG_VIDEO_HW_CURSOR) 229 /* no Cursor defined */ 230 #define CURSOR_ON 231 #define CURSOR_OFF 232 #define CURSOR_SET 233 #endif 234 235 #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR) 236 #if defined(CURSOR_ON) || \ 237 (defined(CONFIG_CONSOLE_CURSOR) && defined(CONFIG_VIDEO_SW_CURSOR)) 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 video_set_cursor() 246 #endif /* CONFIG_CONSOLE_CURSOR || CONFIG_VIDEO_SW_CURSOR */ 247 248 #ifdef CONFIG_CONSOLE_CURSOR 249 #ifndef CONFIG_CONSOLE_TIME 250 #error CONFIG_CONSOLE_CURSOR must be defined for CONFIG_CONSOLE_TIME 251 #endif 252 #ifndef CONFIG_I8042_KBD 253 #warning Cursor drawing on/off needs timer function s.a. drivers/input/i8042.c 254 #endif 255 #endif /* CONFIG_CONSOLE_CURSOR */ 256 257 258 #ifdef CONFIG_VIDEO_HW_CURSOR 259 #ifdef CURSOR_ON 260 #error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \ 261 or CONFIG_VIDEO_HW_CURSOR can be defined 262 #endif 263 #define CURSOR_ON 264 #define CURSOR_OFF 265 #define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \ 266 (console_row * VIDEO_FONT_HEIGHT) + video_logo_height) 267 #endif /* CONFIG_VIDEO_HW_CURSOR */ 268 269 #ifdef CONFIG_VIDEO_LOGO 270 #ifdef CONFIG_VIDEO_BMP_LOGO 271 #include <bmp_logo.h> 272 #include <bmp_logo_data.h> 273 #define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH 274 #define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT 275 #define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET 276 #define VIDEO_LOGO_COLORS BMP_LOGO_COLORS 277 278 #else /* CONFIG_VIDEO_BMP_LOGO */ 279 #define LINUX_LOGO_WIDTH 80 280 #define LINUX_LOGO_HEIGHT 80 281 #define LINUX_LOGO_COLORS 214 282 #define LINUX_LOGO_LUT_OFFSET 0x20 283 #define __initdata 284 #include <linux_logo.h> 285 #define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH 286 #define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT 287 #define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET 288 #define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS 289 #endif /* CONFIG_VIDEO_BMP_LOGO */ 290 #define VIDEO_INFO_X (VIDEO_LOGO_WIDTH) 291 #define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2) 292 #else /* CONFIG_VIDEO_LOGO */ 293 #define VIDEO_LOGO_WIDTH 0 294 #define VIDEO_LOGO_HEIGHT 0 295 #endif /* CONFIG_VIDEO_LOGO */ 296 297 #define VIDEO_COLS VIDEO_VISIBLE_COLS 298 #define VIDEO_ROWS VIDEO_VISIBLE_ROWS 299 #define VIDEO_SIZE (VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE) 300 #define VIDEO_PIX_BLOCKS (VIDEO_SIZE >> 2) 301 #define VIDEO_LINE_LEN (VIDEO_COLS*VIDEO_PIXEL_SIZE) 302 #define VIDEO_BURST_LEN (VIDEO_COLS/8) 303 304 #ifdef CONFIG_VIDEO_LOGO 305 #define CONSOLE_ROWS ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT) 306 #else 307 #define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT) 308 #endif 309 310 #define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH) 311 #define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN) 312 #define CONSOLE_ROW_FIRST (video_console_address) 313 #define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE) 314 #define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE) 315 #define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS) 316 #define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE) 317 318 /* Macros */ 319 #ifdef VIDEO_FB_LITTLE_ENDIAN 320 #define SWAP16(x) ((((x) & 0x00ff) << 8) | \ 321 ((x) >> 8) \ 322 ) 323 #define SWAP32(x) ((((x) & 0x000000ff) << 24) | \ 324 (((x) & 0x0000ff00) << 8) | \ 325 (((x) & 0x00ff0000) >> 8) | \ 326 (((x) & 0xff000000) >> 24) \ 327 ) 328 #define SHORTSWAP32(x) ((((x) & 0x000000ff) << 8) | \ 329 (((x) & 0x0000ff00) >> 8) | \ 330 (((x) & 0x00ff0000) << 8) | \ 331 (((x) & 0xff000000) >> 8) \ 332 ) 333 #else 334 #define SWAP16(x) (x) 335 #define SWAP32(x) (x) 336 #if defined(VIDEO_FB_16BPP_WORD_SWAP) 337 #define SHORTSWAP32(x) (((x) >> 16) | ((x) << 16)) 338 #else 339 #define SHORTSWAP32(x) (x) 340 #endif 341 #endif 342 343 #ifdef CONFIG_CONSOLE_EXTRA_INFO 344 /* 345 * setup a board string: type, speed, etc. 346 * 347 * line_number: location to place info string beside logo 348 * info: buffer for info string 349 */ 350 extern void video_get_info_str(int line_number, char *info); 351 #endif 352 353 DECLARE_GLOBAL_DATA_PTR; 354 355 /* Locals */ 356 static GraphicDevice *pGD; /* Pointer to Graphic array */ 357 358 static void *video_fb_address; /* frame buffer address */ 359 static void *video_console_address; /* console buffer start address */ 360 361 static int video_logo_height = VIDEO_LOGO_HEIGHT; 362 363 static int __maybe_unused cursor_state; 364 static int __maybe_unused old_col; 365 static int __maybe_unused old_row; 366 367 static int console_col; /* cursor col */ 368 static int console_row; /* cursor row */ 369 370 static u32 eorx, fgx, bgx; /* color pats */ 371 372 static int cfb_do_flush_cache; 373 374 #ifdef CONFIG_CFB_CONSOLE_ANSI 375 static char ansi_buf[10]; 376 static int ansi_buf_size; 377 static int ansi_colors_need_revert; 378 static int ansi_cursor_hidden; 379 #endif 380 381 static const int video_font_draw_table8[] = { 382 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, 383 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, 384 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, 385 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff 386 }; 387 388 static const int video_font_draw_table15[] = { 389 0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff 390 }; 391 392 static const int video_font_draw_table16[] = { 393 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff 394 }; 395 396 static const int video_font_draw_table24[16][3] = { 397 {0x00000000, 0x00000000, 0x00000000}, 398 {0x00000000, 0x00000000, 0x00ffffff}, 399 {0x00000000, 0x0000ffff, 0xff000000}, 400 {0x00000000, 0x0000ffff, 0xffffffff}, 401 {0x000000ff, 0xffff0000, 0x00000000}, 402 {0x000000ff, 0xffff0000, 0x00ffffff}, 403 {0x000000ff, 0xffffffff, 0xff000000}, 404 {0x000000ff, 0xffffffff, 0xffffffff}, 405 {0xffffff00, 0x00000000, 0x00000000}, 406 {0xffffff00, 0x00000000, 0x00ffffff}, 407 {0xffffff00, 0x0000ffff, 0xff000000}, 408 {0xffffff00, 0x0000ffff, 0xffffffff}, 409 {0xffffffff, 0xffff0000, 0x00000000}, 410 {0xffffffff, 0xffff0000, 0x00ffffff}, 411 {0xffffffff, 0xffffffff, 0xff000000}, 412 {0xffffffff, 0xffffffff, 0xffffffff} 413 }; 414 415 static const int video_font_draw_table32[16][4] = { 416 {0x00000000, 0x00000000, 0x00000000, 0x00000000}, 417 {0x00000000, 0x00000000, 0x00000000, 0x00ffffff}, 418 {0x00000000, 0x00000000, 0x00ffffff, 0x00000000}, 419 {0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff}, 420 {0x00000000, 0x00ffffff, 0x00000000, 0x00000000}, 421 {0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff}, 422 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000}, 423 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff}, 424 {0x00ffffff, 0x00000000, 0x00000000, 0x00000000}, 425 {0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff}, 426 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000}, 427 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff}, 428 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000}, 429 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff}, 430 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000}, 431 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff} 432 }; 433 434 static void video_drawchars(int xx, int yy, unsigned char *s, int count) 435 { 436 u8 *cdat, *dest, *dest0; 437 int rows, offset, c; 438 439 offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE; 440 dest0 = video_fb_address + offset; 441 442 switch (VIDEO_DATA_FORMAT) { 443 case GDF__8BIT_INDEX: 444 case GDF__8BIT_332RGB: 445 while (count--) { 446 c = *s; 447 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 448 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 449 rows--; dest += VIDEO_LINE_LEN) { 450 u8 bits = *cdat++; 451 452 ((u32 *) dest)[0] = 453 (video_font_draw_table8[bits >> 4] & 454 eorx) ^ bgx; 455 456 if (VIDEO_FONT_WIDTH == 4) 457 continue; 458 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 485 if (VIDEO_FONT_WIDTH == 4) 486 continue; 487 488 ((u32 *) dest)[2] = 489 SHORTSWAP32((video_font_draw_table15 490 [bits >> 2 & 3] & eorx) ^ 491 bgx); 492 ((u32 *) dest)[3] = 493 SHORTSWAP32((video_font_draw_table15 494 [bits & 3] & eorx) ^ 495 bgx); 496 } 497 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 498 s++; 499 } 500 break; 501 502 case GDF_16BIT_565RGB: 503 while (count--) { 504 c = *s; 505 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 506 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 507 rows--; dest += VIDEO_LINE_LEN) { 508 u8 bits = *cdat++; 509 510 ((u32 *) dest)[0] = 511 SHORTSWAP32((video_font_draw_table16 512 [bits >> 6] & eorx) ^ 513 bgx); 514 ((u32 *) dest)[1] = 515 SHORTSWAP32((video_font_draw_table16 516 [bits >> 4 & 3] & eorx) ^ 517 bgx); 518 519 if (VIDEO_FONT_WIDTH == 4) 520 continue; 521 522 ((u32 *) dest)[2] = 523 SHORTSWAP32((video_font_draw_table16 524 [bits >> 2 & 3] & eorx) ^ 525 bgx); 526 ((u32 *) dest)[3] = 527 SHORTSWAP32((video_font_draw_table16 528 [bits & 3] & eorx) ^ 529 bgx); 530 } 531 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 532 s++; 533 } 534 break; 535 536 case GDF_32BIT_X888RGB: 537 while (count--) { 538 c = *s; 539 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 540 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 541 rows--; dest += VIDEO_LINE_LEN) { 542 u8 bits = *cdat++; 543 544 ((u32 *) dest)[0] = 545 SWAP32((video_font_draw_table32 546 [bits >> 4][0] & eorx) ^ bgx); 547 ((u32 *) dest)[1] = 548 SWAP32((video_font_draw_table32 549 [bits >> 4][1] & eorx) ^ bgx); 550 ((u32 *) dest)[2] = 551 SWAP32((video_font_draw_table32 552 [bits >> 4][2] & eorx) ^ bgx); 553 ((u32 *) dest)[3] = 554 SWAP32((video_font_draw_table32 555 [bits >> 4][3] & eorx) ^ bgx); 556 557 558 if (VIDEO_FONT_WIDTH == 4) 559 continue; 560 561 ((u32 *) dest)[4] = 562 SWAP32((video_font_draw_table32 563 [bits & 15][0] & eorx) ^ bgx); 564 ((u32 *) dest)[5] = 565 SWAP32((video_font_draw_table32 566 [bits & 15][1] & eorx) ^ bgx); 567 ((u32 *) dest)[6] = 568 SWAP32((video_font_draw_table32 569 [bits & 15][2] & eorx) ^ bgx); 570 ((u32 *) dest)[7] = 571 SWAP32((video_font_draw_table32 572 [bits & 15][3] & eorx) ^ bgx); 573 } 574 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 575 s++; 576 } 577 break; 578 579 case GDF_24BIT_888RGB: 580 while (count--) { 581 c = *s; 582 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 583 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 584 rows--; dest += VIDEO_LINE_LEN) { 585 u8 bits = *cdat++; 586 587 ((u32 *) dest)[0] = 588 (video_font_draw_table24[bits >> 4][0] 589 & eorx) ^ bgx; 590 ((u32 *) dest)[1] = 591 (video_font_draw_table24[bits >> 4][1] 592 & eorx) ^ bgx; 593 ((u32 *) dest)[2] = 594 (video_font_draw_table24[bits >> 4][2] 595 & eorx) ^ bgx; 596 597 if (VIDEO_FONT_WIDTH == 4) 598 continue; 599 600 ((u32 *) dest)[3] = 601 (video_font_draw_table24[bits & 15][0] 602 & eorx) ^ bgx; 603 ((u32 *) dest)[4] = 604 (video_font_draw_table24[bits & 15][1] 605 & eorx) ^ bgx; 606 ((u32 *) dest)[5] = 607 (video_font_draw_table24[bits & 15][2] 608 & eorx) ^ bgx; 609 } 610 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 611 s++; 612 } 613 break; 614 } 615 } 616 617 static inline void video_drawstring(int xx, int yy, unsigned char *s) 618 { 619 video_drawchars(xx, yy, s, strlen((char *) s)); 620 } 621 622 static void video_putchar(int xx, int yy, unsigned char c) 623 { 624 video_drawchars(xx, yy + video_logo_height, &c, 1); 625 } 626 627 #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR) 628 static void video_set_cursor(void) 629 { 630 if (cursor_state) 631 console_cursor(0); 632 console_cursor(1); 633 } 634 635 static void video_invertchar(int xx, int yy) 636 { 637 int firstx = xx * VIDEO_PIXEL_SIZE; 638 int lastx = (xx + VIDEO_FONT_WIDTH) * VIDEO_PIXEL_SIZE; 639 int firsty = yy * VIDEO_LINE_LEN; 640 int lasty = (yy + VIDEO_FONT_HEIGHT) * VIDEO_LINE_LEN; 641 int x, y; 642 for (y = firsty; y < lasty; y += VIDEO_LINE_LEN) { 643 for (x = firstx; x < lastx; x++) { 644 u8 *dest = (u8 *)(video_fb_address) + x + y; 645 *dest = ~*dest; 646 } 647 } 648 } 649 650 void console_cursor(int state) 651 { 652 #ifdef CONFIG_CONSOLE_TIME 653 struct rtc_time tm; 654 char info[16]; 655 656 /* time update only if cursor is on (faster scroll) */ 657 if (state) { 658 rtc_get(&tm); 659 660 sprintf(info, " %02d:%02d:%02d ", tm.tm_hour, tm.tm_min, 661 tm.tm_sec); 662 video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH, 663 VIDEO_INFO_Y, (uchar *) info); 664 665 sprintf(info, "%02d.%02d.%04d", tm.tm_mday, tm.tm_mon, 666 tm.tm_year); 667 video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH, 668 VIDEO_INFO_Y + 1 * VIDEO_FONT_HEIGHT, 669 (uchar *) info); 670 } 671 #endif 672 673 if (cursor_state != state) { 674 if (cursor_state) { 675 /* turn off the cursor */ 676 video_invertchar(old_col * VIDEO_FONT_WIDTH, 677 old_row * VIDEO_FONT_HEIGHT + 678 video_logo_height); 679 } else { 680 /* turn off the cursor and record where it is */ 681 video_invertchar(console_col * VIDEO_FONT_WIDTH, 682 console_row * VIDEO_FONT_HEIGHT + 683 video_logo_height); 684 old_col = console_col; 685 old_row = console_row; 686 } 687 cursor_state = state; 688 } 689 if (cfb_do_flush_cache) 690 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE); 691 } 692 #endif 693 694 #ifndef VIDEO_HW_RECTFILL 695 static void memsetl(int *p, int c, int v) 696 { 697 while (c--) 698 *(p++) = v; 699 } 700 #endif 701 702 #ifndef VIDEO_HW_BITBLT 703 static void memcpyl(int *d, int *s, int c) 704 { 705 while (c--) 706 *(d++) = *(s++); 707 } 708 #endif 709 710 static void console_clear_line(int line, int begin, int end) 711 { 712 #ifdef VIDEO_HW_RECTFILL 713 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */ 714 VIDEO_FONT_WIDTH * begin, /* dest pos x */ 715 video_logo_height + 716 VIDEO_FONT_HEIGHT * line, /* dest pos y */ 717 VIDEO_FONT_WIDTH * (end - begin + 1), /* fr. width */ 718 VIDEO_FONT_HEIGHT, /* frame height */ 719 bgx /* fill color */ 720 ); 721 #else 722 if (begin == 0 && (end + 1) == CONSOLE_COLS) { 723 memsetl(CONSOLE_ROW_FIRST + 724 CONSOLE_ROW_SIZE * line, /* offset of row */ 725 CONSOLE_ROW_SIZE >> 2, /* length of row */ 726 bgx /* fill color */ 727 ); 728 } else { 729 void *offset; 730 int i, size; 731 732 offset = CONSOLE_ROW_FIRST + 733 CONSOLE_ROW_SIZE * line + /* offset of row */ 734 VIDEO_FONT_WIDTH * 735 VIDEO_PIXEL_SIZE * begin; /* offset of col */ 736 size = VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE * (end - begin + 1); 737 size >>= 2; /* length to end for memsetl() */ 738 /* fill at col offset of i'th line using bgx as fill color */ 739 for (i = 0; i < VIDEO_FONT_HEIGHT; i++) 740 memsetl(offset + i * VIDEO_LINE_LEN, size, bgx); 741 } 742 #endif 743 } 744 745 static void console_scrollup(void) 746 { 747 /* copy up rows ignoring the first one */ 748 749 #ifdef VIDEO_HW_BITBLT 750 video_hw_bitblt(VIDEO_PIXEL_SIZE, /* bytes per pixel */ 751 0, /* source pos x */ 752 video_logo_height + 753 VIDEO_FONT_HEIGHT, /* source pos y */ 754 0, /* dest pos x */ 755 video_logo_height, /* dest pos y */ 756 VIDEO_VISIBLE_COLS, /* frame width */ 757 VIDEO_VISIBLE_ROWS 758 - video_logo_height 759 - VIDEO_FONT_HEIGHT /* frame height */ 760 ); 761 #else 762 memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, 763 CONSOLE_SCROLL_SIZE >> 2); 764 #endif 765 /* clear the last one */ 766 console_clear_line(CONSOLE_ROWS - 1, 0, CONSOLE_COLS - 1); 767 } 768 769 static void console_back(void) 770 { 771 console_col--; 772 773 if (console_col < 0) { 774 console_col = CONSOLE_COLS - 1; 775 console_row--; 776 if (console_row < 0) 777 console_row = 0; 778 } 779 } 780 781 #ifdef CONFIG_CFB_CONSOLE_ANSI 782 783 static void console_clear(void) 784 { 785 #ifdef VIDEO_HW_RECTFILL 786 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */ 787 0, /* dest pos x */ 788 video_logo_height, /* dest pos y */ 789 VIDEO_VISIBLE_COLS, /* frame width */ 790 VIDEO_VISIBLE_ROWS, /* frame height */ 791 bgx /* fill color */ 792 ); 793 #else 794 memsetl(CONSOLE_ROW_FIRST, CONSOLE_SIZE, bgx); 795 #endif 796 } 797 798 static void console_cursor_fix(void) 799 { 800 if (console_row < 0) 801 console_row = 0; 802 if (console_row >= CONSOLE_ROWS) 803 console_row = CONSOLE_ROWS - 1; 804 if (console_col < 0) 805 console_col = 0; 806 if (console_col >= CONSOLE_COLS) 807 console_col = CONSOLE_COLS - 1; 808 } 809 810 static void console_cursor_up(int n) 811 { 812 console_row -= n; 813 console_cursor_fix(); 814 } 815 816 static void console_cursor_down(int n) 817 { 818 console_row += n; 819 console_cursor_fix(); 820 } 821 822 static void console_cursor_left(int n) 823 { 824 console_col -= n; 825 console_cursor_fix(); 826 } 827 828 static void console_cursor_right(int n) 829 { 830 console_col += n; 831 console_cursor_fix(); 832 } 833 834 static void console_cursor_set_position(int row, int col) 835 { 836 if (console_row != -1) 837 console_row = row; 838 if (console_col != -1) 839 console_col = col; 840 console_cursor_fix(); 841 } 842 843 static void console_previousline(int n) 844 { 845 /* FIXME: also scroll terminal ? */ 846 console_row -= n; 847 console_cursor_fix(); 848 } 849 850 static void console_swap_colors(void) 851 { 852 eorx = fgx; 853 fgx = bgx; 854 bgx = eorx; 855 eorx = fgx ^ bgx; 856 } 857 858 static inline int console_cursor_is_visible(void) 859 { 860 return !ansi_cursor_hidden; 861 } 862 #else 863 static inline int console_cursor_is_visible(void) 864 { 865 return 1; 866 } 867 #endif 868 869 static void console_newline(int n) 870 { 871 console_row += n; 872 console_col = 0; 873 874 /* Check if we need to scroll the terminal */ 875 if (console_row >= CONSOLE_ROWS) { 876 /* Scroll everything up */ 877 console_scrollup(); 878 879 /* Decrement row number */ 880 console_row = CONSOLE_ROWS - 1; 881 } 882 } 883 884 static void console_cr(void) 885 { 886 console_col = 0; 887 } 888 889 static void parse_putc(const char c) 890 { 891 static int nl = 1; 892 893 if (console_cursor_is_visible()) 894 CURSOR_OFF; 895 896 switch (c) { 897 case 13: /* back to first column */ 898 console_cr(); 899 break; 900 901 case '\n': /* next line */ 902 if (console_col || (!console_col && nl)) 903 console_newline(1); 904 nl = 1; 905 break; 906 907 case 9: /* tab 8 */ 908 console_col |= 0x0008; 909 console_col &= ~0x0007; 910 911 if (console_col >= CONSOLE_COLS) 912 console_newline(1); 913 break; 914 915 case 8: /* backspace */ 916 console_back(); 917 break; 918 919 case 7: /* bell */ 920 break; /* ignored */ 921 922 default: /* draw the char */ 923 video_putchar(console_col * VIDEO_FONT_WIDTH, 924 console_row * VIDEO_FONT_HEIGHT, c); 925 console_col++; 926 927 /* check for newline */ 928 if (console_col >= CONSOLE_COLS) { 929 console_newline(1); 930 nl = 0; 931 } 932 } 933 934 if (console_cursor_is_visible()) 935 CURSOR_SET; 936 } 937 938 void video_putc(const char c) 939 { 940 #ifdef CONFIG_CFB_CONSOLE_ANSI 941 int i; 942 943 if (c == 27) { 944 for (i = 0; i < ansi_buf_size; ++i) 945 parse_putc(ansi_buf[i]); 946 ansi_buf[0] = 27; 947 ansi_buf_size = 1; 948 return; 949 } 950 951 if (ansi_buf_size > 0) { 952 /* 953 * 0 - ESC 954 * 1 - [ 955 * 2 - num1 956 * 3 - .. 957 * 4 - ; 958 * 5 - num2 959 * 6 - .. 960 * - cchar 961 */ 962 int next = 0; 963 964 int flush = 0; 965 int fail = 0; 966 967 int num1 = 0; 968 int num2 = 0; 969 int cchar = 0; 970 971 ansi_buf[ansi_buf_size++] = c; 972 973 if (ansi_buf_size >= sizeof(ansi_buf)) 974 fail = 1; 975 976 for (i = 0; i < ansi_buf_size; ++i) { 977 if (fail) 978 break; 979 980 switch (next) { 981 case 0: 982 if (ansi_buf[i] == 27) 983 next = 1; 984 else 985 fail = 1; 986 break; 987 988 case 1: 989 if (ansi_buf[i] == '[') 990 next = 2; 991 else 992 fail = 1; 993 break; 994 995 case 2: 996 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { 997 num1 = ansi_buf[i]-'0'; 998 next = 3; 999 } else if (ansi_buf[i] != '?') { 1000 --i; 1001 num1 = 1; 1002 next = 4; 1003 } 1004 break; 1005 1006 case 3: 1007 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { 1008 num1 *= 10; 1009 num1 += ansi_buf[i]-'0'; 1010 } else { 1011 --i; 1012 next = 4; 1013 } 1014 break; 1015 1016 case 4: 1017 if (ansi_buf[i] != ';') { 1018 --i; 1019 next = 7; 1020 } else 1021 next = 5; 1022 break; 1023 1024 case 5: 1025 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { 1026 num2 = ansi_buf[i]-'0'; 1027 next = 6; 1028 } else 1029 fail = 1; 1030 break; 1031 1032 case 6: 1033 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { 1034 num2 *= 10; 1035 num2 += ansi_buf[i]-'0'; 1036 } else { 1037 --i; 1038 next = 7; 1039 } 1040 break; 1041 1042 case 7: 1043 if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H') 1044 || ansi_buf[i] == 'J' 1045 || ansi_buf[i] == 'K' 1046 || ansi_buf[i] == 'h' 1047 || ansi_buf[i] == 'l' 1048 || ansi_buf[i] == 'm') { 1049 cchar = ansi_buf[i]; 1050 flush = 1; 1051 } else 1052 fail = 1; 1053 break; 1054 } 1055 } 1056 1057 if (fail) { 1058 for (i = 0; i < ansi_buf_size; ++i) 1059 parse_putc(ansi_buf[i]); 1060 ansi_buf_size = 0; 1061 return; 1062 } 1063 1064 if (flush) { 1065 if (!ansi_cursor_hidden) 1066 CURSOR_OFF; 1067 ansi_buf_size = 0; 1068 switch (cchar) { 1069 case 'A': 1070 /* move cursor num1 rows up */ 1071 console_cursor_up(num1); 1072 break; 1073 case 'B': 1074 /* move cursor num1 rows down */ 1075 console_cursor_down(num1); 1076 break; 1077 case 'C': 1078 /* move cursor num1 columns forward */ 1079 console_cursor_right(num1); 1080 break; 1081 case 'D': 1082 /* move cursor num1 columns back */ 1083 console_cursor_left(num1); 1084 break; 1085 case 'E': 1086 /* move cursor num1 rows up at begin of row */ 1087 console_previousline(num1); 1088 break; 1089 case 'F': 1090 /* move cursor num1 rows down at begin of row */ 1091 console_newline(num1); 1092 break; 1093 case 'G': 1094 /* move cursor to column num1 */ 1095 console_cursor_set_position(-1, num1-1); 1096 break; 1097 case 'H': 1098 /* move cursor to row num1, column num2 */ 1099 console_cursor_set_position(num1-1, num2-1); 1100 break; 1101 case 'J': 1102 /* clear console and move cursor to 0, 0 */ 1103 console_clear(); 1104 console_cursor_set_position(0, 0); 1105 break; 1106 case 'K': 1107 /* clear line */ 1108 if (num1 == 0) 1109 console_clear_line(console_row, 1110 console_col, 1111 CONSOLE_COLS-1); 1112 else if (num1 == 1) 1113 console_clear_line(console_row, 1114 0, console_col); 1115 else 1116 console_clear_line(console_row, 1117 0, CONSOLE_COLS-1); 1118 break; 1119 case 'h': 1120 ansi_cursor_hidden = 0; 1121 break; 1122 case 'l': 1123 ansi_cursor_hidden = 1; 1124 break; 1125 case 'm': 1126 if (num1 == 0) { /* reset swapped colors */ 1127 if (ansi_colors_need_revert) { 1128 console_swap_colors(); 1129 ansi_colors_need_revert = 0; 1130 } 1131 } else if (num1 == 7) { /* once swap colors */ 1132 if (!ansi_colors_need_revert) { 1133 console_swap_colors(); 1134 ansi_colors_need_revert = 1; 1135 } 1136 } 1137 break; 1138 } 1139 if (!ansi_cursor_hidden) 1140 CURSOR_SET; 1141 } 1142 } else { 1143 parse_putc(c); 1144 } 1145 #else 1146 parse_putc(c); 1147 #endif 1148 if (cfb_do_flush_cache) 1149 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE); 1150 } 1151 1152 void video_puts(const char *s) 1153 { 1154 int count = strlen(s); 1155 1156 while (count--) 1157 video_putc(*s++); 1158 } 1159 1160 /* 1161 * Do not enforce drivers (or board code) to provide empty 1162 * video_set_lut() if they do not support 8 bpp format. 1163 * Implement weak default function instead. 1164 */ 1165 void __video_set_lut(unsigned int index, unsigned char r, 1166 unsigned char g, unsigned char b) 1167 { 1168 } 1169 1170 void video_set_lut(unsigned int, unsigned char, unsigned char, unsigned char) 1171 __attribute__ ((weak, alias("__video_set_lut"))); 1172 1173 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) 1174 1175 #define FILL_8BIT_332RGB(r,g,b) { \ 1176 *fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6); \ 1177 fb ++; \ 1178 } 1179 1180 #define FILL_15BIT_555RGB(r,g,b) { \ 1181 *(unsigned short *)fb = \ 1182 SWAP16((unsigned short)(((r>>3)<<10) | \ 1183 ((g>>3)<<5) | \ 1184 (b>>3))); \ 1185 fb += 2; \ 1186 } 1187 1188 #define FILL_16BIT_565RGB(r,g,b) { \ 1189 *(unsigned short *)fb = \ 1190 SWAP16((unsigned short)((((r)>>3)<<11)| \ 1191 (((g)>>2)<<5) | \ 1192 ((b)>>3))); \ 1193 fb += 2; \ 1194 } 1195 1196 #define FILL_32BIT_X888RGB(r,g,b) { \ 1197 *(unsigned long *)fb = \ 1198 SWAP32((unsigned long)(((r<<16) | \ 1199 (g<<8) | \ 1200 b))); \ 1201 fb += 4; \ 1202 } 1203 1204 #ifdef VIDEO_FB_LITTLE_ENDIAN 1205 #define FILL_24BIT_888RGB(r,g,b) { \ 1206 fb[0] = b; \ 1207 fb[1] = g; \ 1208 fb[2] = r; \ 1209 fb += 3; \ 1210 } 1211 #else 1212 #define FILL_24BIT_888RGB(r,g,b) { \ 1213 fb[0] = r; \ 1214 fb[1] = g; \ 1215 fb[2] = b; \ 1216 fb += 3; \ 1217 } 1218 #endif 1219 1220 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1221 static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b) 1222 { 1223 ushort *dst = (ushort *) fb; 1224 ushort color = (ushort) (((r >> 3) << 10) | 1225 ((g >> 3) << 5) | 1226 (b >> 3)); 1227 if (x & 1) 1228 *(--dst) = color; 1229 else 1230 *(++dst) = color; 1231 } 1232 #endif 1233 1234 /* 1235 * RLE8 bitmap support 1236 */ 1237 1238 #ifdef CONFIG_VIDEO_BMP_RLE8 1239 /* Pre-calculated color table entry */ 1240 struct palette { 1241 union { 1242 unsigned short w; /* word */ 1243 unsigned int dw; /* double word */ 1244 } ce; /* color entry */ 1245 }; 1246 1247 /* 1248 * Helper to draw encoded/unencoded run. 1249 */ 1250 static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p, 1251 int cnt, int enc) 1252 { 1253 ulong addr = (ulong) *fb; 1254 int *off; 1255 int enc_off = 1; 1256 int i; 1257 1258 /* 1259 * Setup offset of the color index in the bitmap. 1260 * Color index of encoded run is at offset 1. 1261 */ 1262 off = enc ? &enc_off : &i; 1263 1264 switch (VIDEO_DATA_FORMAT) { 1265 case GDF__8BIT_INDEX: 1266 for (i = 0; i < cnt; i++) 1267 *(unsigned char *) addr++ = bm[*off]; 1268 break; 1269 case GDF_15BIT_555RGB: 1270 case GDF_16BIT_565RGB: 1271 /* differences handled while pre-calculating palette */ 1272 for (i = 0; i < cnt; i++) { 1273 *(unsigned short *) addr = p[bm[*off]].ce.w; 1274 addr += 2; 1275 } 1276 break; 1277 case GDF_32BIT_X888RGB: 1278 for (i = 0; i < cnt; i++) { 1279 *(unsigned long *) addr = p[bm[*off]].ce.dw; 1280 addr += 4; 1281 } 1282 break; 1283 } 1284 *fb = (uchar *) addr; /* return modified address */ 1285 } 1286 1287 static int display_rle8_bitmap(bmp_image_t *img, int xoff, int yoff, 1288 int width, int height) 1289 { 1290 unsigned char *bm; 1291 unsigned char *fbp; 1292 unsigned int cnt, runlen; 1293 int decode = 1; 1294 int x, y, bpp, i, ncolors; 1295 struct palette p[256]; 1296 bmp_color_table_entry_t cte; 1297 int green_shift, red_off; 1298 int limit = VIDEO_COLS * VIDEO_ROWS; 1299 int pixels = 0; 1300 1301 x = 0; 1302 y = __le32_to_cpu(img->header.height) - 1; 1303 ncolors = __le32_to_cpu(img->header.colors_used); 1304 bpp = VIDEO_PIXEL_SIZE; 1305 fbp = (unsigned char *) ((unsigned int) video_fb_address + 1306 (((y + yoff) * VIDEO_COLS) + xoff) * bpp); 1307 1308 bm = (uchar *) img + __le32_to_cpu(img->header.data_offset); 1309 1310 /* pre-calculate and setup palette */ 1311 switch (VIDEO_DATA_FORMAT) { 1312 case GDF__8BIT_INDEX: 1313 for (i = 0; i < ncolors; i++) { 1314 cte = img->color_table[i]; 1315 video_set_lut(i, cte.red, cte.green, cte.blue); 1316 } 1317 break; 1318 case GDF_15BIT_555RGB: 1319 case GDF_16BIT_565RGB: 1320 if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) { 1321 green_shift = 3; 1322 red_off = 10; 1323 } else { 1324 green_shift = 2; 1325 red_off = 11; 1326 } 1327 for (i = 0; i < ncolors; i++) { 1328 cte = img->color_table[i]; 1329 p[i].ce.w = SWAP16((unsigned short) 1330 (((cte.red >> 3) << red_off) | 1331 ((cte.green >> green_shift) << 5) | 1332 cte.blue >> 3)); 1333 } 1334 break; 1335 case GDF_32BIT_X888RGB: 1336 for (i = 0; i < ncolors; i++) { 1337 cte = img->color_table[i]; 1338 p[i].ce.dw = SWAP32((cte.red << 16) | 1339 (cte.green << 8) | 1340 cte.blue); 1341 } 1342 break; 1343 default: 1344 printf("RLE Bitmap unsupported in video mode 0x%x\n", 1345 VIDEO_DATA_FORMAT); 1346 return -1; 1347 } 1348 1349 while (decode) { 1350 switch (bm[0]) { 1351 case 0: 1352 switch (bm[1]) { 1353 case 0: 1354 /* scan line end marker */ 1355 bm += 2; 1356 x = 0; 1357 y--; 1358 fbp = (unsigned char *) 1359 ((unsigned int) video_fb_address + 1360 (((y + yoff) * VIDEO_COLS) + 1361 xoff) * bpp); 1362 continue; 1363 case 1: 1364 /* end of bitmap data marker */ 1365 decode = 0; 1366 break; 1367 case 2: 1368 /* run offset marker */ 1369 x += bm[2]; 1370 y -= bm[3]; 1371 fbp = (unsigned char *) 1372 ((unsigned int) video_fb_address + 1373 (((y + yoff) * VIDEO_COLS) + 1374 x + xoff) * bpp); 1375 bm += 4; 1376 break; 1377 default: 1378 /* unencoded run */ 1379 cnt = bm[1]; 1380 runlen = cnt; 1381 pixels += cnt; 1382 if (pixels > limit) 1383 goto error; 1384 1385 bm += 2; 1386 if (y < height) { 1387 if (x >= width) { 1388 x += runlen; 1389 goto next_run; 1390 } 1391 if (x + runlen > width) 1392 cnt = width - x; 1393 draw_bitmap(&fbp, bm, p, cnt, 0); 1394 x += runlen; 1395 } 1396 next_run: 1397 bm += runlen; 1398 if (runlen & 1) 1399 bm++; /* 0 padding if length is odd */ 1400 } 1401 break; 1402 default: 1403 /* encoded run */ 1404 cnt = bm[0]; 1405 runlen = cnt; 1406 pixels += cnt; 1407 if (pixels > limit) 1408 goto error; 1409 1410 if (y < height) { /* only draw into visible area */ 1411 if (x >= width) { 1412 x += runlen; 1413 bm += 2; 1414 continue; 1415 } 1416 if (x + runlen > width) 1417 cnt = width - x; 1418 draw_bitmap(&fbp, bm, p, cnt, 1); 1419 x += runlen; 1420 } 1421 bm += 2; 1422 break; 1423 } 1424 } 1425 return 0; 1426 error: 1427 printf("Error: Too much encoded pixel data, validate your bitmap\n"); 1428 return -1; 1429 } 1430 #endif 1431 1432 /* 1433 * Display the BMP file located at address bmp_image. 1434 */ 1435 int video_display_bitmap(ulong bmp_image, int x, int y) 1436 { 1437 ushort xcount, ycount; 1438 uchar *fb; 1439 bmp_image_t *bmp = (bmp_image_t *) bmp_image; 1440 uchar *bmap; 1441 ushort padded_line; 1442 unsigned long width, height, bpp; 1443 unsigned colors; 1444 unsigned long compression; 1445 bmp_color_table_entry_t cte; 1446 1447 #ifdef CONFIG_VIDEO_BMP_GZIP 1448 unsigned char *dst = NULL; 1449 ulong len; 1450 #endif 1451 1452 WATCHDOG_RESET(); 1453 1454 if (!((bmp->header.signature[0] == 'B') && 1455 (bmp->header.signature[1] == 'M'))) { 1456 1457 #ifdef CONFIG_VIDEO_BMP_GZIP 1458 /* 1459 * Could be a gzipped bmp image, try to decrompress... 1460 */ 1461 len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE; 1462 dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE); 1463 if (dst == NULL) { 1464 printf("Error: malloc in gunzip failed!\n"); 1465 return 1; 1466 } 1467 if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, 1468 (uchar *) bmp_image, 1469 &len) != 0) { 1470 printf("Error: no valid bmp or bmp.gz image at %lx\n", 1471 bmp_image); 1472 free(dst); 1473 return 1; 1474 } 1475 if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) { 1476 printf("Image could be truncated " 1477 "(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n"); 1478 } 1479 1480 /* 1481 * Set addr to decompressed image 1482 */ 1483 bmp = (bmp_image_t *) dst; 1484 1485 if (!((bmp->header.signature[0] == 'B') && 1486 (bmp->header.signature[1] == 'M'))) { 1487 printf("Error: no valid bmp.gz image at %lx\n", 1488 bmp_image); 1489 free(dst); 1490 return 1; 1491 } 1492 #else 1493 printf("Error: no valid bmp image at %lx\n", bmp_image); 1494 return 1; 1495 #endif /* CONFIG_VIDEO_BMP_GZIP */ 1496 } 1497 1498 width = le32_to_cpu(bmp->header.width); 1499 height = le32_to_cpu(bmp->header.height); 1500 bpp = le16_to_cpu(bmp->header.bit_count); 1501 colors = le32_to_cpu(bmp->header.colors_used); 1502 compression = le32_to_cpu(bmp->header.compression); 1503 1504 debug("Display-bmp: %ld x %ld with %d colors\n", 1505 width, height, colors); 1506 1507 if (compression != BMP_BI_RGB 1508 #ifdef CONFIG_VIDEO_BMP_RLE8 1509 && compression != BMP_BI_RLE8 1510 #endif 1511 ) { 1512 printf("Error: compression type %ld not supported\n", 1513 compression); 1514 #ifdef CONFIG_VIDEO_BMP_GZIP 1515 if (dst) 1516 free(dst); 1517 #endif 1518 return 1; 1519 } 1520 1521 padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3; 1522 1523 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 1524 if (x == BMP_ALIGN_CENTER) 1525 x = max(0, (VIDEO_VISIBLE_COLS - width) / 2); 1526 else if (x < 0) 1527 x = max(0, VIDEO_VISIBLE_COLS - width + x + 1); 1528 1529 if (y == BMP_ALIGN_CENTER) 1530 y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2); 1531 else if (y < 0) 1532 y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1); 1533 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ 1534 1535 /* 1536 * Just ignore elements which are completely beyond screen 1537 * dimensions. 1538 */ 1539 if ((x >= VIDEO_VISIBLE_COLS) || (y >= VIDEO_VISIBLE_ROWS)) 1540 return 0; 1541 1542 if ((x + width) > VIDEO_VISIBLE_COLS) 1543 width = VIDEO_VISIBLE_COLS - x; 1544 if ((y + height) > VIDEO_VISIBLE_ROWS) 1545 height = VIDEO_VISIBLE_ROWS - y; 1546 1547 bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset); 1548 fb = (uchar *) (video_fb_address + 1549 ((y + height - 1) * VIDEO_COLS * VIDEO_PIXEL_SIZE) + 1550 x * VIDEO_PIXEL_SIZE); 1551 1552 #ifdef CONFIG_VIDEO_BMP_RLE8 1553 if (compression == BMP_BI_RLE8) { 1554 return display_rle8_bitmap(bmp, x, y, width, height); 1555 } 1556 #endif 1557 1558 /* We handle only 4, 8, or 24 bpp bitmaps */ 1559 switch (le16_to_cpu(bmp->header.bit_count)) { 1560 case 4: 1561 padded_line -= width / 2; 1562 ycount = height; 1563 1564 switch (VIDEO_DATA_FORMAT) { 1565 case GDF_32BIT_X888RGB: 1566 while (ycount--) { 1567 WATCHDOG_RESET(); 1568 /* 1569 * Don't assume that 'width' is an 1570 * even number 1571 */ 1572 for (xcount = 0; xcount < width; xcount++) { 1573 uchar idx; 1574 1575 if (xcount & 1) { 1576 idx = *bmap & 0xF; 1577 bmap++; 1578 } else 1579 idx = *bmap >> 4; 1580 cte = bmp->color_table[idx]; 1581 FILL_32BIT_X888RGB(cte.red, cte.green, 1582 cte.blue); 1583 } 1584 bmap += padded_line; 1585 fb -= (VIDEO_VISIBLE_COLS + width) * 1586 VIDEO_PIXEL_SIZE; 1587 } 1588 break; 1589 default: 1590 puts("4bpp bitmap unsupported with current " 1591 "video mode\n"); 1592 break; 1593 } 1594 break; 1595 1596 case 8: 1597 padded_line -= width; 1598 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) { 1599 /* Copy colormap */ 1600 for (xcount = 0; xcount < colors; ++xcount) { 1601 cte = bmp->color_table[xcount]; 1602 video_set_lut(xcount, cte.red, cte.green, 1603 cte.blue); 1604 } 1605 } 1606 ycount = height; 1607 switch (VIDEO_DATA_FORMAT) { 1608 case GDF__8BIT_INDEX: 1609 while (ycount--) { 1610 WATCHDOG_RESET(); 1611 xcount = width; 1612 while (xcount--) { 1613 *fb++ = *bmap++; 1614 } 1615 bmap += padded_line; 1616 fb -= (VIDEO_VISIBLE_COLS + width) * 1617 VIDEO_PIXEL_SIZE; 1618 } 1619 break; 1620 case GDF__8BIT_332RGB: 1621 while (ycount--) { 1622 WATCHDOG_RESET(); 1623 xcount = width; 1624 while (xcount--) { 1625 cte = bmp->color_table[*bmap++]; 1626 FILL_8BIT_332RGB(cte.red, cte.green, 1627 cte.blue); 1628 } 1629 bmap += padded_line; 1630 fb -= (VIDEO_VISIBLE_COLS + width) * 1631 VIDEO_PIXEL_SIZE; 1632 } 1633 break; 1634 case GDF_15BIT_555RGB: 1635 while (ycount--) { 1636 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1637 int xpos = x; 1638 #endif 1639 WATCHDOG_RESET(); 1640 xcount = width; 1641 while (xcount--) { 1642 cte = bmp->color_table[*bmap++]; 1643 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1644 fill_555rgb_pswap(fb, xpos++, cte.red, 1645 cte.green, 1646 cte.blue); 1647 fb += 2; 1648 #else 1649 FILL_15BIT_555RGB(cte.red, cte.green, 1650 cte.blue); 1651 #endif 1652 } 1653 bmap += padded_line; 1654 fb -= (VIDEO_VISIBLE_COLS + width) * 1655 VIDEO_PIXEL_SIZE; 1656 } 1657 break; 1658 case GDF_16BIT_565RGB: 1659 while (ycount--) { 1660 WATCHDOG_RESET(); 1661 xcount = width; 1662 while (xcount--) { 1663 cte = bmp->color_table[*bmap++]; 1664 FILL_16BIT_565RGB(cte.red, cte.green, 1665 cte.blue); 1666 } 1667 bmap += padded_line; 1668 fb -= (VIDEO_VISIBLE_COLS + width) * 1669 VIDEO_PIXEL_SIZE; 1670 } 1671 break; 1672 case GDF_32BIT_X888RGB: 1673 while (ycount--) { 1674 WATCHDOG_RESET(); 1675 xcount = width; 1676 while (xcount--) { 1677 cte = bmp->color_table[*bmap++]; 1678 FILL_32BIT_X888RGB(cte.red, cte.green, 1679 cte.blue); 1680 } 1681 bmap += padded_line; 1682 fb -= (VIDEO_VISIBLE_COLS + width) * 1683 VIDEO_PIXEL_SIZE; 1684 } 1685 break; 1686 case GDF_24BIT_888RGB: 1687 while (ycount--) { 1688 WATCHDOG_RESET(); 1689 xcount = width; 1690 while (xcount--) { 1691 cte = bmp->color_table[*bmap++]; 1692 FILL_24BIT_888RGB(cte.red, cte.green, 1693 cte.blue); 1694 } 1695 bmap += padded_line; 1696 fb -= (VIDEO_VISIBLE_COLS + width) * 1697 VIDEO_PIXEL_SIZE; 1698 } 1699 break; 1700 } 1701 break; 1702 case 24: 1703 padded_line -= 3 * width; 1704 ycount = height; 1705 switch (VIDEO_DATA_FORMAT) { 1706 case GDF__8BIT_332RGB: 1707 while (ycount--) { 1708 WATCHDOG_RESET(); 1709 xcount = width; 1710 while (xcount--) { 1711 FILL_8BIT_332RGB(bmap[2], bmap[1], 1712 bmap[0]); 1713 bmap += 3; 1714 } 1715 bmap += padded_line; 1716 fb -= (VIDEO_VISIBLE_COLS + width) * 1717 VIDEO_PIXEL_SIZE; 1718 } 1719 break; 1720 case GDF_15BIT_555RGB: 1721 while (ycount--) { 1722 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1723 int xpos = x; 1724 #endif 1725 WATCHDOG_RESET(); 1726 xcount = width; 1727 while (xcount--) { 1728 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1729 fill_555rgb_pswap(fb, xpos++, bmap[2], 1730 bmap[1], bmap[0]); 1731 fb += 2; 1732 #else 1733 FILL_15BIT_555RGB(bmap[2], bmap[1], 1734 bmap[0]); 1735 #endif 1736 bmap += 3; 1737 } 1738 bmap += padded_line; 1739 fb -= (VIDEO_VISIBLE_COLS + width) * 1740 VIDEO_PIXEL_SIZE; 1741 } 1742 break; 1743 case GDF_16BIT_565RGB: 1744 while (ycount--) { 1745 WATCHDOG_RESET(); 1746 xcount = width; 1747 while (xcount--) { 1748 FILL_16BIT_565RGB(bmap[2], bmap[1], 1749 bmap[0]); 1750 bmap += 3; 1751 } 1752 bmap += padded_line; 1753 fb -= (VIDEO_VISIBLE_COLS + width) * 1754 VIDEO_PIXEL_SIZE; 1755 } 1756 break; 1757 case GDF_32BIT_X888RGB: 1758 while (ycount--) { 1759 WATCHDOG_RESET(); 1760 xcount = width; 1761 while (xcount--) { 1762 FILL_32BIT_X888RGB(bmap[2], bmap[1], 1763 bmap[0]); 1764 bmap += 3; 1765 } 1766 bmap += padded_line; 1767 fb -= (VIDEO_VISIBLE_COLS + width) * 1768 VIDEO_PIXEL_SIZE; 1769 } 1770 break; 1771 case GDF_24BIT_888RGB: 1772 while (ycount--) { 1773 WATCHDOG_RESET(); 1774 xcount = width; 1775 while (xcount--) { 1776 FILL_24BIT_888RGB(bmap[2], bmap[1], 1777 bmap[0]); 1778 bmap += 3; 1779 } 1780 bmap += padded_line; 1781 fb -= (VIDEO_VISIBLE_COLS + width) * 1782 VIDEO_PIXEL_SIZE; 1783 } 1784 break; 1785 default: 1786 printf("Error: 24 bits/pixel bitmap incompatible " 1787 "with current video mode\n"); 1788 break; 1789 } 1790 break; 1791 default: 1792 printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n", 1793 le16_to_cpu(bmp->header.bit_count)); 1794 break; 1795 } 1796 1797 #ifdef CONFIG_VIDEO_BMP_GZIP 1798 if (dst) { 1799 free(dst); 1800 } 1801 #endif 1802 1803 if (cfb_do_flush_cache) 1804 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE); 1805 return (0); 1806 } 1807 #endif 1808 1809 1810 #ifdef CONFIG_VIDEO_LOGO 1811 static int video_logo_xpos; 1812 static int video_logo_ypos; 1813 1814 static void plot_logo_or_black(void *screen, int width, int x, int y, \ 1815 int black); 1816 1817 static void logo_plot(void *screen, int width, int x, int y) 1818 { 1819 plot_logo_or_black(screen, width, x, y, 0); 1820 } 1821 1822 static void logo_black(void) 1823 { 1824 plot_logo_or_black(video_fb_address, \ 1825 VIDEO_COLS, \ 1826 video_logo_xpos, \ 1827 video_logo_ypos, \ 1828 1); 1829 } 1830 1831 static int do_clrlogo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 1832 { 1833 if (argc != 1) 1834 return cmd_usage(cmdtp); 1835 1836 logo_black(); 1837 return 0; 1838 } 1839 1840 U_BOOT_CMD( 1841 clrlogo, 1, 0, do_clrlogo, 1842 "fill the boot logo area with black", 1843 " " 1844 ); 1845 1846 static void plot_logo_or_black(void *screen, int width, int x, int y, int black) 1847 { 1848 1849 int xcount, i; 1850 int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE; 1851 int ycount = video_logo_height; 1852 unsigned char r, g, b, *logo_red, *logo_blue, *logo_green; 1853 unsigned char *source; 1854 unsigned char *dest; 1855 1856 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 1857 if (x == BMP_ALIGN_CENTER) 1858 x = max(0, (VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2); 1859 else if (x < 0) 1860 x = max(0, VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1); 1861 1862 if (y == BMP_ALIGN_CENTER) 1863 y = max(0, (VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2); 1864 else if (y < 0) 1865 y = max(0, VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1); 1866 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ 1867 1868 dest = (unsigned char *)screen + (y * width + x) * VIDEO_PIXEL_SIZE; 1869 1870 #ifdef CONFIG_VIDEO_BMP_LOGO 1871 source = bmp_logo_bitmap; 1872 1873 /* Allocate temporary space for computing colormap */ 1874 logo_red = malloc(BMP_LOGO_COLORS); 1875 logo_green = malloc(BMP_LOGO_COLORS); 1876 logo_blue = malloc(BMP_LOGO_COLORS); 1877 /* Compute color map */ 1878 for (i = 0; i < VIDEO_LOGO_COLORS; i++) { 1879 logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4; 1880 logo_green[i] = (bmp_logo_palette[i] & 0x00f0); 1881 logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4; 1882 } 1883 #else 1884 source = linux_logo; 1885 logo_red = linux_logo_red; 1886 logo_green = linux_logo_green; 1887 logo_blue = linux_logo_blue; 1888 #endif 1889 1890 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) { 1891 for (i = 0; i < VIDEO_LOGO_COLORS; i++) { 1892 video_set_lut(i + VIDEO_LOGO_LUT_OFFSET, 1893 logo_red[i], logo_green[i], 1894 logo_blue[i]); 1895 } 1896 } 1897 1898 while (ycount--) { 1899 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1900 int xpos = x; 1901 #endif 1902 xcount = VIDEO_LOGO_WIDTH; 1903 while (xcount--) { 1904 if (black) { 1905 r = 0x00; 1906 g = 0x00; 1907 b = 0x00; 1908 } else { 1909 r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET]; 1910 g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET]; 1911 b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET]; 1912 } 1913 1914 switch (VIDEO_DATA_FORMAT) { 1915 case GDF__8BIT_INDEX: 1916 *dest = *source; 1917 break; 1918 case GDF__8BIT_332RGB: 1919 *dest = ((r >> 5) << 5) | 1920 ((g >> 5) << 2) | 1921 (b >> 6); 1922 break; 1923 case GDF_15BIT_555RGB: 1924 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1925 fill_555rgb_pswap(dest, xpos++, r, g, b); 1926 #else 1927 *(unsigned short *) dest = 1928 SWAP16((unsigned short) ( 1929 ((r >> 3) << 10) | 1930 ((g >> 3) << 5) | 1931 (b >> 3))); 1932 #endif 1933 break; 1934 case GDF_16BIT_565RGB: 1935 *(unsigned short *) dest = 1936 SWAP16((unsigned short) ( 1937 ((r >> 3) << 11) | 1938 ((g >> 2) << 5) | 1939 (b >> 3))); 1940 break; 1941 case GDF_32BIT_X888RGB: 1942 *(unsigned long *) dest = 1943 SWAP32((unsigned long) ( 1944 (r << 16) | 1945 (g << 8) | 1946 b)); 1947 break; 1948 case GDF_24BIT_888RGB: 1949 #ifdef VIDEO_FB_LITTLE_ENDIAN 1950 dest[0] = b; 1951 dest[1] = g; 1952 dest[2] = r; 1953 #else 1954 dest[0] = r; 1955 dest[1] = g; 1956 dest[2] = b; 1957 #endif 1958 break; 1959 } 1960 source++; 1961 dest += VIDEO_PIXEL_SIZE; 1962 } 1963 dest += skip; 1964 } 1965 #ifdef CONFIG_VIDEO_BMP_LOGO 1966 free(logo_red); 1967 free(logo_green); 1968 free(logo_blue); 1969 #endif 1970 } 1971 1972 static void *video_logo(void) 1973 { 1974 char info[128]; 1975 int space, len; 1976 __maybe_unused int y_off = 0; 1977 __maybe_unused ulong addr; 1978 __maybe_unused char *s; 1979 1980 splash_get_pos(&video_logo_xpos, &video_logo_ypos); 1981 1982 #ifdef CONFIG_SPLASH_SCREEN 1983 s = getenv("splashimage"); 1984 if (s != NULL) { 1985 splash_screen_prepare(); 1986 addr = simple_strtoul(s, NULL, 16); 1987 1988 if (video_display_bitmap(addr, 1989 video_logo_xpos, 1990 video_logo_ypos) == 0) { 1991 video_logo_height = 0; 1992 return ((void *) (video_fb_address)); 1993 } 1994 } 1995 #endif /* CONFIG_SPLASH_SCREEN */ 1996 1997 logo_plot(video_fb_address, VIDEO_COLS, 1998 video_logo_xpos, video_logo_ypos); 1999 2000 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 2001 /* 2002 * when using splashpos for video_logo, skip any info 2003 * output on video console if the logo is not at 0,0 2004 */ 2005 if (video_logo_xpos || video_logo_ypos) { 2006 /* 2007 * video_logo_height is used in text and cursor offset 2008 * calculations. Since the console is below the logo, 2009 * we need to adjust the logo height 2010 */ 2011 if (video_logo_ypos == BMP_ALIGN_CENTER) 2012 video_logo_height += max(0, (VIDEO_VISIBLE_ROWS - \ 2013 VIDEO_LOGO_HEIGHT) / 2); 2014 else if (video_logo_ypos > 0) 2015 video_logo_height += video_logo_ypos; 2016 2017 return video_fb_address + video_logo_height * VIDEO_LINE_LEN; 2018 } 2019 #endif 2020 2021 sprintf(info, " %s", version_string); 2022 2023 space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH; 2024 len = strlen(info); 2025 2026 if (len > space) { 2027 video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y, 2028 (uchar *) info, space); 2029 video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH, 2030 VIDEO_INFO_Y + VIDEO_FONT_HEIGHT, 2031 (uchar *) info + space, len - space); 2032 y_off = 1; 2033 } else 2034 video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info); 2035 2036 #ifdef CONFIG_CONSOLE_EXTRA_INFO 2037 { 2038 int i, n = 2039 ((video_logo_height - 2040 VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT); 2041 2042 for (i = 1; i < n; i++) { 2043 video_get_info_str(i, info); 2044 if (!*info) 2045 continue; 2046 2047 len = strlen(info); 2048 if (len > space) { 2049 video_drawchars(VIDEO_INFO_X, 2050 VIDEO_INFO_Y + 2051 (i + y_off) * 2052 VIDEO_FONT_HEIGHT, 2053 (uchar *) info, space); 2054 y_off++; 2055 video_drawchars(VIDEO_INFO_X + 2056 VIDEO_FONT_WIDTH, 2057 VIDEO_INFO_Y + 2058 (i + y_off) * 2059 VIDEO_FONT_HEIGHT, 2060 (uchar *) info + space, 2061 len - space); 2062 } else { 2063 video_drawstring(VIDEO_INFO_X, 2064 VIDEO_INFO_Y + 2065 (i + y_off) * 2066 VIDEO_FONT_HEIGHT, 2067 (uchar *) info); 2068 } 2069 } 2070 } 2071 #endif 2072 2073 return (video_fb_address + video_logo_height * VIDEO_LINE_LEN); 2074 } 2075 #endif 2076 2077 static int cfb_fb_is_in_dram(void) 2078 { 2079 bd_t *bd = gd->bd; 2080 #if defined(CONFIG_ARM) || defined(CONFIG_AVR32) || defined(COFNIG_NDS32) || \ 2081 defined(CONFIG_SANDBOX) || defined(CONFIG_X86) 2082 ulong start, end; 2083 int i; 2084 2085 for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) { 2086 start = bd->bi_dram[i].start; 2087 end = bd->bi_dram[i].start + bd->bi_dram[i].size - 1; 2088 if ((ulong)video_fb_address >= start && 2089 (ulong)video_fb_address < end) 2090 return 1; 2091 } 2092 #else 2093 if ((ulong)video_fb_address >= bd->bi_memstart && 2094 (ulong)video_fb_address < bd->bi_memstart + bd->bi_memsize) 2095 return 1; 2096 #endif 2097 return 0; 2098 } 2099 2100 static int video_init(void) 2101 { 2102 unsigned char color8; 2103 2104 pGD = video_hw_init(); 2105 if (pGD == NULL) 2106 return -1; 2107 2108 video_fb_address = (void *) VIDEO_FB_ADRS; 2109 #ifdef CONFIG_VIDEO_HW_CURSOR 2110 video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT); 2111 #endif 2112 2113 cfb_do_flush_cache = cfb_fb_is_in_dram() && dcache_status(); 2114 2115 /* Init drawing pats */ 2116 switch (VIDEO_DATA_FORMAT) { 2117 case GDF__8BIT_INDEX: 2118 video_set_lut(0x01, CONSOLE_FG_COL, CONSOLE_FG_COL, 2119 CONSOLE_FG_COL); 2120 video_set_lut(0x00, CONSOLE_BG_COL, CONSOLE_BG_COL, 2121 CONSOLE_BG_COL); 2122 fgx = 0x01010101; 2123 bgx = 0x00000000; 2124 break; 2125 case GDF__8BIT_332RGB: 2126 color8 = ((CONSOLE_FG_COL & 0xe0) | 2127 ((CONSOLE_FG_COL >> 3) & 0x1c) | 2128 CONSOLE_FG_COL >> 6); 2129 fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | 2130 color8; 2131 color8 = ((CONSOLE_BG_COL & 0xe0) | 2132 ((CONSOLE_BG_COL >> 3) & 0x1c) | 2133 CONSOLE_BG_COL >> 6); 2134 bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | 2135 color8; 2136 break; 2137 case GDF_15BIT_555RGB: 2138 fgx = (((CONSOLE_FG_COL >> 3) << 26) | 2139 ((CONSOLE_FG_COL >> 3) << 21) | 2140 ((CONSOLE_FG_COL >> 3) << 16) | 2141 ((CONSOLE_FG_COL >> 3) << 10) | 2142 ((CONSOLE_FG_COL >> 3) << 5) | 2143 (CONSOLE_FG_COL >> 3)); 2144 bgx = (((CONSOLE_BG_COL >> 3) << 26) | 2145 ((CONSOLE_BG_COL >> 3) << 21) | 2146 ((CONSOLE_BG_COL >> 3) << 16) | 2147 ((CONSOLE_BG_COL >> 3) << 10) | 2148 ((CONSOLE_BG_COL >> 3) << 5) | 2149 (CONSOLE_BG_COL >> 3)); 2150 break; 2151 case GDF_16BIT_565RGB: 2152 fgx = (((CONSOLE_FG_COL >> 3) << 27) | 2153 ((CONSOLE_FG_COL >> 2) << 21) | 2154 ((CONSOLE_FG_COL >> 3) << 16) | 2155 ((CONSOLE_FG_COL >> 3) << 11) | 2156 ((CONSOLE_FG_COL >> 2) << 5) | 2157 (CONSOLE_FG_COL >> 3)); 2158 bgx = (((CONSOLE_BG_COL >> 3) << 27) | 2159 ((CONSOLE_BG_COL >> 2) << 21) | 2160 ((CONSOLE_BG_COL >> 3) << 16) | 2161 ((CONSOLE_BG_COL >> 3) << 11) | 2162 ((CONSOLE_BG_COL >> 2) << 5) | 2163 (CONSOLE_BG_COL >> 3)); 2164 break; 2165 case GDF_32BIT_X888RGB: 2166 fgx = (CONSOLE_FG_COL << 16) | 2167 (CONSOLE_FG_COL << 8) | 2168 CONSOLE_FG_COL; 2169 bgx = (CONSOLE_BG_COL << 16) | 2170 (CONSOLE_BG_COL << 8) | 2171 CONSOLE_BG_COL; 2172 break; 2173 case GDF_24BIT_888RGB: 2174 fgx = (CONSOLE_FG_COL << 24) | 2175 (CONSOLE_FG_COL << 16) | 2176 (CONSOLE_FG_COL << 8) | 2177 CONSOLE_FG_COL; 2178 bgx = (CONSOLE_BG_COL << 24) | 2179 (CONSOLE_BG_COL << 16) | 2180 (CONSOLE_BG_COL << 8) | 2181 CONSOLE_BG_COL; 2182 break; 2183 } 2184 eorx = fgx ^ bgx; 2185 2186 #ifdef CONFIG_VIDEO_LOGO 2187 /* Plot the logo and get start point of console */ 2188 debug("Video: Drawing the logo ...\n"); 2189 video_console_address = video_logo(); 2190 #else 2191 video_console_address = video_fb_address; 2192 #endif 2193 2194 /* Initialize the console */ 2195 console_col = 0; 2196 console_row = 0; 2197 2198 if (cfb_do_flush_cache) 2199 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE); 2200 2201 return 0; 2202 } 2203 2204 /* 2205 * Implement a weak default function for boards that optionally 2206 * need to skip the video initialization. 2207 */ 2208 int __board_video_skip(void) 2209 { 2210 /* As default, don't skip test */ 2211 return 0; 2212 } 2213 2214 int board_video_skip(void) 2215 __attribute__ ((weak, alias("__board_video_skip"))); 2216 2217 int drv_video_init(void) 2218 { 2219 int skip_dev_init; 2220 struct stdio_dev console_dev; 2221 2222 /* Check if video initialization should be skipped */ 2223 if (board_video_skip()) 2224 return 0; 2225 2226 /* Init video chip - returns with framebuffer cleared */ 2227 skip_dev_init = (video_init() == -1); 2228 2229 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE) 2230 debug("KBD: Keyboard init ...\n"); 2231 skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1); 2232 #endif 2233 2234 if (skip_dev_init) 2235 return 0; 2236 2237 /* Init vga device */ 2238 memset(&console_dev, 0, sizeof(console_dev)); 2239 strcpy(console_dev.name, "vga"); 2240 console_dev.ext = DEV_EXT_VIDEO; /* Video extensions */ 2241 console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM; 2242 console_dev.putc = video_putc; /* 'putc' function */ 2243 console_dev.puts = video_puts; /* 'puts' function */ 2244 console_dev.tstc = NULL; /* 'tstc' function */ 2245 console_dev.getc = NULL; /* 'getc' function */ 2246 2247 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE) 2248 /* Also init console device */ 2249 console_dev.flags |= DEV_FLAGS_INPUT; 2250 console_dev.tstc = VIDEO_TSTC_FCT; /* 'tstc' function */ 2251 console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */ 2252 #endif /* CONFIG_VGA_AS_SINGLE_DEVICE */ 2253 2254 if (stdio_register(&console_dev) != 0) 2255 return 0; 2256 2257 /* Return success */ 2258 return 1; 2259 } 2260 2261 void video_position_cursor(unsigned col, unsigned row) 2262 { 2263 console_col = min(col, CONSOLE_COLS - 1); 2264 console_row = min(row, CONSOLE_ROWS - 1); 2265 } 2266 2267 int video_get_pixel_width(void) 2268 { 2269 return VIDEO_VISIBLE_COLS; 2270 } 2271 2272 int video_get_pixel_height(void) 2273 { 2274 return VIDEO_VISIBLE_ROWS; 2275 } 2276 2277 int video_get_screen_rows(void) 2278 { 2279 return CONSOLE_ROWS; 2280 } 2281 2282 int video_get_screen_columns(void) 2283 { 2284 return CONSOLE_COLS; 2285 } 2286 2287 void video_clear(void) 2288 { 2289 if (!video_fb_address) 2290 return; 2291 #ifdef VIDEO_HW_RECTFILL 2292 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */ 2293 0, /* dest pos x */ 2294 0, /* dest pos y */ 2295 VIDEO_VISIBLE_COLS, /* frame width */ 2296 VIDEO_VISIBLE_ROWS, /* frame height */ 2297 bgx /* fill color */ 2298 ); 2299 #else 2300 memsetl(video_fb_address, 2301 (VIDEO_VISIBLE_ROWS * VIDEO_LINE_LEN) / sizeof(int), bgx); 2302 #endif 2303 } 2304