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