diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2005-11-23 17:57:25 +1100 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-01-09 14:49:54 +1100 |
commit | 51d3082fe6e55aecfa17113dbe98077c749f724c (patch) | |
tree | 9a1e2355d5988d8cc1ca511d53c1bb24b0baa17f /arch/powerpc/platforms/powermac | |
parent | 463ce0e103f419f51b1769111e73fe8bb305d0ec (diff) |
[PATCH] powerpc: Unify udbg (#2)
This patch unifies udbg for both ppc32 and ppc64 when building the
merged achitecture. xmon now has a single "back end". The powermac udbg
stuff gets enriched with some ADB capabilities and btext output. In
addition, the early_init callback is now called on ppc32 as well,
approx. in the same order as ppc64 regarding device-tree manipulations.
The init sequences of ppc32 and ppc64 are getting closer, I'll unify
them in a later patch.
For now, you can force udbg to the scc using "sccdbg" or to btext using
"btextdbg" on powermacs. I'll implement a cleaner way of forcing udbg
output to something else than the autodetected OF output device in a
later patch.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/powermac')
-rw-r--r-- | arch/powerpc/platforms/powermac/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/feature.c | 68 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/low_i2c.c | 27 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pic.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/setup.c | 52 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/udbg_adb.c | 218 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/udbg_scc.c | 165 |
7 files changed, 470 insertions, 63 deletions
diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index c9df44fcf57..3e5370eeb1b 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_NVRAM) += nvram.o # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff obj-$(CONFIG_PPC64) += nvram.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_PPC_MERGE) += udbg_scc.o udbg_adb.o diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index f6e22da2a5d..52a9d0c1b8b 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2607,6 +2607,8 @@ found: */ static void __init probe_uninorth(void) { + u32 *addrp; + phys_addr_t address; unsigned long actrl; /* Locate core99 Uni-N */ @@ -2616,20 +2618,23 @@ static void __init probe_uninorth(void) uninorth_node = of_find_node_by_name(NULL, "u3"); uninorth_u3 = 1; } - if (uninorth_node && uninorth_node->n_addrs > 0) { - unsigned long address = uninorth_node->addrs[0].address; - uninorth_base = ioremap(address, 0x40000); - uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); - if (uninorth_u3) - u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); - } else - uninorth_node = NULL; - - if (!uninorth_node) + if (uninorth_node == NULL) return; - printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n", - uninorth_u3 ? "U3" : "UniNorth", uninorth_rev); + addrp = (u32 *)get_property(uninorth_node, "reg", NULL); + if (addrp == NULL) + return; + address = of_translate_address(uninorth_node, addrp); + if (address == 0) + return; + uninorth_base = ioremap(address, 0x40000); + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + if (uninorth_u3) + u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); + + printk(KERN_INFO "Found %s memory controller & host bridge," + " revision: %d\n", uninorth_u3 ? "U3" : "UniNorth", + uninorth_rev); printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); /* Set the arbitrer QAck delay according to what Apple does @@ -2653,18 +2658,17 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ { struct device_node* node; int i; - volatile u32 __iomem * base; - u32* revp; + volatile u32 __iomem *base; + u32 *addrp, *revp; + phys_addr_t addr; + u64 size; - node = find_devices(name); - if (!node || !node->n_addrs) - return; - if (compat) - do { - if (device_is_compatible(node, compat)) - break; - node = node->next; - } while (node); + for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) { + if (!compat) + break; + if (device_is_compatible(node, compat)) + break; + } if (!node) return; for(i=0; i<MAX_MACIO_CHIPS; i++) { @@ -2673,14 +2677,28 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ if (macio_chips[i].of_node == node) return; } + if (i >= MAX_MACIO_CHIPS) { printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); return; } - base = ioremap(node->addrs[0].address, node->addrs[0].size); + addrp = of_get_pci_address(node, 0, &size); + if (addrp == NULL) { + printk(KERN_ERR "pmac_feature: %s: can't find base !\n", + node->full_name); + return; + } + addr = of_translate_address(node, addrp); + if (addr == 0) { + printk(KERN_ERR "pmac_feature: %s, can't translate base !\n", + node->full_name); + return; + } + base = ioremap(addr, (unsigned long)size); if (!base) { - printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); + printk(KERN_ERR "pmac_feature: %s, can't map mac-io chip !\n", + node->full_name); return; } if (type == macio_keylargo) { diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index f3f39e8e337..606e0ed1373 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -36,7 +36,7 @@ #ifdef DEBUG #define DBG(x...) do {\ - printk(KERN_DEBUG "KW:" x); \ + printk(KERN_DEBUG "low_i2c:" x); \ } while(0) #else #define DBG(x...) @@ -342,7 +342,7 @@ static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, static void keywest_low_i2c_add(struct device_node *np) { struct low_i2c_host *host = find_low_i2c_host(NULL); - u32 *psteps, *prate, steps, aoffset = 0; + u32 *psteps, *prate, *addrp, steps; struct device_node *parent; if (host == NULL) { @@ -352,6 +352,16 @@ static void keywest_low_i2c_add(struct device_node *np) } memset(host, 0, sizeof(*host)); + /* Apple is kind enough to provide a valid AAPL,address property + * on all i2c keywest nodes so far ... we would have to fallback + * to macio parsing if that wasn't the case + */ + addrp = (u32 *)get_property(np, "AAPL,address", NULL); + if (addrp == NULL) { + printk(KERN_ERR "low_i2c: Can't find address for %s\n", + np->full_name); + return; + } init_MUTEX(&host->mutex); host->np = of_node_get(np); psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); @@ -360,12 +370,10 @@ static void keywest_low_i2c_add(struct device_node *np) steps >>= 1; parent = of_get_parent(np); host->num_channels = 1; - if (parent && parent->name[0] == 'u') { + if (parent && parent->name[0] == 'u') host->num_channels = 2; - aoffset = 3; - } /* Select interface rate */ - host->speed = KW_I2C_MODE_100KHZ; + host->speed = KW_I2C_MODE_25KHZ; prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); if (prate) switch(*prate) { case 100: @@ -379,9 +387,12 @@ static void keywest_low_i2c_add(struct device_node *np) break; } + printk(KERN_INFO "low_i2c: Bus %s found at 0x%08x, %d channels," + " speed = %d KHz\n", + np->full_name, *addrp, host->num_channels, prate ? *prate : 25); + host->mode = pmac_low_i2c_mode_std; - host->base = ioremap(np->addrs[0].address + aoffset, - np->addrs[0].size); + host->base = ioremap((*addrp), 0x1000); host->func = keywest_low_i2c_func; } diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 90040c49494..ff78eeac10f 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -459,7 +459,7 @@ void __init pmac_pic_init(void) mpic_setup_cascade(irqctrler2->intrs[0].line, pmac_u3_cascade, mpic2); } -#if defined(CONFIG_XMON) && defined(CONFIG_PPC32) +#ifdef CONFIG_XMON { struct device_node* pswitch; int nmi_irq; diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 3b7a492d9b6..6ee620fe519 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -77,6 +77,7 @@ #include <asm/pmc.h> #include <asm/mpic.h> #include <asm/lmb.h> +#include <asm/udbg.h> #include "pmac.h" @@ -322,16 +323,6 @@ void __init pmac_setup_arch(void) l2cr_init(); #endif /* CONFIG_PPC32 */ -#ifdef CONFIG_PPC64 - /* Probe motherboard chipset */ - /* this is done earlier in setup_arch for 32-bit */ - pmac_feature_init(); - - /* We can NAP */ - powersave_nap = 1; - printk(KERN_INFO "Using native/NAP idle loop\n"); -#endif - #ifdef CONFIG_KGDB zs_kgdb_hook(0); #endif @@ -622,13 +613,26 @@ static void __init pmac_init_early(void) * and call ioremap */ hpte_init_native(); +#endif - /* Init SCC */ - if (strstr(cmd_line, "sccdbg")) { - sccdbg = 1; - udbg_init_scc(NULL); + /* Enable early btext debug if requested */ + if (strstr(cmd_line, "btextdbg")) { + udbg_adb_init_early(); + register_early_udbg_console(); } + /* Probe motherboard chipset */ + pmac_feature_init(); + + /* We can NAP */ + powersave_nap = 1; + printk(KERN_INFO "Using native/NAP idle loop\n"); + + /* Initialize debug stuff */ + udbg_scc_init(!!strstr(cmd_line, "sccdbg")); + udbg_adb_init(!!strstr(cmd_line, "btextdbg")); + +#ifdef CONFIG_PPC64 /* Setup interrupt mapping options */ ppc64_interrupt_controller = IC_OPEN_PIC; @@ -638,19 +642,8 @@ static void __init pmac_init_early(void) static void __init pmac_progress(char *s, unsigned short hex) { -#ifdef CONFIG_PPC64 - if (sccdbg) { - udbg_puts(s); - udbg_puts("\n"); - return; - } -#endif -#ifdef CONFIG_BOOTX_TEXT - if (boot_text_mapped) { - btext_drawstring(s); - btext_drawchar('\n'); - } -#endif /* CONFIG_BOOTX_TEXT */ + udbg_puts(s); + udbg_puts("\n"); } /* @@ -735,7 +728,8 @@ static int __init pmac_probe(int platform) } #ifdef CONFIG_PPC64 -static int pmac_probe_mode(struct pci_bus *bus) +/* Move that to pci.c */ +static int pmac_pci_probe_mode(struct pci_bus *bus) { struct device_node *node = bus->sysdata; @@ -771,7 +765,7 @@ struct machdep_calls __initdata pmac_md = { .check_legacy_ioport = pmac_check_legacy_ioport, .progress = pmac_progress, #ifdef CONFIG_PPC64 - .pci_probe_mode = pmac_probe_mode, + .pci_probe_mode = pmac_pci_probe_mode, .idle_loop = native_idle, .enable_pmcs = power4_enable_pmcs, #ifdef CONFIG_KEXEC diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c new file mode 100644 index 00000000000..e51de55b2d6 --- /dev/null +++ b/arch/powerpc/platforms/powermac/udbg_adb.c @@ -0,0 +1,218 @@ +#include <linux/config.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/bitops.h> +#include <linux/ptrace.h> +#include <linux/adb.h> +#include <linux/pmu.h> +#include <linux/cuda.h> +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/xmon.h> +#include <asm/prom.h> +#include <asm/bootx.h> +#include <asm/machdep.h> +#include <asm/errno.h> +#include <asm/pmac_feature.h> +#include <asm/processor.h> +#include <asm/delay.h> +#include <asm/btext.h> +#include <asm/time.h> +#include <asm/udbg.h> + +/* + * This implementation is "special", it can "patch" the current + * udbg implementation and work on top of it. It must thus be + * initialized last + */ + +static void (*udbg_adb_old_putc)(char c); +static char (*udbg_adb_old_getc)(void); +static int (*udbg_adb_old_getc_poll)(void); + +static enum { + input_adb_none, + input_adb_pmu, + input_adb_cuda, +} input_type = input_adb_none; + +static int udbg_adb_use_btext; + +int xmon_wants_key, xmon_adb_keycode; + +static inline void udbg_adb_poll(void) +{ +#ifdef CONFIG_ADB_PMU + if (input_type == input_adb_pmu) + pmu_poll_adb(); +#endif /* CONFIG_ADB_PMU */ +#ifdef CONFIG_ADB_CUDA + if (input_type == input_adb_cuda) + cuda_poll(); +#endif /* CONFIG_ADB_CUDA */ +} + +#ifdef CONFIG_BOOTX_TEXT +static int xmon_adb_shiftstate; + +static unsigned char xmon_keytab[128] = + "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80]o" /* 0x10 - 0x1f */ + "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ + "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ + "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ + +static unsigned char xmon_shift_keytab[128] = + "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */ + "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */ + "U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */ + "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ + "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ + "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ + +static char udbg_adb_local_getc(void) +{ + int k, t, on; + + xmon_wants_key = 1; + for (;;) { + xmon_adb_keycode = -1; + t = 0; + on = 0; + k = -1; + do { + if (--t < 0) { + on = 1 - on; + btext_drawchar(on? 0xdb: 0x20); + btext_drawchar('\b'); + t = 200000; + } + udbg_adb_poll(); + if (udbg_adb_old_getc_poll) + k = udbg_adb_old_getc_poll(); + } while (k == -1 && xmon_adb_keycode == -1); + if (on) + btext_drawstring(" \b"); + if (k != -1) + return k; + k = xmon_adb_keycode; + + /* test for shift keys */ + if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) { + xmon_adb_shiftstate = (k & 0x80) == 0; + continue; + } + if (k >= 0x80) + continue; /* ignore up transitions */ + k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k]; + if (k != 0) + break; + } + xmon_wants_key = 0; + return k; +} +#endif /* CONFIG_BOOTX_TEXT */ + +static char udbg_adb_getc(void) +{ +#ifdef CONFIG_BOOTX_TEXT + if (udbg_adb_use_btext && input_type != input_adb_none) + return udbg_adb_local_getc(); +#endif + if (udbg_adb_old_getc) + return udbg_adb_old_getc(); + return -1; +} + +/* getc_poll() is not really used, unless you have the xmon-over modem + * hack that doesn't quite concern us here, thus we just poll the low level + * ADB driver to prevent it from timing out and call back the original poll + * routine. + */ +static int udbg_adb_getc_poll(void) +{ + udbg_adb_poll(); + + if (udbg_adb_old_getc_poll) + return udbg_adb_old_getc_poll(); + return -1; +} + +static void udbg_adb_putc(char c) +{ +#ifdef CONFIG_BOOTX_TEXT + if (udbg_adb_use_btext) + btext_drawchar(c); +#endif + if (udbg_adb_old_putc) + return udbg_adb_old_putc(c); +} + +void udbg_adb_init_early(void) +{ +#ifdef CONFIG_BOOTX_TEXT + if (btext_find_display(1) == 0) { + udbg_adb_use_btext = 1; + udbg_putc = udbg_adb_putc; + } +#endif +} + +int udbg_adb_init(int force_btext) +{ + struct device_node *np; + + /* Capture existing callbacks */ + udbg_adb_old_putc = udbg_putc; + udbg_adb_old_getc = udbg_getc; + udbg_adb_old_getc_poll = udbg_getc_poll; + + /* Check if our early init was already called */ + if (udbg_adb_old_putc == udbg_adb_putc || + udbg_adb_old_putc == btext_drawchar) + udbg_adb_old_putc = NULL; + + /* Set ours as output */ + udbg_putc = udbg_adb_putc; + udbg_getc = udbg_adb_getc; + udbg_getc_poll = udbg_adb_getc_poll; + +#ifdef CONFIG_BOOTX_TEXT + /* Check if we should use btext output */ + if (btext_find_display(force_btext) == 0) + udbg_adb_use_btext = 1; +#endif + + /* See if there is a keyboard in the device tree with a parent + * of type "adb". If not, we return a failure, but we keep the + * bext output set for now + */ + for (np = NULL; (np = of_find_node_by_name(np, "keyboard")) != NULL;) { + struct device_node *parent = of_get_parent(np); + int found = (parent && !strcmp(parent->type, "adb") == 0); + of_node_put(parent); + if (found) + break; + } + if (np == NULL) + return -ENODEV; + of_node_put(np); + +#ifdef CONFIG_ADB_PMU + if (find_via_pmu()) + input_type = input_adb_pmu; +#endif +#ifdef CONFIG_ADB_CUDA + if (find_via_cuda()) + input_type = input_adb_cuda; +#endif + + /* Same as above: nothing found, keep btext set for output */ + if (input_type == input_adb_none) + return -ENODEV; + + return 0; +} diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c new file mode 100644 index 00000000000..df6dec49c4c --- /dev/null +++ b/arch/powerpc/platforms/powermac/udbg_scc.c @@ -0,0 +1,165 @@ +/* + * udbg for for zilog scc ports as found on Apple PowerMacs + * + * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <linux/config.h> +#include <linux/types.h> +#include <asm/udbg.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/pmac_feature.h> + +extern u8 real_readb(volatile u8 __iomem *addr); +extern void real_writeb(u8 data, volatile u8 __iomem *addr); + +#define SCC_TXRDY 4 +#define SCC_RXRDY 1 + +static volatile u8 __iomem *sccc; +static volatile u8 __iomem *sccd; + +static void udbg_scc_putc(char c) +{ + if (sccc) { + while ((in_8(sccc) & SCC_TXRDY) == 0) + ; + out_8(sccd, c); + if (c == '\n') + udbg_scc_putc('\r'); + } +} + +static int udbg_scc_getc_poll(void) +{ + if (sccc) { + if ((in_8(sccc) & SCC_RXRDY) != 0) + return in_8(sccd); + else + return -1; + } + return -1; +} + +static char udbg_scc_getc(void) +{ + if (sccc) { + while ((in_8(sccc) & SCC_RXRDY) == 0) + ; + return in_8(sccd); + } + return 0; +} + +static unsigned char scc_inittab[] = { + 13, 0, /* set baud rate divisor */ + 12, 0, + 14, 1, /* baud rate gen enable, src=rtxc */ + 11, 0x50, /* clocks = br gen */ + 5, 0xea, /* tx 8 bits, assert DTR & RTS */ + 4, 0x46, /* x16 clock, 1 stop */ + 3, 0xc1, /* rx enable, 8 bits */ +}; + +void udbg_scc_init(int force_scc) +{ + u32 *reg; + unsigned long addr; + struct device_node *stdout = NULL, *escc = NULL, *macio = NULL; + struct device_node *ch, *ch_def = NULL, *ch_a = NULL; + char *path; + int i, x; + + escc = of_find_node_by_name(NULL, "escc"); + if (escc == NULL) + goto bail; + macio = of_get_parent(escc); + if (macio == NULL) + goto bail; + path = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (path != NULL) + stdout = of_find_node_by_path(path); + for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) { + if (ch == stdout) + ch_def = of_node_get(ch); + if (strcmp(ch->name, "ch-a") == 0) + ch_a = of_node_get(ch); + } + if (ch_def == NULL && !force_scc) + goto bail; + + ch = ch_def ? ch_def : ch_a; + + /* Get address within mac-io ASIC */ + reg = (u32 *)get_property(escc, "reg", NULL); + if (reg == NULL) + goto bail; + addr = reg[0]; + + /* Get address of mac-io PCI itself */ + reg = (u32 *)get_property(macio, "assigned-addresses", NULL); + if (reg == NULL) + goto bail; + addr += reg[2]; + + /* Lock the serial port */ + pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch, + PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); + + + /* Setup for 57600 8N1 */ + if (ch == ch_a) + addr += 0x20; + sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; + sccc += addr & ~PAGE_MASK; + sccd = sccc + 0x10; + + mb(); + + for (i = 20000; i != 0; --i) + x = in_8(sccc); + out_8(sccc, 0x09); /* reset A or B side */ + out_8(sccc, 0xc0); + for (i = 0; i < sizeof(scc_inittab); ++i) + out_8(sccc, scc_inittab[i]); + + udbg_putc = udbg_scc_putc; + udbg_getc = udbg_scc_getc; + udbg_getc_poll = udbg_scc_getc_poll; + + udbg_puts("Hello World !\n"); + + bail: + of_node_put(macio); + of_node_put(escc); + of_node_put(stdout); + of_node_put(ch_def); + of_node_put(ch_a); +} + +#ifdef CONFIG_PPC64 +static void udbg_real_scc_putc(char c) +{ + while ((real_readb(sccc) & SCC_TXRDY) == 0) + ; + real_writeb(c, sccd); + if (c == '\n') + udbg_real_scc_putc('\r'); +} + +void udbg_init_pmac_realmode(void) +{ + sccc = (volatile u8 __iomem *)0x80013020ul; + sccd = (volatile u8 __iomem *)0x80013030ul; + + udbg_putc = udbg_real_scc_putc; + udbg_getc = NULL; + udbg_getc_poll = NULL; +} +#endif /* CONFIG_PPC64 */ |