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

4.104.114.84.95
Last change on this file since 772f224 was 772f224, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 20, 2000 at 1:34:45 PM

2000-10-20 Joel Sherrill <joel@…>

  • mpc8xx/console-generic/console-generic.c: Avoid use of BSP definitions and rely on the new routine mbx8xx_console_get_configuration() to get information. This routine was formerly incorrectly called mbx8xx_console_use_maximum_buffer_size(). binding to the exception code.
  • Property mode set to 100644
File size: 30.1 KB
Line 
1/*
2 *  General Serial I/O functions.
3 *
4 *  This file contains the functions for performing serial I/O.
5 *  The actual system calls (console_*) should be in the BSP part
6 *  of the source tree. That way different BSPs can use whichever
7 *  SMCs and SCCs they want. Originally, all the stuff was in
8 *  this file, and it caused problems with one BSP using SCC2
9 *  as /dev/console, others using SMC1 for /dev/console, etc.
10 *
11 *  On-chip resources used:
12 *   resource   minor                note
13 *    SMC1       0
14 *    SMC2       1
15 *    SCC1       2                   N/A. Hardwired as ethernet port
16 *    SCC2       3
17 *    SCC3       4
18 *    SCC4       5
19 *    BRG1
20 *    BRG2
21 *    BRG3
22 *    BRG4
23 *  Author: Jay Monkman (jmonkman@frasca.com)
24 *  Copyright (C) 1998 by Frasca International, Inc.
25 *
26 *  Derived from c/src/lib/libbsp/m68k/gen360/console/console.c written by:
27 *    W. Eric Norum
28 *    Saskatchewan Accelerator Laboratory
29 *    University of Saskatchewan
30 *    Saskatoon, Saskatchewan, CANADA
31 *    eric@skatter.usask.ca
32 *
33 *  COPYRIGHT (c) 1989-1998.
34 *  On-Line Applications Research Corporation (OAR).
35 *
36 *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
37 *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
38 *  Copyright (c) 1999, National Research Council of Canada
39 *
40 *  The license and distribution terms for this file may be
41 *  found in the file LICENSE in this distribution or at
42 *
43 *  http://www.OARcorp.com/rtems/license.html.
44 *
45 *  $Id$
46 */
47
48#include <rtems.h>
49#include <rtems/libio.h>
50#include <mpc8xx.h>
51#include <mpc8xx/console.h>
52#include <mpc8xx/cpm.h>
53#include <stdlib.h>
54#include <unistd.h>
55#include <termios.h>
56
57extern rtems_cpu_table Cpu_table;
58
59/* BSP supplied routine */
60extern int mbx8xx_console_get_configuration();
61
62#ifdef EPPCBUG_SMC1
63extern unsigned32 simask_copy;
64#endif
65
66/*
67 * Interrupt-driven input buffer
68 */
69#define RXBUFSIZE       16
70
71/*
72 *  I/O buffers and pointers to buffer descriptors.
73 *  Currently, single buffered input is done. This will work only
74 *  if the Rx interrupts are serviced quickly.
75 *
76 *  TODO: Add a least double buffering for safety.
77 */
78static volatile char rxBuf[NUM_PORTS][RXBUFSIZE];
79static volatile char txBuf[NUM_PORTS];
80
81/* SCC/SMC buffer descriptors */
82static volatile m8xxBufferDescriptor_t *RxBd[NUM_PORTS], *TxBd[NUM_PORTS];
83
84/* Used to track the usage of the baud rate generators */
85static unsigned long brg_spd[4];
86static char  brg_used[4];
87
88/* Used to track termios private data for callbacks */
89struct rtems_termios_tty *ttyp[NUM_PORTS];
90
91/* Used to record previous ISR */
92static rtems_isr_entry old_handler[NUM_PORTS];
93
94/*
95 * Device-specific routines
96 */
97static int m8xx_get_brg_cd(int);
98static unsigned char m8xx_get_brg_clk(int);
99void m8xx_console_reserve_resources(rtems_configuration_table *);
100static int m8xx_smc_set_attributes(int, const struct termios*);
101static int m8xx_scc_set_attributes(int, const struct termios*);
102static rtems_isr m8xx_smc1_interrupt_handler(rtems_vector_number);
103static rtems_isr m8xx_smc2_interrupt_handler(rtems_vector_number);
104static rtems_isr m8xx_scc2_interrupt_handler(rtems_vector_number);
105#if defined(mpc860)
106static rtems_isr m8xx_scc3_interrupt_handler(rtems_vector_number);
107static rtems_isr m8xx_scc4_interrupt_handler(rtems_vector_number);
108#endif
109
110/*
111 * Compute baud-rate-generator configuration register value
112 */
113static int
114m8xx_get_brg_cd (int baud)
115{
116  int divisor;
117  int div16 = 0;
118
119  divisor = ((Cpu_table.clock_speed / 16) + (baud / 2)) / baud;
120  if (divisor > 4096) {
121    div16 = 1;
122    divisor = (divisor + 8) / 16;
123  }
124  return M8xx_BRG_EN | M8xx_BRG_EXTC_BRGCLK |
125    ((divisor - 1) << 1) | div16;
126}
127
128
129/*
130 *  This function will fail if more that 4 baud rates have been selected
131 *  at any time since the OS started. It needs to be fixed. FIXME
132 */
133static unsigned
134char m8xx_get_brg_clk(int baud)
135{
136  int i;
137
138  /* first try to find a BRG that is already at the right speed */
139  for ( i = 0; i < 4; i++ ) {
140    if ( brg_spd[i] == baud ) {
141      break;
142    }
143  }
144
145  if ( i == 4 ) { /* I guess we didn't find one */
146    for ( i = 0; i < 4; i++ ) {
147      if ( brg_used[i] == 0 ) {
148        break;
149      }
150    }
151  }
152  if (i != 4) {
153    brg_used[i]++;
154    brg_spd[i]=baud;
155    switch (i) {
156    case 0:
157      m8xx.brgc1 = M8xx_BRG_RST;
158      m8xx.brgc1 = m8xx_get_brg_cd(baud);
159      break;
160    case 1:
161      m8xx.brgc2 = M8xx_BRG_RST;
162      m8xx.brgc2 = m8xx_get_brg_cd(baud);
163      break;
164    case 2:
165      m8xx.brgc3 = M8xx_BRG_RST;
166      m8xx.brgc3 = m8xx_get_brg_cd(baud);
167      break;
168    case 3:
169      m8xx.brgc4 = M8xx_BRG_RST;
170      m8xx.brgc4 = m8xx_get_brg_cd(baud);
171      break;
172    }
173    return i;
174  }
175
176  else
177    return 0xff;
178}
179
180
181/*
182 * Hardware-dependent portion of tcsetattr().
183 */
184static int
185m8xx_smc_set_attributes (int minor, const struct termios *t)
186{
187  int baud, brg=0, csize=0, ssize, psize;
188  rtems_unsigned16 clen=0, cstopb, parenb, parodd, cread; 
189
190  /* Baud rate */
191  switch (t->c_cflag & CBAUD) {
192  default:      baud = -1;      break;
193  case B50:     baud = 50;      break;
194  case B75:     baud = 75;      break;
195  case B110:    baud = 110;     break;
196  case B134:    baud = 134;     break;
197  case B150:    baud = 150;     break;
198  case B200:    baud = 200;     break;
199  case B300:    baud = 300;     break;
200  case B600:    baud = 600;     break;
201  case B1200:   baud = 1200;    break;
202  case B1800:   baud = 1800;    break;
203  case B2400:   baud = 2400;    break;
204  case B4800:   baud = 4800;    break;
205  case B9600:   baud = 9600;    break;
206  case B19200:  baud = 19200;   break;
207  case B38400:  baud = 38400;   break;
208  case B57600:  baud = 57600;   break;
209  case B115200: baud = 115200;  break;
210  case B230400: baud = 230400;  break;
211  case B460800: baud = 460800;  break;
212  }
213  if (baud > 0)
214    brg = m8xx_get_brg_clk(baud);     /* 4 BRGs, 6 serial ports - hopefully */
215                                      /*  at least 2 ports will be the same */
216 
217  /* Number of data bits */
218  switch ( t->c_cflag & CSIZE ) {
219    case CS5:     csize = 5;       break;
220    case CS6:     csize = 6;       break;
221    case CS7:     csize = 7;       break;
222    case CS8:     csize = 8;       break;
223  }
224
225  /* Stop bits */
226  if ( t->c_cflag & CSTOPB ) {
227    cstopb = 0x0400;              /* Two stop bits */
228    ssize  = 2;
229  } else {
230    cstopb = 0x0000;              /* One stop bit */
231    ssize  = 1;
232  }
233
234  /* Parity */
235  if ( t->c_cflag & PARENB ) {
236    parenb = 0x0200;              /* Parity enabled on Tx and Rx */
237    psize  = 1;
238  } else {
239    parenb = 0x0000;              /* No parity on Tx and Rx */
240    psize  = 0;
241  }
242 
243  if ( t->c_cflag & PARODD )
244    parodd = 0x0000;              /* Odd parity */
245  else
246    parodd = 0x0100;
247
248  /*
249   * Character Length = start + data + parity + stop - 1
250   */ 
251  switch ( 1 + csize + psize + ssize - 1 ) {
252    case 6:     clen = 0x3000;       break;
253    case 7:     clen = 0x3800;       break;
254    case 8:     clen = 0x4000;       break;
255    case 9:     clen = 0x4800;       break;
256    case 10:    clen = 0x5000;       break;
257    case 11:    clen = 0x5800;       break;
258  }
259
260  if ( t->c_cflag & CREAD )
261    cread = 0x0023;             /* UART normal operation, enable Rx and Tx */
262  else
263    cread = 0x0021;             /* UART normal operation, enable Tx */
264   
265  /* Write the SIMODE/SMCMR registers */
266  switch (minor) {
267    case SMC1_MINOR:
268      m8xx.simode = ( (m8xx.simode & 0xffff8fff) | (brg << 12) );
269      m8xx.smc1.smcmr = clen | cstopb | parenb | parodd | cread;
270      break;
271    case SMC2_MINOR:
272      m8xx.simode = ( (m8xx.simode & 0x8fffffff) | (brg << 28) );
273      m8xx.smc2.smcmr = clen | cstopb | parenb | parodd | cread;
274      break;
275  }
276  return 0;
277}
278
279
280static int
281m8xx_scc_set_attributes (int minor, const struct termios *t)
282{
283  int baud, brg=0;
284  rtems_unsigned16 csize=0, cstopb, parenb, parodd;
285
286  /* Baud rate */
287  switch (t->c_cflag & CBAUD) {
288  default:      baud = -1;      break;
289  case B50:     baud = 50;      break;
290  case B75:     baud = 75;      break;
291  case B110:    baud = 110;     break;
292  case B134:    baud = 134;     break;
293  case B150:    baud = 150;     break;
294  case B200:    baud = 200;     break;
295  case B300:    baud = 300;     break;
296  case B600:    baud = 600;     break;
297  case B1200:   baud = 1200;    break;
298  case B1800:   baud = 1800;    break;
299  case B2400:   baud = 2400;    break;
300  case B4800:   baud = 4800;    break;
301  case B9600:   baud = 9600;    break;
302  case B19200:  baud = 19200;   break;
303  case B38400:  baud = 38400;   break;
304  case B57600:  baud = 57600;   break;
305  case B115200: baud = 115200;  break;
306  case B230400: baud = 230400;  break;
307  case B460800: baud = 460800;  break;
308  }
309  if (baud > 0)
310    brg = m8xx_get_brg_clk(baud);     /* 4 BRGs, 5 serial ports - hopefully */
311                                      /*  at least 2 ports will be the same */
312                                      /*  Write the SICR register below */
313   
314  /* Number of data bits */
315  switch ( t->c_cflag & CSIZE ) {
316    case CS5:     csize = 0x0000;       break;
317    case CS6:     csize = 0x1000;       break;
318    case CS7:     csize = 0x2000;       break;
319    case CS8:     csize = 0x3000;       break;
320  }
321
322  /* Stop bits */
323  if ( t->c_cflag & CSTOPB )
324    cstopb = 0x4000;              /* Two stop bits */
325  else
326    cstopb = 0x0000;              /* One stop bit */
327   
328  /* Parity */
329  if ( t->c_cflag & PARENB )
330    parenb = 0x0010;              /* Parity enabled on Tx and Rx */
331  else
332    parenb = 0x0000;              /* No parity on Tx and Rx */
333   
334  if ( t->c_cflag & PARODD )
335    parodd = 0x0000;              /* Odd parity */
336  else
337    parodd = 0x000a;
338
339  /* Write the SICR/PSMR Registers */
340  switch (minor) {
341    case SCC2_MINOR:
342      m8xx.sicr = ( (m8xx.sicr & 0xffffc0ff) | (brg << 11) | (brg << 8) );
343      m8xx.scc2.psmr = ( (cstopb | csize | parenb | parodd) | (m8xx.scc2.psmr & 0x8fe0) );
344      break;
345  #if defined(mpc860)
346    case SCC3_MINOR:
347      m8xx.sicr = ( (m8xx.sicr & 0xffc0ffff) | (brg << 19) | (brg << 16) );
348      m8xx.scc3.psmr = ( (cstopb | csize | parenb | parodd) | (m8xx.scc3.psmr & 0x8fe0) );
349      break;
350    case SCC4_MINOR:
351      m8xx.sicr = ( (m8xx.sicr & 0xc0ffffff) | (brg << 27) | (brg << 24) );
352      m8xx.scc4.psmr = ( (cstopb | csize | parenb | parodd) | (m8xx.scc4.psmr & 0x8fe0) );
353      break;
354  #endif
355  }
356 
357  return 0;
358}
359
360
361int 
362m8xx_uart_setAttributes(
363  int minor,
364  const struct termios *t
365)
366{
367  /*
368   * Check that port number is valid
369   */
370  if ( (minor < SMC1_MINOR) || (minor > NUM_PORTS-1) ) 
371    return 0;
372
373  switch (minor) {
374    case SMC1_MINOR:
375    case SMC2_MINOR:
376      return m8xx_smc_set_attributes( minor, t );
377
378    case SCC2_MINOR:
379    case SCC3_MINOR:
380    case SCC4_MINOR:
381      return m8xx_scc_set_attributes( minor, t );
382  }
383  return 0;
384}
385
386
387/*
388 * Interrupt handlers
389 */
390static rtems_isr
391m8xx_scc2_interrupt_handler (rtems_vector_number v)
392{
393  int nb_overflow;
394
395  /*
396   * Buffer received?
397   */
398  if ((m8xx.scc2.sccm & M8xx_SCCE_RX) && (m8xx.scc2.scce & M8xx_SCCE_RX)) {
399    m8xx.scc2.scce = M8xx_SCCE_RX;    /* Clear the event */
400
401
402    /* Check that the buffer is ours */
403    if ((RxBd[SCC2_MINOR]->status & M8xx_BD_EMPTY) == 0) {
404      rtems_cache_invalidate_multiple_data_lines( 
405        (const void *) RxBd[SCC2_MINOR]->buffer, 
406        RxBd[SCC2_MINOR]->length );
407      nb_overflow = rtems_termios_enqueue_raw_characters(
408        (void *)ttyp[SCC2_MINOR],
409        (char *)RxBd[SCC2_MINOR]->buffer,
410        (int)RxBd[SCC2_MINOR]->length );
411      RxBd[SCC2_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
412                                 M8xx_BD_INTERRUPT;
413    }
414  }
415
416  /*
417   * Buffer transmitted?
418   */
419  if (m8xx.scc2.scce & M8xx_SCCE_TX) {
420    m8xx.scc2.scce = M8xx_SCCE_TX;  /* Clear the event */
421
422    /* Check that the buffer is ours */
423    if ((TxBd[SCC2_MINOR]->status & M8xx_BD_READY) == 0)
424      rtems_termios_dequeue_characters (
425        (void *)ttyp[SCC2_MINOR],
426        (int)TxBd[SCC2_MINOR]->length);
427  }
428  m8xx.cisr = 1UL << 29;  /* Clear SCC2 interrupt-in-service bit */
429}
430
431
432#ifdef mpc860
433static rtems_isr
434m8xx_scc3_interrupt_handler (rtems_vector_number v)
435{
436  int nb_overflow;
437
438  /*
439   * Buffer received?
440   */
441  if ((m8xx.scc3.sccm & M8xx_SCCE_RX) && (m8xx.scc3.scce & M8xx_SCCE_RX)) {
442    m8xx.scc3.scce = M8xx_SCCE_RX;  /* Clear the event */
443
444
445    /* Check that the buffer is ours */
446    if ((RxBd[SCC3_MINOR]->status & M8xx_BD_EMPTY) == 0) {
447      rtems_cache_invalidate_multiple_data_lines( 
448        (const void *) RxBd[SCC3_MINOR]->buffer, 
449        RxBd[SCC3_MINOR]->length );
450      nb_overflow = rtems_termios_enqueue_raw_characters(
451        (void *)ttyp[SCC3_MINOR],
452        (char *)RxBd[SCC3_MINOR]->buffer,
453        (int)RxBd[SCC3_MINOR]->length );
454      RxBd[SCC3_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
455                                 M8xx_BD_INTERRUPT;
456    }
457  }
458
459  /*
460   * Buffer transmitted?
461   */
462  if (m8xx.scc3.scce & M8xx_SCCE_TX) {
463    m8xx.scc3.scce = M8xx_SCCE_TX;    /* Clear the event */
464
465    /* Check that the buffer is ours */
466    if ((TxBd[SCC3_MINOR]->status & M8xx_BD_READY) == 0)
467      rtems_termios_dequeue_characters (
468        (void *)ttyp[SCC3_MINOR],
469        (int)TxBd[SCC3_MINOR]->length);
470  }
471  m8xx.cisr = 1UL << 28;  /* Clear SCC3 interrupt-in-service bit */
472}
473
474
475static rtems_isr
476m8xx_scc4_interrupt_handler (rtems_vector_number v)
477{
478  int nb_overflow;
479
480  /*
481   * Buffer received?
482   */
483  if ((m8xx.scc4.sccm & M8xx_SCCE_RX) && (m8xx.scc4.scce & M8xx_SCCE_RX)) {
484    m8xx.scc4.scce = M8xx_SCCE_RX;  /* Clear the event */
485
486
487    /* Check that the buffer is ours */
488    if ((RxBd[SCC4_MINOR]->status & M8xx_BD_EMPTY) == 0) {
489      rtems_cache_invalidate_multiple_data_lines( 
490        (const void *) RxBd[SCC4_MINOR]->buffer, 
491        RxBd[SCC4_MINOR]->length );
492      nb_overflow = rtems_termios_enqueue_raw_characters(
493        (void *)ttyp[SCC4_MINOR],
494        (char *)RxBd[SCC4_MINOR]->buffer,
495        (int)RxBd[SCC4_MINOR]->length );
496      RxBd[SCC4_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
497                                 M8xx_BD_INTERRUPT;
498    }
499  }
500
501  /*
502   * Buffer transmitted?
503   */
504  if (m8xx.scc4.scce & M8xx_SCCE_TX) {
505    m8xx.scc4.scce = M8xx_SCCE_TX;    /* Clear the event */
506
507    /* Check that the buffer is ours */
508    if ((TxBd[SCC4_MINOR]->status & M8xx_BD_READY) == 0)
509      rtems_termios_dequeue_characters (
510        (void *)ttyp[SCC4_MINOR],
511        (int)TxBd[SCC4_MINOR]->length);
512  }
513  m8xx.cisr = 1UL << 27;  /* Clear SCC4 interrupt-in-service bit */
514}
515#endif
516
517static rtems_isr
518m8xx_smc1_interrupt_handler (rtems_vector_number v)
519{
520  int nb_overflow;
521
522  /*
523   * Buffer received?
524   */
525  if (m8xx.smc1.smce & M8xx_SMCE_RX) {
526    m8xx.smc1.smce = M8xx_SMCE_RX;  /* Clear the event */
527
528
529    /* Check that the buffer is ours */
530    if ((RxBd[SMC1_MINOR]->status & M8xx_BD_EMPTY) == 0) {
531      rtems_cache_invalidate_multiple_data_lines( 
532        (const void *) RxBd[SMC1_MINOR]->buffer, 
533        RxBd[SMC1_MINOR]->length );
534      nb_overflow = rtems_termios_enqueue_raw_characters(
535        (void *)ttyp[SMC1_MINOR],
536        (char *)RxBd[SMC1_MINOR]->buffer,
537        (int)RxBd[SMC1_MINOR]->length );
538      RxBd[SMC1_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
539                                 M8xx_BD_INTERRUPT;
540    }
541  }
542
543  /*
544   * Buffer transmitted?
545   */
546  if (m8xx.smc1.smce & M8xx_SMCE_TX) {
547    m8xx.smc1.smce = M8xx_SMCE_TX;    /* Clear the event */
548
549    /* Check that the buffer is ours */
550    if ((TxBd[SMC1_MINOR]->status & M8xx_BD_READY) == 0)
551      rtems_termios_dequeue_characters (
552        (void *)ttyp[SMC1_MINOR],
553        (int)TxBd[SMC1_MINOR]->length);
554  }
555  m8xx.cisr = 1UL << 4;  /* Clear SMC1 interrupt-in-service bit */
556}
557
558
559static rtems_isr
560m8xx_smc2_interrupt_handler (rtems_vector_number v)
561{
562  int nb_overflow;
563
564  /*
565   * Buffer received?
566   */
567  if (m8xx.smc2.smce & M8xx_SMCE_RX) {
568    m8xx.smc2.smce = M8xx_SMCE_RX;  /* Clear the event */
569
570
571    /* Check that the buffer is ours */
572    if ((RxBd[SMC2_MINOR]->status & M8xx_BD_EMPTY) == 0) {
573      rtems_cache_invalidate_multiple_data_lines( 
574        (const void *) RxBd[SMC2_MINOR]->buffer, 
575        RxBd[SMC2_MINOR]->length );
576      nb_overflow = rtems_termios_enqueue_raw_characters(
577        (void *)ttyp[SMC2_MINOR],
578        (char *)RxBd[SMC2_MINOR]->buffer,
579        (int)RxBd[SMC2_MINOR]->length );
580      RxBd[SMC2_MINOR]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP |
581                                 M8xx_BD_INTERRUPT;
582    }
583  }
584
585  /*
586   * Buffer transmitted?
587   */
588  if (m8xx.smc2.smce & M8xx_SMCE_TX) {
589    m8xx.smc2.smce = M8xx_SMCE_TX;    /* Clear the event */
590
591    /* Check that the buffer is ours */
592    if ((TxBd[SMC2_MINOR]->status & M8xx_BD_READY) == 0)
593      rtems_termios_dequeue_characters (
594        (void *)ttyp[SMC2_MINOR],
595        (int)TxBd[SMC2_MINOR]->length);
596  }
597  m8xx.cisr = 1UL << 3;  /* Clear SMC2 interrupt-in-service bit */
598}
599
600
601void
602m8xx_uart_scc_initialize (int minor)
603{
604  unsigned char brg;
605  volatile m8xxSCCparms_t *sccparms = 0;
606  volatile m8xxSCCRegisters_t *sccregs = 0;
607
608  /*
609   * Check that minor number is valid
610   */
611  if ( (minor < SCC2_MINOR) || (minor > NUM_PORTS-1) ) 
612    return;
613
614  /* Get the sicr clock source bit values for 9600 bps */
615  brg = m8xx_get_brg_clk(9600);
616
617  /*
618   * Allocate buffer descriptors
619   */
620  RxBd[minor] = m8xx_bd_allocate(1);
621  TxBd[minor] = m8xx_bd_allocate(1);
622
623  /*
624   *  Get the address of the parameter RAM for the specified port,
625   *  configure I/O port A,C & D and put SMC in NMSI mode, connect
626   *  the SCC to the appropriate BRG.
627   *
628   *  SCC2 TxD is shared with port A bit 12
629   *  SCC2 RxD is shared with port A bit 13
630   *  SCC1 TxD is shared with port A bit 14
631   *  SCC1 RxD is shared with port A bit 15
632   *  SCC4 DCD is shared with port C bit 4
633   *  SCC4 CTS is shared with port C bit 5
634   *  SCC3 DCD is shared with port C bit 6
635   *  SCC3 CTS is shared with port C bit 7
636   *  SCC2 DCD is shared with port C bit 8
637   *  SCC2 CTS is shared with port C bit 9
638   *  SCC1 DCD is shared with port C bit 10
639   *  SCC1 CTS is shared with port C bit 11
640   *  SCC2 RTS is shared with port C bit 14
641   *  SCC1 RTS is shared with port C bit 15
642   *  SCC4 RTS is shared with port D bit 6
643   *  SCC3 RTS is shared with port D bit 7
644   *  SCC4 TxD is shared with port D bit 8
645   *  SCC4 RxD is shared with port D bit 9
646   *  SCC3 TxD is shared with port D bit 10
647   *  SCC3 RxD is shared with port D bit 11
648   */
649  switch (minor) {
650    case SCC2_MINOR:
651      sccparms = &m8xx.scc2p;
652      sccregs = &m8xx.scc2;
653     
654      m8xx.papar |=  0x000C;        /* PA12 & PA13 are dedicated peripheral pins */
655      m8xx.padir &= ~0x000C;        /* PA13 & PA12 must not drive the UART lines */
656      m8xx.paodr &= ~0x000C;        /* PA12 & PA13 are not open drain */
657      m8xx.pcpar |=  0x0002;        /* PC14 is SCC2 RTS */
658      m8xx.pcpar &= ~0x00C0;        /* PC8 & PC9 are SCC2 DCD and CTS */
659      m8xx.pcdir &= ~0x00C2;        /* PC8, PC9 & PC14 must not drive the UART lines */
660      m8xx.pcso  |=  0x00C0;        /* Enable DCD and CTS inputs */
661     
662      m8xx.sicr &= 0xFFFF00FF;      /* Clear TCS2 & RCS2, GR2=no grant, SC2=NMSI mode */
663      m8xx.sicr |= (brg<<11) | (brg<<8); /* TCS2 = RCS2 = brg */
664      break;
665
666#ifdef mpc860
667    case SCC3_MINOR:
668      sccparms = &m8xx.scc3p;
669      sccregs = &m8xx.scc3;
670     
671      m8xx.pcpar &= ~0x0300;        /* PC6 & PC7 are SCC3 DCD and CTS */
672      m8xx.pcdir &= ~0x0300;        /* PC6 & PC7 must not drive the UART lines */
673      m8xx.pcso  |=  0x0300;        /* Enable DCD and CTS inputs */
674      m8xx.pdpar |=  0x0130;        /* PD7, PD10 & PD11 are dedicated peripheral pins */
675     
676      m8xx.sicr &= 0xFF00FFFF;      /* Clear TCS3 & RCS3, GR3=no grant, SC3=NMSI mode */
677      m8xx.sicr |= (brg<<19) | (brg<<16); /* TCS3 = RCS3 = brg */
678      break;
679
680    case SCC4_MINOR:
681      sccparms = &m8xx.scc4p;
682      sccregs = &m8xx.scc4;
683     
684      m8xx.pcpar &= ~0x0C00;        /* PC4 & PC5 are SCC4 DCD and CTS */
685      m8xx.pcdir &= ~0x0C00;        /* PC4 & PC5 must not drive the UART lines */
686      m8xx.pcso  |=  0x0C00;        /* Enable DCD and CTS inputs */
687      m8xx.pdpar |=  0x02C0;        /* PD6, PD8 & PD9 are dedicated peripheral pins */
688       
689      m8xx.sicr &= 0x00FFFFFF;      /* Clear TCS4 & RCS4, GR4=no grant, SC4=NMSI mode */
690      m8xx.sicr |= (brg<<27) | (brg<<24); /* TCS4 = RCS4 = brg */
691      break;
692#endif
693  }
694
695  /*
696   *  Set up SDMA
697   */
698  m8xx.sdcr = 0x01;                 /* as per section 16.10.2.1 MPC821UM/AD */
699
700  /*
701   *  Set up the SCC parameter RAM.
702   */
703  sccparms->rbase = (char *)RxBd[minor] - (char *)&m8xx;
704  sccparms->tbase = (char *)TxBd[minor] - (char *)&m8xx;
705
706  sccparms->rfcr = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0);
707  sccparms->tfcr = M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0);
708  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
709    sccparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
710  else
711    sccparms->mrblr = 1;            /* Maximum Rx buffer size */
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  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
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  }
809}
810
811
812void
813m8xx_uart_smc_initialize (int minor)
814{
815  unsigned char brg;
816  volatile m8xxSMCparms_t *smcparms = 0;
817  volatile m8xxSMCRegisters_t *smcregs = 0;
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  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 )
878    smcparms->mrblr = RXBUFSIZE;    /* Maximum Rx buffer size */
879  else
880    smcparms->mrblr = 1;            /* Maximum Rx buffer size */
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  if ( (mbx8xx_console_get_configuration() & 0x06) == 0x02 ) {
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  }
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  m8xx.simask |= M8xx_SIMASK_LVM1;  /* Enable level interrupts */
970#ifdef EPPCBUG_SMC1
971  simask_copy = m8xx.simask;
972#endif
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  rtems_cache_invalidate_multiple_data_lines( 
987    (const void *) RxBd[minor]->buffer,
988    RxBd[minor]->length
989  );
990  c = ((char *)RxBd[minor]->buffer)[0];
991  RxBd[minor]->status = M8xx_BD_EMPTY | M8xx_BD_WRAP;
992  return c;
993}
994
995
996/*
997 *  TODO: Get a free buffer and set it up.
998 */
999int 
1000m8xx_uart_write(
1001  int minor,
1002  const char *buf,
1003  int len
1004)
1005{
1006  rtems_cache_flush_multiple_data_lines( buf, len );
1007  TxBd[minor]->buffer = (char *) buf;
1008  TxBd[minor]->length = len;
1009  TxBd[minor]->status = M8xx_BD_READY | M8xx_BD_WRAP | M8xx_BD_INTERRUPT;
1010  return 0;
1011}
1012 
1013
1014int
1015m8xx_uart_pollWrite(
1016  int minor,
1017  const char *buf,
1018  int len
1019)
1020{
1021  while (len--) {
1022    while (TxBd[minor]->status & M8xx_BD_READY)
1023      continue;
1024    txBuf[minor] = *buf++;
1025    rtems_cache_flush_multiple_data_lines( (void *)&txBuf[minor], 1 );
1026    TxBd[minor]->buffer = &txBuf[minor];
1027    TxBd[minor]->length = 1;
1028    TxBd[minor]->status = M8xx_BD_READY | M8xx_BD_WRAP;
1029  }
1030  return 0;
1031}
1032
1033void
1034m8xx_uart_reserve_resources(
1035  rtems_configuration_table *configuration
1036)
1037{
1038  rtems_termios_reserve_resources (configuration, NUM_PORTS);
1039}
Note: See TracBrowser for help on using the repository browser.