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

5
Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on 03/21/17 at 19:39:48

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

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