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