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

4.104.11
Last change on this file since 39a9f8e was 39a9f8e, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Dec 17, 2009 at 8:42:17 AM

adapted to new prototype for *_write function

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