source: rtems/bsps/powerpc/tqm8xx/dev/console-generic.c @ 11fe8c59

5
Last change on this file since 11fe8c59 was b8c468b, checked in by Sebastian Huber <sebastian.huber@…>, on 03/23/18 at 15:11:55

bsp/tqm8xx: Move libcpu content to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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