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