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

4.115
Last change on this file since cfaa366 was cfaa366, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 17:55:58

General - Remove extraneous blank line in license message

Many files had an extra blank line in the license text
found in the file header. This patch removes that line.

The script that did this also turned off execute permission
when it was turned on incorrectly.

  • 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 *  http://www.rtems.com/license/LICENSE.
43 *
44 *  $Id$
45 */
46
47#include <rtems.h>
48#include <rtems/libio.h>
49#include <mpc8xx.h>
50#include <mpc8xx/console.h>
51#include <mpc8xx/cpm.h>
52#include <stdlib.h>
53#include <unistd.h>
54#include <termios.h>
55#include <bsp/irq.h>
56#include <rtems/bspIo.h>   /* for printk */
57
58int BSP_irq_enabled_at_cpm(const rtems_irq_number irqLine);
59
60/* BSP supplied routine */
61extern int mbx8xx_console_get_configuration(void);
62
63extern uint32_t bsp_clock_speed;
64
65/*
66 * Interrupt-driven input buffer
67 */
68#define RXBUFSIZE       16
69
70/*
71 *  I/O buffers and pointers to buffer descriptors.
72 *  Currently, single buffered input is done. This will work only
73 *  if the Rx interrupts are serviced quickly.
74 *
75 *  TODO: Add a least double buffering for safety.
76 */
77static volatile char rxBuf[NUM_PORTS][RXBUFSIZE];
78static volatile char txBuf[NUM_PORTS];
79
80/* SCC/SMC buffer descriptors */
81static volatile m8xxBufferDescriptor_t *RxBd[NUM_PORTS], *TxBd[NUM_PORTS];
82
83/* Used to track the usage of the baud rate generators */
84static unsigned long brg_spd[4];
85static char  brg_used[4];
86
87/* Used to track termios private data for callbacks */
88struct rtems_termios_tty *ttyp[NUM_PORTS];
89
90/*
91 * Device-specific routines
92 */
93static int m8xx_get_brg_cd(int);
94static unsigned char m8xx_get_brg_clk(int);
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 *unused);
98static void m8xx_smc2_interrupt_handler(void *unused);
99static void m8xx_scc2_interrupt_handler(void *unused);
100#if defined(mpc860)
101static void m8xx_scc3_interrupt_handler(void *unused);
102static void m8xx_scc4_interrupt_handler(void *unused);
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 = ((bsp_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  uint16_t   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  uint16_t   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 (void *unused)
386{
387  /*
388   * Buffer received?
389   */
390  if ((m8xx.scc2.sccm & M8xx_SCCE_RX) && (m8xx.scc2.scce & M8xx_SCCE_RX)) {
391    m8xx.scc2.scce = M8xx_SCCE_RX;    /* Clear the event */
392
393
394    /* Check that the buffer is ours */
395    if ((RxBd[SCC2_MINOR]->status & M8xx_BD_EMPTY) == 0) {
396      rtems_cache_invalidate_multiple_data_lines(
397        (const void *) RxBd[SCC2_MINOR]->buffer,
398        RxBd[SCC2_MINOR]->length );
399      rtems_termios_enqueue_raw_characters(
400        (void *)ttyp[SCC2_MINOR],
401        (char *)RxBd[SCC2_MINOR]->buffer,
402        (int)RxBd[SCC2_MINOR]->length );
403      RxBd[SCC2_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
404                                 M8xx_BD_INTERRUPT;
405    }
406  }
407
408  /*
409   * Buffer transmitted?
410   */
411  if (m8xx.scc2.scce & M8xx_SCCE_TX) {
412    m8xx.scc2.scce = M8xx_SCCE_TX;  /* Clear the event */
413
414    /* Check that the buffer is ours */
415    if ((TxBd[SCC2_MINOR]->status & M8xx_BD_READY) == 0)
416      rtems_termios_dequeue_characters (
417        (void *)ttyp[SCC2_MINOR],
418        (int)TxBd[SCC2_MINOR]->length);
419  }
420}
421
422
423#ifdef mpc860
424static void
425m8xx_scc3_interrupt_handler (void *unused)
426{
427  /*
428   * Buffer received?
429   */
430  if ((m8xx.scc3.sccm & M8xx_SCCE_RX) && (m8xx.scc3.scce & M8xx_SCCE_RX)) {
431    m8xx.scc3.scce = M8xx_SCCE_RX;  /* Clear the event */
432
433
434    /* Check that the buffer is ours */
435    if ((RxBd[SCC3_MINOR]->status & M8xx_BD_EMPTY) == 0) {
436      rtems_cache_invalidate_multiple_data_lines(
437        (const void *) RxBd[SCC3_MINOR]->buffer,
438        RxBd[SCC3_MINOR]->length );
439      rtems_termios_enqueue_raw_characters(
440        (void *)ttyp[SCC3_MINOR],
441        (char *)RxBd[SCC3_MINOR]->buffer,
442        (int)RxBd[SCC3_MINOR]->length );
443      RxBd[SCC3_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
444                                 M8xx_BD_INTERRUPT;
445    }
446  }
447
448  /*
449   * Buffer transmitted?
450   */
451  if (m8xx.scc3.scce & M8xx_SCCE_TX) {
452    m8xx.scc3.scce = M8xx_SCCE_TX;    /* Clear the event */
453
454    /* Check that the buffer is ours */
455    if ((TxBd[SCC3_MINOR]->status & M8xx_BD_READY) == 0)
456      rtems_termios_dequeue_characters (
457        (void *)ttyp[SCC3_MINOR],
458        (int)TxBd[SCC3_MINOR]->length);
459  }
460}
461
462
463static void
464m8xx_scc4_interrupt_handler (void *unused)
465{
466  /*
467   * Buffer received?
468   */
469  if ((m8xx.scc4.sccm & M8xx_SCCE_RX) && (m8xx.scc4.scce & M8xx_SCCE_RX)) {
470    m8xx.scc4.scce = M8xx_SCCE_RX;  /* Clear the event */
471
472
473    /* Check that the buffer is ours */
474    if ((RxBd[SCC4_MINOR]->status & M8xx_BD_EMPTY) == 0) {
475      rtems_cache_invalidate_multiple_data_lines(
476        (const void *) RxBd[SCC4_MINOR]->buffer,
477        RxBd[SCC4_MINOR]->length );
478      rtems_termios_enqueue_raw_characters(
479        (void *)ttyp[SCC4_MINOR],
480        (char *)RxBd[SCC4_MINOR]->buffer,
481        (int)RxBd[SCC4_MINOR]->length );
482      RxBd[SCC4_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
483                                 M8xx_BD_INTERRUPT;
484    }
485  }
486
487  /*
488   * Buffer transmitted?
489   */
490  if (m8xx.scc4.scce & M8xx_SCCE_TX) {
491    m8xx.scc4.scce = M8xx_SCCE_TX;    /* Clear the event */
492
493    /* Check that the buffer is ours */
494    if ((TxBd[SCC4_MINOR]->status & M8xx_BD_READY) == 0)
495      rtems_termios_dequeue_characters (
496        (void *)ttyp[SCC4_MINOR],
497        (int)TxBd[SCC4_MINOR]->length);
498  }
499}
500#endif
501
502static void
503m8xx_smc1_interrupt_handler (void *unused)
504{
505  /*
506   * Buffer received?
507   */
508  if (m8xx.smc1.smce & M8xx_SMCE_RX) {
509    m8xx.smc1.smce = M8xx_SMCE_RX;  /* Clear the event */
510
511
512    /* Check that the buffer is ours */
513    if ((RxBd[SMC1_MINOR]->status & M8xx_BD_EMPTY) == 0) {
514      rtems_cache_invalidate_multiple_data_lines(
515        (const void *) RxBd[SMC1_MINOR]->buffer,
516        RxBd[SMC1_MINOR]->length );
517      rtems_termios_enqueue_raw_characters(
518        (void *)ttyp[SMC1_MINOR],
519        (char *)RxBd[SMC1_MINOR]->buffer,
520        (int)RxBd[SMC1_MINOR]->length );
521      RxBd[SMC1_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
522                                 M8xx_BD_INTERRUPT;
523    }
524  }
525
526  /*
527   * Buffer transmitted?
528   */
529  if (m8xx.smc1.smce & M8xx_SMCE_TX) {
530    m8xx.smc1.smce = M8xx_SMCE_TX;    /* Clear the event */
531
532    /* Check that the buffer is ours */
533    if ((TxBd[SMC1_MINOR]->status & M8xx_BD_READY) == 0)
534      rtems_termios_dequeue_characters (
535        (void *)ttyp[SMC1_MINOR],
536        (int)TxBd[SMC1_MINOR]->length);
537  }
538}
539
540
541static void
542m8xx_smc2_interrupt_handler (void *unused)
543{
544  /*
545   * Buffer received?
546   */
547  if (m8xx.smc2.smce & M8xx_SMCE_RX) {
548    m8xx.smc2.smce = M8xx_SMCE_RX;  /* Clear the event */
549
550
551    /* Check that the buffer is ours */
552    if ((RxBd[SMC2_MINOR]->status & M8xx_BD_EMPTY) == 0) {
553      rtems_cache_invalidate_multiple_data_lines(
554        (const void *) RxBd[SMC2_MINOR]->buffer,
555        RxBd[SMC2_MINOR]->length );
556      rtems_termios_enqueue_raw_characters(
557        (void *)ttyp[SMC2_MINOR],
558        (char *)RxBd[SMC2_MINOR]->buffer,
559        (int)RxBd[SMC2_MINOR]->length );
560      RxBd[SMC2_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
561                                 M8xx_BD_INTERRUPT;
562    }
563  }
564
565  /*
566   * Buffer transmitted?
567   */
568  if (m8xx.smc2.smce & M8xx_SMCE_TX) {
569    m8xx.smc2.smce = M8xx_SMCE_TX;    /* Clear the event */
570
571    /* Check that the buffer is ours */
572    if ((TxBd[SMC2_MINOR]->status & M8xx_BD_READY) == 0)
573      rtems_termios_dequeue_characters (
574        (void *)ttyp[SMC2_MINOR],
575        (int)TxBd[SMC2_MINOR]->length);
576  }
577}
578
579void m8xx_scc_enable(const rtems_irq_connect_data* ptr)
580{
581  volatile m8xxSCCRegisters_t *sccregs = 0;
582  switch (ptr->name) {
583#if defined(mpc860)
584  case BSP_CPM_IRQ_SCC4 :
585    sccregs = &m8xx.scc4;
586    break;
587  case BSP_CPM_IRQ_SCC3 :
588    sccregs = &m8xx.scc3;
589    break;
590#endif
591  case BSP_CPM_IRQ_SCC2 :
592    sccregs = &m8xx.scc2;
593    break;
594  case BSP_CPM_IRQ_SCC1 :
595    sccregs = &m8xx.scc1;
596    break;
597  default:
598    break;
599  }
600  sccregs->sccm = 3;
601}
602
603void m8xx_scc_disable(const rtems_irq_connect_data* ptr)
604{
605  volatile m8xxSCCRegisters_t *sccregs = 0;
606  switch (ptr->name) {
607#if defined(mpc860)
608  case BSP_CPM_IRQ_SCC4 :
609    sccregs = &m8xx.scc4;
610    break;
611  case BSP_CPM_IRQ_SCC3 :
612    sccregs = &m8xx.scc3;
613    break;
614#endif
615  case BSP_CPM_IRQ_SCC2 :
616    sccregs = &m8xx.scc2;
617    break;
618  case BSP_CPM_IRQ_SCC1 :
619    sccregs = &m8xx.scc1;
620    break;
621  default:
622    break;
623  }
624  sccregs->sccm &= (~3);
625}
626
627int m8xx_scc_isOn(const rtems_irq_connect_data* ptr)
628{
629 return BSP_irq_enabled_at_cpm (ptr->name);
630}
631
632static rtems_irq_connect_data consoleIrqData;
633
634void
635m8xx_uart_scc_initialize (int minor)
636{
637  unsigned char brg;
638  volatile m8xxSCCparms_t *sccparms = 0;
639  volatile m8xxSCCRegisters_t *sccregs = 0;
640
641  /*
642   * Check that minor number is valid
643   */
644  if ( (minor < SCC2_MINOR) || (minor > NUM_PORTS-1) )
645    return;
646
647  /* Get the sicr clock source bit values for 9600 bps */
648  brg = m8xx_get_brg_clk(9600);
649
650  /*
651   * Allocate buffer descriptors
652   */
653  RxBd[minor] = m8xx_bd_allocate(1);
654  TxBd[minor] = m8xx_bd_allocate(1);
655
656  /*
657   *  Get the address of the parameter RAM for the specified port,
658   *  configure I/O port A,C & D and put SMC in NMSI mode, connect
659   *  the SCC to the appropriate BRG.
660   *
661   *  SCC2 TxD is shared with port A bit 12
662   *  SCC2 RxD is shared with port A bit 13
663   *  SCC1 TxD is shared with port A bit 14
664   *  SCC1 RxD is shared with port A bit 15
665   *  SCC4 DCD is shared with port C bit 4
666   *  SCC4 CTS is shared with port C bit 5
667   *  SCC3 DCD is shared with port C bit 6
668   *  SCC3 CTS is shared with port C bit 7
669   *  SCC2 DCD is shared with port C bit 8
670   *  SCC2 CTS is shared with port C bit 9
671   *  SCC1 DCD is shared with port C bit 10
672   *  SCC1 CTS is shared with port C bit 11
673   *  SCC2 RTS is shared with port C bit 14
674   *  SCC1 RTS is shared with port C bit 15
675   *  SCC4 RTS is shared with port D bit 6
676   *  SCC3 RTS is shared with port D bit 7
677   *  SCC4 TxD is shared with port D bit 8
678   *  SCC4 RxD is shared with port D bit 9
679   *  SCC3 TxD is shared with port D bit 10
680   *  SCC3 RxD is shared with port D bit 11
681   */
682  switch (minor) {
683    case SCC2_MINOR:
684      sccparms = &m8xx.scc2p;
685      sccregs = &m8xx.scc2;
686
687      m8xx.papar |=  0x000C;        /* PA12 & PA13 are dedicated peripheral pins */
688      m8xx.padir &= ~0x000C;        /* PA13 & PA12 must not drive the UART lines */
689      m8xx.paodr &= ~0x000C;        /* PA12 & PA13 are not open drain */
690      m8xx.pcpar |=  0x0002;        /* PC14 is SCC2 RTS */
691      m8xx.pcpar &= ~0x00C0;        /* PC8 & PC9 are SCC2 DCD and CTS */
692      m8xx.pcdir &= ~0x00C2;        /* PC8, PC9 & PC14 must not drive the UART lines */
693      m8xx.pcso  |=  0x00C0;        /* Enable DCD and CTS inputs */
694
695      m8xx.sicr &= 0xFFFF00FF;      /* Clear TCS2 & RCS2, GR2=no grant, SC2=NMSI mode */
696      m8xx.sicr |= (brg<<11) | (brg<<8); /* TCS2 = RCS2 = brg */
697      break;
698
699#ifdef mpc860
700    case SCC3_MINOR:
701      sccparms = &m8xx.scc3p;
702      sccregs = &m8xx.scc3;
703
704      m8xx.pcpar &= ~0x0300;        /* PC6 & PC7 are SCC3 DCD and CTS */
705      m8xx.pcdir &= ~0x0300;        /* PC6 & PC7 must not drive the UART lines */
706      m8xx.pcso  |=  0x0300;        /* Enable DCD and CTS inputs */
707      m8xx.pdpar |=  0x0130;        /* PD7, PD10 & PD11 are dedicated peripheral pins */
708
709      m8xx.sicr &= 0xFF00FFFF;      /* Clear TCS3 & RCS3, GR3=no grant, SC3=NMSI mode */
710      m8xx.sicr |= (brg<<19) | (brg<<16); /* TCS3 = RCS3 = brg */
711      break;
712
713    case SCC4_MINOR:
714      sccparms = &m8xx.scc4p;
715      sccregs = &m8xx.scc4;
716
717      m8xx.pcpar &= ~0x0C00;        /* PC4 & PC5 are SCC4 DCD and CTS */
718      m8xx.pcdir &= ~0x0C00;        /* PC4 & PC5 must not drive the UART lines */
719      m8xx.pcso  |=  0x0C00;        /* Enable DCD and CTS inputs */
720      m8xx.pdpar |=  0x02C0;        /* PD6, PD8 & PD9 are dedicated peripheral pins */
721
722      m8xx.sicr &= 0x00FFFFFF;      /* Clear TCS4 & RCS4, GR4=no grant, SC4=NMSI mode */
723      m8xx.sicr |= (brg<<27) | (brg<<24); /* TCS4 = RCS4 = brg */
724      break;
725#endif
726  }
727
728  /*
729   *  Set up SDMA
730   */
731  m8xx.sdcr = 0x01;                 /* as per section 16.10.2.1 MPC821UM/AD */
732
733  /*
734   *  Set up the SCC parameter RAM.
735   */
736  sccparms->rbase = (char *)RxBd[minor] - (char *)&m8xx;
737  sccparms->tbase = (char *)TxBd[minor] - (char *)&m8xx;
738
739  sccparms->rfcr = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0);
740  sccparms->tfcr = M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0);
741  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
742    sccparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
743  else
744    sccparms->mrblr = 1;            /* Maximum Rx buffer size */
745  sccparms->un.uart.max_idl = 10;   /* Set nb of idle chars to close buffer */
746  sccparms->un.uart.brkcr = 0;      /* Set nb of breaks to send for STOP Tx */
747
748  sccparms->un.uart.parec = 0;      /* Clear parity error counter */
749  sccparms->un.uart.frmec = 0;      /* Clear framing error counter */
750  sccparms->un.uart.nosec = 0;      /* Clear noise counter */
751  sccparms->un.uart.brkec = 0;      /* Clear break counter */
752
753  sccparms->un.uart.uaddr[0] = 0;   /* Not in multidrop mode, so clear */
754  sccparms->un.uart.uaddr[1] = 0;   /* Not in multidrop mode, so clear */
755  sccparms->un.uart.toseq  = 0;     /* Tx Out-Of-SEQuence--no XON/XOFF now */
756
757  sccparms->un.uart.character[0] = 0x8000; /* Entry is invalid */
758  sccparms->un.uart.character[1] = 0x8000; /* Entry is invalid */
759  sccparms->un.uart.character[2] = 0x8000; /* Entry is invalid */
760  sccparms->un.uart.character[3] = 0x8000; /* Entry is invalid */
761  sccparms->un.uart.character[4] = 0x8000; /* Entry is invalid */
762  sccparms->un.uart.character[5] = 0x8000; /* Entry is invalid */
763  sccparms->un.uart.character[6] = 0x8000; /* Entry is invalid */
764  sccparms->un.uart.character[7] = 0x8000; /* Entry is invalid */
765
766
767  sccparms->un.uart.rccm = 0xc0ff;  /* No masking */
768
769  /*
770   * Set up the Receive Buffer Descriptor
771   */
772  RxBd[minor]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP | M8xx_BD_INTERRUPT;
773  RxBd[minor]->length = 0;
774  RxBd[minor]->buffer = rxBuf[minor];
775
776  /*
777   * Setup the Transmit Buffer Descriptor
778   */
779  TxBd[minor]->status = M8xx_BD_WRAP;
780
781 /*
782   * Set up SCCx general and protocol-specific mode registers
783   */
784  sccregs->gsmr_h = 0x00000020;     /* RFW=low latency operation */
785  sccregs->gsmr_l = 0x00028004;     /* TDCR=RDCR=16x clock mode, MODE=uart*/
786  sccregs->scce = ~0;               /* Clear any pending event */
787  sccregs->sccm = 0;                /* Mask all interrupt/event sources */
788  sccregs->psmr = 0x3000;           /* Normal operation & mode, 1 stop bit,
789                                       8 data bits, no parity */
790  sccregs->dsr = 0x7E7E;            /* No fractional stop bits */
791  sccregs->gsmr_l = 0x00028034;     /* ENT=enable Tx, ENR=enable Rx */
792
793  /*
794   *  Initialize the Rx and Tx with the new parameters.
795   */
796  switch (minor) {
797    case SCC2_MINOR:
798      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SCC2);
799      break;
800
801#ifdef mpc860
802    case SCC3_MINOR:
803      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SCC3);
804      break;
805    case SCC4_MINOR:
806      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SCC4);
807      break;
808#endif
809  }
810  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
811    consoleIrqData.on = m8xx_scc_enable;
812    consoleIrqData.off = m8xx_scc_disable;
813    consoleIrqData.isOn = m8xx_scc_isOn;
814
815    switch (minor) {
816    case SCC2_MINOR:
817      consoleIrqData.name = BSP_CPM_IRQ_SCC2;
818      consoleIrqData.hdl = m8xx_scc2_interrupt_handler;
819      break;
820
821#ifdef mpc860
822    case SCC3_MINOR:
823      consoleIrqData.name = BSP_CPM_IRQ_SCC3;
824      consoleIrqData.hdl = m8xx_scc3_interrupt_handler;
825      break;
826
827    case SCC4_MINOR:
828      consoleIrqData.name = BSP_CPM_IRQ_SCC4;
829      consoleIrqData.hdl = m8xx_scc4_interrupt_handler;
830      break;
831#endif /* mpc860 */
832    }
833    if (!BSP_install_rtems_irq_handler (&consoleIrqData)) {
834        printk("Unable to connect SCC Irq handler\n");
835        rtems_fatal_error_occurred(1);
836    }
837  }
838}
839
840void m8xx_smc_enable(const rtems_irq_connect_data* ptr)
841{
842  volatile m8xxSMCRegisters_t *smcregs = 0;
843  switch (ptr->name) {
844  case BSP_CPM_IRQ_SMC1 :
845    smcregs = &m8xx.smc1;
846    break;
847  case BSP_CPM_IRQ_SMC2_OR_PIP :
848    smcregs = &m8xx.smc2;
849    break;
850  default:
851    break;
852  }
853  smcregs->smcm = 3;
854}
855
856void m8xx_smc_disable(const rtems_irq_connect_data* ptr)
857{
858  volatile m8xxSMCRegisters_t *smcregs = 0;
859  switch (ptr->name) {
860  case BSP_CPM_IRQ_SMC1 :
861    smcregs = &m8xx.smc1;
862    break;
863  case BSP_CPM_IRQ_SMC2_OR_PIP :
864    smcregs = &m8xx.smc2;
865    break;
866  default:
867    break;
868  }
869  smcregs->smcm &= (~3);
870}
871
872int m8xx_smc_isOn(const rtems_irq_connect_data* ptr)
873{
874 return BSP_irq_enabled_at_cpm (ptr->name);
875}
876
877void
878m8xx_uart_smc_initialize (int minor)
879{
880  unsigned char brg;
881  volatile m8xxSMCparms_t *smcparms = 0;
882  volatile m8xxSMCRegisters_t *smcregs = 0;
883
884  /*
885   * Check that minor number is valid
886   */
887  if ( (minor < SMC1_MINOR) || (minor > SMC2_MINOR) )
888    return;
889
890  m8xx.sdcr = 0x01;                 /* as per section 16.10.2.1 MPC821UM/AD */
891  /* Get the simode clock source bit values for 9600 bps */
892  brg = m8xx_get_brg_clk(9600);
893
894  /*
895   * Allocate buffer descriptors
896   */
897  RxBd[minor] = m8xx_bd_allocate (1);
898  TxBd[minor] = m8xx_bd_allocate (1);
899
900  /*
901   *  Get the address of the parameter RAM for the specified port,
902   *  configure I/O port B and put SMC in NMSI mode, connect the
903   *  SMC to the appropriate BRG.
904   *
905   *  SMC2 RxD is shared with port B bit 20
906   *  SMC2 TxD is shared with port B bit 21
907   *  SMC1 RxD is shared with port B bit 24
908   *  SMC1 TxD is shared with port B bit 25
909   */
910  switch (minor) {
911    case SMC1_MINOR:
912      smcparms = &m8xx.smc1p;
913      smcregs = &m8xx.smc1;
914
915      m8xx.pbpar |=  0x000000C0;    /* PB24 & PB25 are dedicated peripheral pins */
916      m8xx.pbdir &= ~0x000000C0;    /* PB24 & PB25 must not drive UART lines */
917      m8xx.pbodr &= ~0x000000C0;    /* PB24 & PB25 are not open drain */
918
919      m8xx.simode &= 0xFFFF0FFF;    /* Clear SMC1CS & SMC1 for NMSI mode */
920      m8xx.simode |= brg << 12;     /* SMC1CS = brg */
921      break;
922
923    case SMC2_MINOR:
924      smcparms = &m8xx.smc2p;
925      smcregs = &m8xx.smc2;
926
927      m8xx.pbpar |=  0x00000C00;    /* PB20 & PB21 are dedicated peripheral pins */
928      m8xx.pbdir &= ~0x00000C00;    /* PB20 & PB21 must not drive the UART lines */
929      m8xx.pbodr &= ~0x00000C00;    /* PB20 & PB21 are not open drain */
930
931      m8xx.simode &= 0x0FFFFFFF;    /* Clear SMC2CS & SMC2 for NMSI mode */
932      m8xx.simode |= brg << 28;     /* SMC2CS = brg */
933      break;
934  }
935
936  /*
937   * Set up SMC1 parameter RAM common to all protocols
938   */
939  smcparms->rbase = (char *)RxBd[minor] - (char *)&m8xx;
940  smcparms->tbase = (char *)TxBd[minor] - (char *)&m8xx;
941  smcparms->rfcr = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0);
942  smcparms->tfcr = M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0);
943  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
944    smcparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
945  else
946    smcparms->mrblr = 1;            /* Maximum Rx buffer size */
947
948  /*
949   * Set up SMC1 parameter RAM UART-specific parameters
950   */
951  smcparms->un.uart.max_idl = 10;   /* Set nb of idle chars to close buffer */
952  smcparms->un.uart.brkcr = 0;      /* Set nb of breaks to send for STOP Tx */
953  smcparms->un.uart.brkec = 0;      /* Clear break counter */
954
955  /*
956   * Set up the Receive Buffer Descriptor
957   */
958  RxBd[minor]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP | M8xx_BD_INTERRUPT;
959  RxBd[minor]->length = 0;
960  RxBd[minor]->buffer = rxBuf[minor];
961
962  /*
963   * Setup the Transmit Buffer Descriptor
964   */
965  TxBd[minor]->status = M8xx_BD_WRAP;
966
967  /*
968   * Set up SMCx general and protocol-specific mode registers
969   */
970  smcregs->smce = ~0;               /* Clear any pending events */
971  smcregs->smcm = 0;                /* Enable SMC Rx & Tx interrupts */
972  smcregs->smcmr = M8xx_SMCMR_CLEN(9) | M8xx_SMCMR_SM_UART;
973
974  /*
975   * Send "Init parameters" command
976   */
977  switch (minor) {
978    case SMC1_MINOR:
979      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SMC1);
980      break;
981
982    case SMC2_MINOR:
983      m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SMC2);
984      break;
985  }
986
987  /*
988   * Enable receiver and transmitter
989   */
990  smcregs->smcmr |= M8xx_SMCMR_TEN | M8xx_SMCMR_REN;
991  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
992    consoleIrqData.on = m8xx_smc_enable;
993    consoleIrqData.off = m8xx_smc_disable;
994    consoleIrqData.isOn = m8xx_smc_isOn;
995    switch (minor) {
996        case SMC1_MINOR:
997          consoleIrqData.name = BSP_CPM_IRQ_SMC1;
998          consoleIrqData.hdl  = m8xx_smc1_interrupt_handler;
999          break;
1000
1001        case SMC2_MINOR:
1002          consoleIrqData.name = BSP_CPM_IRQ_SMC2_OR_PIP;
1003          consoleIrqData.hdl  = m8xx_smc2_interrupt_handler;
1004          break;
1005    }
1006    if (!BSP_install_rtems_irq_handler (&consoleIrqData)) {
1007        printk("Unable to connect SMC Irq handler\n");
1008        rtems_fatal_error_occurred(1);
1009    }
1010  }
1011}
1012
1013void
1014m8xx_uart_initialize(void)
1015{
1016  int i;
1017
1018  for (i=0; i < 4; i++) {
1019    brg_spd[i] = 0;
1020    brg_used[i] = 0;
1021  }
1022}
1023
1024
1025
1026int
1027m8xx_uart_pollRead(
1028  int minor
1029)
1030{
1031  unsigned char c;
1032
1033  if (RxBd[minor]->status & M8xx_BD_EMPTY) {
1034    return -1;
1035  }
1036  rtems_cache_invalidate_multiple_data_lines(
1037    (const void *) RxBd[minor]->buffer,
1038    RxBd[minor]->length
1039  );
1040  c = ((char *)RxBd[minor]->buffer)[0];
1041  RxBd[minor]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP;
1042  return c;
1043}
1044
1045
1046/*
1047 *  TODO: Get a free buffer and set it up.
1048 */
1049ssize_t
1050m8xx_uart_write(
1051  int minor,
1052  const char *buf,
1053  size_t len
1054)
1055{
1056  rtems_cache_flush_multiple_data_lines( buf, len );
1057  TxBd[minor]->buffer = (char *) buf;
1058  TxBd[minor]->length = len;
1059  TxBd[minor]->status = M8xx_BD_READY | M8xx_BD_WRAP | M8xx_BD_INTERRUPT;
1060  return 0;
1061}
1062
1063
1064ssize_t
1065m8xx_uart_pollWrite(
1066  int minor,
1067  const char *buf,
1068  size_t len
1069)
1070{
1071  while (len--) {
1072    while (TxBd[minor]->status & M8xx_BD_READY)
1073      continue;
1074    txBuf[minor] = *buf++;
1075    rtems_cache_flush_multiple_data_lines( (void *)&txBuf[minor], 1 );
1076    TxBd[minor]->buffer = &txBuf[minor];
1077    TxBd[minor]->length = 1;
1078    TxBd[minor]->status = M8xx_BD_READY | M8xx_BD_WRAP;
1079  }
1080  return len;
1081}
Note: See TracBrowser for help on using the repository browser.