source: rtems/c/src/lib/libcpu/powerpc/mpc8xx/console-generic/console-generic.c @ 4b05b38f

4.104.114.84.95
Last change on this file since 4b05b38f was 4b05b38f, checked in by Joel Sherrill <joel.sherrill@…>, on 04/08/02 at 18:28:51

2002-04-06 Ralf Corsepius <corsepiu@…>

  • console-generic/console-generic.c: Remove unused variable "res".
  • Property mode set to 100644
File size: 30.4 KB
Line 
1/*
2 *  General Serial I/O functions.
3 *
4 *  This file contains the functions for performing serial I/O.
5 *  The actual system calls (console_*) should be in the BSP part
6 *  of the source tree. That way different BSPs can use whichever
7 *  SMCs and SCCs they want. Originally, all the stuff was in
8 *  this file, and it caused problems with one BSP using SCC2
9 *  as /dev/console, others using SMC1 for /dev/console, etc.
10 *
11 *  On-chip resources used:
12 *   resource   minor                note
13 *    SMC1       0
14 *    SMC2       1
15 *    SCC1       2                   N/A. Hardwired as ethernet port
16 *    SCC2       3
17 *    SCC3       4
18 *    SCC4       5
19 *    BRG1
20 *    BRG2
21 *    BRG3
22 *    BRG4
23 *  Author: Jay Monkman (jmonkman@frasca.com)
24 *  Copyright (C) 1998 by Frasca International, Inc.
25 *
26 *  Derived from c/src/lib/libbsp/m68k/gen360/console/console.c written by:
27 *    W. Eric Norum
28 *    Saskatchewan Accelerator Laboratory
29 *    University of Saskatchewan
30 *    Saskatoon, Saskatchewan, CANADA
31 *    eric@skatter.usask.ca
32 *
33 *  COPYRIGHT (c) 1989-1998.
34 *  On-Line Applications Research Corporation (OAR).
35 *
36 *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
37 *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
38 *  Copyright (c) 1999, National Research Council of Canada
39 *
40 *  The license and distribution terms for this file may be
41 *  found in the file LICENSE in this distribution or at
42 *
43 *  http://www.OARcorp.com/rtems/license.html.
44 *
45 *  $Id$
46 */
47
48#include <rtems.h>
49#include <rtems/libio.h>
50#include <mpc8xx.h>
51#include <mpc8xx/console.h>
52#include <mpc8xx/cpm.h>
53#include <stdlib.h>
54#include <unistd.h>
55#include <termios.h>
56#include <bsp/irq.h>
57#include <rtems/bspIo.h>   /* for printk */
58
59extern rtems_cpu_table Cpu_table;
60
61/* BSP supplied routine */
62extern int mbx8xx_console_get_configuration();
63
64/*
65 * Interrupt-driven input buffer
66 */
67#define RXBUFSIZE       16
68
69/*
70 *  I/O buffers and pointers to buffer descriptors.
71 *  Currently, single buffered input is done. This will work only
72 *  if the Rx interrupts are serviced quickly.
73 *
74 *  TODO: Add a least double buffering for safety.
75 */
76static volatile char rxBuf[NUM_PORTS][RXBUFSIZE];
77static volatile char txBuf[NUM_PORTS];
78
79/* SCC/SMC buffer descriptors */
80static volatile m8xxBufferDescriptor_t *RxBd[NUM_PORTS], *TxBd[NUM_PORTS];
81
82/* Used to track the usage of the baud rate generators */
83static unsigned long brg_spd[4];
84static char  brg_used[4];
85
86/* Used to track termios private data for callbacks */
87struct rtems_termios_tty *ttyp[NUM_PORTS];
88
89/*
90 * Device-specific routines
91 */
92static int m8xx_get_brg_cd(int);
93static unsigned char m8xx_get_brg_clk(int);
94void m8xx_console_reserve_resources(rtems_configuration_table *);
95static int m8xx_smc_set_attributes(int, const struct termios*);
96static int m8xx_scc_set_attributes(int, const struct termios*);
97static void m8xx_smc1_interrupt_handler(void);
98static void m8xx_smc2_interrupt_handler(void);
99static void m8xx_scc2_interrupt_handler(void);
100#if defined(mpc860)
101static void m8xx_scc3_interrupt_handler(void);
102static void m8xx_scc4_interrupt_handler(void);
103#endif
104
105/*
106 * Compute baud-rate-generator configuration register value
107 */
108static int
109m8xx_get_brg_cd (int baud)
110{
111  int divisor;
112  int div16 = 0;
113
114  divisor = ((Cpu_table.clock_speed / 16) + (baud / 2)) / baud;
115  if (divisor > 4096) {
116    div16 = 1;
117    divisor = (divisor + 8) / 16;
118  }
119  return M8xx_BRG_EN | M8xx_BRG_EXTC_BRGCLK |
120    ((divisor - 1) << 1) | div16;
121}
122
123
124/*
125 *  This function will fail if more that 4 baud rates have been selected
126 *  at any time since the OS started. It needs to be fixed. FIXME
127 */
128static unsigned
129char m8xx_get_brg_clk(int baud)
130{
131  int i;
132
133  /* first try to find a BRG that is already at the right speed */
134  for ( i = 0; i < 4; i++ ) {
135    if ( brg_spd[i] == baud ) {
136      break;
137    }
138  }
139
140  if ( i == 4 ) { /* I guess we didn't find one */
141    for ( i = 0; i < 4; i++ ) {
142      if ( brg_used[i] == 0 ) {
143        break;
144      }
145    }
146  }
147  if (i != 4) {
148    brg_used[i]++;
149    brg_spd[i]=baud;
150    switch (i) {
151    case 0:
152      m8xx.brgc1 = M8xx_BRG_RST;
153      m8xx.brgc1 = m8xx_get_brg_cd(baud);
154      break;
155    case 1:
156      m8xx.brgc2 = M8xx_BRG_RST;
157      m8xx.brgc2 = m8xx_get_brg_cd(baud);
158      break;
159    case 2:
160      m8xx.brgc3 = M8xx_BRG_RST;
161      m8xx.brgc3 = m8xx_get_brg_cd(baud);
162      break;
163    case 3:
164      m8xx.brgc4 = M8xx_BRG_RST;
165      m8xx.brgc4 = m8xx_get_brg_cd(baud);
166      break;
167    }
168    return i;
169  }
170
171  else
172    return 0xff;
173}
174
175
176/*
177 * Hardware-dependent portion of tcsetattr().
178 */
179static int
180m8xx_smc_set_attributes (int minor, const struct termios *t)
181{
182  int baud, brg=0, csize=0, ssize, psize;
183  rtems_unsigned16 clen=0, cstopb, parenb, parodd, cread;
184
185  /* Baud rate */
186  switch (t->c_cflag & CBAUD) {
187  default:      baud = -1;      break;
188  case B50:     baud = 50;      break;
189  case B75:     baud = 75;      break;
190  case B110:    baud = 110;     break;
191  case B134:    baud = 134;     break;
192  case B150:    baud = 150;     break;
193  case B200:    baud = 200;     break;
194  case B300:    baud = 300;     break;
195  case B600:    baud = 600;     break;
196  case B1200:   baud = 1200;    break;
197  case B1800:   baud = 1800;    break;
198  case B2400:   baud = 2400;    break;
199  case B4800:   baud = 4800;    break;
200  case B9600:   baud = 9600;    break;
201  case B19200:  baud = 19200;   break;
202  case B38400:  baud = 38400;   break;
203  case B57600:  baud = 57600;   break;
204  case B115200: baud = 115200;  break;
205  case B230400: baud = 230400;  break;
206  case B460800: baud = 460800;  break;
207  }
208  if (baud > 0)
209    brg = m8xx_get_brg_clk(baud);     /* 4 BRGs, 6 serial ports - hopefully */
210                                      /*  at least 2 ports will be the same */
211 
212  /* Number of data bits */
213  switch ( t->c_cflag & CSIZE ) {
214    case CS5:     csize = 5;       break;
215    case CS6:     csize = 6;       break;
216    case CS7:     csize = 7;       break;
217    case CS8:     csize = 8;       break;
218  }
219
220  /* Stop bits */
221  if ( t->c_cflag & CSTOPB ) {
222    cstopb = 0x0400;              /* Two stop bits */
223    ssize  = 2;
224  } else {
225    cstopb = 0x0000;              /* One stop bit */
226    ssize  = 1;
227  }
228
229  /* Parity */
230  if ( t->c_cflag & PARENB ) {
231    parenb = 0x0200;              /* Parity enabled on Tx and Rx */
232    psize  = 1;
233  } else {
234    parenb = 0x0000;              /* No parity on Tx and Rx */
235    psize  = 0;
236  }
237 
238  if ( t->c_cflag & PARODD )
239    parodd = 0x0000;              /* Odd parity */
240  else
241    parodd = 0x0100;
242
243  /*
244   * Character Length = start + data + parity + stop - 1
245   */
246  switch ( 1 + csize + psize + ssize - 1 ) {
247    case 6:     clen = 0x3000;       break;
248    case 7:     clen = 0x3800;       break;
249    case 8:     clen = 0x4000;       break;
250    case 9:     clen = 0x4800;       break;
251    case 10:    clen = 0x5000;       break;
252    case 11:    clen = 0x5800;       break;
253  }
254
255  if ( t->c_cflag & CREAD )
256    cread = 0x0023;             /* UART normal operation, enable Rx and Tx */
257  else
258    cread = 0x0021;             /* UART normal operation, enable Tx */
259   
260  /* Write the SIMODE/SMCMR registers */
261  switch (minor) {
262    case SMC1_MINOR:
263      m8xx.simode = ( (m8xx.simode & 0xffff8fff) | (brg << 12) );
264      m8xx.smc1.smcmr = clen | cstopb | parenb | parodd | cread;
265      break;
266    case SMC2_MINOR:
267      m8xx.simode = ( (m8xx.simode & 0x8fffffff) | (brg << 28) );
268      m8xx.smc2.smcmr = clen | cstopb | parenb | parodd | cread;
269      break;
270  }
271  return 0;
272}
273
274
275static int
276m8xx_scc_set_attributes (int minor, const struct termios *t)
277{
278  int baud, brg=0;
279  rtems_unsigned16 csize=0, cstopb, parenb, parodd;
280
281  /* Baud rate */
282  switch (t->c_cflag & CBAUD) {
283  default:      baud = -1;      break;
284  case B50:     baud = 50;      break;
285  case B75:     baud = 75;      break;
286  case B110:    baud = 110;     break;
287  case B134:    baud = 134;     break;
288  case B150:    baud = 150;     break;
289  case B200:    baud = 200;     break;
290  case B300:    baud = 300;     break;
291  case B600:    baud = 600;     break;
292  case B1200:   baud = 1200;    break;
293  case B1800:   baud = 1800;    break;
294  case B2400:   baud = 2400;    break;
295  case B4800:   baud = 4800;    break;
296  case B9600:   baud = 9600;    break;
297  case B19200:  baud = 19200;   break;
298  case B38400:  baud = 38400;   break;
299  case B57600:  baud = 57600;   break;
300  case B115200: baud = 115200;  break;
301  case B230400: baud = 230400;  break;
302  case B460800: baud = 460800;  break;
303  }
304  if (baud > 0)
305    brg = m8xx_get_brg_clk(baud);     /* 4 BRGs, 5 serial ports - hopefully */
306                                      /*  at least 2 ports will be the same */
307                                      /*  Write the SICR register below */
308   
309  /* Number of data bits */
310  switch ( t->c_cflag & CSIZE ) {
311    case CS5:     csize = 0x0000;       break;
312    case CS6:     csize = 0x1000;       break;
313    case CS7:     csize = 0x2000;       break;
314    case CS8:     csize = 0x3000;       break;
315  }
316
317  /* Stop bits */
318  if ( t->c_cflag & CSTOPB )
319    cstopb = 0x4000;              /* Two stop bits */
320  else
321    cstopb = 0x0000;              /* One stop bit */
322   
323  /* Parity */
324  if ( t->c_cflag & PARENB )
325    parenb = 0x0010;              /* Parity enabled on Tx and Rx */
326  else
327    parenb = 0x0000;              /* No parity on Tx and Rx */
328   
329  if ( t->c_cflag & PARODD )
330    parodd = 0x0000;              /* Odd parity */
331  else
332    parodd = 0x000a;
333
334  /* Write the SICR/PSMR Registers */
335  switch (minor) {
336    case SCC2_MINOR:
337      m8xx.sicr = ( (m8xx.sicr & 0xffffc0ff) | (brg << 11) | (brg << 8) );
338      m8xx.scc2.psmr = ( (cstopb | csize | parenb | parodd) | (m8xx.scc2.psmr & 0x8fe0) );
339      break;
340  #if defined(mpc860)
341    case SCC3_MINOR:
342      m8xx.sicr = ( (m8xx.sicr & 0xffc0ffff) | (brg << 19) | (brg << 16) );
343      m8xx.scc3.psmr = ( (cstopb | csize | parenb | parodd) | (m8xx.scc3.psmr & 0x8fe0) );
344      break;
345    case SCC4_MINOR:
346      m8xx.sicr = ( (m8xx.sicr & 0xc0ffffff) | (brg << 27) | (brg << 24) );
347      m8xx.scc4.psmr = ( (cstopb | csize | parenb | parodd) | (m8xx.scc4.psmr & 0x8fe0) );
348      break;
349  #endif
350  }
351 
352  return 0;
353}
354
355
356int
357m8xx_uart_setAttributes(
358  int minor,
359  const struct termios *t
360)
361{
362  /*
363   * Check that port number is valid
364   */
365  if ( (minor < SMC1_MINOR) || (minor > NUM_PORTS-1) )
366    return 0;
367
368  switch (minor) {
369    case SMC1_MINOR:
370    case SMC2_MINOR:
371      return m8xx_smc_set_attributes( minor, t );
372
373    case SCC2_MINOR:
374    case SCC3_MINOR:
375    case SCC4_MINOR:
376      return m8xx_scc_set_attributes( minor, t );
377  }
378  return 0;
379}
380
381
382/*
383 * Interrupt handlers
384 */
385static void m8xx_scc2_interrupt_handler ()
386{
387  int nb_overflow;
388
389  /*
390   * Buffer received?
391   */
392  if ((m8xx.scc2.sccm & M8xx_SCCE_RX) && (m8xx.scc2.scce & M8xx_SCCE_RX)) {
393    m8xx.scc2.scce = M8xx_SCCE_RX;    /* Clear the event */
394
395
396    /* Check that the buffer is ours */
397    if ((RxBd[SCC2_MINOR]->status & M8xx_BD_EMPTY) == 0) {
398      rtems_cache_invalidate_multiple_data_lines(
399        (const void *) RxBd[SCC2_MINOR]->buffer,
400        RxBd[SCC2_MINOR]->length );
401      nb_overflow = rtems_termios_enqueue_raw_characters(
402        (void *)ttyp[SCC2_MINOR],
403        (char *)RxBd[SCC2_MINOR]->buffer,
404        (int)RxBd[SCC2_MINOR]->length );
405      RxBd[SCC2_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
406                                 M8xx_BD_INTERRUPT;
407    }
408  }
409
410  /*
411   * Buffer transmitted?
412   */
413  if (m8xx.scc2.scce & M8xx_SCCE_TX) {
414    m8xx.scc2.scce = M8xx_SCCE_TX;  /* Clear the event */
415
416    /* Check that the buffer is ours */
417    if ((TxBd[SCC2_MINOR]->status & M8xx_BD_READY) == 0)
418      rtems_termios_dequeue_characters (
419        (void *)ttyp[SCC2_MINOR],
420        (int)TxBd[SCC2_MINOR]->length);
421  }
422}
423
424
425#ifdef mpc860
426static void
427m8xx_scc3_interrupt_handler (void)
428{
429  int nb_overflow;
430
431  /*
432   * Buffer received?
433   */
434  if ((m8xx.scc3.sccm & M8xx_SCCE_RX) && (m8xx.scc3.scce & M8xx_SCCE_RX)) {
435    m8xx.scc3.scce = M8xx_SCCE_RX;  /* Clear the event */
436
437
438    /* Check that the buffer is ours */
439    if ((RxBd[SCC3_MINOR]->status & M8xx_BD_EMPTY) == 0) {
440      rtems_cache_invalidate_multiple_data_lines(
441        (const void *) RxBd[SCC3_MINOR]->buffer,
442        RxBd[SCC3_MINOR]->length );
443      nb_overflow = rtems_termios_enqueue_raw_characters(
444        (void *)ttyp[SCC3_MINOR],
445        (char *)RxBd[SCC3_MINOR]->buffer,
446        (int)RxBd[SCC3_MINOR]->length );
447      RxBd[SCC3_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
448                                 M8xx_BD_INTERRUPT;
449    }
450  }
451
452  /*
453   * Buffer transmitted?
454   */
455  if (m8xx.scc3.scce & M8xx_SCCE_TX) {
456    m8xx.scc3.scce = M8xx_SCCE_TX;    /* Clear the event */
457
458    /* Check that the buffer is ours */
459    if ((TxBd[SCC3_MINOR]->status & M8xx_BD_READY) == 0)
460      rtems_termios_dequeue_characters (
461        (void *)ttyp[SCC3_MINOR],
462        (int)TxBd[SCC3_MINOR]->length);
463  }
464}
465
466
467static void
468m8xx_scc4_interrupt_handler (void)
469{
470  int nb_overflow;
471
472  /*
473   * Buffer received?
474   */
475  if ((m8xx.scc4.sccm & M8xx_SCCE_RX) && (m8xx.scc4.scce & M8xx_SCCE_RX)) {
476    m8xx.scc4.scce = M8xx_SCCE_RX;  /* Clear the event */
477
478
479    /* Check that the buffer is ours */
480    if ((RxBd[SCC4_MINOR]->status & M8xx_BD_EMPTY) == 0) {
481      rtems_cache_invalidate_multiple_data_lines(
482        (const void *) RxBd[SCC4_MINOR]->buffer,
483        RxBd[SCC4_MINOR]->length );
484      nb_overflow = rtems_termios_enqueue_raw_characters(
485        (void *)ttyp[SCC4_MINOR],
486        (char *)RxBd[SCC4_MINOR]->buffer,
487        (int)RxBd[SCC4_MINOR]->length );
488      RxBd[SCC4_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
489                                 M8xx_BD_INTERRUPT;
490    }
491  }
492
493  /*
494   * Buffer transmitted?
495   */
496  if (m8xx.scc4.scce & M8xx_SCCE_TX) {
497    m8xx.scc4.scce = M8xx_SCCE_TX;    /* Clear the event */
498
499    /* Check that the buffer is ours */
500    if ((TxBd[SCC4_MINOR]->status & M8xx_BD_READY) == 0)
501      rtems_termios_dequeue_characters (
502        (void *)ttyp[SCC4_MINOR],
503        (int)TxBd[SCC4_MINOR]->length);
504  }
505}
506#endif
507
508static void
509m8xx_smc1_interrupt_handler (void)
510{
511  int nb_overflow;
512
513  /*
514   * Buffer received?
515   */
516  if (m8xx.smc1.smce & M8xx_SMCE_RX) {
517    m8xx.smc1.smce = M8xx_SMCE_RX;  /* Clear the event */
518
519
520    /* Check that the buffer is ours */
521    if ((RxBd[SMC1_MINOR]->status & M8xx_BD_EMPTY) == 0) {
522      rtems_cache_invalidate_multiple_data_lines(
523        (const void *) RxBd[SMC1_MINOR]->buffer,
524        RxBd[SMC1_MINOR]->length );
525      nb_overflow = rtems_termios_enqueue_raw_characters(
526        (void *)ttyp[SMC1_MINOR],
527        (char *)RxBd[SMC1_MINOR]->buffer,
528        (int)RxBd[SMC1_MINOR]->length );
529      RxBd[SMC1_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
530                                 M8xx_BD_INTERRUPT;
531    }
532  }
533
534  /*
535   * Buffer transmitted?
536   */
537  if (m8xx.smc1.smce & M8xx_SMCE_TX) {
538    m8xx.smc1.smce = M8xx_SMCE_TX;    /* Clear the event */
539
540    /* Check that the buffer is ours */
541    if ((TxBd[SMC1_MINOR]->status & M8xx_BD_READY) == 0)
542      rtems_termios_dequeue_characters (
543        (void *)ttyp[SMC1_MINOR],
544        (int)TxBd[SMC1_MINOR]->length);
545  }
546}
547
548
549static void
550m8xx_smc2_interrupt_handler (void)
551{
552  int nb_overflow;
553
554  /*
555   * Buffer received?
556   */
557  if (m8xx.smc2.smce & M8xx_SMCE_RX) {
558    m8xx.smc2.smce = M8xx_SMCE_RX;  /* Clear the event */
559
560
561    /* Check that the buffer is ours */
562    if ((RxBd[SMC2_MINOR]->status & M8xx_BD_EMPTY) == 0) {
563      rtems_cache_invalidate_multiple_data_lines(
564        (const void *) RxBd[SMC2_MINOR]->buffer,
565        RxBd[SMC2_MINOR]->length );
566      nb_overflow = rtems_termios_enqueue_raw_characters(
567        (void *)ttyp[SMC2_MINOR],
568        (char *)RxBd[SMC2_MINOR]->buffer,
569        (int)RxBd[SMC2_MINOR]->length );
570      RxBd[SMC2_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
571                                 M8xx_BD_INTERRUPT;
572    }
573  }
574
575  /*
576   * Buffer transmitted?
577   */
578  if (m8xx.smc2.smce & M8xx_SMCE_TX) {
579    m8xx.smc2.smce = M8xx_SMCE_TX;    /* Clear the event */
580
581    /* Check that the buffer is ours */
582    if ((TxBd[SMC2_MINOR]->status & M8xx_BD_READY) == 0)
583      rtems_termios_dequeue_characters (
584        (void *)ttyp[SMC2_MINOR],
585        (int)TxBd[SMC2_MINOR]->length);
586  }
587}
588
589void m8xx_scc_enable(const rtems_irq_connect_data* ptr)
590{
591  volatile m8xxSCCRegisters_t *sccregs = 0;
592  switch (ptr->name) {
593#if defined(mpc860)
594  case BSP_CPM_IRQ_SCC4 :
595    sccregs = &m8xx.scc4;
596    break;
597  case BSP_CPM_IRQ_SCC3 :
598    sccregs = &m8xx.scc3;
599    break;
600#endif
601  case BSP_CPM_IRQ_SCC2 :
602    sccregs = &m8xx.scc2;
603    break;
604  case BSP_CPM_IRQ_SCC1 :
605    sccregs = &m8xx.scc1;
606    break;
607  default:
608    break;
609  }
610  sccregs->sccm = 3;
611}
612
613void m8xx_scc_disable(const rtems_irq_connect_data* ptr)
614{
615  volatile m8xxSCCRegisters_t *sccregs = 0;
616  switch (ptr->name) {
617#if defined(mpc860)
618  case BSP_CPM_IRQ_SCC4 :
619    sccregs = &m8xx.scc4;
620    break;
621  case BSP_CPM_IRQ_SCC3 :
622    sccregs = &m8xx.scc3;
623    break;
624#endif
625  case BSP_CPM_IRQ_SCC2 :
626    sccregs = &m8xx.scc2;
627    break;
628  case BSP_CPM_IRQ_SCC1 :
629    sccregs = &m8xx.scc1;
630    break;
631  default:
632    break;
633  }
634  sccregs->sccm &= (~3);
635}
636
637int m8xx_scc_isOn(const rtems_irq_connect_data* ptr)
638{
639 return BSP_irq_enabled_at_cpm (ptr->name);
640}
641
642static rtems_irq_connect_data consoleIrqData;
643       
644void
645m8xx_uart_scc_initialize (int minor)
646{
647  unsigned char brg;
648  volatile m8xxSCCparms_t *sccparms = 0;
649  volatile m8xxSCCRegisters_t *sccregs = 0;
650
651  /*
652   * Check that minor number is valid
653   */
654  if ( (minor < SCC2_MINOR) || (minor > NUM_PORTS-1) )
655    return;
656
657  /* Get the sicr clock source bit values for 9600 bps */
658  brg = m8xx_get_brg_clk(9600);
659
660  /*
661   * Allocate buffer descriptors
662   */
663  RxBd[minor] = m8xx_bd_allocate(1);
664  TxBd[minor] = m8xx_bd_allocate(1);
665
666  /*
667   *  Get the address of the parameter RAM for the specified port,
668   *  configure I/O port A,C & D and put SMC in NMSI mode, connect
669   *  the SCC to the appropriate BRG.
670   *
671   *  SCC2 TxD is shared with port A bit 12
672   *  SCC2 RxD is shared with port A bit 13
673   *  SCC1 TxD is shared with port A bit 14
674   *  SCC1 RxD is shared with port A bit 15
675   *  SCC4 DCD is shared with port C bit 4
676   *  SCC4 CTS is shared with port C bit 5
677   *  SCC3 DCD is shared with port C bit 6
678   *  SCC3 CTS is shared with port C bit 7
679   *  SCC2 DCD is shared with port C bit 8
680   *  SCC2 CTS is shared with port C bit 9
681   *  SCC1 DCD is shared with port C bit 10
682   *  SCC1 CTS is shared with port C bit 11
683   *  SCC2 RTS is shared with port C bit 14
684   *  SCC1 RTS is shared with port C bit 15
685   *  SCC4 RTS is shared with port D bit 6
686   *  SCC3 RTS is shared with port D bit 7
687   *  SCC4 TxD is shared with port D bit 8
688   *  SCC4 RxD is shared with port D bit 9
689   *  SCC3 TxD is shared with port D bit 10
690   *  SCC3 RxD is shared with port D bit 11
691   */
692  switch (minor) {
693    case SCC2_MINOR:
694      sccparms = &m8xx.scc2p;
695      sccregs = &m8xx.scc2;
696     
697      m8xx.papar |=  0x000C;        /* PA12 & PA13 are dedicated peripheral pins */
698      m8xx.padir &= ~0x000C;        /* PA13 & PA12 must not drive the UART lines */
699      m8xx.paodr &= ~0x000C;        /* PA12 & PA13 are not open drain */
700      m8xx.pcpar |=  0x0002;        /* PC14 is SCC2 RTS */
701      m8xx.pcpar &= ~0x00C0;        /* PC8 & PC9 are SCC2 DCD and CTS */
702      m8xx.pcdir &= ~0x00C2;        /* PC8, PC9 & PC14 must not drive the UART lines */
703      m8xx.pcso  |=  0x00C0;        /* Enable DCD and CTS inputs */
704     
705      m8xx.sicr &= 0xFFFF00FF;      /* Clear TCS2 & RCS2, GR2=no grant, SC2=NMSI mode */
706      m8xx.sicr |= (brg<<11) | (brg<<8); /* TCS2 = RCS2 = brg */
707      break;
708
709#ifdef mpc860
710    case SCC3_MINOR:
711      sccparms = &m8xx.scc3p;
712      sccregs = &m8xx.scc3;
713     
714      m8xx.pcpar &= ~0x0300;        /* PC6 & PC7 are SCC3 DCD and CTS */
715      m8xx.pcdir &= ~0x0300;        /* PC6 & PC7 must not drive the UART lines */
716      m8xx.pcso  |=  0x0300;        /* Enable DCD and CTS inputs */
717      m8xx.pdpar |=  0x0130;        /* PD7, PD10 & PD11 are dedicated peripheral pins */
718     
719      m8xx.sicr &= 0xFF00FFFF;      /* Clear TCS3 & RCS3, GR3=no grant, SC3=NMSI mode */
720      m8xx.sicr |= (brg<<19) | (brg<<16); /* TCS3 = RCS3 = brg */
721      break;
722
723    case SCC4_MINOR:
724      sccparms = &m8xx.scc4p;
725      sccregs = &m8xx.scc4;
726     
727      m8xx.pcpar &= ~0x0C00;        /* PC4 & PC5 are SCC4 DCD and CTS */
728      m8xx.pcdir &= ~0x0C00;        /* PC4 & PC5 must not drive the UART lines */
729      m8xx.pcso  |=  0x0C00;        /* Enable DCD and CTS inputs */
730      m8xx.pdpar |=  0x02C0;        /* PD6, PD8 & PD9 are dedicated peripheral pins */
731       
732      m8xx.sicr &= 0x00FFFFFF;      /* Clear TCS4 & RCS4, GR4=no grant, SC4=NMSI mode */
733      m8xx.sicr |= (brg<<27) | (brg<<24); /* TCS4 = RCS4 = brg */
734      break;
735#endif
736  }
737
738  /*
739   *  Set up SDMA
740   */
741  m8xx.sdcr = 0x01;                 /* as per section 16.10.2.1 MPC821UM/AD */
742
743  /*
744   *  Set up the SCC parameter RAM.
745   */
746  sccparms->rbase = (char *)RxBd[minor] - (char *)&m8xx;
747  sccparms->tbase = (char *)TxBd[minor] - (char *)&m8xx;
748
749  sccparms->rfcr = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0);
750  sccparms->tfcr = M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0);
751  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
752    sccparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
753  else
754    sccparms->mrblr = 1;            /* Maximum Rx buffer size */
755  sccparms->un.uart.max_idl = 10;   /* Set nb of idle chars to close buffer */
756  sccparms->un.uart.brkcr = 0;      /* Set nb of breaks to send for STOP Tx */
757
758  sccparms->un.uart.parec = 0;      /* Clear parity error counter */
759  sccparms->un.uart.frmec = 0;      /* Clear framing error counter */
760  sccparms->un.uart.nosec = 0;      /* Clear noise counter */
761  sccparms->un.uart.brkec = 0;      /* Clear break counter */
762
763  sccparms->un.uart.uaddr[0] = 0;   /* Not in multidrop mode, so clear */
764  sccparms->un.uart.uaddr[1] = 0;   /* Not in multidrop mode, so clear */
765  sccparms->un.uart.toseq  = 0;     /* Tx Out-Of-SEQuence--no XON/XOFF now */
766
767  sccparms->un.uart.character[0] = 0x8000; /* Entry is invalid */
768  sccparms->un.uart.character[1] = 0x8000; /* Entry is invalid */
769  sccparms->un.uart.character[2] = 0x8000; /* Entry is invalid */
770  sccparms->un.uart.character[3] = 0x8000; /* Entry is invalid */
771  sccparms->un.uart.character[4] = 0x8000; /* Entry is invalid */
772  sccparms->un.uart.character[5] = 0x8000; /* Entry is invalid */
773  sccparms->un.uart.character[6] = 0x8000; /* Entry is invalid */
774  sccparms->un.uart.character[7] = 0x8000; /* Entry is invalid */
775
776
777  sccparms->un.uart.rccm = 0xc0ff;  /* No masking */
778
779  /*
780   * Set up the Receive Buffer Descriptor
781   */
782  RxBd[minor]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP | M8xx_BD_INTERRUPT;
783  RxBd[minor]->length = 0;
784  RxBd[minor]->buffer = rxBuf[minor];
785
786  /*
787   * Setup the Transmit Buffer Descriptor
788   */
789  TxBd[minor]->status = M8xx_BD_WRAP;
790
791 /*
792   * Set up SCCx general and protocol-specific mode registers
793   */
794  sccregs->gsmr_h = 0x00000020;     /* RFW=low latency operation */
795  sccregs->gsmr_l = 0x00028004;     /* TDCR=RDCR=16x clock mode, MODE=uart*/
796  sccregs->scce = ~0;               /* Clear any pending event */
797  sccregs->sccm = 0;                /* Mask all interrupt/event sources */
798  sccregs->psmr = 0x3000;           /* Normal operation & mode, 1 stop bit,
799                                       8 data bits, no parity */
800  sccregs->dsr = 0x7E7E;            /* No fractional stop bits */
801  sccregs->gsmr_l = 0x00028034;     /* ENT=enable Tx, ENR=enable Rx */
802
803  /*
804   *  Initialize the Rx and Tx with the new parameters.
805   */
806  switch (minor) {
807    case SCC2_MINOR:
808      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SCC2);
809      break;
810
811#ifdef mpc860
812    case SCC3_MINOR:
813      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SCC3);
814      break;
815    case SCC4_MINOR:
816      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SCC4);
817      break;
818#endif
819  }
820  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
821    consoleIrqData.on = m8xx_scc_enable;
822    consoleIrqData.off = m8xx_scc_disable;
823    consoleIrqData.isOn = m8xx_scc_isOn;
824   
825    switch (minor) {
826    case SCC2_MINOR:
827      consoleIrqData.name = BSP_CPM_IRQ_SCC2;
828      consoleIrqData.hdl = m8xx_scc2_interrupt_handler;
829      break;
830
831#ifdef mpc860
832    case SCC3_MINOR:
833      consoleIrqData.name = BSP_CPM_IRQ_SCC3;
834      consoleIrqData.hdl = m8xx_scc3_interrupt_handler;
835      break;
836     
837    case SCC4_MINOR:
838      consoleIrqData.name = BSP_CPM_IRQ_SCC4;
839      consoleIrqData.hdl = m8xx_scc4_interrupt_handler;
840      break;
841#endif /* mpc860 */
842    }
843    if (!BSP_install_rtems_irq_handler (&consoleIrqData)) {
844        printk("Unable to connect SCC Irq handler\n");
845        rtems_fatal_error_occurred(1);
846    }
847  }
848}
849
850void m8xx_smc_enable(const rtems_irq_connect_data* ptr)
851{
852  volatile m8xxSMCRegisters_t *smcregs = 0;
853  switch (ptr->name) {
854  case BSP_CPM_IRQ_SMC1 :
855    smcregs = &m8xx.smc1;
856    break;
857  case BSP_CPM_IRQ_SMC2_OR_PIP :
858    smcregs = &m8xx.smc2;
859    break;
860  default:
861    break;
862  }
863  smcregs->smcm = 3;
864}
865
866void m8xx_smc_disable(const rtems_irq_connect_data* ptr)
867{
868  volatile m8xxSMCRegisters_t *smcregs = 0;
869  switch (ptr->name) {
870  case BSP_CPM_IRQ_SMC1 :
871    smcregs = &m8xx.smc1;
872    break;
873  case BSP_CPM_IRQ_SMC2_OR_PIP :
874    smcregs = &m8xx.smc2;
875    break;
876  default:
877    break;
878  }
879  smcregs->smcm &= (~3);
880}
881
882int m8xx_smc_isOn(const rtems_irq_connect_data* ptr)
883{
884 return BSP_irq_enabled_at_cpm (ptr->name);
885}
886
887void
888m8xx_uart_smc_initialize (int minor)
889{
890  unsigned char brg;
891  volatile m8xxSMCparms_t *smcparms = 0;
892  volatile m8xxSMCRegisters_t *smcregs = 0;
893
894  /*
895   * Check that minor number is valid
896   */
897  if ( (minor < SMC1_MINOR) || (minor > SMC2_MINOR) )
898    return;
899
900  m8xx.sdcr = 0x01;                 /* as per section 16.10.2.1 MPC821UM/AD */
901  /* Get the simode clock source bit values for 9600 bps */
902  brg = m8xx_get_brg_clk(9600);
903
904  /*
905   * Allocate buffer descriptors
906   */
907  RxBd[minor] = m8xx_bd_allocate (1);
908  TxBd[minor] = m8xx_bd_allocate (1);
909
910  /*
911   *  Get the address of the parameter RAM for the specified port,
912   *  configure I/O port B and put SMC in NMSI mode, connect the
913   *  SMC to the appropriate BRG.
914   *
915   *  SMC2 RxD is shared with port B bit 20
916   *  SMC2 TxD is shared with port B bit 21
917   *  SMC1 RxD is shared with port B bit 24
918   *  SMC1 TxD is shared with port B bit 25
919   */
920  switch (minor) {
921    case SMC1_MINOR:
922      smcparms = &m8xx.smc1p;
923      smcregs = &m8xx.smc1;
924     
925      m8xx.pbpar |=  0x000000C0;    /* PB24 & PB25 are dedicated peripheral pins */
926      m8xx.pbdir &= ~0x000000C0;    /* PB24 & PB25 must not drive UART lines */
927      m8xx.pbodr &= ~0x000000C0;    /* PB24 & PB25 are not open drain */
928
929      m8xx.simode &= 0xFFFF0FFF;    /* Clear SMC1CS & SMC1 for NMSI mode */
930      m8xx.simode |= brg << 12;     /* SMC1CS = brg */
931      break;
932
933    case SMC2_MINOR:
934      smcparms = &m8xx.smc2p;
935      smcregs = &m8xx.smc2;
936     
937      m8xx.pbpar |=  0x00000C00;    /* PB20 & PB21 are dedicated peripheral pins */
938      m8xx.pbdir &= ~0x00000C00;    /* PB20 & PB21 must not drive the UART lines */
939      m8xx.pbodr &= ~0x00000C00;    /* PB20 & PB21 are not open drain */
940     
941      m8xx.simode &= 0x0FFFFFFF;    /* Clear SMC2CS & SMC2 for NMSI mode */
942      m8xx.simode |= brg << 28;     /* SMC2CS = brg */
943      break;
944  }
945 
946  /*
947   * Set up SMC1 parameter RAM common to all protocols
948   */
949  smcparms->rbase = (char *)RxBd[minor] - (char *)&m8xx;
950  smcparms->tbase = (char *)TxBd[minor] - (char *)&m8xx;
951  smcparms->rfcr = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0);
952  smcparms->tfcr = M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0);
953  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
954    smcparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
955  else
956    smcparms->mrblr = 1;            /* Maximum Rx buffer size */
957
958  /*
959   * Set up SMC1 parameter RAM UART-specific parameters
960   */
961  smcparms->un.uart.max_idl = 10;   /* Set nb of idle chars to close buffer */
962  smcparms->un.uart.brkcr = 0;      /* Set nb of breaks to send for STOP Tx */
963  smcparms->un.uart.brkec = 0;      /* Clear break counter */
964
965  /*
966   * Set up the Receive Buffer Descriptor
967   */
968  RxBd[minor]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP | M8xx_BD_INTERRUPT;
969  RxBd[minor]->length = 0;
970  RxBd[minor]->buffer = rxBuf[minor];
971
972  /*
973   * Setup the Transmit Buffer Descriptor
974   */
975  TxBd[minor]->status = M8xx_BD_WRAP;
976
977  /*
978   * Set up SMCx general and protocol-specific mode registers
979   */
980  smcregs->smce = ~0;               /* Clear any pending events */
981  smcregs->smcm = 0;                /* Enable SMC Rx & Tx interrupts */
982  smcregs->smcmr = M8xx_SMCMR_CLEN(9) | M8xx_SMCMR_SM_UART;
983
984  /*
985   * Send "Init parameters" command
986   */
987  switch (minor) {
988    case SMC1_MINOR:
989      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SMC1);
990      break;
991
992    case SMC2_MINOR:
993      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SMC2);
994      break;
995  }
996 
997  /*
998   * Enable receiver and transmitter
999   */
1000  smcregs->smcmr |= M8xx_SMCMR_TEN | M8xx_SMCMR_REN;
1001  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
1002    consoleIrqData.on = m8xx_smc_enable;
1003    consoleIrqData.off = m8xx_smc_disable;
1004    consoleIrqData.isOn = m8xx_smc_isOn;
1005    switch (minor) {
1006        case SMC1_MINOR:
1007          consoleIrqData.name = BSP_CPM_IRQ_SMC1;
1008          consoleIrqData.hdl  = m8xx_smc1_interrupt_handler;
1009          break;
1010     
1011        case SMC2_MINOR:
1012          consoleIrqData.name = BSP_CPM_IRQ_SMC2_OR_PIP;
1013          consoleIrqData.hdl  = m8xx_smc2_interrupt_handler;
1014          break;
1015    }
1016    if (!BSP_install_rtems_irq_handler (&consoleIrqData)) {
1017        printk("Unable to connect SMC Irq handler\n");
1018        rtems_fatal_error_occurred(1);
1019    }
1020  }
1021}
1022
1023void
1024m8xx_uart_initialize(void)
1025{
1026  int i;
1027 
1028  for (i=0; i < 4; i++) {
1029    brg_spd[i] = 0;
1030    brg_used[i] = 0;
1031  }
1032}
1033
1034
1035
1036int
1037m8xx_uart_pollRead(
1038  int minor
1039)
1040{
1041  unsigned char c;
1042
1043  if (RxBd[minor]->status & M8xx_BD_EMPTY) {
1044    return -1;
1045  }
1046  rtems_cache_invalidate_multiple_data_lines(
1047    (const void *) RxBd[minor]->buffer,
1048    RxBd[minor]->length
1049  );
1050  c = ((char *)RxBd[minor]->buffer)[0];
1051  RxBd[minor]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP;
1052  return c;
1053}
1054
1055
1056/*
1057 *  TODO: Get a free buffer and set it up.
1058 */
1059int
1060m8xx_uart_write(
1061  int minor,
1062  const char *buf,
1063  int len
1064)
1065{
1066  rtems_cache_flush_multiple_data_lines( buf, len );
1067  TxBd[minor]->buffer = (char *) buf;
1068  TxBd[minor]->length = len;
1069  TxBd[minor]->status = M8xx_BD_READY | M8xx_BD_WRAP | M8xx_BD_INTERRUPT;
1070  return 0;
1071}
1072 
1073
1074int
1075m8xx_uart_pollWrite(
1076  int minor,
1077  const char *buf,
1078  int len
1079)
1080{
1081  while (len--) {
1082    while (TxBd[minor]->status & M8xx_BD_READY)
1083      continue;
1084    txBuf[minor] = *buf++;
1085    rtems_cache_flush_multiple_data_lines( (void *)&txBuf[minor], 1 );
1086    TxBd[minor]->buffer = &txBuf[minor];
1087    TxBd[minor]->length = 1;
1088    TxBd[minor]->status = M8xx_BD_READY | M8xx_BD_WRAP;
1089  }
1090  return 0;
1091}
1092
1093void
1094m8xx_uart_reserve_resources(
1095  rtems_configuration_table *configuration
1096)
1097{
1098  rtems_termios_reserve_resources (configuration, NUM_PORTS);
1099}
Note: See TracBrowser for help on using the repository browser.