Commit | Line | Data |
---|---|---|
9b41fcb0 DF |
1 | /* |
2 | * udbg serial input/output routines for the Marvell MV64x60 (Discovery). | |
3 | * | |
4 | * Author: Dale Farnsworth <dale@farnsworth.org> | |
5 | * | |
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. | |
10 | */ | |
11 | ||
12 | #include <asm/io.h> | |
13 | #include <asm/prom.h> | |
14 | #include <asm/udbg.h> | |
15 | ||
16 | #include <sysdev/mv64x60.h> | |
17 | ||
18 | #define MPSC_0_CR1_OFFSET 0x000c | |
19 | ||
20 | #define MPSC_0_CR2_OFFSET 0x0010 | |
21 | #define MPSC_CHR_2_TCS (1 << 9) | |
22 | ||
23 | #define MPSC_0_CHR_10_OFFSET 0x0030 | |
24 | ||
25 | #define MPSC_INTR_CAUSE_OFF_0 0x0004 | |
26 | #define MPSC_INTR_CAUSE_OFF_1 0x000c | |
27 | #define MPSC_INTR_CAUSE_RCC (1<<6) | |
28 | ||
29 | static void __iomem *mpsc_base; | |
30 | static void __iomem *mpsc_intr_cause; | |
31 | ||
32 | static void mv64x60_udbg_putc(char c) | |
33 | { | |
34 | if (c == '\n') | |
35 | mv64x60_udbg_putc('\r'); | |
36 | ||
37 | while(in_le32(mpsc_base + MPSC_0_CR2_OFFSET) & MPSC_CHR_2_TCS) | |
38 | ; | |
39 | out_le32(mpsc_base + MPSC_0_CR1_OFFSET, c); | |
40 | out_le32(mpsc_base + MPSC_0_CR2_OFFSET, MPSC_CHR_2_TCS); | |
41 | } | |
42 | ||
43 | static int mv64x60_udbg_testc(void) | |
44 | { | |
45 | return (in_le32(mpsc_intr_cause) & MPSC_INTR_CAUSE_RCC) != 0; | |
46 | } | |
47 | ||
48 | static int mv64x60_udbg_getc(void) | |
49 | { | |
50 | int cause = 0; | |
51 | int c; | |
52 | ||
53 | while (!mv64x60_udbg_testc()) | |
54 | ; | |
55 | ||
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; | |
60 | } | |
61 | ||
62 | static int mv64x60_udbg_getc_poll(void) | |
63 | { | |
64 | if (!mv64x60_udbg_testc()) | |
65 | return -1; | |
66 | ||
67 | return mv64x60_udbg_getc(); | |
68 | } | |
69 | ||
70 | static void mv64x60_udbg_init(void) | |
71 | { | |
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; | |
79 | ||
80 | path = of_get_property(of_chosen, "linux,stdout-path", NULL); | |
81 | if (!path) | |
82 | return; | |
83 | ||
84 | stdout = of_find_node_by_path(path); | |
85 | if (!stdout) | |
86 | return; | |
87 | ||
a1810b44 | 88 | for_each_compatible_node(np, "serial", "marvell,mv64360-mpsc") { |
9b41fcb0 DF |
89 | if (np == stdout) |
90 | break; | |
26cb7d8b | 91 | } |
9b41fcb0 DF |
92 | |
93 | of_node_put(stdout); | |
94 | if (!np) | |
95 | return; | |
96 | ||
df40a57e | 97 | block_index = of_get_property(np, "cell-index", NULL); |
9b41fcb0 DF |
98 | if (!block_index) |
99 | goto error; | |
100 | ||
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; | |
110 | } | |
111 | ||
112 | err = of_address_to_resource(np, 0, &r[0]); | |
113 | if (err) | |
114 | goto error; | |
115 | ||
116 | ph = of_get_property(np, "mpscintr", NULL); | |
117 | mpscintr = of_find_node_by_phandle(*ph); | |
118 | if (!mpscintr) | |
119 | goto error; | |
120 | ||
121 | err = of_address_to_resource(mpscintr, 0, &r[1]); | |
122 | of_node_put(mpscintr); | |
123 | if (err) | |
124 | goto error; | |
125 | ||
126 | of_node_put(np); | |
127 | ||
128 | mpsc_base = ioremap(r[0].start, r[0].end - r[0].start + 1); | |
129 | if (!mpsc_base) | |
130 | return; | |
131 | ||
132 | mpsc_intr_cause = ioremap(r[1].start, r[1].end - r[1].start + 1); | |
133 | if (!mpsc_intr_cause) { | |
134 | iounmap(mpsc_base); | |
135 | return; | |
136 | } | |
137 | mpsc_intr_cause += intr_cause_offset; | |
138 | ||
139 | udbg_putc = mv64x60_udbg_putc; | |
140 | udbg_getc = mv64x60_udbg_getc; | |
141 | udbg_getc_poll = mv64x60_udbg_getc_poll; | |
142 | ||
143 | return; | |
144 | ||
145 | error: | |
146 | of_node_put(np); | |
147 | } | |
148 | ||
149 | void mv64x60_init_early(void) | |
150 | { | |
151 | mv64x60_udbg_init(); | |
152 | } |