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

4.104.114.84.9
Last change on this file since 73cdeb6 was 73cdeb6, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Jul 4, 2007 at 12:25:49 PM

merged individual exception handler code to a common one.

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