Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/pmac: Early debug output on screen on 64-bit macs

We have a bunch of CONFIG_PPC_EARLY_DEBUG_* options that are intended
for bringup/debug only. They hard wire a machine specific udbg backend
very early on (before we even probe the platform), and use whatever
tricks are available on each machine/cpu to be able to get some kind
of output out there early on.

So far, on powermac with no serial ports, we have CONFIG_PPC_EARLY_DEBUG_BOOTX
to use the low-level btext engine on the screen, but it doesn't do much, at
least on 64-bit. It only really gets enabled after the platform has been
probed and the MMU enabled.

This adds a way to enable it much earlier. From prom_init.c (while still
running with Open Firmware), we grab the screen details and set things up
using the physical address of the frame buffer.

Then btext itself uses the "rm_ci" feature of the 970 processor (Real
Mode Cache Inhibited) to access it while in real mode.

We need to do a little bit of reorg of the btext code to inline things
better, in order to limit how much we touch memory while in this mode as
the consequences might be ... interesting.

This successfully allowed me to debug problems early on with the G5
(related to gold being broken vs. ppc64 kernels).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

+202 -117
+1
arch/powerpc/include/asm/btext.h
··· 13 13 extern void btext_setup_display(int width, int height, int depth, int pitch, 14 14 unsigned long address); 15 15 extern void btext_prepare_BAT(void); 16 + extern void btext_map(void); 16 17 extern void btext_unmap(void); 17 18 18 19 extern void btext_drawchar(char c);
+139 -115
arch/powerpc/kernel/btext.c
··· 25 25 static void scrollscreen(void); 26 26 #endif 27 27 28 - static void draw_byte(unsigned char c, long locX, long locY); 29 - static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb); 30 - static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb); 31 - static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb); 32 - 33 28 #define __force_data __attribute__((__section__(".data"))) 34 29 35 30 static int g_loc_X __force_data; ··· 46 51 47 52 int boot_text_mapped __force_data = 0; 48 53 int force_printk_to_btext = 0; 54 + 55 + extern void rmci_on(void); 56 + extern void rmci_off(void); 57 + 58 + static inline void rmci_maybe_on(void) 59 + { 60 + #ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX 61 + if (!(mfmsr() & MSR_DR)) 62 + rmci_on(); 63 + #endif 64 + } 65 + 66 + static inline void rmci_maybe_off(void) 67 + { 68 + #ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX 69 + if (!(mfmsr() & MSR_DR)) 70 + rmci_off(); 71 + #endif 72 + } 73 + 49 74 50 75 #ifdef CONFIG_PPC32 51 76 /* Calc BAT values for mapping the display and store them ··· 149 134 * changes. 150 135 */ 151 136 152 - static void map_boot_text(void) 137 + void btext_map(void) 153 138 { 154 139 unsigned long base, offset, size; 155 140 unsigned char *vbase; ··· 224 209 dispDeviceRect[2] = width; 225 210 dispDeviceRect[3] = height; 226 211 227 - map_boot_text(); 212 + btext_map(); 228 213 229 214 return 0; 230 215 } ··· 298 283 iounmap(logicalDisplayBase); 299 284 boot_text_mapped = 0; 300 285 } 301 - map_boot_text(); 286 + btext_map(); 302 287 g_loc_X = 0; 303 288 g_loc_Y = 0; 304 289 g_max_loc_X = width / 8; ··· 313 298 (dispDeviceDepth >> 3)) >> 2; 314 299 int i,j; 315 300 301 + rmci_maybe_on(); 316 302 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) 317 303 { 318 304 unsigned int *ptr = base; ··· 321 305 *(ptr++) = 0; 322 306 base += (dispDeviceRowBytes >> 2); 323 307 } 308 + rmci_maybe_off(); 324 309 } 325 310 326 311 void btext_flushscreen(void) ··· 372 355 (dispDeviceDepth >> 3)) >> 2; 373 356 int i,j; 374 357 358 + rmci_maybe_on(); 359 + 375 360 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) 376 361 { 377 362 unsigned int *src_ptr = src; ··· 390 371 *(dst_ptr++) = 0; 391 372 dst += (dispDeviceRowBytes >> 2); 392 373 } 374 + 375 + rmci_maybe_off(); 393 376 } 394 377 #endif /* ndef NO_SCROLL */ 378 + 379 + static unsigned int expand_bits_8[16] = { 380 + 0x00000000, 381 + 0x000000ff, 382 + 0x0000ff00, 383 + 0x0000ffff, 384 + 0x00ff0000, 385 + 0x00ff00ff, 386 + 0x00ffff00, 387 + 0x00ffffff, 388 + 0xff000000, 389 + 0xff0000ff, 390 + 0xff00ff00, 391 + 0xff00ffff, 392 + 0xffff0000, 393 + 0xffff00ff, 394 + 0xffffff00, 395 + 0xffffffff 396 + }; 397 + 398 + static unsigned int expand_bits_16[4] = { 399 + 0x00000000, 400 + 0x0000ffff, 401 + 0xffff0000, 402 + 0xffffffff 403 + }; 404 + 405 + 406 + static void draw_byte_32(unsigned char *font, unsigned int *base, int rb) 407 + { 408 + int l, bits; 409 + int fg = 0xFFFFFFFFUL; 410 + int bg = 0x00000000UL; 411 + 412 + for (l = 0; l < 16; ++l) 413 + { 414 + bits = *font++; 415 + base[0] = (-(bits >> 7) & fg) ^ bg; 416 + base[1] = (-((bits >> 6) & 1) & fg) ^ bg; 417 + base[2] = (-((bits >> 5) & 1) & fg) ^ bg; 418 + base[3] = (-((bits >> 4) & 1) & fg) ^ bg; 419 + base[4] = (-((bits >> 3) & 1) & fg) ^ bg; 420 + base[5] = (-((bits >> 2) & 1) & fg) ^ bg; 421 + base[6] = (-((bits >> 1) & 1) & fg) ^ bg; 422 + base[7] = (-(bits & 1) & fg) ^ bg; 423 + base = (unsigned int *) ((char *)base + rb); 424 + } 425 + } 426 + 427 + static inline void draw_byte_16(unsigned char *font, unsigned int *base, int rb) 428 + { 429 + int l, bits; 430 + int fg = 0xFFFFFFFFUL; 431 + int bg = 0x00000000UL; 432 + unsigned int *eb = (int *)expand_bits_16; 433 + 434 + for (l = 0; l < 16; ++l) 435 + { 436 + bits = *font++; 437 + base[0] = (eb[bits >> 6] & fg) ^ bg; 438 + base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; 439 + base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; 440 + base[3] = (eb[bits & 3] & fg) ^ bg; 441 + base = (unsigned int *) ((char *)base + rb); 442 + } 443 + } 444 + 445 + static inline void draw_byte_8(unsigned char *font, unsigned int *base, int rb) 446 + { 447 + int l, bits; 448 + int fg = 0x0F0F0F0FUL; 449 + int bg = 0x00000000UL; 450 + unsigned int *eb = (int *)expand_bits_8; 451 + 452 + for (l = 0; l < 16; ++l) 453 + { 454 + bits = *font++; 455 + base[0] = (eb[bits >> 4] & fg) ^ bg; 456 + base[1] = (eb[bits & 0xf] & fg) ^ bg; 457 + base = (unsigned int *) ((char *)base + rb); 458 + } 459 + } 460 + 461 + static noinline void draw_byte(unsigned char c, long locX, long locY) 462 + { 463 + unsigned char *base = calc_base(locX << 3, locY << 4); 464 + unsigned char *font = &vga_font[((unsigned int)c) * 16]; 465 + int rb = dispDeviceRowBytes; 466 + 467 + rmci_maybe_on(); 468 + switch(dispDeviceDepth) { 469 + case 24: 470 + case 32: 471 + draw_byte_32(font, (unsigned int *)base, rb); 472 + break; 473 + case 15: 474 + case 16: 475 + draw_byte_16(font, (unsigned int *)base, rb); 476 + break; 477 + case 8: 478 + draw_byte_8(font, (unsigned int *)base, rb); 479 + break; 480 + } 481 + rmci_maybe_off(); 482 + } 395 483 396 484 void btext_drawchar(char c) 397 485 { ··· 591 465 btext_drawchar(' '); 592 466 } 593 467 594 - static void draw_byte(unsigned char c, long locX, long locY) 468 + void __init udbg_init_btext(void) 595 469 { 596 - unsigned char *base = calc_base(locX << 3, locY << 4); 597 - unsigned char *font = &vga_font[((unsigned int)c) * 16]; 598 - int rb = dispDeviceRowBytes; 599 - 600 - switch(dispDeviceDepth) { 601 - case 24: 602 - case 32: 603 - draw_byte_32(font, (unsigned int *)base, rb); 604 - break; 605 - case 15: 606 - case 16: 607 - draw_byte_16(font, (unsigned int *)base, rb); 608 - break; 609 - case 8: 610 - draw_byte_8(font, (unsigned int *)base, rb); 611 - break; 612 - } 613 - } 614 - 615 - static unsigned int expand_bits_8[16] = { 616 - 0x00000000, 617 - 0x000000ff, 618 - 0x0000ff00, 619 - 0x0000ffff, 620 - 0x00ff0000, 621 - 0x00ff00ff, 622 - 0x00ffff00, 623 - 0x00ffffff, 624 - 0xff000000, 625 - 0xff0000ff, 626 - 0xff00ff00, 627 - 0xff00ffff, 628 - 0xffff0000, 629 - 0xffff00ff, 630 - 0xffffff00, 631 - 0xffffffff 632 - }; 633 - 634 - static unsigned int expand_bits_16[4] = { 635 - 0x00000000, 636 - 0x0000ffff, 637 - 0xffff0000, 638 - 0xffffffff 639 - }; 640 - 641 - 642 - static void draw_byte_32(unsigned char *font, unsigned int *base, int rb) 643 - { 644 - int l, bits; 645 - int fg = 0xFFFFFFFFUL; 646 - int bg = 0x00000000UL; 647 - 648 - for (l = 0; l < 16; ++l) 649 - { 650 - bits = *font++; 651 - base[0] = (-(bits >> 7) & fg) ^ bg; 652 - base[1] = (-((bits >> 6) & 1) & fg) ^ bg; 653 - base[2] = (-((bits >> 5) & 1) & fg) ^ bg; 654 - base[3] = (-((bits >> 4) & 1) & fg) ^ bg; 655 - base[4] = (-((bits >> 3) & 1) & fg) ^ bg; 656 - base[5] = (-((bits >> 2) & 1) & fg) ^ bg; 657 - base[6] = (-((bits >> 1) & 1) & fg) ^ bg; 658 - base[7] = (-(bits & 1) & fg) ^ bg; 659 - base = (unsigned int *) ((char *)base + rb); 660 - } 661 - } 662 - 663 - static void draw_byte_16(unsigned char *font, unsigned int *base, int rb) 664 - { 665 - int l, bits; 666 - int fg = 0xFFFFFFFFUL; 667 - int bg = 0x00000000UL; 668 - unsigned int *eb = (int *)expand_bits_16; 669 - 670 - for (l = 0; l < 16; ++l) 671 - { 672 - bits = *font++; 673 - base[0] = (eb[bits >> 6] & fg) ^ bg; 674 - base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; 675 - base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; 676 - base[3] = (eb[bits & 3] & fg) ^ bg; 677 - base = (unsigned int *) ((char *)base + rb); 678 - } 679 - } 680 - 681 - static void draw_byte_8(unsigned char *font, unsigned int *base, int rb) 682 - { 683 - int l, bits; 684 - int fg = 0x0F0F0F0FUL; 685 - int bg = 0x00000000UL; 686 - unsigned int *eb = (int *)expand_bits_8; 687 - 688 - for (l = 0; l < 16; ++l) 689 - { 690 - bits = *font++; 691 - base[0] = (eb[bits >> 4] & fg) ^ bg; 692 - base[1] = (eb[bits & 0xf] & fg) ^ bg; 693 - base = (unsigned int *) ((char *)base + rb); 694 - } 470 + /* If btext is enabled, we might have a BAT setup for early display, 471 + * thus we do enable some very basic udbg output 472 + */ 473 + udbg_putc = btext_drawchar; 695 474 } 696 475 697 476 static unsigned char vga_font[cmapsz] = { ··· 944 913 0x00, 0x00, 0x00, 0x00, 945 914 }; 946 915 947 - void __init udbg_init_btext(void) 948 - { 949 - /* If btext is enabled, we might have a BAT setup for early display, 950 - * thus we do enable some very basic udbg output 951 - */ 952 - udbg_putc = btext_drawchar; 953 - }
+31
arch/powerpc/kernel/misc_64.S
··· 249 249 blr 250 250 251 251 #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) 252 + 253 + _GLOBAL(rmci_on) 254 + sync 255 + isync 256 + li r3,0x100 257 + rldicl r3,r3,32,0 258 + mfspr r5,SPRN_HID4 259 + or r5,r5,r3 260 + sync 261 + mtspr SPRN_HID4,r5 262 + isync 263 + slbia 264 + isync 265 + sync 266 + blr 267 + 268 + _GLOBAL(rmci_off) 269 + sync 270 + isync 271 + li r3,0x100 272 + rldicl r3,r3,32,0 273 + mfspr r5,SPRN_HID4 274 + andc r5,r5,r3 275 + sync 276 + mtspr SPRN_HID4,r5 277 + isync 278 + slbia 279 + isync 280 + sync 281 + blr 282 + 252 283 /* 253 284 * Do an IO access in real mode 254 285 */
+16
arch/powerpc/kernel/prom_init.c
··· 2082 2082 clut[2]) != 0) 2083 2083 break; 2084 2084 #endif /* CONFIG_LOGO_LINUX_CLUT224 */ 2085 + 2086 + #ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX 2087 + if (prom_getprop(node, "linux,boot-display", NULL, 0) != 2088 + PROM_ERROR) { 2089 + u32 width, height, pitch, addr; 2090 + 2091 + prom_printf("Setting btext !\n"); 2092 + prom_getprop(node, "width", &width, 4); 2093 + prom_getprop(node, "height", &height, 4); 2094 + prom_getprop(node, "linebytes", &pitch, 4); 2095 + prom_getprop(node, "address", &addr, 4); 2096 + prom_printf("W=%d H=%d LB=%d addr=0x%x\n", 2097 + width, height, pitch, addr); 2098 + btext_setup_display(width, height, 8, pitch, addr); 2099 + } 2100 + #endif /* CONFIG_PPC_EARLY_DEBUG_BOOTX */ 2085 2101 } 2086 2102 } 2087 2103
+2 -1
arch/powerpc/kernel/prom_init_check.sh
··· 22 22 strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 23 23 reloc_got2 kernstart_addr memstart_addr linux_banner _stext 24 24 opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry 25 - boot_command_line __prom_init_toc_start __prom_init_toc_end" 25 + boot_command_line __prom_init_toc_start __prom_init_toc_end 26 + btext_setup_display" 26 27 27 28 NM="$1" 28 29 OBJ="$2"
+13 -1
arch/powerpc/kernel/setup_64.c
··· 10 10 * 2 of the License, or (at your option) any later version. 11 11 */ 12 12 13 - #undef DEBUG 13 + #define DEBUG 14 14 15 15 #include <linux/export.h> 16 16 #include <linux/string.h> ··· 240 240 reserve_hugetlb_gpages(); 241 241 242 242 DBG(" <- early_setup()\n"); 243 + 244 + #ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX 245 + /* 246 + * This needs to be done *last* (after the above DBG() even) 247 + * 248 + * Right after we return from this function, we turn on the MMU 249 + * which means the real-mode access trick that btext does will 250 + * no longer work, it needs to switch to using a real MMU 251 + * mapping. This call will ensure that it does 252 + */ 253 + btext_map(); 254 + #endif /* CONFIG_PPC_EARLY_DEBUG_BOOTX */ 243 255 } 244 256 245 257 #ifdef CONFIG_SMP