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 normaly goes to serial port) can be drawed. 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 delay 63 loop in VIDEO_TSTC_FCT (i8042) 64 CONFIG_SYS_CONSOLE_BLINK_COUNT - value for delay loop - blink rate 65 CONFIG_CONSOLE_TIME - display time/date in upper right corner, 66 needs CONFIG_CMD_DATE and CONFIG_CONSOLE_CURSOR 67 CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner 68 CONFIG_VIDEO_BMP_LOGO - use bmp_logo instead of linux_logo 69 CONFIG_CONSOLE_EXTRA_INFO - display additional board information strings 70 that normaly goes to serial port. This define 71 requires a board specific function: 72 video_drawstring (VIDEO_INFO_X, 73 VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT, 74 info); 75 that fills a info buffer at i=row. 76 s.a: board/eltec/bab7xx. 77 CONFIG_VGA_AS_SINGLE_DEVICE - If set the framebuffer device will be initialised 78 as an output only device. The Keyboard driver 79 will not be set-up. This may be used, if you 80 have none or more than one Keyboard devices 81 (USB Keyboard, AT Keyboard). 82 83 CONFIG_VIDEO_SW_CURSOR: - Draws a cursor after the last character. No 84 blinking is provided. Uses the macros CURSOR_SET 85 and CURSOR_OFF. 86 CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability of the 87 graphic chip. Uses the macro CURSOR_SET. 88 ATTENTION: If booting an OS, the display driver 89 must disable the hardware register of the graphic 90 chip. Otherwise a blinking field is displayed 91 */ 92 93 #include <common.h> 94 #include <version.h> 95 96 #include <malloc.h> 97 98 /*****************************************************************************/ 99 /* Console device defines with SMI graphic */ 100 /* Any other graphic must change this section */ 101 /*****************************************************************************/ 102 103 #ifdef CONFIG_VIDEO_SMI_LYNXEM 104 105 #define VIDEO_FB_LITTLE_ENDIAN 106 #define VIDEO_HW_RECTFILL 107 #define VIDEO_HW_BITBLT 108 #endif 109 110 /*****************************************************************************/ 111 /* Defines for the CT69000 driver */ 112 /*****************************************************************************/ 113 #ifdef CONFIG_VIDEO_CT69000 114 115 #define VIDEO_FB_LITTLE_ENDIAN 116 #define VIDEO_HW_RECTFILL 117 #define VIDEO_HW_BITBLT 118 #endif 119 120 /*****************************************************************************/ 121 /* Defines for the SED13806 driver */ 122 /*****************************************************************************/ 123 #ifdef CONFIG_VIDEO_SED13806 124 125 #ifndef CONFIG_TOTAL5200 126 #define VIDEO_FB_LITTLE_ENDIAN 127 #endif 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_SM501 136 137 #ifdef CONFIG_HH405 138 #define VIDEO_FB_LITTLE_ENDIAN 139 #endif 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 /* Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc */ 158 /*****************************************************************************/ 159 #include <video_fb.h> 160 161 /*****************************************************************************/ 162 /* some Macros */ 163 /*****************************************************************************/ 164 #define VIDEO_VISIBLE_COLS (pGD->winSizeX) 165 #define VIDEO_VISIBLE_ROWS (pGD->winSizeY) 166 #define VIDEO_PIXEL_SIZE (pGD->gdfBytesPP) 167 #define VIDEO_DATA_FORMAT (pGD->gdfIndex) 168 #define VIDEO_FB_ADRS (pGD->frameAdrs) 169 170 /*****************************************************************************/ 171 /* Console device defines with i8042 keyboard controller */ 172 /* Any other keyboard controller must change this section */ 173 /*****************************************************************************/ 174 175 #ifdef CONFIG_I8042_KBD 176 #include <i8042.h> 177 178 #define VIDEO_KBD_INIT_FCT i8042_kbd_init() 179 #define VIDEO_TSTC_FCT i8042_tstc 180 #define VIDEO_GETC_FCT i8042_getc 181 #endif 182 183 /*****************************************************************************/ 184 /* Console device */ 185 /*****************************************************************************/ 186 187 #include <version.h> 188 #include <linux/types.h> 189 #include <stdio_dev.h> 190 #include <video_font.h> 191 192 #if defined(CONFIG_CMD_DATE) 193 #include <rtc.h> 194 #endif 195 196 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) 197 #include <watchdog.h> 198 #include <bmp_layout.h> 199 200 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 201 #define BMP_ALIGN_CENTER 0x7FFF 202 #endif 203 204 #endif 205 206 /*****************************************************************************/ 207 /* Cursor definition: */ 208 /* CONFIG_CONSOLE_CURSOR: Uses a timer function (see drivers/input/i8042.c) */ 209 /* to let the cursor blink. Uses the macros */ 210 /* CURSOR_OFF and CURSOR_ON. */ 211 /* CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No */ 212 /* blinking is provided. Uses the macros CURSOR_SET */ 213 /* and CURSOR_OFF. */ 214 /* CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the */ 215 /* graphic chip. Uses the macro CURSOR_SET. */ 216 /* ATTENTION: If booting an OS, the display driver */ 217 /* must disable the hardware register of the graphic */ 218 /* chip. Otherwise a blinking field is displayed */ 219 /*****************************************************************************/ 220 #if !defined(CONFIG_CONSOLE_CURSOR) && \ 221 !defined(CONFIG_VIDEO_SW_CURSOR) && \ 222 !defined(CONFIG_VIDEO_HW_CURSOR) 223 /* no Cursor defined */ 224 #define CURSOR_ON 225 #define CURSOR_OFF 226 #define CURSOR_SET 227 #endif 228 229 #ifdef CONFIG_CONSOLE_CURSOR 230 #ifdef CURSOR_ON 231 #error only one of CONFIG_CONSOLE_CURSOR,CONFIG_VIDEO_SW_CURSOR,CONFIG_VIDEO_HW_CURSOR can be defined 232 #endif 233 void console_cursor (int state); 234 #define CURSOR_ON console_cursor(1) 235 #define CURSOR_OFF console_cursor(0) 236 #define CURSOR_SET 237 #ifndef CONFIG_I8042_KBD 238 #warning Cursor drawing on/off needs timer function s.a. drivers/input/i8042.c 239 #endif 240 #else 241 #ifdef CONFIG_CONSOLE_TIME 242 #error CONFIG_CONSOLE_CURSOR must be defined for CONFIG_CONSOLE_TIME 243 #endif 244 #endif /* CONFIG_CONSOLE_CURSOR */ 245 246 #ifdef CONFIG_VIDEO_SW_CURSOR 247 #ifdef CURSOR_ON 248 #error only one of CONFIG_CONSOLE_CURSOR,CONFIG_VIDEO_SW_CURSOR,CONFIG_VIDEO_HW_CURSOR can be defined 249 #endif 250 #define CURSOR_ON 251 #define CURSOR_OFF video_putchar(console_col * VIDEO_FONT_WIDTH,\ 252 console_row * VIDEO_FONT_HEIGHT, ' ') 253 #define CURSOR_SET video_set_cursor() 254 #endif /* CONFIG_VIDEO_SW_CURSOR */ 255 256 257 #ifdef CONFIG_VIDEO_HW_CURSOR 258 #ifdef CURSOR_ON 259 #error only one of CONFIG_CONSOLE_CURSOR,CONFIG_VIDEO_SW_CURSOR,CONFIG_VIDEO_HW_CURSOR can be defined 260 #endif 261 #define CURSOR_ON 262 #define CURSOR_OFF 263 #define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \ 264 (console_row * VIDEO_FONT_HEIGHT) + video_logo_height) 265 #endif /* CONFIG_VIDEO_HW_CURSOR */ 266 267 #ifdef CONFIG_VIDEO_LOGO 268 #ifdef CONFIG_VIDEO_BMP_LOGO 269 #include <bmp_logo.h> 270 #define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH 271 #define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT 272 #define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET 273 #define VIDEO_LOGO_COLORS BMP_LOGO_COLORS 274 275 #else /* CONFIG_VIDEO_BMP_LOGO */ 276 #define LINUX_LOGO_WIDTH 80 277 #define LINUX_LOGO_HEIGHT 80 278 #define LINUX_LOGO_COLORS 214 279 #define LINUX_LOGO_LUT_OFFSET 0x20 280 #define __initdata 281 #include <linux_logo.h> 282 #define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH 283 #define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT 284 #define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET 285 #define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS 286 #endif /* CONFIG_VIDEO_BMP_LOGO */ 287 #define VIDEO_INFO_X (VIDEO_LOGO_WIDTH) 288 #define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2) 289 #else /* CONFIG_VIDEO_LOGO */ 290 #define VIDEO_LOGO_WIDTH 0 291 #define VIDEO_LOGO_HEIGHT 0 292 #endif /* CONFIG_VIDEO_LOGO */ 293 294 #define VIDEO_COLS VIDEO_VISIBLE_COLS 295 #define VIDEO_ROWS VIDEO_VISIBLE_ROWS 296 #define VIDEO_SIZE (VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE) 297 #define VIDEO_PIX_BLOCKS (VIDEO_SIZE >> 2) 298 #define VIDEO_LINE_LEN (VIDEO_COLS*VIDEO_PIXEL_SIZE) 299 #define VIDEO_BURST_LEN (VIDEO_COLS/8) 300 301 #ifdef CONFIG_VIDEO_LOGO 302 #define CONSOLE_ROWS ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT) 303 #else 304 #define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT) 305 #endif 306 307 #define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH) 308 #define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN) 309 #define CONSOLE_ROW_FIRST (video_console_address) 310 #define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE) 311 #define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE) 312 #define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS) 313 #define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE) 314 315 /* Macros */ 316 #ifdef VIDEO_FB_LITTLE_ENDIAN 317 #define SWAP16(x) ((((x) & 0x00ff) << 8) | ( (x) >> 8)) 318 #define SWAP32(x) ((((x) & 0x000000ff) << 24) | (((x) & 0x0000ff00) << 8)|\ 319 (((x) & 0x00ff0000) >> 8) | (((x) & 0xff000000) >> 24) ) 320 #define SHORTSWAP32(x) ((((x) & 0x000000ff) << 8) | (((x) & 0x0000ff00) >> 8)|\ 321 (((x) & 0x00ff0000) << 8) | (((x) & 0xff000000) >> 8) ) 322 #else 323 #define SWAP16(x) (x) 324 #define SWAP32(x) (x) 325 #if defined(VIDEO_FB_16BPP_WORD_SWAP) 326 #define SHORTSWAP32(x) ( ((x) >> 16) | ((x) << 16) ) 327 #else 328 #define SHORTSWAP32(x) (x) 329 #endif 330 #endif 331 332 #if defined(DEBUG) || defined(DEBUG_CFB_CONSOLE) 333 #define PRINTD(x) printf(x) 334 #else 335 #define PRINTD(x) 336 #endif 337 338 339 #ifdef CONFIG_CONSOLE_EXTRA_INFO 340 extern void video_get_info_str ( /* setup a board string: type, speed, etc. */ 341 int line_number, /* location to place info string beside logo */ 342 char *info /* buffer for info string */ 343 ); 344 345 #endif 346 347 /* Locals */ 348 static GraphicDevice *pGD; /* Pointer to Graphic array */ 349 350 static void *video_fb_address; /* frame buffer address */ 351 static void *video_console_address; /* console buffer start address */ 352 353 static int video_logo_height = VIDEO_LOGO_HEIGHT; 354 355 static int console_col = 0; /* cursor col */ 356 static int console_row = 0; /* cursor row */ 357 358 static u32 eorx, fgx, bgx; /* color pats */ 359 360 static const int video_font_draw_table8[] = { 361 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, 362 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, 363 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, 364 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff }; 365 366 static const int video_font_draw_table15[] = { 367 0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff }; 368 369 static const int video_font_draw_table16[] = { 370 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff }; 371 372 static const int video_font_draw_table24[16][3] = { 373 { 0x00000000, 0x00000000, 0x00000000 }, 374 { 0x00000000, 0x00000000, 0x00ffffff }, 375 { 0x00000000, 0x0000ffff, 0xff000000 }, 376 { 0x00000000, 0x0000ffff, 0xffffffff }, 377 { 0x000000ff, 0xffff0000, 0x00000000 }, 378 { 0x000000ff, 0xffff0000, 0x00ffffff }, 379 { 0x000000ff, 0xffffffff, 0xff000000 }, 380 { 0x000000ff, 0xffffffff, 0xffffffff }, 381 { 0xffffff00, 0x00000000, 0x00000000 }, 382 { 0xffffff00, 0x00000000, 0x00ffffff }, 383 { 0xffffff00, 0x0000ffff, 0xff000000 }, 384 { 0xffffff00, 0x0000ffff, 0xffffffff }, 385 { 0xffffffff, 0xffff0000, 0x00000000 }, 386 { 0xffffffff, 0xffff0000, 0x00ffffff }, 387 { 0xffffffff, 0xffffffff, 0xff000000 }, 388 { 0xffffffff, 0xffffffff, 0xffffffff } }; 389 390 static const int video_font_draw_table32[16][4] = { 391 { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, 392 { 0x00000000, 0x00000000, 0x00000000, 0x00ffffff }, 393 { 0x00000000, 0x00000000, 0x00ffffff, 0x00000000 }, 394 { 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff }, 395 { 0x00000000, 0x00ffffff, 0x00000000, 0x00000000 }, 396 { 0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff }, 397 { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000 }, 398 { 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff }, 399 { 0x00ffffff, 0x00000000, 0x00000000, 0x00000000 }, 400 { 0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff }, 401 { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000 }, 402 { 0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff }, 403 { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000 }, 404 { 0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff }, 405 { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000 }, 406 { 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff } }; 407 408 409 /******************************************************************************/ 410 411 static void video_drawchars (int xx, int yy, unsigned char *s, int count) 412 { 413 u8 *cdat, *dest, *dest0; 414 int rows, offset, c; 415 416 offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE; 417 dest0 = video_fb_address + offset; 418 419 switch (VIDEO_DATA_FORMAT) { 420 case GDF__8BIT_INDEX: 421 case GDF__8BIT_332RGB: 422 while (count--) { 423 c = *s; 424 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 425 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 426 rows--; 427 dest += VIDEO_LINE_LEN) { 428 u8 bits = *cdat++; 429 430 ((u32 *) dest)[0] = (video_font_draw_table8[bits >> 4] & eorx) ^ bgx; 431 ((u32 *) dest)[1] = (video_font_draw_table8[bits & 15] & eorx) ^ bgx; 432 } 433 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 434 s++; 435 } 436 break; 437 438 case GDF_15BIT_555RGB: 439 while (count--) { 440 c = *s; 441 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 442 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 443 rows--; 444 dest += VIDEO_LINE_LEN) { 445 u8 bits = *cdat++; 446 447 ((u32 *) dest)[0] = SHORTSWAP32 ((video_font_draw_table15 [bits >> 6] & eorx) ^ bgx); 448 ((u32 *) dest)[1] = SHORTSWAP32 ((video_font_draw_table15 [bits >> 4 & 3] & eorx) ^ bgx); 449 ((u32 *) dest)[2] = SHORTSWAP32 ((video_font_draw_table15 [bits >> 2 & 3] & eorx) ^ bgx); 450 ((u32 *) dest)[3] = SHORTSWAP32 ((video_font_draw_table15 [bits & 3] & eorx) ^ bgx); 451 } 452 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 453 s++; 454 } 455 break; 456 457 case GDF_16BIT_565RGB: 458 while (count--) { 459 c = *s; 460 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 461 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 462 rows--; 463 dest += VIDEO_LINE_LEN) { 464 u8 bits = *cdat++; 465 466 ((u32 *) dest)[0] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 6] & eorx) ^ bgx); 467 ((u32 *) dest)[1] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 4 & 3] & eorx) ^ bgx); 468 ((u32 *) dest)[2] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 2 & 3] & eorx) ^ bgx); 469 ((u32 *) dest)[3] = SHORTSWAP32 ((video_font_draw_table16 [bits & 3] & eorx) ^ bgx); 470 } 471 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 472 s++; 473 } 474 break; 475 476 case GDF_32BIT_X888RGB: 477 while (count--) { 478 c = *s; 479 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 480 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 481 rows--; 482 dest += VIDEO_LINE_LEN) { 483 u8 bits = *cdat++; 484 485 ((u32 *) dest)[0] = SWAP32 ((video_font_draw_table32 [bits >> 4][0] & eorx) ^ bgx); 486 ((u32 *) dest)[1] = SWAP32 ((video_font_draw_table32 [bits >> 4][1] & eorx) ^ bgx); 487 ((u32 *) dest)[2] = SWAP32 ((video_font_draw_table32 [bits >> 4][2] & eorx) ^ bgx); 488 ((u32 *) dest)[3] = SWAP32 ((video_font_draw_table32 [bits >> 4][3] & eorx) ^ bgx); 489 ((u32 *) dest)[4] = SWAP32 ((video_font_draw_table32 [bits & 15][0] & eorx) ^ bgx); 490 ((u32 *) dest)[5] = SWAP32 ((video_font_draw_table32 [bits & 15][1] & eorx) ^ bgx); 491 ((u32 *) dest)[6] = SWAP32 ((video_font_draw_table32 [bits & 15][2] & eorx) ^ bgx); 492 ((u32 *) dest)[7] = SWAP32 ((video_font_draw_table32 [bits & 15][3] & eorx) ^ bgx); 493 } 494 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 495 s++; 496 } 497 break; 498 499 case GDF_24BIT_888RGB: 500 while (count--) { 501 c = *s; 502 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT; 503 for (rows = VIDEO_FONT_HEIGHT, dest = dest0; 504 rows--; 505 dest += VIDEO_LINE_LEN) { 506 u8 bits = *cdat++; 507 508 ((u32 *) dest)[0] = (video_font_draw_table24[bits >> 4][0] & eorx) ^ bgx; 509 ((u32 *) dest)[1] = (video_font_draw_table24[bits >> 4][1] & eorx) ^ bgx; 510 ((u32 *) dest)[2] = (video_font_draw_table24[bits >> 4][2] & eorx) ^ bgx; 511 ((u32 *) dest)[3] = (video_font_draw_table24[bits & 15][0] & eorx) ^ bgx; 512 ((u32 *) dest)[4] = (video_font_draw_table24[bits & 15][1] & eorx) ^ bgx; 513 ((u32 *) dest)[5] = (video_font_draw_table24[bits & 15][2] & eorx) ^ bgx; 514 } 515 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; 516 s++; 517 } 518 break; 519 } 520 } 521 522 /*****************************************************************************/ 523 524 static inline void video_drawstring (int xx, int yy, unsigned char *s) 525 { 526 video_drawchars (xx, yy, s, strlen ((char *)s)); 527 } 528 529 /*****************************************************************************/ 530 531 static void video_putchar (int xx, int yy, unsigned char c) 532 { 533 video_drawchars (xx, yy + video_logo_height, &c, 1); 534 } 535 536 /*****************************************************************************/ 537 #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR) 538 static void video_set_cursor (void) 539 { 540 /* swap drawing colors */ 541 eorx = fgx; 542 fgx = bgx; 543 bgx = eorx; 544 eorx = fgx ^ bgx; 545 /* draw cursor */ 546 video_putchar (console_col * VIDEO_FONT_WIDTH, 547 console_row * VIDEO_FONT_HEIGHT, 548 ' '); 549 /* restore drawing colors */ 550 eorx = fgx; 551 fgx = bgx; 552 bgx = eorx; 553 eorx = fgx ^ bgx; 554 } 555 #endif 556 /*****************************************************************************/ 557 #ifdef CONFIG_CONSOLE_CURSOR 558 void console_cursor (int state) 559 { 560 static int last_state = 0; 561 562 #ifdef CONFIG_CONSOLE_TIME 563 struct rtc_time tm; 564 char info[16]; 565 566 /* time update only if cursor is on (faster scroll) */ 567 if (state) { 568 rtc_get (&tm); 569 570 sprintf (info, " %02d:%02d:%02d ", tm.tm_hour, tm.tm_min, 571 tm.tm_sec); 572 video_drawstring (VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH, 573 VIDEO_INFO_Y, (uchar *)info); 574 575 sprintf (info, "%02d.%02d.%04d", tm.tm_mday, tm.tm_mon, 576 tm.tm_year); 577 video_drawstring (VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH, 578 VIDEO_INFO_Y + 1 * VIDEO_FONT_HEIGHT, (uchar *)info); 579 } 580 #endif 581 582 if (state && (last_state != state)) { 583 video_set_cursor (); 584 } 585 586 if (!state && (last_state != state)) { 587 /* clear cursor */ 588 video_putchar (console_col * VIDEO_FONT_WIDTH, 589 console_row * VIDEO_FONT_HEIGHT, 590 ' '); 591 } 592 593 last_state = state; 594 } 595 #endif 596 597 /*****************************************************************************/ 598 599 #ifndef VIDEO_HW_RECTFILL 600 static void memsetl (int *p, int c, int v) 601 { 602 while (c--) 603 *(p++) = v; 604 } 605 #endif 606 607 /*****************************************************************************/ 608 609 #ifndef VIDEO_HW_BITBLT 610 static void memcpyl (int *d, int *s, int c) 611 { 612 while (c--) 613 *(d++) = *(s++); 614 } 615 #endif 616 617 /*****************************************************************************/ 618 619 static void console_scrollup (void) 620 { 621 /* copy up rows ignoring the first one */ 622 623 #ifdef VIDEO_HW_BITBLT 624 video_hw_bitblt (VIDEO_PIXEL_SIZE, /* bytes per pixel */ 625 0, /* source pos x */ 626 video_logo_height + VIDEO_FONT_HEIGHT, /* source pos y */ 627 0, /* dest pos x */ 628 video_logo_height, /* dest pos y */ 629 VIDEO_VISIBLE_COLS, /* frame width */ 630 VIDEO_VISIBLE_ROWS - video_logo_height - VIDEO_FONT_HEIGHT /* frame height */ 631 ); 632 #else 633 memcpyl (CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, 634 CONSOLE_SCROLL_SIZE >> 2); 635 #endif 636 637 /* clear the last one */ 638 #ifdef VIDEO_HW_RECTFILL 639 video_hw_rectfill (VIDEO_PIXEL_SIZE, /* bytes per pixel */ 640 0, /* dest pos x */ 641 VIDEO_VISIBLE_ROWS - VIDEO_FONT_HEIGHT, /* dest pos y */ 642 VIDEO_VISIBLE_COLS, /* frame width */ 643 VIDEO_FONT_HEIGHT, /* frame height */ 644 CONSOLE_BG_COL /* fill color */ 645 ); 646 #else 647 memsetl (CONSOLE_ROW_LAST, CONSOLE_ROW_SIZE >> 2, CONSOLE_BG_COL); 648 #endif 649 } 650 651 /*****************************************************************************/ 652 653 static void console_back (void) 654 { 655 CURSOR_OFF; 656 console_col--; 657 658 if (console_col < 0) { 659 console_col = CONSOLE_COLS - 1; 660 console_row--; 661 if (console_row < 0) 662 console_row = 0; 663 } 664 video_putchar (console_col * VIDEO_FONT_WIDTH, 665 console_row * VIDEO_FONT_HEIGHT, 666 ' '); 667 } 668 669 /*****************************************************************************/ 670 671 static void console_newline (void) 672 { 673 /* Check if last character in the line was just drawn. If so, cursor was 674 overwriten and need not to be cleared. Cursor clearing without this 675 check causes overwriting the 1st character of the line if line lenght 676 is >= CONSOLE_COLS 677 */ 678 if (console_col < CONSOLE_COLS) 679 CURSOR_OFF; 680 console_row++; 681 console_col = 0; 682 683 /* Check if we need to scroll the terminal */ 684 if (console_row >= CONSOLE_ROWS) { 685 /* Scroll everything up */ 686 console_scrollup (); 687 688 /* Decrement row number */ 689 console_row--; 690 } 691 } 692 693 static void console_cr (void) 694 { 695 CURSOR_OFF; 696 console_col = 0; 697 } 698 699 /*****************************************************************************/ 700 701 void video_putc (const char c) 702 { 703 static int nl = 1; 704 705 switch (c) { 706 case 13: /* back to first column */ 707 console_cr (); 708 break; 709 710 case '\n': /* next line */ 711 if (console_col || (!console_col && nl)) 712 console_newline (); 713 nl = 1; 714 break; 715 716 case 9: /* tab 8 */ 717 CURSOR_OFF; 718 console_col |= 0x0008; 719 console_col &= ~0x0007; 720 721 if (console_col >= CONSOLE_COLS) 722 console_newline (); 723 break; 724 725 case 8: /* backspace */ 726 console_back (); 727 break; 728 729 default: /* draw the char */ 730 video_putchar (console_col * VIDEO_FONT_WIDTH, 731 console_row * VIDEO_FONT_HEIGHT, 732 c); 733 console_col++; 734 735 /* check for newline */ 736 if (console_col >= CONSOLE_COLS) { 737 console_newline (); 738 nl = 0; 739 } 740 } 741 CURSOR_SET; 742 } 743 744 745 /*****************************************************************************/ 746 747 void video_puts (const char *s) 748 { 749 int count = strlen (s); 750 751 while (count--) 752 video_putc (*s++); 753 } 754 755 /*****************************************************************************/ 756 757 /* 758 * Do not enforce drivers (or board code) to provide empty 759 * video_set_lut() if they do not support 8 bpp format. 760 * Implement weak default function instead. 761 */ 762 void __video_set_lut (unsigned int index, unsigned char r, 763 unsigned char g, unsigned char b) 764 { 765 } 766 void video_set_lut (unsigned int, unsigned char, unsigned char, unsigned char) 767 __attribute__((weak, alias("__video_set_lut"))); 768 769 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) 770 771 #define FILL_8BIT_332RGB(r,g,b) { \ 772 *fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6); \ 773 fb ++; \ 774 } 775 776 #define FILL_15BIT_555RGB(r,g,b) { \ 777 *(unsigned short *)fb = SWAP16((unsigned short)(((r>>3)<<10) | ((g>>3)<<5) | (b>>3))); \ 778 fb += 2; \ 779 } 780 781 #define FILL_16BIT_565RGB(r,g,b) { \ 782 *(unsigned short *)fb = SWAP16((unsigned short)((((r)>>3)<<11) | (((g)>>2)<<5) | ((b)>>3))); \ 783 fb += 2; \ 784 } 785 786 #define FILL_32BIT_X888RGB(r,g,b) { \ 787 *(unsigned long *)fb = SWAP32((unsigned long)(((r<<16) | (g<<8) | b))); \ 788 fb += 4; \ 789 } 790 791 #ifdef VIDEO_FB_LITTLE_ENDIAN 792 #define FILL_24BIT_888RGB(r,g,b) { \ 793 fb[0] = b; \ 794 fb[1] = g; \ 795 fb[2] = r; \ 796 fb += 3; \ 797 } 798 #else 799 #define FILL_24BIT_888RGB(r,g,b) { \ 800 fb[0] = r; \ 801 fb[1] = g; \ 802 fb[2] = b; \ 803 fb += 3; \ 804 } 805 #endif 806 807 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 808 static void inline fill_555rgb_pswap(uchar *fb, int x, 809 u8 r, u8 g, u8 b) 810 { 811 ushort *dst = (ushort *)fb; 812 ushort color = (ushort)(((r >> 3) << 10) | 813 ((g >> 3) << 5) | 814 (b >> 3)); 815 if (x & 1) 816 *(--dst) = color; 817 else 818 *(++dst) = color; 819 } 820 #endif 821 822 /* 823 * RLE8 bitmap support 824 */ 825 826 #ifdef CONFIG_VIDEO_BMP_RLE8 827 /* Pre-calculated color table entry */ 828 struct palette { 829 union { 830 unsigned short w; /* word */ 831 unsigned int dw; /* double word */ 832 } ce; /* color entry */ 833 }; 834 835 /* 836 * Helper to draw encoded/unencoded run. 837 */ 838 static void draw_bitmap (uchar **fb, uchar *bm, struct palette *p, 839 int cnt, int enc) 840 { 841 ulong addr = (ulong)*fb; 842 int *off; 843 int enc_off = 1; 844 int i; 845 846 /* 847 * Setup offset of the color index in the bitmap. 848 * Color index of encoded run is at offset 1. 849 */ 850 off = enc ? &enc_off : &i; 851 852 switch (VIDEO_DATA_FORMAT) { 853 case GDF__8BIT_INDEX: 854 for (i = 0; i < cnt; i++) 855 *(unsigned char *)addr++ = bm[*off]; 856 break; 857 case GDF_15BIT_555RGB: 858 case GDF_16BIT_565RGB: 859 /* differences handled while pre-calculating palette */ 860 for (i = 0; i < cnt; i++) { 861 *(unsigned short *)addr = p[bm[*off]].ce.w; 862 addr += 2; 863 } 864 break; 865 case GDF_32BIT_X888RGB: 866 for (i = 0; i < cnt; i++) { 867 *(unsigned long *)addr = p[bm[*off]].ce.dw; 868 addr += 4; 869 } 870 break; 871 } 872 *fb = (uchar *)addr; /* return modified address */ 873 } 874 875 static int display_rle8_bitmap (bmp_image_t *img, int xoff, int yoff, 876 int width, int height) 877 { 878 unsigned char *bm; 879 unsigned char *fbp; 880 unsigned int cnt, runlen; 881 int decode = 1; 882 int x, y, bpp, i, ncolors; 883 struct palette p[256]; 884 bmp_color_table_entry_t cte; 885 int green_shift, red_off; 886 int limit = VIDEO_COLS * VIDEO_ROWS; 887 int pixels = 0; 888 889 x = 0; 890 y = __le32_to_cpu(img->header.height) - 1; 891 ncolors = __le32_to_cpu(img->header.colors_used); 892 bpp = VIDEO_PIXEL_SIZE; 893 fbp = (unsigned char *)((unsigned int)video_fb_address + 894 (((y + yoff) * VIDEO_COLS) + xoff) * bpp); 895 896 bm = (uchar *)img + __le32_to_cpu(img->header.data_offset); 897 898 /* pre-calculate and setup palette */ 899 switch (VIDEO_DATA_FORMAT) { 900 case GDF__8BIT_INDEX: 901 for (i = 0; i < ncolors; i++) { 902 cte = img->color_table[i]; 903 video_set_lut (i, cte.red, cte.green, cte.blue); 904 } 905 break; 906 case GDF_15BIT_555RGB: 907 case GDF_16BIT_565RGB: 908 if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) { 909 green_shift = 3; 910 red_off = 10; 911 } else { 912 green_shift = 2; 913 red_off = 11; 914 } 915 for (i = 0; i < ncolors; i++) { 916 cte = img->color_table[i]; 917 p[i].ce.w = SWAP16((unsigned short) 918 (((cte.red >> 3) << red_off) | 919 ((cte.green >> green_shift) << 5) | 920 cte.blue >> 3)); 921 } 922 break; 923 case GDF_32BIT_X888RGB: 924 for (i = 0; i < ncolors; i++) { 925 cte = img->color_table[i]; 926 p[i].ce.dw = SWAP32((cte.red << 16) | (cte.green << 8) | 927 cte.blue); 928 } 929 break; 930 default: 931 printf("RLE Bitmap unsupported in video mode 0x%x\n", 932 VIDEO_DATA_FORMAT); 933 return -1; 934 } 935 936 while (decode) { 937 switch (bm[0]) { 938 case 0: 939 switch (bm[1]) { 940 case 0: 941 /* scan line end marker */ 942 bm += 2; 943 x = 0; 944 y--; 945 fbp = (unsigned char *) 946 ((unsigned int)video_fb_address + 947 (((y + yoff) * VIDEO_COLS) + 948 xoff) * bpp); 949 continue; 950 case 1: 951 /* end of bitmap data marker */ 952 decode = 0; 953 break; 954 case 2: 955 /* run offset marker */ 956 x += bm[2]; 957 y -= bm[3]; 958 fbp = (unsigned char *) 959 ((unsigned int)video_fb_address + 960 (((y + yoff) * VIDEO_COLS) + 961 x + xoff) * bpp); 962 bm += 4; 963 break; 964 default: 965 /* unencoded run */ 966 cnt = bm[1]; 967 runlen = cnt; 968 pixels += cnt; 969 if (pixels > limit) 970 goto error; 971 972 bm += 2; 973 if (y < height) { 974 if (x >= width) { 975 x += runlen; 976 goto next_run; 977 } 978 if (x + runlen > width) 979 cnt = width - x; 980 draw_bitmap (&fbp, bm, p, cnt, 0); 981 x += runlen; 982 } 983 next_run: 984 bm += runlen; 985 if (runlen & 1) 986 bm++; /* 0 padding if length is odd */ 987 } 988 break; 989 default: 990 /* encoded run */ 991 cnt = bm[0]; 992 runlen = cnt; 993 pixels += cnt; 994 if (pixels > limit) 995 goto error; 996 997 if (y < height) { /* only draw into visible area */ 998 if (x >= width) { 999 x += runlen; 1000 bm += 2; 1001 continue; 1002 } 1003 if (x + runlen > width) 1004 cnt = width - x; 1005 draw_bitmap (&fbp, bm, p, cnt, 1); 1006 x += runlen; 1007 } 1008 bm += 2; 1009 break; 1010 } 1011 } 1012 return 0; 1013 error: 1014 printf("Error: Too much encoded pixel data, validate your bitmap\n"); 1015 return -1; 1016 } 1017 #endif 1018 1019 /* 1020 * Display the BMP file located at address bmp_image. 1021 */ 1022 int video_display_bitmap (ulong bmp_image, int x, int y) 1023 { 1024 ushort xcount, ycount; 1025 uchar *fb; 1026 bmp_image_t *bmp = (bmp_image_t *) bmp_image; 1027 uchar *bmap; 1028 ushort padded_line; 1029 unsigned long width, height, bpp; 1030 unsigned colors; 1031 unsigned long compression; 1032 bmp_color_table_entry_t cte; 1033 #ifdef CONFIG_VIDEO_BMP_GZIP 1034 unsigned char *dst = NULL; 1035 ulong len; 1036 #endif 1037 1038 WATCHDOG_RESET (); 1039 1040 if (!((bmp->header.signature[0] == 'B') && 1041 (bmp->header.signature[1] == 'M'))) { 1042 1043 #ifdef CONFIG_VIDEO_BMP_GZIP 1044 /* 1045 * Could be a gzipped bmp image, try to decrompress... 1046 */ 1047 len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE; 1048 dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE); 1049 if (dst == NULL) { 1050 printf("Error: malloc in gunzip failed!\n"); 1051 return(1); 1052 } 1053 if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, (uchar *)bmp_image, &len) != 0) { 1054 printf ("Error: no valid bmp or bmp.gz image at %lx\n", bmp_image); 1055 free(dst); 1056 return 1; 1057 } 1058 if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) { 1059 printf("Image could be truncated (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n"); 1060 } 1061 1062 /* 1063 * Set addr to decompressed image 1064 */ 1065 bmp = (bmp_image_t *)dst; 1066 1067 if (!((bmp->header.signature[0] == 'B') && 1068 (bmp->header.signature[1] == 'M'))) { 1069 printf ("Error: no valid bmp.gz image at %lx\n", bmp_image); 1070 free(dst); 1071 return 1; 1072 } 1073 #else 1074 printf ("Error: no valid bmp image at %lx\n", bmp_image); 1075 return 1; 1076 #endif /* CONFIG_VIDEO_BMP_GZIP */ 1077 } 1078 1079 width = le32_to_cpu (bmp->header.width); 1080 height = le32_to_cpu (bmp->header.height); 1081 bpp = le16_to_cpu (bmp->header.bit_count); 1082 colors = le32_to_cpu (bmp->header.colors_used); 1083 compression = le32_to_cpu (bmp->header.compression); 1084 1085 debug ("Display-bmp: %d x %d with %d colors\n", 1086 width, height, colors); 1087 1088 if (compression != BMP_BI_RGB 1089 #ifdef CONFIG_VIDEO_BMP_RLE8 1090 && compression != BMP_BI_RLE8 1091 #endif 1092 ) { 1093 printf ("Error: compression type %ld not supported\n", 1094 compression); 1095 #ifdef CONFIG_VIDEO_BMP_GZIP 1096 if (dst) 1097 free(dst); 1098 #endif 1099 return 1; 1100 } 1101 1102 padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3; 1103 1104 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 1105 if (x == BMP_ALIGN_CENTER) 1106 x = max(0, (VIDEO_VISIBLE_COLS - width) / 2); 1107 else if (x < 0) 1108 x = max(0, VIDEO_VISIBLE_COLS - width + x + 1); 1109 1110 if (y == BMP_ALIGN_CENTER) 1111 y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2); 1112 else if (y < 0) 1113 y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1); 1114 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ 1115 1116 if ((x + width) > VIDEO_VISIBLE_COLS) 1117 width = VIDEO_VISIBLE_COLS - x; 1118 if ((y + height) > VIDEO_VISIBLE_ROWS) 1119 height = VIDEO_VISIBLE_ROWS - y; 1120 1121 bmap = (uchar *) bmp + le32_to_cpu (bmp->header.data_offset); 1122 fb = (uchar *) (video_fb_address + 1123 ((y + height - 1) * VIDEO_COLS * VIDEO_PIXEL_SIZE) + 1124 x * VIDEO_PIXEL_SIZE); 1125 1126 #ifdef CONFIG_VIDEO_BMP_RLE8 1127 if (compression == BMP_BI_RLE8) { 1128 return display_rle8_bitmap(bmp, 1129 x, y, width, height); 1130 } 1131 #endif 1132 1133 /* We handle only 4, 8, or 24 bpp bitmaps */ 1134 switch (le16_to_cpu (bmp->header.bit_count)) { 1135 case 4: 1136 padded_line -= width / 2; 1137 ycount = height; 1138 1139 switch (VIDEO_DATA_FORMAT) { 1140 case GDF_32BIT_X888RGB: 1141 while (ycount--) { 1142 WATCHDOG_RESET (); 1143 /* 1144 * Don't assume that 'width' is an 1145 * even number 1146 */ 1147 for (xcount = 0; xcount < width; xcount++) { 1148 uchar idx; 1149 1150 if (xcount & 1) { 1151 idx = *bmap & 0xF; 1152 bmap++; 1153 } else 1154 idx = *bmap >> 4; 1155 cte = bmp->color_table[idx]; 1156 FILL_32BIT_X888RGB(cte.red, cte.green, 1157 cte.blue); 1158 } 1159 bmap += padded_line; 1160 fb -= (VIDEO_VISIBLE_COLS + width) * 1161 VIDEO_PIXEL_SIZE; 1162 } 1163 break; 1164 default: 1165 puts("4bpp bitmap unsupported with current " 1166 "video mode\n"); 1167 break; 1168 } 1169 break; 1170 1171 case 8: 1172 padded_line -= width; 1173 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) { 1174 /* Copy colormap */ 1175 for (xcount = 0; xcount < colors; ++xcount) { 1176 cte = bmp->color_table[xcount]; 1177 video_set_lut (xcount, cte.red, cte.green, cte.blue); 1178 } 1179 } 1180 ycount = height; 1181 switch (VIDEO_DATA_FORMAT) { 1182 case GDF__8BIT_INDEX: 1183 while (ycount--) { 1184 WATCHDOG_RESET (); 1185 xcount = width; 1186 while (xcount--) { 1187 *fb++ = *bmap++; 1188 } 1189 bmap += padded_line; 1190 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1191 } 1192 break; 1193 case GDF__8BIT_332RGB: 1194 while (ycount--) { 1195 WATCHDOG_RESET (); 1196 xcount = width; 1197 while (xcount--) { 1198 cte = bmp->color_table[*bmap++]; 1199 FILL_8BIT_332RGB (cte.red, cte.green, cte.blue); 1200 } 1201 bmap += padded_line; 1202 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1203 } 1204 break; 1205 case GDF_15BIT_555RGB: 1206 while (ycount--) { 1207 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1208 int xpos = x; 1209 #endif 1210 WATCHDOG_RESET (); 1211 xcount = width; 1212 while (xcount--) { 1213 cte = bmp->color_table[*bmap++]; 1214 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1215 fill_555rgb_pswap (fb, xpos++, cte.red, 1216 cte.green, cte.blue); 1217 fb += 2; 1218 #else 1219 FILL_15BIT_555RGB (cte.red, cte.green, cte.blue); 1220 #endif 1221 } 1222 bmap += padded_line; 1223 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1224 } 1225 break; 1226 case GDF_16BIT_565RGB: 1227 while (ycount--) { 1228 WATCHDOG_RESET (); 1229 xcount = width; 1230 while (xcount--) { 1231 cte = bmp->color_table[*bmap++]; 1232 FILL_16BIT_565RGB (cte.red, cte.green, cte.blue); 1233 } 1234 bmap += padded_line; 1235 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1236 } 1237 break; 1238 case GDF_32BIT_X888RGB: 1239 while (ycount--) { 1240 WATCHDOG_RESET (); 1241 xcount = width; 1242 while (xcount--) { 1243 cte = bmp->color_table[*bmap++]; 1244 FILL_32BIT_X888RGB (cte.red, cte.green, cte.blue); 1245 } 1246 bmap += padded_line; 1247 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1248 } 1249 break; 1250 case GDF_24BIT_888RGB: 1251 while (ycount--) { 1252 WATCHDOG_RESET (); 1253 xcount = width; 1254 while (xcount--) { 1255 cte = bmp->color_table[*bmap++]; 1256 FILL_24BIT_888RGB (cte.red, cte.green, cte.blue); 1257 } 1258 bmap += padded_line; 1259 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1260 } 1261 break; 1262 } 1263 break; 1264 case 24: 1265 padded_line -= 3 * width; 1266 ycount = height; 1267 switch (VIDEO_DATA_FORMAT) { 1268 case GDF__8BIT_332RGB: 1269 while (ycount--) { 1270 WATCHDOG_RESET (); 1271 xcount = width; 1272 while (xcount--) { 1273 FILL_8BIT_332RGB (bmap[2], bmap[1], bmap[0]); 1274 bmap += 3; 1275 } 1276 bmap += padded_line; 1277 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1278 } 1279 break; 1280 case GDF_15BIT_555RGB: 1281 while (ycount--) { 1282 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1283 int xpos = x; 1284 #endif 1285 WATCHDOG_RESET (); 1286 xcount = width; 1287 while (xcount--) { 1288 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1289 fill_555rgb_pswap (fb, xpos++, bmap[2], 1290 bmap[1], bmap[0]); 1291 fb += 2; 1292 #else 1293 FILL_15BIT_555RGB (bmap[2], bmap[1], bmap[0]); 1294 #endif 1295 bmap += 3; 1296 } 1297 bmap += padded_line; 1298 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1299 } 1300 break; 1301 case GDF_16BIT_565RGB: 1302 while (ycount--) { 1303 WATCHDOG_RESET (); 1304 xcount = width; 1305 while (xcount--) { 1306 FILL_16BIT_565RGB (bmap[2], bmap[1], bmap[0]); 1307 bmap += 3; 1308 } 1309 bmap += padded_line; 1310 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1311 } 1312 break; 1313 case GDF_32BIT_X888RGB: 1314 while (ycount--) { 1315 WATCHDOG_RESET (); 1316 xcount = width; 1317 while (xcount--) { 1318 FILL_32BIT_X888RGB (bmap[2], bmap[1], bmap[0]); 1319 bmap += 3; 1320 } 1321 bmap += padded_line; 1322 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1323 } 1324 break; 1325 case GDF_24BIT_888RGB: 1326 while (ycount--) { 1327 WATCHDOG_RESET (); 1328 xcount = width; 1329 while (xcount--) { 1330 FILL_24BIT_888RGB (bmap[2], bmap[1], bmap[0]); 1331 bmap += 3; 1332 } 1333 bmap += padded_line; 1334 fb -= (VIDEO_VISIBLE_COLS + width) * VIDEO_PIXEL_SIZE; 1335 } 1336 break; 1337 default: 1338 printf ("Error: 24 bits/pixel bitmap incompatible with current video mode\n"); 1339 break; 1340 } 1341 break; 1342 default: 1343 printf ("Error: %d bit/pixel bitmaps not supported by U-Boot\n", 1344 le16_to_cpu (bmp->header.bit_count)); 1345 break; 1346 } 1347 1348 #ifdef CONFIG_VIDEO_BMP_GZIP 1349 if (dst) { 1350 free(dst); 1351 } 1352 #endif 1353 1354 return (0); 1355 } 1356 #endif 1357 1358 /*****************************************************************************/ 1359 1360 #ifdef CONFIG_VIDEO_LOGO 1361 void logo_plot (void *screen, int width, int x, int y) 1362 { 1363 1364 int xcount, i; 1365 int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE; 1366 int ycount = video_logo_height; 1367 unsigned char r, g, b, *logo_red, *logo_blue, *logo_green; 1368 unsigned char *source; 1369 unsigned char *dest = (unsigned char *)screen + 1370 ((y * width * VIDEO_PIXEL_SIZE) + 1371 x * VIDEO_PIXEL_SIZE); 1372 1373 #ifdef CONFIG_VIDEO_BMP_LOGO 1374 source = bmp_logo_bitmap; 1375 1376 /* Allocate temporary space for computing colormap */ 1377 logo_red = malloc (BMP_LOGO_COLORS); 1378 logo_green = malloc (BMP_LOGO_COLORS); 1379 logo_blue = malloc (BMP_LOGO_COLORS); 1380 /* Compute color map */ 1381 for (i = 0; i < VIDEO_LOGO_COLORS; i++) { 1382 logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4; 1383 logo_green[i] = (bmp_logo_palette[i] & 0x00f0); 1384 logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4; 1385 } 1386 #else 1387 source = linux_logo; 1388 logo_red = linux_logo_red; 1389 logo_green = linux_logo_green; 1390 logo_blue = linux_logo_blue; 1391 #endif 1392 1393 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) { 1394 for (i = 0; i < VIDEO_LOGO_COLORS; i++) { 1395 video_set_lut (i + VIDEO_LOGO_LUT_OFFSET, 1396 logo_red[i], logo_green[i], logo_blue[i]); 1397 } 1398 } 1399 1400 while (ycount--) { 1401 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1402 int xpos = x; 1403 #endif 1404 xcount = VIDEO_LOGO_WIDTH; 1405 while (xcount--) { 1406 r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET]; 1407 g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET]; 1408 b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET]; 1409 1410 switch (VIDEO_DATA_FORMAT) { 1411 case GDF__8BIT_INDEX: 1412 *dest = *source; 1413 break; 1414 case GDF__8BIT_332RGB: 1415 *dest = ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); 1416 break; 1417 case GDF_15BIT_555RGB: 1418 #if defined(VIDEO_FB_16BPP_PIXEL_SWAP) 1419 fill_555rgb_pswap (dest, xpos++, r, g, b); 1420 #else 1421 *(unsigned short *) dest = 1422 SWAP16 ((unsigned short) (((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3))); 1423 #endif 1424 break; 1425 case GDF_16BIT_565RGB: 1426 *(unsigned short *) dest = 1427 SWAP16 ((unsigned short) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3))); 1428 break; 1429 case GDF_32BIT_X888RGB: 1430 *(unsigned long *) dest = 1431 SWAP32 ((unsigned long) ((r << 16) | (g << 8) | b)); 1432 break; 1433 case GDF_24BIT_888RGB: 1434 #ifdef VIDEO_FB_LITTLE_ENDIAN 1435 dest[0] = b; 1436 dest[1] = g; 1437 dest[2] = r; 1438 #else 1439 dest[0] = r; 1440 dest[1] = g; 1441 dest[2] = b; 1442 #endif 1443 break; 1444 } 1445 source++; 1446 dest += VIDEO_PIXEL_SIZE; 1447 } 1448 dest += skip; 1449 } 1450 #ifdef CONFIG_VIDEO_BMP_LOGO 1451 free (logo_red); 1452 free (logo_green); 1453 free (logo_blue); 1454 #endif 1455 } 1456 1457 /*****************************************************************************/ 1458 1459 static void *video_logo (void) 1460 { 1461 char info[128]; 1462 int space, len, y_off = 0; 1463 1464 #ifdef CONFIG_SPLASH_SCREEN 1465 char *s; 1466 ulong addr; 1467 1468 if ((s = getenv ("splashimage")) != NULL) { 1469 int x = 0, y = 0; 1470 1471 addr = simple_strtoul (s, NULL, 16); 1472 #ifdef CONFIG_SPLASH_SCREEN_ALIGN 1473 if ((s = getenv ("splashpos")) != NULL) { 1474 if (s[0] == 'm') 1475 x = BMP_ALIGN_CENTER; 1476 else 1477 x = simple_strtol (s, NULL, 0); 1478 1479 if ((s = strchr (s + 1, ',')) != NULL) { 1480 if (s[1] == 'm') 1481 y = BMP_ALIGN_CENTER; 1482 else 1483 y = simple_strtol (s + 1, NULL, 0); 1484 } 1485 } 1486 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */ 1487 1488 if (video_display_bitmap (addr, x, y) == 0) { 1489 video_logo_height = 0; 1490 return ((void *) (video_fb_address)); 1491 } 1492 } 1493 #endif /* CONFIG_SPLASH_SCREEN */ 1494 1495 logo_plot (video_fb_address, VIDEO_COLS, 0, 0); 1496 1497 sprintf (info, " %s", version_string); 1498 1499 space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH; 1500 len = strlen(info); 1501 1502 if (len > space) { 1503 video_drawchars (VIDEO_INFO_X, VIDEO_INFO_Y, 1504 (uchar *)info, space); 1505 video_drawchars (VIDEO_INFO_X + VIDEO_FONT_WIDTH, 1506 VIDEO_INFO_Y + VIDEO_FONT_HEIGHT, 1507 (uchar *)info + space, len - space); 1508 y_off = 1; 1509 } else 1510 video_drawstring (VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *)info); 1511 1512 #ifdef CONFIG_CONSOLE_EXTRA_INFO 1513 { 1514 int i, n = ((video_logo_height - VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT); 1515 1516 for (i = 1; i < n; i++) { 1517 video_get_info_str (i, info); 1518 if (!*info) 1519 continue; 1520 1521 len = strlen(info); 1522 if (len > space) { 1523 video_drawchars (VIDEO_INFO_X, 1524 VIDEO_INFO_Y + 1525 (i + y_off) * VIDEO_FONT_HEIGHT, 1526 (uchar *)info, space); 1527 y_off++; 1528 video_drawchars (VIDEO_INFO_X + VIDEO_FONT_WIDTH, 1529 VIDEO_INFO_Y + 1530 (i + y_off) * VIDEO_FONT_HEIGHT, 1531 (uchar *)info + space, 1532 len - space); 1533 } else { 1534 video_drawstring (VIDEO_INFO_X, 1535 VIDEO_INFO_Y + 1536 (i + y_off) * VIDEO_FONT_HEIGHT, 1537 (uchar *)info); 1538 } 1539 } 1540 } 1541 #endif 1542 1543 return (video_fb_address + video_logo_height * VIDEO_LINE_LEN); 1544 } 1545 #endif 1546 1547 1548 /*****************************************************************************/ 1549 1550 static int video_init (void) 1551 { 1552 unsigned char color8; 1553 1554 if ((pGD = video_hw_init ()) == NULL) 1555 return -1; 1556 1557 video_fb_address = (void *) VIDEO_FB_ADRS; 1558 #ifdef CONFIG_VIDEO_HW_CURSOR 1559 video_init_hw_cursor (VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT); 1560 #endif 1561 1562 /* Init drawing pats */ 1563 switch (VIDEO_DATA_FORMAT) { 1564 case GDF__8BIT_INDEX: 1565 video_set_lut (0x01, CONSOLE_FG_COL, CONSOLE_FG_COL, CONSOLE_FG_COL); 1566 video_set_lut (0x00, CONSOLE_BG_COL, CONSOLE_BG_COL, CONSOLE_BG_COL); 1567 fgx = 0x01010101; 1568 bgx = 0x00000000; 1569 break; 1570 case GDF__8BIT_332RGB: 1571 color8 = ((CONSOLE_FG_COL & 0xe0) | 1572 ((CONSOLE_FG_COL >> 3) & 0x1c) | CONSOLE_FG_COL >> 6); 1573 fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8; 1574 color8 = ((CONSOLE_BG_COL & 0xe0) | 1575 ((CONSOLE_BG_COL >> 3) & 0x1c) | CONSOLE_BG_COL >> 6); 1576 bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) | color8; 1577 break; 1578 case GDF_15BIT_555RGB: 1579 fgx = (((CONSOLE_FG_COL >> 3) << 26) | 1580 ((CONSOLE_FG_COL >> 3) << 21) | ((CONSOLE_FG_COL >> 3) << 16) | 1581 ((CONSOLE_FG_COL >> 3) << 10) | ((CONSOLE_FG_COL >> 3) << 5) | 1582 (CONSOLE_FG_COL >> 3)); 1583 bgx = (((CONSOLE_BG_COL >> 3) << 26) | 1584 ((CONSOLE_BG_COL >> 3) << 21) | ((CONSOLE_BG_COL >> 3) << 16) | 1585 ((CONSOLE_BG_COL >> 3) << 10) | ((CONSOLE_BG_COL >> 3) << 5) | 1586 (CONSOLE_BG_COL >> 3)); 1587 break; 1588 case GDF_16BIT_565RGB: 1589 fgx = (((CONSOLE_FG_COL >> 3) << 27) | 1590 ((CONSOLE_FG_COL >> 2) << 21) | ((CONSOLE_FG_COL >> 3) << 16) | 1591 ((CONSOLE_FG_COL >> 3) << 11) | ((CONSOLE_FG_COL >> 2) << 5) | 1592 (CONSOLE_FG_COL >> 3)); 1593 bgx = (((CONSOLE_BG_COL >> 3) << 27) | 1594 ((CONSOLE_BG_COL >> 2) << 21) | ((CONSOLE_BG_COL >> 3) << 16) | 1595 ((CONSOLE_BG_COL >> 3) << 11) | ((CONSOLE_BG_COL >> 2) << 5) | 1596 (CONSOLE_BG_COL >> 3)); 1597 break; 1598 case GDF_32BIT_X888RGB: 1599 fgx = (CONSOLE_FG_COL << 16) | (CONSOLE_FG_COL << 8) | CONSOLE_FG_COL; 1600 bgx = (CONSOLE_BG_COL << 16) | (CONSOLE_BG_COL << 8) | CONSOLE_BG_COL; 1601 break; 1602 case GDF_24BIT_888RGB: 1603 fgx = (CONSOLE_FG_COL << 24) | (CONSOLE_FG_COL << 16) | 1604 (CONSOLE_FG_COL << 8) | CONSOLE_FG_COL; 1605 bgx = (CONSOLE_BG_COL << 24) | (CONSOLE_BG_COL << 16) | 1606 (CONSOLE_BG_COL << 8) | CONSOLE_BG_COL; 1607 break; 1608 } 1609 eorx = fgx ^ bgx; 1610 1611 #ifdef CONFIG_VIDEO_LOGO 1612 /* Plot the logo and get start point of console */ 1613 PRINTD ("Video: Drawing the logo ...\n"); 1614 video_console_address = video_logo (); 1615 #else 1616 video_console_address = video_fb_address; 1617 #endif 1618 1619 /* Initialize the console */ 1620 console_col = 0; 1621 console_row = 0; 1622 1623 return 0; 1624 } 1625 1626 1627 /*****************************************************************************/ 1628 1629 /* 1630 * Implement a weak default function for boards that optionally 1631 * need to skip the video initialization. 1632 */ 1633 int __board_video_skip(void) 1634 { 1635 /* As default, don't skip test */ 1636 return 0; 1637 } 1638 int board_video_skip(void) __attribute__((weak, alias("__board_video_skip"))); 1639 1640 int drv_video_init (void) 1641 { 1642 int skip_dev_init; 1643 struct stdio_dev console_dev; 1644 1645 /* Check if video initialization should be skipped */ 1646 if (board_video_skip()) 1647 return 0; 1648 1649 /* Init video chip - returns with framebuffer cleared */ 1650 skip_dev_init = (video_init () == -1); 1651 1652 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE) 1653 PRINTD ("KBD: Keyboard init ...\n"); 1654 skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1); 1655 #endif 1656 1657 if (skip_dev_init) 1658 return 0; 1659 1660 /* Init vga device */ 1661 memset (&console_dev, 0, sizeof (console_dev)); 1662 strcpy (console_dev.name, "vga"); 1663 console_dev.ext = DEV_EXT_VIDEO; /* Video extensions */ 1664 console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM; 1665 console_dev.putc = video_putc; /* 'putc' function */ 1666 console_dev.puts = video_puts; /* 'puts' function */ 1667 console_dev.tstc = NULL; /* 'tstc' function */ 1668 console_dev.getc = NULL; /* 'getc' function */ 1669 1670 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE) 1671 /* Also init console device */ 1672 console_dev.flags |= DEV_FLAGS_INPUT; 1673 console_dev.tstc = VIDEO_TSTC_FCT; /* 'tstc' function */ 1674 console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */ 1675 #endif /* CONFIG_VGA_AS_SINGLE_DEVICE */ 1676 1677 if (stdio_register (&console_dev) != 0) 1678 return 0; 1679 1680 /* Return success */ 1681 return 1; 1682 } 1683