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