aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-07-24 22:12:32 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-08-14 00:57:40 -0400
commit7191b615759ec10cab9eea43be5ecc42cda82364 (patch)
tree48e96713113f5c8a54a7021d0dd5bc6b31d32f15 /arch/powerpc/kernel
parent1a85d66bcc90e2cbdf04f70d6586b82532142e85 (diff)
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>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/btext.c254
-rw-r--r--arch/powerpc/kernel/misc_64.S31
-rw-r--r--arch/powerpc/kernel/prom_init.c16
-rw-r--r--arch/powerpc/kernel/prom_init_check.sh3
-rw-r--r--arch/powerpc/kernel/setup_64.c14
5 files changed, 201 insertions, 117 deletions
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
index ac8f52732fde..0428992fdb4b 100644
--- a/arch/powerpc/kernel/btext.c
+++ b/arch/powerpc/kernel/btext.c
@@ -25,11 +25,6 @@
25static void scrollscreen(void); 25static void scrollscreen(void);
26#endif 26#endif
27 27
28static void draw_byte(unsigned char c, long locX, long locY);
29static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb);
30static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
31static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);
32
33#define __force_data __attribute__((__section__(".data"))) 28#define __force_data __attribute__((__section__(".data")))
34 29
35static int g_loc_X __force_data; 30static int g_loc_X __force_data;
@@ -52,6 +47,26 @@ static unsigned char vga_font[cmapsz];
52int boot_text_mapped __force_data = 0; 47int boot_text_mapped __force_data = 0;
53int force_printk_to_btext = 0; 48int force_printk_to_btext = 0;
54 49
50extern void rmci_on(void);
51extern void rmci_off(void);
52
53static inline void rmci_maybe_on(void)
54{
55#ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX
56 if (!(mfmsr() & MSR_DR))
57 rmci_on();
58#endif
59}
60
61static inline void rmci_maybe_off(void)
62{
63#ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX
64 if (!(mfmsr() & MSR_DR))
65 rmci_off();
66#endif
67}
68
69
55#ifdef CONFIG_PPC32 70#ifdef CONFIG_PPC32
56/* Calc BAT values for mapping the display and store them 71/* Calc BAT values for mapping the display and store them
57 * in disp_BAT. Those values are then used from head.S to map 72 * in disp_BAT. Those values are then used from head.S to map
@@ -134,7 +149,7 @@ void __init btext_unmap(void)
134 * changes. 149 * changes.
135 */ 150 */
136 151
137static void map_boot_text(void) 152void btext_map(void)
138{ 153{
139 unsigned long base, offset, size; 154 unsigned long base, offset, size;
140 unsigned char *vbase; 155 unsigned char *vbase;
@@ -209,7 +224,7 @@ int btext_initialize(struct device_node *np)
209 dispDeviceRect[2] = width; 224 dispDeviceRect[2] = width;
210 dispDeviceRect[3] = height; 225 dispDeviceRect[3] = height;
211 226
212 map_boot_text(); 227 btext_map();
213 228
214 return 0; 229 return 0;
215} 230}
@@ -283,7 +298,7 @@ void btext_update_display(unsigned long phys, int width, int height,
283 iounmap(logicalDisplayBase); 298 iounmap(logicalDisplayBase);
284 boot_text_mapped = 0; 299 boot_text_mapped = 0;
285 } 300 }
286 map_boot_text(); 301 btext_map();
287 g_loc_X = 0; 302 g_loc_X = 0;
288 g_loc_Y = 0; 303 g_loc_Y = 0;
289 g_max_loc_X = width / 8; 304 g_max_loc_X = width / 8;
@@ -298,6 +313,7 @@ void btext_clearscreen(void)
298 (dispDeviceDepth >> 3)) >> 2; 313 (dispDeviceDepth >> 3)) >> 2;
299 int i,j; 314 int i,j;
300 315
316 rmci_maybe_on();
301 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) 317 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
302 { 318 {
303 unsigned int *ptr = base; 319 unsigned int *ptr = base;
@@ -305,6 +321,7 @@ void btext_clearscreen(void)
305 *(ptr++) = 0; 321 *(ptr++) = 0;
306 base += (dispDeviceRowBytes >> 2); 322 base += (dispDeviceRowBytes >> 2);
307 } 323 }
324 rmci_maybe_off();
308} 325}
309 326
310void btext_flushscreen(void) 327void btext_flushscreen(void)
@@ -355,6 +372,8 @@ static void scrollscreen(void)
355 (dispDeviceDepth >> 3)) >> 2; 372 (dispDeviceDepth >> 3)) >> 2;
356 int i,j; 373 int i,j;
357 374
375 rmci_maybe_on();
376
358 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) 377 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
359 { 378 {
360 unsigned int *src_ptr = src; 379 unsigned int *src_ptr = src;
@@ -371,9 +390,116 @@ static void scrollscreen(void)
371 *(dst_ptr++) = 0; 390 *(dst_ptr++) = 0;
372 dst += (dispDeviceRowBytes >> 2); 391 dst += (dispDeviceRowBytes >> 2);
373 } 392 }
393
394 rmci_maybe_off();
374} 395}
375#endif /* ndef NO_SCROLL */ 396#endif /* ndef NO_SCROLL */
376 397
398static unsigned int expand_bits_8[16] = {
399 0x00000000,
400 0x000000ff,
401 0x0000ff00,
402 0x0000ffff,
403 0x00ff0000,
404 0x00ff00ff,
405 0x00ffff00,
406 0x00ffffff,
407 0xff000000,
408 0xff0000ff,
409 0xff00ff00,
410 0xff00ffff,
411 0xffff0000,
412 0xffff00ff,
413 0xffffff00,
414 0xffffffff
415};
416
417static unsigned int expand_bits_16[4] = {
418 0x00000000,
419 0x0000ffff,
420 0xffff0000,
421 0xffffffff
422};
423
424
425static void draw_byte_32(unsigned char *font, unsigned int *base, int rb)
426{
427 int l, bits;
428 int fg = 0xFFFFFFFFUL;
429 int bg = 0x00000000UL;
430
431 for (l = 0; l < 16; ++l)
432 {
433 bits = *font++;
434 base[0] = (-(bits >> 7) & fg) ^ bg;
435 base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
436 base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
437 base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
438 base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
439 base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
440 base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
441 base[7] = (-(bits & 1) & fg) ^ bg;
442 base = (unsigned int *) ((char *)base + rb);
443 }
444}
445
446static inline void draw_byte_16(unsigned char *font, unsigned int *base, int rb)
447{
448 int l, bits;
449 int fg = 0xFFFFFFFFUL;
450 int bg = 0x00000000UL;
451 unsigned int *eb = (int *)expand_bits_16;
452
453 for (l = 0; l < 16; ++l)
454 {
455 bits = *font++;
456 base[0] = (eb[bits >> 6] & fg) ^ bg;
457 base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
458 base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
459 base[3] = (eb[bits & 3] & fg) ^ bg;
460 base = (unsigned int *) ((char *)base + rb);
461 }
462}
463
464static inline void draw_byte_8(unsigned char *font, unsigned int *base, int rb)
465{
466 int l, bits;
467 int fg = 0x0F0F0F0FUL;
468 int bg = 0x00000000UL;
469 unsigned int *eb = (int *)expand_bits_8;
470
471 for (l = 0; l < 16; ++l)
472 {
473 bits = *font++;
474 base[0] = (eb[bits >> 4] & fg) ^ bg;
475 base[1] = (eb[bits & 0xf] & fg) ^ bg;
476 base = (unsigned int *) ((char *)base + rb);
477 }
478}
479
480static noinline void draw_byte(unsigned char c, long locX, long locY)
481{
482 unsigned char *base = calc_base(locX << 3, locY << 4);
483 unsigned char *font = &vga_font[((unsigned int)c) * 16];
484 int rb = dispDeviceRowBytes;
485
486 rmci_maybe_on();
487 switch(dispDeviceDepth) {
488 case 24:
489 case 32:
490 draw_byte_32(font, (unsigned int *)base, rb);
491 break;
492 case 15:
493 case 16:
494 draw_byte_16(font, (unsigned int *)base, rb);
495 break;
496 case 8:
497 draw_byte_8(font, (unsigned int *)base, rb);
498 break;
499 }
500 rmci_maybe_off();
501}
502
377void btext_drawchar(char c) 503void btext_drawchar(char c)
378{ 504{
379 int cline = 0; 505 int cline = 0;
@@ -465,107 +591,12 @@ void btext_drawhex(unsigned long v)
465 btext_drawchar(' '); 591 btext_drawchar(' ');
466} 592}
467 593
468static void draw_byte(unsigned char c, long locX, long locY) 594void __init udbg_init_btext(void)
469{
470 unsigned char *base = calc_base(locX << 3, locY << 4);
471 unsigned char *font = &vga_font[((unsigned int)c) * 16];
472 int rb = dispDeviceRowBytes;
473
474 switch(dispDeviceDepth) {
475 case 24:
476 case 32:
477 draw_byte_32(font, (unsigned int *)base, rb);
478 break;
479 case 15:
480 case 16:
481 draw_byte_16(font, (unsigned int *)base, rb);
482 break;
483 case 8:
484 draw_byte_8(font, (unsigned int *)base, rb);
485 break;
486 }
487}
488
489static unsigned int expand_bits_8[16] = {
490 0x00000000,
491 0x000000ff,
492 0x0000ff00,
493 0x0000ffff,
494 0x00ff0000,
495 0x00ff00ff,
496 0x00ffff00,
497 0x00ffffff,
498 0xff000000,
499 0xff0000ff,
500 0xff00ff00,
501 0xff00ffff,
502 0xffff0000,
503 0xffff00ff,
504 0xffffff00,
505 0xffffffff
506};
507
508static unsigned int expand_bits_16[4] = {
509 0x00000000,
510 0x0000ffff,
511 0xffff0000,
512 0xffffffff
513};
514
515
516static void draw_byte_32(unsigned char *font, unsigned int *base, int rb)
517{
518 int l, bits;
519 int fg = 0xFFFFFFFFUL;
520 int bg = 0x00000000UL;
521
522 for (l = 0; l < 16; ++l)
523 {
524 bits = *font++;
525 base[0] = (-(bits >> 7) & fg) ^ bg;
526 base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
527 base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
528 base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
529 base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
530 base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
531 base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
532 base[7] = (-(bits & 1) & fg) ^ bg;
533 base = (unsigned int *) ((char *)base + rb);
534 }
535}
536
537static void draw_byte_16(unsigned char *font, unsigned int *base, int rb)
538{
539 int l, bits;
540 int fg = 0xFFFFFFFFUL;
541 int bg = 0x00000000UL;
542 unsigned int *eb = (int *)expand_bits_16;
543
544 for (l = 0; l < 16; ++l)
545 {
546 bits = *font++;
547 base[0] = (eb[bits >> 6] & fg) ^ bg;
548 base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
549 base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
550 base[3] = (eb[bits & 3] & fg) ^ bg;
551 base = (unsigned int *) ((char *)base + rb);
552 }
553}
554
555static void draw_byte_8(unsigned char *font, unsigned int *base, int rb)
556{ 595{
557 int l, bits; 596 /* If btext is enabled, we might have a BAT setup for early display,
558 int fg = 0x0F0F0F0FUL; 597 * thus we do enable some very basic udbg output
559 int bg = 0x00000000UL; 598 */
560 unsigned int *eb = (int *)expand_bits_8; 599 udbg_putc = btext_drawchar;
561
562 for (l = 0; l < 16; ++l)
563 {
564 bits = *font++;
565 base[0] = (eb[bits >> 4] & fg) ^ bg;
566 base[1] = (eb[bits & 0xf] & fg) ^ bg;
567 base = (unsigned int *) ((char *)base + rb);
568 }
569} 600}
570 601
571static unsigned char vga_font[cmapsz] = { 602static unsigned char vga_font[cmapsz] = {
@@ -913,10 +944,3 @@ static unsigned char vga_font[cmapsz] = {
9130x00, 0x00, 0x00, 0x00, 9440x00, 0x00, 0x00, 0x00,
914}; 945};
915 946
916void __init udbg_init_btext(void)
917{
918 /* If btext is enabled, we might have a BAT setup for early display,
919 * thus we do enable some very basic udbg output
920 */
921 udbg_putc = btext_drawchar;
922}
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index a781566d3993..0db7cb4060c1 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -249,6 +249,37 @@ _GLOBAL(__bswapdi2)
249 blr 249 blr
250 250
251#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) 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 * Do an IO access in real mode 284 * Do an IO access in real mode
254 */ 285 */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 607902424e73..57df5cb1dcc4 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -2082,6 +2082,22 @@ static void __init prom_check_displays(void)
2082 clut[2]) != 0) 2082 clut[2]) != 0)
2083 break; 2083 break;
2084#endif /* CONFIG_LOGO_LINUX_CLUT224 */ 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
diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh
index 3765da6be4f2..b0c263da219a 100644
--- a/arch/powerpc/kernel/prom_init_check.sh
+++ b/arch/powerpc/kernel/prom_init_check.sh
@@ -22,7 +22,8 @@ __secondary_hold_acknowledge __secondary_hold_spinloop __start
22strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 22strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224
23reloc_got2 kernstart_addr memstart_addr linux_banner _stext 23reloc_got2 kernstart_addr memstart_addr linux_banner _stext
24opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry 24opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry
25boot_command_line __prom_init_toc_start __prom_init_toc_end" 25boot_command_line __prom_init_toc_start __prom_init_toc_end
26btext_setup_display"
26 27
27NM="$1" 28NM="$1"
28OBJ="$2" 29OBJ="$2"
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 79ba9b77fe72..0c0450dd4d31 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -10,7 +10,7 @@
10 * 2 of the License, or (at your option) any later version. 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#include <linux/export.h> 15#include <linux/export.h>
16#include <linux/string.h> 16#include <linux/string.h>
@@ -240,6 +240,18 @@ void __init early_setup(unsigned long dt_ptr)
240 reserve_hugetlb_gpages(); 240 reserve_hugetlb_gpages();
241 241
242 DBG(" <- early_setup()\n"); 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#ifdef CONFIG_SMP 257#ifdef CONFIG_SMP