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