summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/mv64x60_udbg.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-11 21:55:47 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-11 21:55:47 -0700
commite86908614f2c7fec401827e5cefd7a6ea9407f85 (patch)
treefcb5d9e52422b37bdaf0e647126ebdfc1680f162 /arch/powerpc/sysdev/mv64x60_udbg.c
parent547307420931344a868275bd7ea7a30f117a15a9 (diff)
parent9b4b8feb962f4b3e74768b7205f1f8f6cce87238 (diff)
downloadlinux-e86908614f2c7fec401827e5cefd7a6ea9407f85.tar.gz
linux-e86908614f2c7fec401827e5cefd7a6ea9407f85.tar.bz2
linux-e86908614f2c7fec401827e5cefd7a6ea9407f85.zip
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (408 commits) [POWERPC] Add memchr() to the bootwrapper [POWERPC] Implement logging of unhandled signals [POWERPC] Add legacy serial support for OPB with flattened device tree [POWERPC] Use 1TB segments [POWERPC] XilinxFB: Allow fixed framebuffer base address [POWERPC] XilinxFB: Add support for custom screen resolution [POWERPC] XilinxFB: Use pdata to pass around framebuffer parameters [POWERPC] PCI: Add 64-bit physical address support to setup_indirect_pci [POWERPC] 4xx: Kilauea defconfig file [POWERPC] 4xx: Kilauea DTS [POWERPC] 4xx: Add AMCC Kilauea eval board support to platforms/40x [POWERPC] 4xx: Add AMCC 405EX support to cputable.c [POWERPC] Adjust TASK_SIZE on ppc32 systems to 3GB that are capable [POWERPC] Use PAGE_OFFSET to tell if an address is user/kernel in SW TLB handlers [POWERPC] 85xx: Enable FP emulation in MPC8560 ADS defconfig [POWERPC] 85xx: Killed <asm/mpc85xx.h> [POWERPC] 85xx: Add cpm nodes for 8541/8555 CDS [POWERPC] 85xx: Convert mpc8560ads to the new CPM binding. [POWERPC] mpc8272ads: Remove muram from the CPM reg property. [POWERPC] Make clockevents work on PPC601 processors ... Fixed up conflict in Documentation/powerpc/booting-without-of.txt manually.
Diffstat (limited to 'arch/powerpc/sysdev/mv64x60_udbg.c')
-rw-r--r--arch/powerpc/sysdev/mv64x60_udbg.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/mv64x60_udbg.c b/arch/powerpc/sysdev/mv64x60_udbg.c
new file mode 100644
index 000000000000..367e7b13ec00
--- /dev/null
+++ b/arch/powerpc/sysdev/mv64x60_udbg.c
@@ -0,0 +1,152 @@
+/*
+ * udbg serial input/output routines for the Marvell MV64x60 (Discovery).
+ *
+ * Author: Dale Farnsworth <dale@farnsworth.org>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+
+#include <sysdev/mv64x60.h>
+
+#define MPSC_0_CR1_OFFSET 0x000c
+
+#define MPSC_0_CR2_OFFSET 0x0010
+#define MPSC_CHR_2_TCS (1 << 9)
+
+#define MPSC_0_CHR_10_OFFSET 0x0030
+
+#define MPSC_INTR_CAUSE_OFF_0 0x0004
+#define MPSC_INTR_CAUSE_OFF_1 0x000c
+#define MPSC_INTR_CAUSE_RCC (1<<6)
+
+static void __iomem *mpsc_base;
+static void __iomem *mpsc_intr_cause;
+
+static void mv64x60_udbg_putc(char c)
+{
+ if (c == '\n')
+ mv64x60_udbg_putc('\r');
+
+ while(in_le32(mpsc_base + MPSC_0_CR2_OFFSET) & MPSC_CHR_2_TCS)
+ ;
+ out_le32(mpsc_base + MPSC_0_CR1_OFFSET, c);
+ out_le32(mpsc_base + MPSC_0_CR2_OFFSET, MPSC_CHR_2_TCS);
+}
+
+static int mv64x60_udbg_testc(void)
+{
+ return (in_le32(mpsc_intr_cause) & MPSC_INTR_CAUSE_RCC) != 0;
+}
+
+static int mv64x60_udbg_getc(void)
+{
+ int cause = 0;
+ int c;
+
+ while (!mv64x60_udbg_testc())
+ ;
+
+ c = in_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2);
+ out_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2, c);
+ out_le32(mpsc_intr_cause, cause & ~MPSC_INTR_CAUSE_RCC);
+ return c;
+}
+
+static int mv64x60_udbg_getc_poll(void)
+{
+ if (!mv64x60_udbg_testc())
+ return -1;
+
+ return mv64x60_udbg_getc();
+}
+
+static void mv64x60_udbg_init(void)
+{
+ struct device_node *np, *mpscintr, *stdout = NULL;
+ const char *path;
+ const phandle *ph;
+ struct resource r[2];
+ const int *block_index;
+ int intr_cause_offset;
+ int err;
+
+ path = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ if (!path)
+ return;
+
+ stdout = of_find_node_by_path(path);
+ if (!stdout)
+ return;
+
+ for (np = NULL;
+ (np = of_find_compatible_node(np, "serial", "marvell,mpsc")); )
+ if (np == stdout)
+ break;
+
+ of_node_put(stdout);
+ if (!np)
+ return;
+
+ block_index = of_get_property(np, "block-index", NULL);
+ if (!block_index)
+ goto error;
+
+ switch (*block_index) {
+ case 0:
+ intr_cause_offset = MPSC_INTR_CAUSE_OFF_0;
+ break;
+ case 1:
+ intr_cause_offset = MPSC_INTR_CAUSE_OFF_1;
+ break;
+ default:
+ goto error;
+ }
+
+ err = of_address_to_resource(np, 0, &r[0]);
+ if (err)
+ goto error;
+
+ ph = of_get_property(np, "mpscintr", NULL);
+ mpscintr = of_find_node_by_phandle(*ph);
+ if (!mpscintr)
+ goto error;
+
+ err = of_address_to_resource(mpscintr, 0, &r[1]);
+ of_node_put(mpscintr);
+ if (err)
+ goto error;
+
+ of_node_put(np);
+
+ mpsc_base = ioremap(r[0].start, r[0].end - r[0].start + 1);
+ if (!mpsc_base)
+ return;
+
+ mpsc_intr_cause = ioremap(r[1].start, r[1].end - r[1].start + 1);
+ if (!mpsc_intr_cause) {
+ iounmap(mpsc_base);
+ return;
+ }
+ mpsc_intr_cause += intr_cause_offset;
+
+ udbg_putc = mv64x60_udbg_putc;
+ udbg_getc = mv64x60_udbg_getc;
+ udbg_getc_poll = mv64x60_udbg_getc_poll;
+
+ return;
+
+error:
+ of_node_put(np);
+}
+
+void mv64x60_init_early(void)
+{
+ mv64x60_udbg_init();
+}