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