Merge remote-tracking branch 'moduleh/module.h-split'
[linux-2.6/next.git] / arch / powerpc / sysdev / mv64x60_udbg.c
blob50a81387e9b1537f70f195037319f395869d4cfb
1 /*
2 * udbg serial input/output routines for the Marvell MV64x60 (Discovery).
4 * Author: Dale Farnsworth <dale@farnsworth.org>
6 * 2007 (c) MontaVista Software, Inc. This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
12 #include <asm/io.h>
13 #include <asm/prom.h>
14 #include <asm/udbg.h>
16 #include <sysdev/mv64x60.h>
18 #define MPSC_0_CR1_OFFSET 0x000c
20 #define MPSC_0_CR2_OFFSET 0x0010
21 #define MPSC_CHR_2_TCS (1 << 9)
23 #define MPSC_0_CHR_10_OFFSET 0x0030
25 #define MPSC_INTR_CAUSE_OFF_0 0x0004
26 #define MPSC_INTR_CAUSE_OFF_1 0x000c
27 #define MPSC_INTR_CAUSE_RCC (1<<6)
29 static void __iomem *mpsc_base;
30 static void __iomem *mpsc_intr_cause;
32 static void mv64x60_udbg_putc(char c)
34 if (c == '\n')
35 mv64x60_udbg_putc('\r');
37 while(in_le32(mpsc_base + MPSC_0_CR2_OFFSET) & MPSC_CHR_2_TCS)
39 out_le32(mpsc_base + MPSC_0_CR1_OFFSET, c);
40 out_le32(mpsc_base + MPSC_0_CR2_OFFSET, MPSC_CHR_2_TCS);
43 static int mv64x60_udbg_testc(void)
45 return (in_le32(mpsc_intr_cause) & MPSC_INTR_CAUSE_RCC) != 0;
48 static int mv64x60_udbg_getc(void)
50 int cause = 0;
51 int c;
53 while (!mv64x60_udbg_testc())
56 c = in_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2);
57 out_8(mpsc_base + MPSC_0_CHR_10_OFFSET + 2, c);
58 out_le32(mpsc_intr_cause, cause & ~MPSC_INTR_CAUSE_RCC);
59 return c;
62 static int mv64x60_udbg_getc_poll(void)
64 if (!mv64x60_udbg_testc())
65 return -1;
67 return mv64x60_udbg_getc();
70 static void mv64x60_udbg_init(void)
72 struct device_node *np, *mpscintr, *stdout = NULL;
73 const char *path;
74 const phandle *ph;
75 struct resource r[2];
76 const int *block_index;
77 int intr_cause_offset;
78 int err;
80 path = of_get_property(of_chosen, "linux,stdout-path", NULL);
81 if (!path)
82 return;
84 stdout = of_find_node_by_path(path);
85 if (!stdout)
86 return;
88 for_each_compatible_node(np, "serial", "marvell,mv64360-mpsc") {
89 if (np == stdout)
90 break;
93 of_node_put(stdout);
94 if (!np)
95 return;
97 block_index = of_get_property(np, "cell-index", NULL);
98 if (!block_index)
99 goto error;
101 switch (*block_index) {
102 case 0:
103 intr_cause_offset = MPSC_INTR_CAUSE_OFF_0;
104 break;
105 case 1:
106 intr_cause_offset = MPSC_INTR_CAUSE_OFF_1;
107 break;
108 default:
109 goto error;
112 err = of_address_to_resource(np, 0, &r[0]);
113 if (err)
114 goto error;
116 ph = of_get_property(np, "mpscintr", NULL);
117 mpscintr = of_find_node_by_phandle(*ph);
118 if (!mpscintr)
119 goto error;
121 err = of_address_to_resource(mpscintr, 0, &r[1]);
122 of_node_put(mpscintr);
123 if (err)
124 goto error;
126 of_node_put(np);
128 mpsc_base = ioremap(r[0].start, resource_size(&r[0]));
129 if (!mpsc_base)
130 return;
132 mpsc_intr_cause = ioremap(r[1].start, resource_size(&r[1]));
133 if (!mpsc_intr_cause) {
134 iounmap(mpsc_base);
135 return;
137 mpsc_intr_cause += intr_cause_offset;
139 udbg_putc = mv64x60_udbg_putc;
140 udbg_getc = mv64x60_udbg_getc;
141 udbg_getc_poll = mv64x60_udbg_getc_poll;
143 return;
145 error:
146 of_node_put(np);
149 void mv64x60_init_early(void)
151 mv64x60_udbg_init();