]>
Commit | Line | Data |
---|---|---|
4a9cbbe8 WD |
1 | /* |
2 | * (C) Copyright 2000, 2001, 2002 | |
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 | |
24 | * changes based on the file arch/ppc/mbxboot/m8260_tty.c from the | |
25 | * Linux/PPC sources (m8260_tty.c had no copyright info in it). | |
26 | */ | |
27 | ||
28 | /* | |
29 | * Minimal serial functions needed to use one of the SMC ports | |
30 | * as serial console interface. | |
31 | */ | |
32 | ||
33 | #include <common.h> | |
34 | #include <mpc8260.h> | |
35 | #include <asm/cpm_8260.h> | |
36 | ||
d87080b7 WD |
37 | DECLARE_GLOBAL_DATA_PTR; |
38 | ||
4a9cbbe8 WD |
39 | #if defined(CONFIG_CONS_ON_SMC) |
40 | ||
41 | #if CONFIG_CONS_INDEX == 1 /* Console on SMC1 */ | |
42 | ||
43 | #define SMC_INDEX 0 | |
44 | #define PROFF_SMC_BASE PROFF_SMC1_BASE | |
45 | #define PROFF_SMC PROFF_SMC1 | |
46 | #define CPM_CR_SMC_PAGE CPM_CR_SMC1_PAGE | |
47 | #define CPM_CR_SMC_SBLOCK CPM_CR_SMC1_SBLOCK | |
48 | #define CMXSMR_MASK (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK) | |
49 | #define CMXSMR_VALUE CMXSMR_SMC1CS_BRG7 | |
50 | ||
51 | #elif CONFIG_CONS_INDEX == 2 /* Console on SMC2 */ | |
52 | ||
53 | #define SMC_INDEX 1 | |
54 | #define PROFF_SMC_BASE PROFF_SMC2_BASE | |
55 | #define PROFF_SMC PROFF_SMC2 | |
56 | #define CPM_CR_SMC_PAGE CPM_CR_SMC2_PAGE | |
57 | #define CPM_CR_SMC_SBLOCK CPM_CR_SMC2_SBLOCK | |
58 | #define CMXSMR_MASK (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK) | |
59 | #define CMXSMR_VALUE CMXSMR_SMC2CS_BRG8 | |
60 | ||
61 | #else | |
62 | ||
63 | #error "console not correctly defined" | |
64 | ||
65 | #endif | |
66 | ||
67 | /* map rs_table index to baud rate generator index */ | |
68 | static unsigned char brg_map[] = { | |
69 | 6, /* BRG7 for SMC1 */ | |
70 | 7, /* BRG8 for SMC2 */ | |
71 | 0, /* BRG1 for SCC1 */ | |
72 | 1, /* BRG1 for SCC2 */ | |
73 | 2, /* BRG1 for SCC3 */ | |
74 | 3, /* BRG1 for SCC4 */ | |
75 | }; | |
76 | ||
77 | int serial_init (void) | |
78 | { | |
6d0f6bcf | 79 | volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
4a9cbbe8 WD |
80 | volatile smc_t *sp; |
81 | volatile smc_uart_t *up; | |
82 | volatile cbd_t *tbdf, *rbdf; | |
83 | volatile cpm8260_t *cp = &(im->im_cpm); | |
84 | uint dpaddr; | |
85 | ||
86 | /* initialize pointers to SMC */ | |
87 | ||
88 | sp = (smc_t *) &(im->im_smc[SMC_INDEX]); | |
89 | *(ushort *)(&im->im_dprambase[PROFF_SMC_BASE]) = PROFF_SMC; | |
90 | up = (smc_uart_t *)&im->im_dprambase[PROFF_SMC]; | |
91 | ||
92 | /* Disable transmitter/receiver. | |
93 | */ | |
94 | sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | |
95 | ||
96 | /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */ | |
97 | ||
98 | /* Allocate space for two buffer descriptors in the DP ram. | |
99 | * damm: allocating space after the two buffers for rx/tx data | |
100 | */ | |
101 | ||
102 | dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); | |
103 | ||
104 | /* Set the physical address of the host memory buffers in | |
105 | * the buffer descriptors. | |
106 | */ | |
107 | rbdf = (cbd_t *)&im->im_dprambase[dpaddr]; | |
108 | rbdf->cbd_bufaddr = (uint) (rbdf+2); | |
109 | rbdf->cbd_sc = 0; | |
110 | tbdf = rbdf + 1; | |
111 | tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; | |
112 | tbdf->cbd_sc = 0; | |
113 | ||
114 | /* Set up the uart parameters in the parameter ram. | |
115 | */ | |
116 | up->smc_rbase = dpaddr; | |
117 | up->smc_tbase = dpaddr+sizeof(cbd_t); | |
118 | up->smc_rfcr = CPMFCR_EB; | |
119 | up->smc_tfcr = CPMFCR_EB; | |
120 | up->smc_brklen = 0; | |
121 | up->smc_brkec = 0; | |
122 | up->smc_brkcr = 0; | |
123 | ||
124 | /* Set UART mode, 8 bit, no parity, one stop. | |
125 | * Enable receive and transmit. | |
126 | */ | |
127 | sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; | |
128 | ||
129 | /* Mask all interrupts and remove anything pending. | |
130 | */ | |
131 | sp->smc_smcm = 0; | |
132 | sp->smc_smce = 0xff; | |
133 | ||
134 | /* put the SMC channel into NMSI (non multiplexd serial interface) | |
135 | * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17). | |
136 | */ | |
137 | im->im_cpmux.cmx_smr = (im->im_cpmux.cmx_smr&~CMXSMR_MASK)|CMXSMR_VALUE; | |
138 | ||
139 | /* Set up the baud rate generator. | |
140 | */ | |
141 | serial_setbrg (); | |
142 | ||
143 | /* Make the first buffer the only buffer. | |
144 | */ | |
145 | tbdf->cbd_sc |= BD_SC_WRAP; | |
146 | rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; | |
147 | ||
148 | /* Single character receive. | |
149 | */ | |
150 | up->smc_mrblr = 1; | |
151 | up->smc_maxidl = 0; | |
152 | ||
153 | /* Initialize Tx/Rx parameters. | |
154 | */ | |
155 | ||
156 | while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
157 | ; | |
158 | ||
159 | cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC_PAGE, CPM_CR_SMC_SBLOCK, | |
160 | 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
161 | ||
162 | while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
163 | ; | |
164 | ||
165 | /* Enable transmitter/receiver. | |
166 | */ | |
167 | sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; | |
168 | ||
169 | return (0); | |
170 | } | |
171 | ||
172 | void | |
173 | serial_setbrg (void) | |
174 | { | |
4a9cbbe8 WD |
175 | #if defined(CONFIG_CONS_USE_EXTC) |
176 | m8260_cpm_extcbrg(brg_map[SMC_INDEX], gd->baudrate, | |
177 | CONFIG_CONS_EXTC_RATE, CONFIG_CONS_EXTC_PINSEL); | |
178 | #else | |
179 | m8260_cpm_setbrg(brg_map[SMC_INDEX], gd->baudrate); | |
180 | #endif | |
181 | } | |
182 | ||
183 | void | |
184 | serial_putc(const char c) | |
185 | { | |
186 | volatile cbd_t *tbdf; | |
187 | volatile char *buf; | |
188 | volatile smc_uart_t *up; | |
6d0f6bcf | 189 | volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
4a9cbbe8 WD |
190 | |
191 | if (c == '\n') | |
192 | serial_putc ('\r'); | |
193 | ||
194 | up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]); | |
195 | ||
196 | tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase]; | |
197 | ||
198 | /* Wait for last character to go. | |
199 | */ | |
200 | buf = (char *)tbdf->cbd_bufaddr; | |
201 | while (tbdf->cbd_sc & BD_SC_READY) | |
202 | ; | |
203 | ||
204 | *buf = c; | |
205 | tbdf->cbd_datlen = 1; | |
206 | tbdf->cbd_sc |= BD_SC_READY; | |
207 | } | |
208 | ||
209 | void | |
210 | serial_puts (const char *s) | |
211 | { | |
212 | while (*s) { | |
213 | serial_putc (*s++); | |
214 | } | |
215 | } | |
216 | ||
217 | int | |
218 | serial_getc(void) | |
219 | { | |
220 | volatile cbd_t *rbdf; | |
221 | volatile unsigned char *buf; | |
222 | volatile smc_uart_t *up; | |
6d0f6bcf | 223 | volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
4a9cbbe8 WD |
224 | unsigned char c; |
225 | ||
226 | up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]); | |
227 | ||
228 | rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase]; | |
229 | ||
230 | /* Wait for character to show up. | |
231 | */ | |
232 | buf = (unsigned char *)rbdf->cbd_bufaddr; | |
233 | while (rbdf->cbd_sc & BD_SC_EMPTY) | |
234 | ; | |
235 | c = *buf; | |
236 | rbdf->cbd_sc |= BD_SC_EMPTY; | |
237 | ||
238 | return(c); | |
239 | } | |
240 | ||
241 | int | |
242 | serial_tstc() | |
243 | { | |
244 | volatile cbd_t *rbdf; | |
245 | volatile smc_uart_t *up; | |
6d0f6bcf | 246 | volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
4a9cbbe8 WD |
247 | |
248 | up = (smc_uart_t *)&(im->im_dprambase[PROFF_SMC]); | |
249 | ||
250 | rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase]; | |
251 | ||
252 | return(!(rbdf->cbd_sc & BD_SC_EMPTY)); | |
253 | } | |
254 | ||
255 | #endif /* CONFIG_CONS_ON_SMC */ | |
256 | ||
257 | #if defined(CONFIG_KGDB_ON_SMC) | |
258 | ||
259 | #if defined(CONFIG_CONS_ON_SMC) && CONFIG_KGDB_INDEX == CONFIG_CONS_INDEX | |
260 | #error Whoops! serial console and kgdb are on the same smc serial port | |
261 | #endif | |
262 | ||
263 | #if CONFIG_KGDB_INDEX == 1 /* KGDB Port on SMC1 */ | |
264 | ||
265 | #define KGDB_SMC_INDEX 0 | |
266 | #define KGDB_PROFF_SMC_BASE PROFF_SMC1_BASE | |
267 | #define KGDB_PROFF_SMC PROFF_SMC1 | |
268 | #define KGDB_CPM_CR_SMC_PAGE CPM_CR_SMC1_PAGE | |
269 | #define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC1_SBLOCK | |
270 | #define KGDB_CMXSMR_MASK (CMXSMR_SMC1|CMXSMR_SMC1CS_MSK) | |
271 | #define KGDB_CMXSMR_VALUE CMXSMR_SMC1CS_BRG7 | |
272 | ||
273 | #elif CONFIG_KGDB_INDEX == 2 /* KGDB Port on SMC2 */ | |
274 | ||
275 | #define KGDB_SMC_INDEX 1 | |
276 | #define KGDB_PROFF_SMC_BASE PROFF_SMC2_BASE | |
277 | #define KGDB_PROFF_SMC PROFF_SMC2 | |
278 | #define KGDB_CPM_CR_SMC_PAGE CPM_CR_SMC2_PAGE | |
279 | #define KGDB_CPM_CR_SMC_SBLOCK CPM_CR_SMC2_SBLOCK | |
280 | #define KGDB_CMXSMR_MASK (CMXSMR_SMC2|CMXSMR_SMC2CS_MSK) | |
281 | #define KGDB_CMXSMR_VALUE CMXSMR_SMC2CS_BRG8 | |
282 | ||
283 | #else | |
284 | ||
285 | #error "console not correctly defined" | |
286 | ||
287 | #endif | |
288 | ||
289 | void | |
290 | kgdb_serial_init (void) | |
291 | { | |
6d0f6bcf | 292 | volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
4a9cbbe8 WD |
293 | volatile smc_t *sp; |
294 | volatile smc_uart_t *up; | |
295 | volatile cbd_t *tbdf, *rbdf; | |
296 | volatile cpm8260_t *cp = &(im->im_cpm); | |
297 | uint dpaddr, speed = CONFIG_KGDB_BAUDRATE; | |
298 | char *s, *e; | |
299 | ||
300 | if ((s = getenv("kgdbrate")) != NULL && *s != '\0') { | |
301 | ulong rate = simple_strtoul(s, &e, 10); | |
302 | if (e > s && *e == '\0') | |
303 | speed = rate; | |
304 | } | |
305 | ||
306 | /* initialize pointers to SMC */ | |
307 | ||
308 | sp = (smc_t *) &(im->im_smc[KGDB_SMC_INDEX]); | |
309 | *(ushort *)(&im->im_dprambase[KGDB_PROFF_SMC_BASE]) = KGDB_PROFF_SMC; | |
310 | up = (smc_uart_t *)&im->im_dprambase[KGDB_PROFF_SMC]; | |
311 | ||
312 | /* Disable transmitter/receiver. | |
313 | */ | |
314 | sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); | |
315 | ||
316 | /* NOTE: I/O port pins are set up via the iop_conf_tab[] table */ | |
317 | ||
318 | /* Allocate space for two buffer descriptors in the DP ram. | |
319 | * damm: allocating space after the two buffers for rx/tx data | |
320 | */ | |
321 | ||
322 | dpaddr = m8260_cpm_dpalloc((2 * sizeof (cbd_t)) + 2, 16); | |
323 | ||
324 | /* Set the physical address of the host memory buffers in | |
325 | * the buffer descriptors. | |
326 | */ | |
327 | rbdf = (cbd_t *)&im->im_dprambase[dpaddr]; | |
328 | rbdf->cbd_bufaddr = (uint) (rbdf+2); | |
329 | rbdf->cbd_sc = 0; | |
330 | tbdf = rbdf + 1; | |
331 | tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1; | |
332 | tbdf->cbd_sc = 0; | |
333 | ||
334 | /* Set up the uart parameters in the parameter ram. | |
335 | */ | |
336 | up->smc_rbase = dpaddr; | |
337 | up->smc_tbase = dpaddr+sizeof(cbd_t); | |
338 | up->smc_rfcr = CPMFCR_EB; | |
339 | up->smc_tfcr = CPMFCR_EB; | |
340 | up->smc_brklen = 0; | |
341 | up->smc_brkec = 0; | |
342 | up->smc_brkcr = 0; | |
343 | ||
344 | /* Set UART mode, 8 bit, no parity, one stop. | |
345 | * Enable receive and transmit. | |
346 | */ | |
347 | sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; | |
348 | ||
349 | /* Mask all interrupts and remove anything pending. | |
350 | */ | |
351 | sp->smc_smcm = 0; | |
352 | sp->smc_smce = 0xff; | |
353 | ||
354 | /* put the SMC channel into NMSI (non multiplexd serial interface) | |
355 | * mode and wire either BRG7 to SMC1 or BRG8 to SMC2 (15-17). | |
356 | */ | |
357 | im->im_cpmux.cmx_smr = | |
358 | (im->im_cpmux.cmx_smr & ~KGDB_CMXSMR_MASK) | KGDB_CMXSMR_VALUE; | |
359 | ||
360 | /* Set up the baud rate generator. | |
361 | */ | |
362 | #if defined(CONFIG_KGDB_USE_EXTC) | |
5633796c | 363 | m8260_cpm_extcbrg(brg_map[KGDB_SMC_INDEX], speed, |
4a9cbbe8 WD |
364 | CONFIG_KGDB_EXTC_RATE, CONFIG_KGDB_EXTC_PINSEL); |
365 | #else | |
5633796c | 366 | m8260_cpm_setbrg(brg_map[KGDB_SMC_INDEX], speed); |
4a9cbbe8 WD |
367 | #endif |
368 | ||
369 | /* Make the first buffer the only buffer. | |
370 | */ | |
371 | tbdf->cbd_sc |= BD_SC_WRAP; | |
372 | rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; | |
373 | ||
374 | /* Single character receive. | |
375 | */ | |
376 | up->smc_mrblr = 1; | |
377 | up->smc_maxidl = 0; | |
378 | ||
379 | /* Initialize Tx/Rx parameters. | |
380 | */ | |
381 | ||
382 | while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
383 | ; | |
384 | ||
385 | cp->cp_cpcr = mk_cr_cmd(KGDB_CPM_CR_SMC_PAGE, KGDB_CPM_CR_SMC_SBLOCK, | |
386 | 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
387 | ||
388 | while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */ | |
389 | ; | |
390 | ||
391 | /* Enable transmitter/receiver. | |
392 | */ | |
393 | sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; | |
394 | ||
395 | printf("SMC%d at %dbps ", CONFIG_KGDB_INDEX, speed); | |
396 | } | |
397 | ||
398 | void | |
399 | putDebugChar(const char c) | |
400 | { | |
401 | volatile cbd_t *tbdf; | |
402 | volatile char *buf; | |
403 | volatile smc_uart_t *up; | |
6d0f6bcf | 404 | volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
4a9cbbe8 WD |
405 | |
406 | if (c == '\n') | |
407 | putDebugChar ('\r'); | |
408 | ||
409 | up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]); | |
410 | ||
411 | tbdf = (cbd_t *)&im->im_dprambase[up->smc_tbase]; | |
412 | ||
413 | /* Wait for last character to go. | |
414 | */ | |
415 | buf = (char *)tbdf->cbd_bufaddr; | |
416 | while (tbdf->cbd_sc & BD_SC_READY) | |
417 | ; | |
418 | ||
419 | *buf = c; | |
420 | tbdf->cbd_datlen = 1; | |
421 | tbdf->cbd_sc |= BD_SC_READY; | |
422 | } | |
423 | ||
424 | void | |
425 | putDebugStr (const char *s) | |
426 | { | |
427 | while (*s) { | |
428 | putDebugChar (*s++); | |
429 | } | |
430 | } | |
431 | ||
432 | int | |
433 | getDebugChar(void) | |
434 | { | |
435 | volatile cbd_t *rbdf; | |
436 | volatile unsigned char *buf; | |
437 | volatile smc_uart_t *up; | |
6d0f6bcf | 438 | volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; |
4a9cbbe8 WD |
439 | unsigned char c; |
440 | ||
441 | up = (smc_uart_t *)&(im->im_dprambase[KGDB_PROFF_SMC]); | |
442 | ||
443 | rbdf = (cbd_t *)&im->im_dprambase[up->smc_rbase]; | |
444 | ||
445 | /* Wait for character to show up. | |
446 | */ | |
447 | buf = (unsigned char *)rbdf->cbd_bufaddr; | |
448 | while (rbdf->cbd_sc & BD_SC_EMPTY) | |
449 | ; | |
450 | c = *buf; | |
451 | rbdf->cbd_sc |= BD_SC_EMPTY; | |
452 | ||
453 | return(c); | |
454 | } | |
455 | ||
456 | void | |
457 | kgdb_interruptible(int yes) | |
458 | { | |
459 | return; | |
460 | } | |
461 | ||
462 | #endif /* CONFIG_KGDB_ON_SMC */ |