]>
Commit | Line | Data |
---|---|---|
945af8d7 WD |
1 | /* |
2 | * (C) Copyright 2000 - 2003 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | * | |
23 | * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with | |
a47a12be | 24 | * changes based on the file arch/powerpc/mbxboot/m8260_tty.c from the |
945af8d7 | 25 | * Linux/PPC sources (m8260_tty.c had no copyright info in it). |
c12cffc5 WD |
26 | * |
27 | * Martin Krause, 8 Jun 2006 | |
a3827250 | 28 | * Added SERIAL_MULTI support |
945af8d7 WD |
29 | */ |
30 | ||
31 | /* | |
32 | * Minimal serial functions needed to use one of the PSC ports | |
33 | * as serial console interface. | |
34 | */ | |
35 | ||
36 | #include <common.h> | |
6c768ca7 | 37 | #include <linux/compiler.h> |
945af8d7 | 38 | #include <mpc5xxx.h> |
c12cffc5 | 39 | #include <serial.h> |
c12cffc5 | 40 | |
d87080b7 WD |
41 | DECLARE_GLOBAL_DATA_PTR; |
42 | ||
945af8d7 WD |
43 | #if defined(CONFIG_PSC_CONSOLE) |
44 | ||
45 | #if CONFIG_PSC_CONSOLE == 1 | |
46 | #define PSC_BASE MPC5XXX_PSC1 | |
47 | #elif CONFIG_PSC_CONSOLE == 2 | |
48 | #define PSC_BASE MPC5XXX_PSC2 | |
49 | #elif CONFIG_PSC_CONSOLE == 3 | |
50 | #define PSC_BASE MPC5XXX_PSC3 | |
945af8d7 WD |
51 | #elif CONFIG_PSC_CONSOLE == 4 |
52 | #define PSC_BASE MPC5XXX_PSC4 | |
53 | #elif CONFIG_PSC_CONSOLE == 5 | |
54 | #define PSC_BASE MPC5XXX_PSC5 | |
55 | #elif CONFIG_PSC_CONSOLE == 6 | |
56 | #define PSC_BASE MPC5XXX_PSC6 | |
57 | #else | |
58 | #error CONFIG_PSC_CONSOLE must be in 1 ... 6 | |
59 | #endif | |
60 | ||
a3827250 | 61 | #if defined(CONFIG_PSC_CONSOLE2) |
c12cffc5 | 62 | |
c12cffc5 WD |
63 | #if CONFIG_PSC_CONSOLE2 == 1 |
64 | #define PSC_BASE2 MPC5XXX_PSC1 | |
65 | #elif CONFIG_PSC_CONSOLE2 == 2 | |
66 | #define PSC_BASE2 MPC5XXX_PSC2 | |
67 | #elif CONFIG_PSC_CONSOLE2 == 3 | |
68 | #define PSC_BASE2 MPC5XXX_PSC3 | |
c12cffc5 WD |
69 | #elif CONFIG_PSC_CONSOLE2 == 4 |
70 | #define PSC_BASE2 MPC5XXX_PSC4 | |
71 | #elif CONFIG_PSC_CONSOLE2 == 5 | |
72 | #define PSC_BASE2 MPC5XXX_PSC5 | |
73 | #elif CONFIG_PSC_CONSOLE2 == 6 | |
74 | #define PSC_BASE2 MPC5XXX_PSC6 | |
75 | #else | |
76 | #error CONFIG_PSC_CONSOLE2 must be in 1 ... 6 | |
77 | #endif | |
c12cffc5 | 78 | |
c12cffc5 | 79 | #endif |
a3827250 MV |
80 | |
81 | int serial_init_dev (unsigned long dev_base) | |
945af8d7 | 82 | { |
c12cffc5 | 83 | volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base; |
945af8d7 WD |
84 | unsigned long baseclk; |
85 | int div; | |
86 | ||
87 | /* reset PSC */ | |
88 | psc->command = PSC_SEL_MODE_REG_1; | |
89 | ||
90 | /* select clock sources */ | |
945af8d7 | 91 | psc->psc_clock_select = 0; |
b2877496 | 92 | baseclk = (gd->arch.ipb_clk + 16) / 32; |
945af8d7 WD |
93 | |
94 | /* switch to UART mode */ | |
95 | psc->sicr = 0; | |
96 | ||
97 | /* configure parity, bit length and so on */ | |
945af8d7 | 98 | psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE; |
945af8d7 WD |
99 | psc->mode = PSC_MODE_ONE_STOP; |
100 | ||
101 | /* set up UART divisor */ | |
b98fff1d WD |
102 | div = (baseclk + (gd->baudrate/2)) / gd->baudrate; |
103 | psc->ctur = (div >> 8) & 0xff; | |
945af8d7 WD |
104 | psc->ctlr = div & 0xff; |
105 | ||
106 | /* disable all interrupts */ | |
107 | psc->psc_imr = 0; | |
108 | ||
109 | /* reset and enable Rx/Tx */ | |
110 | psc->command = PSC_RST_RX; | |
111 | psc->command = PSC_RST_TX; | |
112 | psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE; | |
113 | ||
114 | return (0); | |
115 | } | |
116 | ||
c12cffc5 | 117 | void serial_putc_dev (unsigned long dev_base, const char c) |
945af8d7 | 118 | { |
c12cffc5 | 119 | volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base; |
945af8d7 WD |
120 | |
121 | if (c == '\n') | |
c12cffc5 | 122 | serial_putc_dev (dev_base, '\r'); |
945af8d7 WD |
123 | |
124 | /* Wait for last character to go. */ | |
125 | while (!(psc->psc_status & PSC_SR_TXEMP)) | |
126 | ; | |
127 | ||
128 | psc->psc_buffer_8 = c; | |
129 | } | |
130 | ||
e8143e72 | 131 | void serial_putc_raw_dev(unsigned long dev_base, const char c) |
e8143e72 | 132 | { |
e8143e72 | 133 | volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base; |
e8143e72 WD |
134 | /* Wait for last character to go. */ |
135 | while (!(psc->psc_status & PSC_SR_TXEMP)) | |
136 | ; | |
137 | ||
138 | psc->psc_buffer_8 = c; | |
139 | } | |
140 | ||
141 | ||
c12cffc5 | 142 | void serial_puts_dev (unsigned long dev_base, const char *s) |
945af8d7 WD |
143 | { |
144 | while (*s) { | |
c12cffc5 | 145 | serial_putc_dev (dev_base, *s++); |
945af8d7 WD |
146 | } |
147 | } | |
148 | ||
c12cffc5 | 149 | int serial_getc_dev (unsigned long dev_base) |
945af8d7 | 150 | { |
c12cffc5 | 151 | volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base; |
945af8d7 WD |
152 | |
153 | /* Wait for a character to arrive. */ | |
154 | while (!(psc->psc_status & PSC_SR_RXRDY)) | |
155 | ; | |
156 | ||
157 | return psc->psc_buffer_8; | |
158 | } | |
159 | ||
c12cffc5 | 160 | int serial_tstc_dev (unsigned long dev_base) |
945af8d7 | 161 | { |
c12cffc5 | 162 | volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base; |
945af8d7 WD |
163 | |
164 | return (psc->psc_status & PSC_SR_RXRDY); | |
165 | } | |
166 | ||
c12cffc5 | 167 | void serial_setbrg_dev (unsigned long dev_base) |
945af8d7 | 168 | { |
c12cffc5 | 169 | volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base; |
945af8d7 WD |
170 | unsigned long baseclk, div; |
171 | ||
b2877496 | 172 | baseclk = (gd->arch.ipb_clk + 16) / 32; |
945af8d7 WD |
173 | |
174 | /* set up UART divisor */ | |
342717f7 | 175 | div = (baseclk + (gd->baudrate/2)) / gd->baudrate; |
9f221d07 WD |
176 | psc->ctur = (div >> 8) & 0xFF; |
177 | psc->ctlr = div & 0xff; | |
945af8d7 | 178 | } |
c12cffc5 | 179 | |
e8143e72 | 180 | void serial_setrts_dev (unsigned long dev_base, int s) |
e8143e72 | 181 | { |
e8143e72 | 182 | volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base; |
e8143e72 WD |
183 | |
184 | if (s) { | |
185 | /* Assert RTS (become LOW) */ | |
186 | psc->op1 = 0x1; | |
187 | } | |
188 | else { | |
189 | /* Negate RTS (become HIGH) */ | |
190 | psc->op0 = 0x1; | |
191 | } | |
192 | } | |
193 | ||
e8143e72 | 194 | int serial_getcts_dev (unsigned long dev_base) |
e8143e72 | 195 | { |
e8143e72 | 196 | volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)dev_base; |
e8143e72 WD |
197 | |
198 | return (psc->ip & 0x1) ? 0 : 1; | |
199 | } | |
200 | ||
c12cffc5 WD |
201 | int serial0_init(void) |
202 | { | |
203 | return (serial_init_dev(PSC_BASE)); | |
204 | } | |
205 | ||
c12cffc5 WD |
206 | void serial0_setbrg (void) |
207 | { | |
208 | serial_setbrg_dev(PSC_BASE); | |
209 | } | |
c12cffc5 WD |
210 | |
211 | void serial0_putc(const char c) | |
212 | { | |
213 | serial_putc_dev(PSC_BASE,c); | |
214 | } | |
215 | ||
c12cffc5 WD |
216 | void serial0_puts(const char *s) |
217 | { | |
218 | serial_puts_dev(PSC_BASE, s); | |
219 | } | |
220 | ||
c12cffc5 WD |
221 | int serial0_getc(void) |
222 | { | |
223 | return(serial_getc_dev(PSC_BASE)); | |
224 | } | |
225 | ||
c12cffc5 WD |
226 | int serial0_tstc(void) |
227 | { | |
228 | return (serial_tstc_dev(PSC_BASE)); | |
229 | } | |
230 | ||
c12cffc5 WD |
231 | struct serial_device serial0_device = |
232 | { | |
90bad891 MV |
233 | .name = "serial0", |
234 | .start = serial0_init, | |
235 | .stop = NULL, | |
236 | .setbrg = serial0_setbrg, | |
237 | .getc = serial0_getc, | |
238 | .tstc = serial0_tstc, | |
239 | .putc = serial0_putc, | |
240 | .puts = serial0_puts, | |
c12cffc5 WD |
241 | }; |
242 | ||
6c768ca7 MF |
243 | __weak struct serial_device *default_serial_console(void) |
244 | { | |
245 | return &serial0_device; | |
246 | } | |
247 | ||
a3827250 MV |
248 | #ifdef CONFIG_PSC_CONSOLE2 |
249 | int serial1_init(void) | |
250 | { | |
251 | return serial_init_dev(PSC_BASE2); | |
252 | } | |
253 | ||
254 | void serial1_setbrg(void) | |
255 | { | |
256 | serial_setbrg_dev(PSC_BASE2); | |
257 | } | |
258 | ||
259 | void serial1_putc(const char c) | |
260 | { | |
261 | serial_putc_dev(PSC_BASE2, c); | |
262 | } | |
263 | ||
264 | void serial1_puts(const char *s) | |
265 | { | |
266 | serial_puts_dev(PSC_BASE2, s); | |
267 | } | |
268 | ||
269 | int serial1_getc(void) | |
270 | { | |
271 | return serial_getc_dev(PSC_BASE2); | |
272 | } | |
273 | ||
274 | int serial1_tstc(void) | |
275 | { | |
276 | return serial_tstc_dev(PSC_BASE2); | |
277 | } | |
278 | ||
c12cffc5 WD |
279 | struct serial_device serial1_device = |
280 | { | |
90bad891 MV |
281 | .name = "serial1", |
282 | .start = serial1_init, | |
283 | .stop = NULL, | |
284 | .setbrg = serial1_setbrg, | |
285 | .getc = serial1_getc, | |
286 | .tstc = serial1_tstc, | |
287 | .putc = serial1_putc, | |
288 | .puts = serial1_puts, | |
c12cffc5 | 289 | }; |
a3827250 | 290 | #endif /* CONFIG_PSC_CONSOLE2 */ |
c12cffc5 | 291 | |
945af8d7 | 292 | #endif /* CONFIG_PSC_CONSOLE */ |