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

4.11
Last change on this file since 5039d92 was 5039d92, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 12, 2014 at 7:00:22 PM

libcpu/powerpc/ppc403: Fix warnings

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