summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powermac
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-23 17:57:25 +1100
committerPaul Mackerras <paulus@samba.org>2006-01-09 14:49:54 +1100
commit51d3082fe6e55aecfa17113dbe98077c749f724c (patch)
tree9a1e2355d5988d8cc1ca511d53c1bb24b0baa17f /arch/powerpc/platforms/powermac
parent463ce0e103f419f51b1769111e73fe8bb305d0ec (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/Makefile1
-rw-r--r--arch/powerpc/platforms/powermac/feature.c68
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c27
-rw-r--r--arch/powerpc/platforms/powermac/pic.c2
-rw-r--r--arch/powerpc/platforms/powermac/setup.c52
-rw-r--r--arch/powerpc/platforms/powermac/udbg_adb.c218
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c165
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 */