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

4.104.114.95
Last change on this file since 7f5ecbc2 was 7f5ecbc2, checked in by Till Straumann <strauman@…>, on 05/23/08 at 01:10:17

2008-05-22 Till Straumann <strauman@…>

  • ppc403/tty_drv/tty_drv.c, ppc403/console/console405.c: ../ictrl/ictrl.h has gone; include ../irq/ictrl.h
  • 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
21extern uint32_t bsp_serial_per_sec;
22extern boolean bsp_serial_external_clock;
23extern boolean bsp_serial_cts_rts;
24extern boolean 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 int
222tty0PollWrite(int minor,const char *buf,int 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 int tty0InterruptWrite (int minor, const char *buf, int 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  extern uint32_t bsp_serial_rate;
354  extern boolean bsp_serial_external_clock;
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  tty0port->IER = 0;
376
377  /* set up tty0port control: 8 bit,1 stop,no parity */
378  tty0port->LCR = LCR_WL8 | LCR_SB1 | LCR_PN;
379
380  /* set up baud rate */
381  tty0BaudSet(bsp_serial_rate);
382 
383
384#ifdef TTY0_USE_INTERRUPT
385
386    /* add rx/tx isr to vector table */
387
388    if (TTY0_USE_UART==0)
389        ictrl_set_vector(tty0serial_ISR,PPC_IRQ_EXT_UART0,&previous_isr);
390    else
391        ictrl_set_vector(tty0serial_ISR,PPC_IRQ_EXT_UART1,&previous_isr);
392   
393    /* Enable and clear FIFO */
394    tty0port->FCR = FCR_FE | FCR_CRF | FCR_CTF | FCR_RT14;
395
396    /* Read status to clear them */
397    _tmp = tty0port->LSR;   
398    _tmp = tty0port->RBR;
399    _tmp = tty0port->MSR;
400
401    /* Enable recive interrupts, don't enable TxInt yet */
402    tty0port->IER=IER_RCV;
403
404#else
405
406    tty0port->IER=_ier;
407
408#endif
409
410  atexit(tty0DeInit);
411
412  return RTEMS_SUCCESSFUL;
413}
414
415/*
416 ***************
417 * BOILERPLATE *
418 ***************
419 */
420
421/*  console_initialize
422 *
423 *  This routine initializes the console IO driver.
424 *
425 *  Input parameters: NONE
426 *
427 *  Output parameters:  NONE
428 *
429 *  Return values:
430 */
431
432rtems_device_driver tty0_initialize(
433  rtems_device_major_number  major,
434  rtems_device_minor_number  minor,
435  void                      *arg
436)
437{
438  rtems_status_code status;
439
440
441  /*
442   * Set up TERMIOS
443   */
444  rtems_termios_initialize ();
445
446  /*
447   * Do device-specific initialization
448   */
449   
450  /*tty0Initialize ();   Moved this to open instead */
451 
452  /*
453   * Register the device
454   */
455  status = rtems_io_register_name ("/dev/ttyS0", major, 0);
456  if (status != RTEMS_SUCCESSFUL)
457    rtems_fatal_error_occurred (status);
458  return RTEMS_SUCCESSFUL;
459}
460
461
462/*
463 *  Open entry point
464 */
465 
466rtems_device_driver tty0_open(
467  rtems_device_major_number major,
468  rtems_device_minor_number minor,
469  void                    * arg
470)
471{
472  rtems_status_code sc;
473
474#ifdef TTY0_USE_INTERRUPT
475
476  static const rtems_termios_callbacks intrCallbacks = {
477    NULL,               /* firstOpen */
478    NULL,               /* lastClose */
479    NULL,               /* pollRead */
480    tty0InterruptWrite, /* write */
481    tty0SetAttributes,  /* setAttributes */
482    NULL,               /* stopRemoteTx */
483    NULL,               /* startRemoteTx */
484    TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */
485  };
486  rtems_libio_open_close_args_t *args = arg;
487
488    tty0Initialize ();  /* Initalize hardware */
489
490    sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
491    tty0ttyp = args->iop->data1;
492
493#else
494
495  static const rtems_termios_callbacks pollCallbacks = {
496    NULL,               /* firstOpen */
497    NULL,               /* lastClose */
498    tty0PollRead,       /* pollRead */
499    tty0PollWrite,      /* write */
500    tty0SetAttributes,  /* setAttributes */
501    NULL,               /* stopRemoteTx */
502    NULL,               /* startRemoteTx */
503    0                   /* outputUsesInterrupts */
504  };
505
506    tty0Initialize ();  /* Initalize hardware */
507
508    sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
509
510#endif
511
512    return sc;
513}
514 
515/*
516 *  Close entry point
517 */
518 
519rtems_device_driver tty0_close(
520  rtems_device_major_number major,
521  rtems_device_minor_number minor,
522  void                    * arg
523)
524{
525  return rtems_termios_close (arg);
526}
527 
528/*
529 * read bytes from the serial port. We only have stdin.
530 */
531 
532rtems_device_driver tty0_read(
533  rtems_device_major_number major,
534  rtems_device_minor_number minor,
535  void                    * arg
536)
537{
538  return rtems_termios_read (arg);
539}
540 
541/*
542 * write bytes to the serial port. Stdout and stderr are the same.
543 */
544 
545rtems_device_driver tty0_write(
546  rtems_device_major_number major,
547  rtems_device_minor_number minor,
548  void                    * arg
549)
550{
551  return rtems_termios_write (arg);
552}
553 
554/*
555 *  IO Control entry point
556 */
557 
558rtems_device_driver tty0_control(
559  rtems_device_major_number major,
560  rtems_device_minor_number minor,
561  void                    * arg
562)
563{
564  return rtems_termios_ioctl (arg);
565}
Note: See TracBrowser for help on using the repository browser.