blob: 106a9b87d2cfd43c888683fa2b075701954176a6 [file] [log] [blame]
Wolfgang Denkb38e0df2007-03-06 18:08:43 +01001/*
2 * (C) Copyright 2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
Wolfgang Denkb38e0df2007-03-06 18:08:43 +01006 */
7
8#include <common.h>
9
10/*
11 * UART test
12 *
13 * The Serial Management Controllers (SMC) and the Serial Communication
14 * Controllers (SCC) listed in ctlr_list array below are tested in
15 * the loopback UART mode.
16 * The controllers are configured accordingly and several characters
17 * are transmitted. The configurable test parameters are:
18 * MIN_PACKET_LENGTH - minimum size of packet to transmit
19 * MAX_PACKET_LENGTH - maximum size of packet to transmit
20 * TEST_NUM - number of tests
21 */
22
Wolfgang Denkb38e0df2007-03-06 18:08:43 +010023#include <post.h>
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020024#if CONFIG_POST & CONFIG_SYS_POST_UART
Wolfgang Denkb38e0df2007-03-06 18:08:43 +010025#if defined(CONFIG_8xx)
26#include <commproc.h>
27#elif defined(CONFIG_MPC8260)
28#include <asm/cpm_8260.h>
29#else
30#error "Apparently a bad configuration, please fix."
31#endif
32#include <command.h>
33#include <serial.h>
34
35DECLARE_GLOBAL_DATA_PTR;
36
37#define CTLR_SMC 0
38#define CTLR_SCC 1
39
40/* The list of controllers to test */
41#if defined(CONFIG_MPC823)
42static int ctlr_list[][2] =
43 { {CTLR_SMC, 0}, {CTLR_SMC, 1}, {CTLR_SCC, 1} };
44#else
45static int ctlr_list[][2] = { };
46#endif
47
Wolfgang Denkb38e0df2007-03-06 18:08:43 +010048static struct {
49 void (*init) (int index);
50 void (*halt) (int index);
51 void (*putc) (int index, const char c);
52 int (*getc) (int index);
53} ctlr_proc[2];
54
55static char *ctlr_name[2] = { "SMC", "SCC" };
56
57static int proff_smc[] = { PROFF_SMC1, PROFF_SMC2 };
58static int proff_scc[] =
59 { PROFF_SCC1, PROFF_SCC2, PROFF_SCC3, PROFF_SCC4 };
60
61/*
62 * SMC callbacks
63 */
64
65static void smc_init (int smc_index)
66{
67 static int cpm_cr_ch[] = { CPM_CR_CH_SMC1, CPM_CR_CH_SMC2 };
68
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020069 volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
Wolfgang Denkb38e0df2007-03-06 18:08:43 +010070 volatile smc_t *sp;
71 volatile smc_uart_t *up;
72 volatile cbd_t *tbdf, *rbdf;
73 volatile cpm8xx_t *cp = &(im->im_cpm);
74 uint dpaddr;
75
76 /* initialize pointers to SMC */
77
78 sp = (smc_t *) & (cp->cp_smc[smc_index]);
79 up = (smc_uart_t *) & cp->cp_dparam[proff_smc[smc_index]];
80
81 /* Disable transmitter/receiver.
82 */
83 sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
84
85 /* Enable SDMA.
86 */
87 im->im_siu_conf.sc_sdcr = 1;
88
89 /* clear error conditions */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020090#ifdef CONFIG_SYS_SDSR
91 im->im_sdma.sdma_sdsr = CONFIG_SYS_SDSR;
Wolfgang Denkb38e0df2007-03-06 18:08:43 +010092#else
93 im->im_sdma.sdma_sdsr = 0x83;
94#endif
95
96 /* clear SDMA interrupt mask */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020097#ifdef CONFIG_SYS_SDMR
98 im->im_sdma.sdma_sdmr = CONFIG_SYS_SDMR;
Wolfgang Denkb38e0df2007-03-06 18:08:43 +010099#else
100 im->im_sdma.sdma_sdmr = 0x00;
101#endif
102
103#if defined(CONFIG_FADS)
104 /* Enable RS232 */
105 *((uint *) BCSR1) &=
106 ~(smc_index == 1 ? BCSR1_RS232EN_1 : BCSR1_RS232EN_2);
107#endif
108
109#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
110 /* Enable Monitor Port Transceiver */
111 *((uchar *) BCSR0) |= BCSR0_ENMONXCVR;
112#endif
113
114 /* Set the physical address of the host memory buffers in
115 * the buffer descriptors.
116 */
117
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200118#ifdef CONFIG_SYS_ALLOC_DPRAM
Wolfgang Denkb38e0df2007-03-06 18:08:43 +0100119 dpaddr = dpram_alloc_align (sizeof (cbd_t) * 2 + 2, 8);
120#else
121 dpaddr = CPM_POST_BASE;
122#endif
123
124 /* Allocate space for two buffer descriptors in the DP ram.
125 * For now, this address seems OK, but it may have to
126 * change with newer versions of the firmware.
127 * damm: allocating space after the two buffers for rx/tx data
128 */
129
130 rbdf = (cbd_t *) & cp->cp_dpmem[dpaddr];
131 rbdf->cbd_bufaddr = (uint) (rbdf + 2);
132 rbdf->cbd_sc = 0;
133 tbdf = rbdf + 1;
134 tbdf->cbd_bufaddr = ((uint) (rbdf + 2)) + 1;
135 tbdf->cbd_sc = 0;
136
137 /* Set up the uart parameters in the parameter ram.
138 */
139 up->smc_rbase = dpaddr;
140 up->smc_tbase = dpaddr + sizeof (cbd_t);
141 up->smc_rfcr = SMC_EB;
142 up->smc_tfcr = SMC_EB;
143
144#if defined(CONFIG_MBX)
145 board_serial_init ();
146#endif
147
148 /* Set UART mode, 8 bit, no parity, one stop.
149 * Enable receive and transmit.
150 * Set local loopback mode.
151 */
152 sp->smc_smcmr = smcr_mk_clen (9) | SMCMR_SM_UART | (ushort) 0x0004;
153
154 /* Mask all interrupts and remove anything pending.
155 */
156 sp->smc_smcm = 0;
157 sp->smc_smce = 0xff;
158
159 /* Set up the baud rate generator.
160 */
161 cp->cp_simode = 0x00000000;
162
163 cp->cp_brgc1 =
164 (((gd->cpu_clk / 16 / gd->baudrate) -
165 1) << 1) | CPM_BRG_EN;
166
167 /* Make the first buffer the only buffer.
168 */
169 tbdf->cbd_sc |= BD_SC_WRAP;
170 rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
171
172 /* Single character receive.
173 */
174 up->smc_mrblr = 1;
175 up->smc_maxidl = 0;
176
177 /* Initialize Tx/Rx parameters.
178 */
179
180 while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
181 ;
182
183 cp->cp_cpcr =
184 mk_cr_cmd (cpm_cr_ch[smc_index], CPM_CR_INIT_TRX) | CPM_CR_FLG;
185
186 while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
187 ;
188
189 /* Enable transmitter/receiver.
190 */
191 sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
192}
193
194static void smc_halt(int smc_index)
195{
196}
197
198static void smc_putc (int smc_index, const char c)
199{
200 volatile cbd_t *tbdf;
201 volatile char *buf;
202 volatile smc_uart_t *up;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200203 volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
Wolfgang Denkb38e0df2007-03-06 18:08:43 +0100204 volatile cpm8xx_t *cpmp = &(im->im_cpm);
205
206 up = (smc_uart_t *) & cpmp->cp_dparam[proff_smc[smc_index]];
207
208 tbdf = (cbd_t *) & cpmp->cp_dpmem[up->smc_tbase];
209
210 /* Wait for last character to go.
211 */
212
213 buf = (char *) tbdf->cbd_bufaddr;
214#if 0
215 __asm__ ("eieio");
216 while (tbdf->cbd_sc & BD_SC_READY)
217 __asm__ ("eieio");
218#endif
219
220 *buf = c;
221 tbdf->cbd_datlen = 1;
222 tbdf->cbd_sc |= BD_SC_READY;
223 __asm__ ("eieio");
224#if 1
225 while (tbdf->cbd_sc & BD_SC_READY)
226 __asm__ ("eieio");
227#endif
228}
229
230static int smc_getc (int smc_index)
231{
232 volatile cbd_t *rbdf;
233 volatile unsigned char *buf;
234 volatile smc_uart_t *up;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200235 volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
Wolfgang Denkb38e0df2007-03-06 18:08:43 +0100236 volatile cpm8xx_t *cpmp = &(im->im_cpm);
237 unsigned char c;
238 int i;
239
240 up = (smc_uart_t *) & cpmp->cp_dparam[proff_smc[smc_index]];
241
242 rbdf = (cbd_t *) & cpmp->cp_dpmem[up->smc_rbase];
243
244 /* Wait for character to show up.
245 */
246 buf = (unsigned char *) rbdf->cbd_bufaddr;
247#if 0
248 while (rbdf->cbd_sc & BD_SC_EMPTY);
249#else
250 for (i = 100; i > 0; i--) {
251 if (!(rbdf->cbd_sc & BD_SC_EMPTY))
252 break;
253 udelay (1000);
254 }
255
256 if (i == 0)
257 return -1;
258#endif
259 c = *buf;
260 rbdf->cbd_sc |= BD_SC_EMPTY;
261
262 return (c);
263}
264
265 /*
266 * SCC callbacks
267 */
268
269static void scc_init (int scc_index)
270{
271 static int cpm_cr_ch[] = {
272 CPM_CR_CH_SCC1,
273 CPM_CR_CH_SCC2,
274 CPM_CR_CH_SCC3,
275 CPM_CR_CH_SCC4,
276 };
277
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200278 volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
Wolfgang Denkb38e0df2007-03-06 18:08:43 +0100279 volatile scc_t *sp;
280 volatile scc_uart_t *up;
281 volatile cbd_t *tbdf, *rbdf;
282 volatile cpm8xx_t *cp = &(im->im_cpm);
283 uint dpaddr;
284
285 /* initialize pointers to SCC */
286
287 sp = (scc_t *) & (cp->cp_scc[scc_index]);
288 up = (scc_uart_t *) & cp->cp_dparam[proff_scc[scc_index]];
289
290 /* Disable transmitter/receiver.
291 */
292 sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
293
294
295 /* Allocate space for two buffer descriptors in the DP ram.
296 */
297
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200298#ifdef CONFIG_SYS_ALLOC_DPRAM
Wolfgang Denkb38e0df2007-03-06 18:08:43 +0100299 dpaddr = dpram_alloc_align (sizeof (cbd_t) * 2 + 2, 8);
300#else
301 dpaddr = CPM_POST_BASE;
302#endif
303
304 /* Enable SDMA.
305 */
306 im->im_siu_conf.sc_sdcr = 0x0001;
307
308 /* Set the physical address of the host memory buffers in
309 * the buffer descriptors.
310 */
311
312 rbdf = (cbd_t *) & cp->cp_dpmem[dpaddr];
313 rbdf->cbd_bufaddr = (uint) (rbdf + 2);
314 rbdf->cbd_sc = 0;
315 tbdf = rbdf + 1;
316 tbdf->cbd_bufaddr = ((uint) (rbdf + 2)) + 1;
317 tbdf->cbd_sc = 0;
318
319 /* Set up the baud rate generator.
320 */
321 cp->cp_sicr &= ~(0x000000FF << (8 * scc_index));
322 /* no |= needed, since BRG1 is 000 */
323
324 cp->cp_brgc1 =
325 (((gd->cpu_clk / 16 / gd->baudrate) -
326 1) << 1) | CPM_BRG_EN;
327
328 /* Set up the uart parameters in the parameter ram.
329 */
330 up->scc_genscc.scc_rbase = dpaddr;
331 up->scc_genscc.scc_tbase = dpaddr + sizeof (cbd_t);
332
333 /* Initialize Tx/Rx parameters.
334 */
335 while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
336 ;
337 cp->cp_cpcr =
338 mk_cr_cmd (cpm_cr_ch[scc_index], CPM_CR_INIT_TRX) | CPM_CR_FLG;
339
340 while (cp->cp_cpcr & CPM_CR_FLG) /* wait if cp is busy */
341 ;
342
343 up->scc_genscc.scc_rfcr = SCC_EB | 0x05;
344 up->scc_genscc.scc_tfcr = SCC_EB | 0x05;
345
346 up->scc_genscc.scc_mrblr = 1; /* Single character receive */
347 up->scc_maxidl = 0; /* disable max idle */
348 up->scc_brkcr = 1; /* send one break character on stop TX */
349 up->scc_parec = 0;
350 up->scc_frmec = 0;
351 up->scc_nosec = 0;
352 up->scc_brkec = 0;
353 up->scc_uaddr1 = 0;
354 up->scc_uaddr2 = 0;
355 up->scc_toseq = 0;
356 up->scc_char1 = 0x8000;
357 up->scc_char2 = 0x8000;
358 up->scc_char3 = 0x8000;
359 up->scc_char4 = 0x8000;
360 up->scc_char5 = 0x8000;
361 up->scc_char6 = 0x8000;
362 up->scc_char7 = 0x8000;
363 up->scc_char8 = 0x8000;
364 up->scc_rccm = 0xc0ff;
365
366 /* Set low latency / small fifo.
367 */
368 sp->scc_gsmrh = SCC_GSMRH_RFW;
369
370 /* Set UART mode
371 */
372 sp->scc_gsmrl &= ~0xF;
373 sp->scc_gsmrl |= SCC_GSMRL_MODE_UART;
374
375 /* Set local loopback mode.
376 */
377 sp->scc_gsmrl &= ~SCC_GSMRL_DIAG_LE;
378 sp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP;
379
380 /* Set clock divider 16 on Tx and Rx
381 */
382 sp->scc_gsmrl |= (SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
383
384 sp->scc_psmr |= SCU_PSMR_CL;
385
386 /* Mask all interrupts and remove anything pending.
387 */
388 sp->scc_sccm = 0;
389 sp->scc_scce = 0xffff;
390 sp->scc_dsr = 0x7e7e;
391 sp->scc_psmr = 0x3000;
392
393 /* Make the first buffer the only buffer.
394 */
395 tbdf->cbd_sc |= BD_SC_WRAP;
396 rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
397
398 /* Enable transmitter/receiver.
399 */
400 sp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
401}
402
403static void scc_halt(int scc_index)
404{
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200405 volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
Wolfgang Denkb38e0df2007-03-06 18:08:43 +0100406 volatile cpm8xx_t *cp = &(im->im_cpm);
407 volatile scc_t *sp = (scc_t *) & (cp->cp_scc[scc_index]);
408
409 sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT | SCC_GSMRL_DIAG_LE);
410}
411
412static void scc_putc (int scc_index, const char c)
413{
414 volatile cbd_t *tbdf;
415 volatile char *buf;
416 volatile scc_uart_t *up;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200417 volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
Wolfgang Denkb38e0df2007-03-06 18:08:43 +0100418 volatile cpm8xx_t *cpmp = &(im->im_cpm);
419
420 up = (scc_uart_t *) & cpmp->cp_dparam[proff_scc[scc_index]];
421
422 tbdf = (cbd_t *) & cpmp->cp_dpmem[up->scc_genscc.scc_tbase];
423
424 /* Wait for last character to go.
425 */
426
427 buf = (char *) tbdf->cbd_bufaddr;
428#if 0
429 __asm__ ("eieio");
430 while (tbdf->cbd_sc & BD_SC_READY)
431 __asm__ ("eieio");
432#endif
433
434 *buf = c;
435 tbdf->cbd_datlen = 1;
436 tbdf->cbd_sc |= BD_SC_READY;
437 __asm__ ("eieio");
438#if 1
439 while (tbdf->cbd_sc & BD_SC_READY)
440 __asm__ ("eieio");
441#endif
442}
443
444static int scc_getc (int scc_index)
445{
446 volatile cbd_t *rbdf;
447 volatile unsigned char *buf;
448 volatile scc_uart_t *up;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200449 volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
Wolfgang Denkb38e0df2007-03-06 18:08:43 +0100450 volatile cpm8xx_t *cpmp = &(im->im_cpm);
451 unsigned char c;
452 int i;
453
454 up = (scc_uart_t *) & cpmp->cp_dparam[proff_scc[scc_index]];
455
456 rbdf = (cbd_t *) & cpmp->cp_dpmem[up->scc_genscc.scc_rbase];
457
458 /* Wait for character to show up.
459 */
460 buf = (unsigned char *) rbdf->cbd_bufaddr;
461#if 0
462 while (rbdf->cbd_sc & BD_SC_EMPTY);
463#else
464 for (i = 100; i > 0; i--) {
465 if (!(rbdf->cbd_sc & BD_SC_EMPTY))
466 break;
467 udelay (1000);
468 }
469
470 if (i == 0)
471 return -1;
472#endif
473 c = *buf;
474 rbdf->cbd_sc |= BD_SC_EMPTY;
475
476 return (c);
477}
478
479 /*
480 * Test routines
481 */
482
483static int test_ctlr (int ctlr, int index)
484{
485 int res = -1;
486 char test_str[] = "*** UART Test String ***\r\n";
487 int i;
488
489 ctlr_proc[ctlr].init (index);
490
491 for (i = 0; i < sizeof (test_str) - 1; i++) {
492 ctlr_proc[ctlr].putc (index, test_str[i]);
493 if (ctlr_proc[ctlr].getc (index) != test_str[i])
494 goto Done;
495 }
496
497 res = 0;
498
499Done:
500 ctlr_proc[ctlr].halt (index);
501
502 if (res != 0) {
503 post_log ("uart %s%d test failed\n",
504 ctlr_name[ctlr], index + 1);
505 }
506
507 return res;
508}
509
510int uart_post_test (int flags)
511{
512 int res = 0;
513 int i;
514
515 ctlr_proc[CTLR_SMC].init = smc_init;
516 ctlr_proc[CTLR_SMC].halt = smc_halt;
517 ctlr_proc[CTLR_SMC].putc = smc_putc;
518 ctlr_proc[CTLR_SMC].getc = smc_getc;
519
520 ctlr_proc[CTLR_SCC].init = scc_init;
521 ctlr_proc[CTLR_SCC].halt = scc_halt;
522 ctlr_proc[CTLR_SCC].putc = scc_putc;
523 ctlr_proc[CTLR_SCC].getc = scc_getc;
524
Mike Frysinger83a687b2011-05-10 07:28:35 +0000525 for (i = 0; i < ARRAY_SIZE(ctlr_list); i++) {
Wolfgang Denkb38e0df2007-03-06 18:08:43 +0100526 if (test_ctlr (ctlr_list[i][0], ctlr_list[i][1]) != 0) {
527 res = -1;
528 }
529 }
530
531#if !defined(CONFIG_8xx_CONS_NONE)
532 serial_reinit_all ();
533#endif
534
535 return res;
536}
537
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200538#endif /* CONFIG_POST & CONFIG_SYS_POST_UART */