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