source: rtems/c/src/lib/libcpu/powerpc/mpc8260/console-generic/console-generic.c @ 9cc1892

4.115
Last change on this file since 9cc1892 was 9cc1892, checked in by Joel Sherrill <joel.sherrill@…>, on 03/08/15 at 23:00:07

libcpu/powerpc/mpc8260/console-generic/console-generic.c: Include bsp.h to fix warning

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