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

4.104.114.84.95
Last change on this file since 8ef3818 was 8ef3818, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 12, 2000 at 7:57:02 PM

Patch from John Cotton <john.cotton@…>, Charles-Antoine Gauthier
<charles.gauthier@…>, and Darlene A. Stewart
<Darlene.Stewart@…> to add support for a number of very
significant things:

+ BSPs for many variations on the Motorola MBX8xx board series
+ Cache Manager including initial support for m68040

and PowerPC

+ Rework of mpc8xx libcpu code so all mpc8xx CPUs now use

same code base.

+ Rework of eth_comm BSP to utiltize above.

John reports this works on the 821 and 860

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