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

4.115
Last change on this file since f865fc5d was f865fc5d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 12/01/11 at 08:20:03

2011-12-01 Ralf Corsépius <ralf.corsepius@…>

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