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

4.104.114.84.95
Last change on this file since 5e77d129 was 5e77d129, checked in by Joel Sherrill <joel.sherrill@…>, on 06/14/00 at 20:32:44

Patch from John Cotton <john.cotton@…> to correct cache
routine naming to follow RTEMS package/object.method rule.
This patch also eliminated calls to the obsolete routine
m68k_enable_caching.

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