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