source: rtems/c/src/lib/libcpu/powerpc/ppc403/tty_drv/tty_drv.c @ f9acc33

4.115
Last change on this file since f9acc33 was f9acc33, checked in by Ralf Corsepius <ralf.corsepius@…>, on 02/11/11 at 09:46:53

2011-02-11 Ralf Corsépius <ralf.corsepius@…>

  • e500/mmu/mmu.c, mpc505/ictrl/ictrl.c, mpc505/timer/timer.c, mpc5xx/ictrl/ictrl.c, mpc5xx/timer/timer.c, mpc6xx/altivec/vec_sup.c, mpc6xx/clock/c_clock.c, mpc6xx/mmu/bat.c, mpc6xx/mmu/bat.h, mpc6xx/mmu/pte121.c, mpc8260/timer/timer.c, mpc8xx/timer/timer.c, new-exceptions/cpu.c, new-exceptions/bspsupport/ppc_exc_initialize.c, ppc403/clock/clock.c, ppc403/console/console.c, ppc403/console/console.c.polled, ppc403/console/console405.c, ppc403/irq/ictrl.c, ppc403/tty_drv/tty_drv.c, rtems/powerpc/cache.h, shared/include/powerpc-utility.h, shared/src/cache.c: Use "asm" instead of "asm" for improved c99-compliance.
  • Property mode set to 100644
File size: 13.2 KB
Line 
1/*
2 * This file contains the PowerPC 405GP tty driver.
3 *
4 * Derived from /c/src/lib/libbsp/i386/shared/comm/tty_drv.c
5 *
6 * Modifications to PPC405GP by Dennis Ehlin
7 *
8 */
9
10#define NO_BSP_INIT
11
12#include <stdio.h>
13#include <rtems/termiostypes.h>
14#include <termios.h>
15#include <assert.h>
16#include <rtems.h>
17#include <rtems/libio.h>
18#include "../irq/ictrl.h"
19#include <stdlib.h>                                     /* for atexit() */
20
21extern uint32_t bsp_serial_per_sec;
22extern bool bsp_serial_external_clock;
23extern bool bsp_serial_cts_rts;
24extern bool bsp_serial_xon_xoff;
25extern uint32_t bsp_serial_rate;
26
27struct ttyasync {
28/*---------------------------------------------------------------------------+
29| Data Register.
30+---------------------------------------------------------------------------*/
31  unsigned char RBR;    /* 0x00 */
32  #define THR   RBR
33/*---------------------------------------------------------------------------+
34| Interrupt registers
35+---------------------------------------------------------------------------*/
36  unsigned char IER;    /* Interrupt Enable Register 0x01 */
37  #define IER_RCV                0x01
38  #define IER_XMT                0x02
39  #define IER_LS                 0x04
40  #define IER_MS                 0x08
41
42  unsigned char ISR;    /* Interrupt Status Register 0x02 */
43  #define ISR_MS                 0x00
44  #define ISR_nIP                0x01
45  #define ISR_Tx                 0x02
46  #define ISR_Rx                 0x04
47  #define ISR_LS                 0x06
48  #define ISR_RxTO               0x0C
49  #define ISR_64BFIFO            0x20
50  #define ISR_FIFOworks          0x40
51  #define ISR_FIFOen             0x80
52
53/*---------------------------------------------------------------------------+
54| FIFO Control registers
55+---------------------------------------------------------------------------*/
56  #define FCR   ISR
57  #define FCR_FE                0x01    /* FIFO enable */
58  #define FCR_CRF               0x02    /* Clear receive FIFO */
59  #define FCR_CTF               0x04    /* Clear transmit FIFO */
60  #define FCR_DMA               0x08    /* DMA mode select */
61  #define FCR_F64               0x20    /* Enable 64 byte fifo (16750+) */
62  #define FCR_RT14              0xC0    /* Set Rx trigger at 14 */
63  #define FCR_RT8               0x80    /* Set Rx trigger at 8 */
64  #define FCR_RT4               0x40    /* Set Rx trigger at 4 */
65  #define FCR_RT1               0x00    /* Set Rx trigger at 1 */
66
67/*---------------------------------------------------------------------------+
68| Baud rate divisor registers
69+---------------------------------------------------------------------------*/
70  #define DLL   RBR
71  #define DLM   IER
72
73/*---------------------------------------------------------------------------+
74| Alternate function registers
75+---------------------------------------------------------------------------*/
76  #define AFR   ISR
77
78/*---------------------------------------------------------------------------+
79| Line control Register.
80+---------------------------------------------------------------------------*/
81  unsigned char LCR;    /* 0x03 */
82  #define LCR_WL5                0x00   /* Word length 5 */
83  #define LCR_WL6                0x01   /* Word length 6 */
84  #define LCR_WL7                0x02   /* Word length 7 */
85  #define LCR_WL8                0x03   /* Word length 8 */
86
87  #define LCR_SB1                0x00   /* 1 stop bits */
88  #define LCR_SB1_5              0x04   /* 1.5 stop bits , only valid with 5 bit words*/
89  #define LCR_SB1_5              0x04   /* 2 stop bits */
90
91  #define LCR_PN                 0x00   /* Parity NONE */
92  #define LCR_PE                 0x0C   /* Parity EVEN */
93  #define LCR_PO                 0x08   /* Parity ODD */
94  #define LCR_PM                 0x28   /* Forced "mark" parity */
95  #define LCR_PS                 0x38   /* Forced "space" parity */
96
97  #define LCR_DL                 0x80   /* Enable baudrate latch */
98
99/*---------------------------------------------------------------------------+
100| Modem control Register.
101+---------------------------------------------------------------------------*/
102  unsigned char MCR;    /* 0x04 */
103  #define MCR_DTR                0x01
104  #define MCR_RTS                0x02
105  #define MCR_INT                0x08   /* Enable interrupts */
106  #define MCR_LOOP               0x10   /* Loopback mode */
107
108/*---------------------------------------------------------------------------+
109| Line status Register.
110+---------------------------------------------------------------------------*/
111  unsigned char LSR;    /* 0x05 */
112  #define LSR_RSR                0x01
113  #define LSR_OE                 0x02
114  #define LSR_PE                 0x04
115  #define LSR_FE                 0x08
116  #define LSR_BI                 0x10
117  #define LSR_THE                0x20
118  #define LSR_TEMT               0x40
119  #define LSR_FIE                0x80
120
121/*---------------------------------------------------------------------------+
122| Modem status Register.
123+---------------------------------------------------------------------------*/
124  unsigned char MSR;    /* 0x06 */
125  #define UART_MSR_DCTS          0x01
126  #define UART_MSR_DDSR          0x02
127  #define UART_MSR_TERI          0x04
128  #define UART_MSR_DDCD          0x08
129  #define UART_MSR_CTS           0x10
130  #define UART_MSR_DSR           0x20
131  #define UART_MSR_RI            0x40
132  #define UART_MSR_CD            0x80
133
134/*---------------------------------------------------------------------------+
135| Scratch pad Register.
136+---------------------------------------------------------------------------*/
137  unsigned char SCR;    /* 0x07 */
138};
139
140
141#define TTY0_USE_UART 1 /* 0=UART0 1=UART1 */
142#define TTY0_UART_INTERNAL_CLOCK_DIVISOR 16
143#define TTY0_USE_INTERRUPT
144
145
146typedef volatile struct ttyasync *tty0pasync;
147static const tty0pasync tty0port = (tty0pasync)(0xEF600300   + (TTY0_USE_UART*0x100));  /* 0xEF600300 - port A,  0xEF600400 - port B */
148
149static void *tty0ttyp;         /* handle for termios */
150
151
152int tty0_round(double x)
153{
154  return (int)((int)((x-(int)x)*1000)>500 ? x+1 : x);
155}
156
157void
158tty0BaudSet(uint32_t   baudrate)
159{
160  uint32_t   tmp;
161
162  tmp = tty0_round( (double)bsp_serial_per_sec / (baudrate * 16) );
163
164  tty0port->LCR = tty0port->LCR | LCR_DL;
165
166  tty0port->DLL = tmp & 0xff;
167  tty0port->DLM = tmp >> 8;
168
169  tty0port->LCR = tty0port->LCR & ~LCR_DL;
170}
171/*
172 * Hardware-dependent portion of tcsetattr().
173 */
174static int
175tty0SetAttributes (int minor, const struct termios *t)
176{
177  int baud;
178
179  /* FIXME: check c_cflag & CRTSCTS for hardware flowcontrol */
180  /* FIXME: check and IMPLEMENT XON/XOFF                     */
181  switch (t->c_cflag & CBAUD) {
182  default:      baud = -1;      break;
183  case B50:     baud = 50;      break;
184  case B75:     baud = 75;      break;
185  case B110:    baud = 110;     break;
186  case B134:    baud = 134;     break;
187  case B150:    baud = 150;     break;
188  case B200:    baud = 200;     break;
189  case B300:    baud = 300;     break;
190  case B600:    baud = 600;     break;
191  case B1200:   baud = 1200;    break;
192  case B1800:   baud = 1800;    break;
193  case B2400:   baud = 2400;    break;
194  case B4800:   baud = 4800;    break;
195  case B9600:   baud = 9600;    break;
196  case B19200:  baud = 19200;   break;
197  case B38400:  baud = 38400;   break;
198  case B57600:  baud = 57600;   break;
199  case B115200: baud = 115200;  break;
200  case B230400: baud = 230400;  break;
201  case B460800: baud = 460800;  break;
202  }
203  if (baud > 0) {
204    tty0BaudSet(baud);
205  }
206  return 0;
207}
208
209#ifndef TTY0_USE_INTERRUPT
210static int
211tty0PollRead (int minor)
212{
213
214  /* Wait for character */
215  while ((tty0port->LSR & LSR_RSR)==0);;
216
217  return tty0port->RBR;
218}
219
220
221static ssize_t
222tty0PollWrite(int minor, const char *buf, size_t len)
223{
224
225  while (len-- > 0) {
226    while (!(tty0port->LSR & LSR_THE));;
227    tty0port->THR = *buf++;
228  }
229  return 0;
230}
231#endif
232
233/* ================ Termios support  =================*/
234
235static ssize_t tty0InterruptWrite (int minor, const char *buf, size_t len)
236{
237
238  if(len <= 0)
239    {
240      return 0;
241    }
242
243  /* Write character */
244
245  tty0port->THR = (*buf &0xff);
246  tty0port->IER |= IER_XMT;     /* always enable tx interrupt */
247
248  return 0;
249
250}
251
252static rtems_isr tty0serial_ISR(rtems_vector_number v)
253{
254  char buf[128];
255  int      off, ret, vect;
256
257  off = 0;
258
259  for(;;)
260    {
261          vect = tty0port->ISR & 0x0f;
262          if(vect & 1)
263          {
264                  /* no more interrupts */
265          if(off > 0) {
266                  /* Update rx buffer */
267                  rtems_termios_enqueue_raw_characters(tty0ttyp, buf, off );
268
269                  tty0port->IER |= IER_RCV;     /* always enable rx interrupt */
270                 /*rtems_termios_rxirq_occured(tty0ttyp);*/
271          }
272            return;
273          }
274
275        vect = vect & 0xe; /*mask out all except interrupt pending*/
276
277    switch(vect)
278        {
279
280        case ISR_Tx :
281          /*
282           * TX holding empty: we have to disable these interrupts
283           * if there is nothing more to send.
284           */
285
286          /* If nothing else to send disable interrupts */
287          ret = rtems_termios_dequeue_characters(tty0ttyp, 1);
288
289          if ( ret == 0 ) {
290            tty0port->IER &= ~IER_XMT;
291          }
292
293          break;
294        case ISR_RxTO:
295        case ISR_Rx :
296
297              /* disable interrupts and notify termios */
298               tty0port->IER &= ~IER_RCV;
299
300              /* read all bytes in fifo*/
301               while (( off < sizeof(buf) ) && (  tty0port->LSR & LSR_RSR ))
302                          {
303                                buf[off++] = tty0port->RBR;
304                          }
305
306          break;
307        case ISR_LS:
308          /* RX error: eat character */
309          /* printk("********* Error **********\n"); */
310          break;
311        default:
312          /* Should not happen */
313          /* printk("error vect=%x",vect); */
314          return;
315        }
316    }
317
318}
319
320
321/*
322 *
323 * deinit TTY0
324 *
325 */
326void
327tty0DeInit(void)
328{
329  /*
330   * disable interrupts for serial tty0port
331   * set it to state to work with polling boot monitor, if any...
332   */
333
334  /* set up baud rate to original state */
335  tty0BaudSet(bsp_serial_rate);
336
337  tty0port->IER = 0;
338
339}
340
341/*
342 *
343 * init SPI
344 *
345 */
346rtems_status_code
347tty0Initialize(void)
348{
349  register unsigned tmp;
350  rtems_isr_entry previous_isr; /* this is a dummy */
351  unsigned char _ier;
352  unsigned char _tmp;
353
354  /*
355   * Initialise the serial tty0port
356   */
357
358  /*
359   * Select clock source and set uart internal clock divisor
360   */
361
362  __asm__ volatile ("mfdcr %0, 0x0b1" : "=r" (tmp)); /* CPC_CR0 0x0b1 */
363
364  /* UART0 bit 24 0x80, UART1 bit 25 0x40 */
365  tmp |= (bsp_serial_external_clock ?  (TTY0_USE_UART ? 0x40 : 0x80) : 0);
366
367  tmp |= (bsp_serial_external_clock ?  0: ((TTY0_UART_INTERNAL_CLOCK_DIVISOR -1) << 1));
368
369  __asm__ volatile ("mtdcr 0x0b1, %0" : "=r" (tmp) : "0" (tmp)); /* CPC_CR0 0x0b1*/
370
371  /* Disable tty0port interrupts while changing hardware */
372  _ier = tty0port->IER;
373  tty0port->IER = 0;
374
375  /* set up tty0port control: 8 bit,1 stop,no parity */
376  tty0port->LCR = LCR_WL8 | LCR_SB1 | LCR_PN;
377
378  /* set up baud rate */
379  tty0BaudSet(bsp_serial_rate);
380
381
382#ifdef TTY0_USE_INTERRUPT
383
384    /* add rx/tx isr to vector table */
385
386    if (TTY0_USE_UART==0)
387        ictrl_set_vector(tty0serial_ISR,PPC_IRQ_EXT_UART0,&previous_isr);
388    else
389        ictrl_set_vector(tty0serial_ISR,PPC_IRQ_EXT_UART1,&previous_isr);
390
391    /* Enable and clear FIFO */
392    tty0port->FCR = FCR_FE | FCR_CRF | FCR_CTF | FCR_RT14;
393
394    /* Read status to clear them */
395    _tmp = tty0port->LSR;
396    _tmp = tty0port->RBR;
397    _tmp = tty0port->MSR;
398
399    /* Enable recive interrupts, don't enable TxInt yet */
400    tty0port->IER=IER_RCV;
401
402#else
403
404    tty0port->IER=_ier;
405
406#endif
407
408  atexit(tty0DeInit);
409
410  return RTEMS_SUCCESSFUL;
411}
412
413/*
414 ***************
415 * BOILERPLATE *
416 ***************
417 */
418
419/*  console_initialize
420 *
421 *  This routine initializes the console IO driver.
422 *
423 *  Input parameters: NONE
424 *
425 *  Output parameters:  NONE
426 *
427 *  Return values:
428 */
429
430rtems_device_driver tty0_initialize(
431  rtems_device_major_number  major,
432  rtems_device_minor_number  minor,
433  void                      *arg
434)
435{
436  rtems_status_code status;
437
438
439  /*
440   * Set up TERMIOS
441   */
442  rtems_termios_initialize ();
443
444  /*
445   * Do device-specific initialization
446   */
447
448  /*tty0Initialize ();   Moved this to open instead */
449
450  /*
451   * Register the device
452   */
453  status = rtems_io_register_name ("/dev/ttyS0", major, 0);
454  if (status != RTEMS_SUCCESSFUL)
455    rtems_fatal_error_occurred (status);
456  return RTEMS_SUCCESSFUL;
457}
458
459
460/*
461 *  Open entry point
462 */
463
464rtems_device_driver tty0_open(
465  rtems_device_major_number major,
466  rtems_device_minor_number minor,
467  void                    * arg
468)
469{
470  rtems_status_code sc;
471
472#ifdef TTY0_USE_INTERRUPT
473
474  static const rtems_termios_callbacks intrCallbacks = {
475    NULL,               /* firstOpen */
476    NULL,               /* lastClose */
477    NULL,               /* pollRead */
478    tty0InterruptWrite, /* write */
479    tty0SetAttributes,  /* setAttributes */
480    NULL,               /* stopRemoteTx */
481    NULL,               /* startRemoteTx */
482    TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */
483  };
484  rtems_libio_open_close_args_t *args = arg;
485
486    tty0Initialize ();  /* Initalize hardware */
487
488    sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
489    tty0ttyp = args->iop->data1;
490
491#else
492
493  static const rtems_termios_callbacks pollCallbacks = {
494    NULL,               /* firstOpen */
495    NULL,               /* lastClose */
496    tty0PollRead,       /* pollRead */
497    tty0PollWrite,      /* write */
498    tty0SetAttributes,  /* setAttributes */
499    NULL,               /* stopRemoteTx */
500    NULL,               /* startRemoteTx */
501    0                   /* outputUsesInterrupts */
502  };
503
504    tty0Initialize ();  /* Initalize hardware */
505
506    sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
507
508#endif
509
510    return sc;
511}
512
513/*
514 *  Close entry point
515 */
516
517rtems_device_driver tty0_close(
518  rtems_device_major_number major,
519  rtems_device_minor_number minor,
520  void                    * arg
521)
522{
523  return rtems_termios_close (arg);
524}
525
526/*
527 * read bytes from the serial port. We only have stdin.
528 */
529
530rtems_device_driver tty0_read(
531  rtems_device_major_number major,
532  rtems_device_minor_number minor,
533  void                    * arg
534)
535{
536  return rtems_termios_read (arg);
537}
538
539/*
540 * write bytes to the serial port. Stdout and stderr are the same.
541 */
542
543rtems_device_driver tty0_write(
544  rtems_device_major_number major,
545  rtems_device_minor_number minor,
546  void                    * arg
547)
548{
549  return rtems_termios_write (arg);
550}
551
552/*
553 *  IO Control entry point
554 */
555
556rtems_device_driver tty0_control(
557  rtems_device_major_number major,
558  rtems_device_minor_number minor,
559  void                    * arg
560)
561{
562  return rtems_termios_ioctl (arg);
563}
Note: See TracBrowser for help on using the repository browser.