Stefan Reinauer | f05dcb8 | 2004-04-24 22:29:44 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Procedures for drawing on the screen early on in the boot process. |
| 3 | * |
| 4 | * Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| 5 | * |
| 6 | * move to LinuxBIOS by LYH yhlu@tyan.com |
| 7 | */ |
| 8 | |
| 9 | #if 0 |
| 10 | |
| 11 | #include <delay.h> |
| 12 | #include <stdlib.h> |
| 13 | #include <string.h> |
| 14 | #include <arch/io.h> |
| 15 | |
| 16 | #include <console/console.h> |
| 17 | #include <device/device.h> |
| 18 | #include <device/pci.h> |
| 19 | #include <device/pci_ids.h> |
| 20 | #include <device/pci_ops.h> |
| 21 | |
| 22 | #endif |
| 23 | |
| 24 | #include <arch/io.h> |
| 25 | #include <string.h> |
| 26 | #include <console/console.h> |
| 27 | |
| 28 | |
| 29 | #include <arch/byteorder.h> |
| 30 | |
Stefan Reinauer | 234454d | 2004-04-24 23:10:51 +0000 | [diff] [blame] | 31 | #include <console/btext.h> |
Stefan Reinauer | f05dcb8 | 2004-04-24 22:29:44 +0000 | [diff] [blame] | 32 | |
| 33 | //#define NO_SCROLL |
| 34 | |
| 35 | #ifndef NO_SCROLL |
| 36 | static void scrollscreen(void); |
| 37 | #endif |
| 38 | |
| 39 | static void draw_byte(unsigned char c, u32 locX, u32 locY); |
| 40 | #if 0 |
| 41 | static void draw_byte_32(unsigned char *bits, u32 *base, u32 rb); |
| 42 | static void draw_byte_16(unsigned char *bits, u32 *base, u32 rb); |
| 43 | #endif |
| 44 | static void draw_byte_8(unsigned char *bits, u32 *base, u32 rb); |
| 45 | |
| 46 | static u32 g_loc_X; |
| 47 | static u32 g_loc_Y; |
| 48 | static u32 g_max_loc_X; |
| 49 | static u32 g_max_loc_Y; |
| 50 | |
Yinghai Lu | 97c4947 | 2004-04-28 05:37:36 +0000 | [diff] [blame] | 51 | #define CHAR_256 0 |
| 52 | |
| 53 | #if CHAR_256==1 |
Stefan Reinauer | f05dcb8 | 2004-04-24 22:29:44 +0000 | [diff] [blame] | 54 | #define cmapsz (16*256) |
Yinghai Lu | 97c4947 | 2004-04-28 05:37:36 +0000 | [diff] [blame] | 55 | #else |
| 56 | #define cmapsz (16*96) |
| 57 | #endif |
Stefan Reinauer | f05dcb8 | 2004-04-24 22:29:44 +0000 | [diff] [blame] | 58 | |
Yinghai Lu | 9709908 | 2004-12-16 02:44:25 +0000 | [diff] [blame] | 59 | extern unsigned char vga_font[cmapsz]; |
Stefan Reinauer | f05dcb8 | 2004-04-24 22:29:44 +0000 | [diff] [blame] | 60 | |
| 61 | u32 boot_text_mapped; |
| 62 | |
| 63 | boot_infos_t disp_bi; |
| 64 | |
| 65 | #define BTEXT |
| 66 | #define BTDATA |
| 67 | |
| 68 | |
| 69 | /* This function will enable the early boot text when doing OF booting. This |
| 70 | * way, xmon output should work too |
| 71 | */ |
| 72 | void |
| 73 | btext_setup_display(u32 width, u32 height, u32 depth, u32 pitch, |
| 74 | unsigned long address) |
| 75 | { |
| 76 | boot_infos_t* bi = &disp_bi; |
| 77 | |
| 78 | g_loc_X = 0; |
| 79 | g_loc_Y = 0; |
| 80 | g_max_loc_X = width / 8; |
| 81 | g_max_loc_Y = height / 16; |
| 82 | // bi->logicalDisplayBase = (unsigned char *)address; |
| 83 | bi->dispDeviceBase = (unsigned char *)address; |
| 84 | bi->dispDeviceRowBytes = pitch; |
| 85 | bi->dispDeviceDepth = depth; |
| 86 | bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; |
| 87 | bi->dispDeviceRect[2] = width; |
| 88 | bi->dispDeviceRect[3] = height; |
| 89 | boot_text_mapped = 0; |
| 90 | } |
| 91 | |
| 92 | /* Here's a small text engine to use during early boot |
| 93 | * or for debugging purposes |
| 94 | * |
| 95 | * todo: |
| 96 | * |
| 97 | * - build some kind of vgacon with it to enable early printk |
| 98 | * - move to a separate file |
| 99 | * - add a few video driver hooks to keep in sync with display |
| 100 | * changes. |
| 101 | */ |
| 102 | |
| 103 | void |
| 104 | map_boot_text(void) |
| 105 | { |
| 106 | #if 0 |
| 107 | unsigned long base, offset, size; |
| 108 | boot_infos_t *bi = &disp_bi; |
| 109 | |
| 110 | if (bi->dispDeviceBase == 0) |
| 111 | return; |
| 112 | base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL; |
| 113 | offset = ((unsigned long) bi->dispDeviceBase) - base; |
| 114 | size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset |
| 115 | + bi->dispDeviceRect[0]; |
| 116 | bi->logicalDisplayBase = ioremap(base,0x800000 ); |
| 117 | if (bi->logicalDisplayBase == 0) |
| 118 | return; |
| 119 | // bi->logicalDisplayBase += offset; |
| 120 | #endif |
| 121 | boot_text_mapped = 1; |
| 122 | } |
| 123 | |
| 124 | /* Calc the base address of a given point (x,y) */ |
| 125 | static unsigned char * BTEXT |
| 126 | calc_base(boot_infos_t *bi, u32 x, u32 y) |
| 127 | { |
| 128 | unsigned char *base; |
| 129 | #if 0 |
| 130 | base = bi->logicalDisplayBase; |
| 131 | if (base == 0) |
| 132 | #endif |
| 133 | base = bi->dispDeviceBase; |
| 134 | base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3); |
| 135 | base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes; |
| 136 | return base; |
| 137 | } |
| 138 | |
| 139 | /* Adjust the display to a new resolution */ |
| 140 | void |
| 141 | btext_update_display(unsigned long phys, u32 width, u32 height, |
| 142 | u32 depth, u32 pitch) |
| 143 | { |
| 144 | boot_infos_t *bi = &disp_bi; |
| 145 | #if 0 |
| 146 | if (bi->dispDeviceBase == 0) |
| 147 | return; |
| 148 | /* check it's the same frame buffer (within 256MB) */ |
| 149 | if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000) |
| 150 | return; |
| 151 | #endif |
| 152 | |
| 153 | bi->dispDeviceBase = (u8 *) phys; |
| 154 | bi->dispDeviceRect[0] = 0; |
| 155 | bi->dispDeviceRect[1] = 0; |
| 156 | bi->dispDeviceRect[2] = width; |
| 157 | bi->dispDeviceRect[3] = height; |
| 158 | bi->dispDeviceDepth = depth; |
| 159 | bi->dispDeviceRowBytes = pitch; |
| 160 | if (boot_text_mapped) { |
| 161 | #if 0 |
| 162 | iounmap(bi->logicalDisplayBase); |
| 163 | #endif |
| 164 | boot_text_mapped = 0; |
| 165 | } |
| 166 | map_boot_text(); |
| 167 | g_loc_X = 0; |
| 168 | g_loc_Y = 0; |
| 169 | g_max_loc_X = width / 8; |
| 170 | g_max_loc_Y = height / 16; |
| 171 | } |
| 172 | |
| 173 | void BTEXT btext_clearscreen(void) |
| 174 | { |
| 175 | boot_infos_t* bi = &disp_bi; |
| 176 | u32 *base = (u32 *)calc_base(bi, 0, 0); |
| 177 | u32 width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * |
| 178 | (bi->dispDeviceDepth >> 3)) >> 2; |
| 179 | u32 i,j; |
| 180 | |
| 181 | for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) |
| 182 | { |
| 183 | u32 *ptr = base; |
| 184 | for(j=width; j; --j) |
| 185 | *(ptr++) = 0; |
| 186 | base += (bi->dispDeviceRowBytes >> 2); |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | #if 0 |
| 191 | __inline__ void dcbst(const void* addr) |
| 192 | { |
| 193 | __asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr)); |
| 194 | } |
| 195 | |
| 196 | void BTEXT btext_flushscreen(void) |
| 197 | { |
| 198 | boot_infos_t* bi = &disp_bi; |
| 199 | u32 *base = (unsigned long *)calc_base(bi, 0, 0); |
| 200 | u32 width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * |
| 201 | (bi->dispDeviceDepth >> 3)) >> 2; |
| 202 | u32 i,j; |
| 203 | |
| 204 | for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) |
| 205 | { |
| 206 | u32 *ptr = base; |
| 207 | for(j=width; j>0; j-=8) { |
| 208 | dcbst(ptr); |
| 209 | ptr += 8; |
| 210 | } |
| 211 | base += (bi->dispDeviceRowBytes >> 2); |
| 212 | } |
| 213 | } |
| 214 | #endif |
| 215 | |
| 216 | |
| 217 | #ifndef NO_SCROLL |
| 218 | static BTEXT void |
| 219 | scrollscreen(void) |
| 220 | { |
| 221 | boot_infos_t* bi = &disp_bi; |
| 222 | u32 *src = (u32 *)calc_base(bi,0,16); |
| 223 | u32 *dst = (u32 *)calc_base(bi,0,0); |
| 224 | u32 width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * |
| 225 | (bi->dispDeviceDepth >> 3)) >> 2; |
| 226 | u32 i,j; |
| 227 | |
| 228 | for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) |
| 229 | { |
| 230 | u32 *src_ptr = src; |
| 231 | u32 *dst_ptr = dst; |
| 232 | for(j=width; j; --j) |
| 233 | *(dst_ptr++) = *(src_ptr++); |
| 234 | src += (bi->dispDeviceRowBytes >> 2); |
| 235 | dst += (bi->dispDeviceRowBytes >> 2); |
| 236 | } |
| 237 | for (i=0; i<16; i++) |
| 238 | { |
| 239 | u32 *dst_ptr = dst; |
| 240 | for(j=width; j; --j) |
| 241 | *(dst_ptr++) = 0; |
| 242 | dst += (bi->dispDeviceRowBytes >> 2); |
| 243 | } |
| 244 | } |
| 245 | #endif /* ndef NO_SCROLL */ |
| 246 | |
| 247 | void BTEXT btext_drawchar(char c) |
| 248 | { |
| 249 | u32 cline = 0; |
| 250 | |
| 251 | if (!boot_text_mapped) |
| 252 | return; |
| 253 | |
| 254 | switch (c) { |
| 255 | case '\b': |
| 256 | if (g_loc_X > 0) |
| 257 | --g_loc_X; |
| 258 | break; |
| 259 | case '\t': |
| 260 | g_loc_X = (g_loc_X & -8) + 8; |
| 261 | break; |
| 262 | case '\r': |
| 263 | g_loc_X = 0; |
| 264 | break; |
| 265 | case '\n': |
| 266 | g_loc_X = 0; |
| 267 | g_loc_Y++; |
| 268 | cline = 1; |
| 269 | break; |
| 270 | default: |
| 271 | draw_byte(c, g_loc_X++, g_loc_Y); |
| 272 | } |
| 273 | if (g_loc_X >= g_max_loc_X) { |
| 274 | g_loc_X = 0; |
| 275 | g_loc_Y++; |
| 276 | cline = 1; |
| 277 | } |
| 278 | #ifndef NO_SCROLL |
| 279 | while (g_loc_Y >= g_max_loc_Y) { |
| 280 | scrollscreen(); |
| 281 | g_loc_Y--; |
| 282 | } |
| 283 | #else |
| 284 | /* wrap around from bottom to top of screen so we don't |
| 285 | waste time scrolling each line. -- paulus. */ |
| 286 | if (g_loc_Y >= g_max_loc_Y) |
| 287 | g_loc_Y = 0; |
| 288 | if (cline) { |
| 289 | for (x = 0; x < g_max_loc_X; ++x) |
| 290 | draw_byte(' ', x, g_loc_Y); |
| 291 | } |
| 292 | #endif |
| 293 | } |
Yinghai Lu | 97c4947 | 2004-04-28 05:37:36 +0000 | [diff] [blame] | 294 | #if 0 |
Stefan Reinauer | f05dcb8 | 2004-04-24 22:29:44 +0000 | [diff] [blame] | 295 | void BTEXT |
| 296 | btext_drawstring(const char *c) |
| 297 | { |
| 298 | if (!boot_text_mapped) |
| 299 | return; |
| 300 | while (*c) |
| 301 | btext_drawchar(*c++); |
| 302 | } |
| 303 | |
| 304 | void BTEXT |
| 305 | btext_drawhex(u32 v) |
| 306 | { |
| 307 | static char hex_table[] = "0123456789abcdef"; |
| 308 | |
| 309 | if (!boot_text_mapped) |
| 310 | return; |
| 311 | btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]); |
| 312 | btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]); |
| 313 | btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]); |
| 314 | btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]); |
| 315 | btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]); |
| 316 | btext_drawchar(hex_table[(v >> 8) & 0x0000000FUL]); |
| 317 | btext_drawchar(hex_table[(v >> 4) & 0x0000000FUL]); |
| 318 | btext_drawchar(hex_table[(v >> 0) & 0x0000000FUL]); |
| 319 | btext_drawchar(' '); |
| 320 | } |
Yinghai Lu | 97c4947 | 2004-04-28 05:37:36 +0000 | [diff] [blame] | 321 | #endif |
Stefan Reinauer | f05dcb8 | 2004-04-24 22:29:44 +0000 | [diff] [blame] | 322 | static void BTEXT |
| 323 | draw_byte(unsigned char c, u32 locX, u32 locY) |
| 324 | { |
| 325 | boot_infos_t* bi = &disp_bi; |
| 326 | unsigned char *base = calc_base(bi, locX << 3, locY << 4); |
Yinghai Lu | 97c4947 | 2004-04-28 05:37:36 +0000 | [diff] [blame] | 327 | #if CHAR_256==1 |
| 328 | unsigned char *font = &vga_font[((u32)c) * 16]; |
| 329 | #else |
| 330 | unsigned char *font = &vga_font[((u32)c-0x20) * 16]; // skip the first 0x20 |
| 331 | #endif |
Stefan Reinauer | f05dcb8 | 2004-04-24 22:29:44 +0000 | [diff] [blame] | 332 | u32 rb = bi->dispDeviceRowBytes; |
| 333 | |
| 334 | switch(bi->dispDeviceDepth) { |
| 335 | #if 0 |
| 336 | case 24: |
| 337 | case 32: |
| 338 | draw_byte_32(font, (u32 *)base, rb); |
| 339 | break; |
| 340 | case 15: |
| 341 | case 16: |
| 342 | draw_byte_16(font, (u32 *)base, rb); |
| 343 | break; |
| 344 | #endif |
| 345 | case 8: |
| 346 | draw_byte_8(font, (u32 *)base, rb); |
| 347 | break; |
| 348 | } |
| 349 | } |
| 350 | static u32 expand_bits_8[16] BTDATA = { |
| 351 | #if defined(__BIG_ENDIAN) |
| 352 | 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, |
| 353 | 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, |
| 354 | 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, |
| 355 | 0xffff0000,0xffff00ff,0xffffff00,0xffffffff |
| 356 | #elif defined(__LITTLE_ENDIAN) |
| 357 | 0x00000000,0xff000000,0x00ff0000,0xffff0000, |
| 358 | 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, |
| 359 | 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, |
| 360 | 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff |
| 361 | #else |
| 362 | #error FIXME: No endianness?? |
| 363 | #endif |
| 364 | }; |
| 365 | #if 0 |
| 366 | static const u32 expand_bits_16[4] BTDATA = { |
| 367 | #if defined(__BIG_ENDIAN) |
| 368 | 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff |
| 369 | #elif defined(__LITTLE_ENDIAN) |
| 370 | 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff |
| 371 | #else |
| 372 | #error FIXME: No endianness?? |
| 373 | #endif |
| 374 | }; |
| 375 | #endif |
| 376 | #if 0 |
| 377 | static void BTEXT |
| 378 | draw_byte_32(unsigned char *font, u32 *base, u32 rb) |
| 379 | { |
| 380 | u32 l, bits; |
| 381 | u32 fg = 0xFFFFFFFF; |
| 382 | u32 bg = 0x00000000; |
| 383 | |
| 384 | for (l = 0; l < 16; ++l) |
| 385 | { |
| 386 | bits = *font++; |
| 387 | base[0] = (-(bits >> 7) & fg) ^ bg; |
| 388 | base[1] = (-((bits >> 6) & 1) & fg) ^ bg; |
| 389 | base[2] = (-((bits >> 5) & 1) & fg) ^ bg; |
| 390 | base[3] = (-((bits >> 4) & 1) & fg) ^ bg; |
| 391 | base[4] = (-((bits >> 3) & 1) & fg) ^ bg; |
| 392 | base[5] = (-((bits >> 2) & 1) & fg) ^ bg; |
| 393 | base[6] = (-((bits >> 1) & 1) & fg) ^ bg; |
| 394 | base[7] = (-(bits & 1) & fg) ^ bg; |
| 395 | base = (u32 *) ((char *)base + rb); |
| 396 | } |
| 397 | } |
| 398 | |
| 399 | static void BTEXT |
| 400 | draw_byte_16(unsigned char *font, u32 *base, u32 rb) |
| 401 | { |
| 402 | u32 l, bits; |
| 403 | u32 fg = 0xFFFFFFFF; |
| 404 | u32 bg = 0x00000000; |
| 405 | u32 *eb = expand_bits_16; |
| 406 | |
| 407 | for (l = 0; l < 16; ++l) |
| 408 | { |
| 409 | bits = *font++; |
| 410 | base[0] = (eb[bits >> 6] & fg) ^ bg; |
| 411 | base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; |
| 412 | base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; |
| 413 | base[3] = (eb[bits & 3] & fg) ^ bg; |
| 414 | base = (u32 *) ((char *)base + rb); |
| 415 | } |
| 416 | } |
| 417 | #endif |
| 418 | static void BTEXT |
| 419 | draw_byte_8(unsigned char *font, u32 *base, u32 rb) |
| 420 | { |
| 421 | u32 l, bits; |
| 422 | u32 fg = 0x0F0F0F0F; |
| 423 | u32 bg = 0x00000000; |
| 424 | u32 *eb = expand_bits_8; |
| 425 | |
| 426 | for (l = 0; l < 16; ++l) |
| 427 | { |
| 428 | bits = *font++; |
| 429 | base[0] = (eb[bits >> 4] & fg) ^ bg; |
| 430 | base[1] = (eb[bits & 0xf] & fg) ^ bg; |
| 431 | base = (u32 *) ((char *)base + rb); |
| 432 | } |
| 433 | } |
| 434 | |
| 435 | void btext_init(void) |
| 436 | { |
| 437 | btext_setup_display(640, 480, 8, 640,0xfc000000); |
| 438 | // Not realy init |
| 439 | // It will be init in xlinit.c because We only can access fb after the device resource is allocated and enabled. |
| 440 | |
| 441 | } |
| 442 | |
| 443 | void btext_tx_byte(unsigned char data) |
| 444 | { |
| 445 | btext_drawchar(data); |
| 446 | } |
| 447 | |
| 448 | static struct console_driver btext_console __console = { |
| 449 | .init = btext_init, |
| 450 | .tx_byte = btext_tx_byte, |
| 451 | .rx_byte = 0, |
| 452 | .tst_byte = 0, |
| 453 | }; |
| 454 | |