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