source: rtems/c/src/lib/libbsp/powerpc/shared/console/uart.c @ 3c6fe2e

4.104.114.9
Last change on this file since 3c6fe2e was 3c6fe2e, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Jul 14, 2008 at 8:46:06 AM

added haleakala BSP contributed by Michael Hamel

  • Property mode set to 100644
File size: 15.5 KB
Line 
1/*
2 * This software is Copyright (C) 1998 by T.sqware - all rights limited
3 * It is provided in to the public domain "as is", can be freely modified
4 * as far as this copyight notice is kept unchanged, but does not imply
5 * an endorsement by T.sqware of the product in which it is included.
6 *
7 *  $Id$
8 */
9
10#include <stdio.h>
11#include <bsp.h>
12#include <bsp/irq.h>
13#include <bsp/uart.h>
14#include <rtems/libio.h>
15#include <rtems/bspIo.h>
16#include <rtems/termiostypes.h>
17#include <termios.h>
18#include <assert.h>
19
20/*
21 * Basic 16552 driver
22 */
23
24struct uart_data
25{
26  unsigned long       ioBase;
27  int                 irq;
28  int                 hwFlow;
29  int                 baud;
30  BSP_UartBreakCbRec  breakCallback;
31  int                 ioMode;
32};
33
34/*
35 * Initialization of BSP specific data.
36 * The constants are pulled in from a BSP
37 * specific file, whereas all of the code
38 * in this file is generic and makes no
39 * assumptions about addresses, irq vectors
40 * etc...
41 */
42
43#define UART_UNSUPP ((unsigned long)(-1))
44
45static struct uart_data uart_data[2] = {
46        {
47#ifdef  BSP_UART_IOBASE_COM1
48                BSP_UART_IOBASE_COM1,
49                BSP_UART_COM1_IRQ,
50#else
51                UART_UNSUPP,
52                -1,
53#endif
54        },
55        {
56#ifdef  BSP_UART_IOBASE_COM2
57                BSP_UART_IOBASE_COM2,
58                BSP_UART_COM2_IRQ,
59#else
60                UART_UNSUPP,
61                -1,
62#endif
63        },
64};
65
66#define MAX_UARTS (sizeof(uart_data)/sizeof(uart_data[0]))
67#define SANITY_CHECK(uart) \
68  assert( MAX_UARTS > (unsigned)(uart) && uart_data[(uart)].ioBase != UART_UNSUPP )
69/*
70 * Macros to read/write register of uart, if configuration is
71 * different just rewrite these macros
72 */
73
74static inline unsigned char
75uread(int uart, unsigned int reg)
76{
77        return in_8((unsigned char*)(uart_data[uart].ioBase + reg));
78}
79
80static inline void
81uwrite(int uart, int reg, unsigned int val)
82{
83        out_8((unsigned char*)(uart_data[uart].ioBase + reg), val);
84}
85
86
87#ifdef UARTDEBUG
88    static void
89uartError(int uart, void *termiosPrivate)
90{
91  unsigned char uartStatus, dummy;
92  BSP_UartBreakCbProc           h;
93
94  uartStatus = uread(uart, LSR);
95  dummy = uread(uart, RBR);
96
97  if (uartStatus & OE)
98    printk("********* Over run Error **********\n");
99  if (uartStatus & PE)
100    printk("********* Parity Error   **********\n");
101  if (uartStatus & FE)
102    printk("********* Framing Error  **********\n");
103  if (uartStatus & BI) {
104    printk("********* BREAK INTERRUPT *********\n");
105        if ((h=uart_data[uart].breakCallback.handler))
106                h(uart,
107                  (dummy<<8)|uartStatus,
108                  termiosPrivate,
109                  uart_data[uart].breakCallback.private);
110
111  }
112  if (uartStatus & ERFIFO)
113    printk("********* Error receive Fifo **********\n");
114
115}
116#else
117inline void uartError(int uart, void *termiosPrivate)
118{
119  unsigned char uartStatus,dummy;
120  BSP_UartBreakCbProc           h;
121
122  uartStatus = uread(uart, LSR);
123  dummy          = uread(uart, RBR);
124  if ((uartStatus & BI) && (h=uart_data[uart].breakCallback.handler))
125                h(uart,
126                  (dummy<<8)|uartStatus,
127                  termiosPrivate,
128                  uart_data[uart].breakCallback.private);
129}
130#endif
131
132/*
133 * Uart initialization, it is hardcoded to 8 bit, no parity,
134 * one stop bit, FIFO, things to be changed
135 * are baud rate and nad hw flow control,
136 * and longest rx fifo setting
137 */
138void
139BSP_uart_init(int uart, int baud, int hwFlow)
140{
141  unsigned char tmp;
142
143  /* Sanity check */
144  SANITY_CHECK(uart);
145 
146  /* Make sure any printk activity drains before
147   * re-initializing.
148   */
149  while ( ! (uread(uart, LSR) & TEMT) )
150        ;
151
152  switch(baud)
153    {
154    case 50:
155    case 75:
156    case 110:
157    case 134:
158    case 300:
159    case 600:
160    case 1200:
161    case 2400:
162    case 9600:
163    case 19200:
164    case 38400:
165    case 57600:
166    case 115200:
167      break;
168    default:
169      assert(0);
170      return;
171    }
172
173  /* Set DLAB bit to 1 */
174  uwrite(uart, LCR, DLAB);
175
176  if ( (int)BSPBaseBaud <= 0 ) {
177        /* Use current divisor assuming BSPBaseBaud gives us the current speed */
178        BSPBaseBaud  = BSPBaseBaud ? -BSPBaseBaud : 9600;
179        BSPBaseBaud *= ((uread(uart, DLM) << 8) | uread(uart, DLL));
180  }
181
182  /* Set baud rate */
183  uwrite(uart, DLL,  (BSPBaseBaud/baud) & 0xff);
184  uwrite(uart, DLM,  ((BSPBaseBaud/baud) >> 8) & 0xff);
185
186  /* 8-bit, no parity , 1 stop */
187  uwrite(uart, LCR, CHR_8_BITS);
188
189  /* Set DTR, RTS and OUT2 high */
190  uwrite(uart, MCR, DTR | RTS | OUT_2);
191
192  /* Enable FIFO */
193  uwrite(uart, FCR, FIFO_EN | XMIT_RESET | RCV_RESET | RECEIVE_FIFO_TRIGGER12);
194
195  /* Disable Interrupts */
196  uwrite(uart, IER, 0);
197
198  /* Read status to clear them */
199  tmp = uread(uart, LSR);
200  tmp = uread(uart, RBR);
201  tmp = uread(uart, MSR);
202
203  /* Remember state */
204  uart_data[uart].hwFlow     = hwFlow;
205  uart_data[uart].baud       = baud;
206  return;
207}
208
209/*
210 * Set baud
211 */
212void
213BSP_uart_set_baud(int uart, int baud)
214{
215  unsigned char mcr, ier;
216
217  /* Sanity check */
218  SANITY_CHECK(uart);
219
220  /*
221   * This function may be called whenever TERMIOS parameters
222   * are changed, so we have to make sure that baud change is
223   * indeed required.
224   */
225
226  if(baud == uart_data[uart].baud)
227    {
228      return;
229    }
230
231  mcr = uread(uart, MCR);
232  ier = uread(uart, IER);
233
234  BSP_uart_init(uart, baud, uart_data[uart].hwFlow);
235
236  uwrite(uart, MCR, mcr);
237  uwrite(uart, IER, ier);
238
239  return;
240}
241
242/*
243 * Enable/disable interrupts
244 */
245void
246BSP_uart_intr_ctrl(int uart, int cmd)
247{
248
249  SANITY_CHECK(uart);
250
251  switch(cmd)
252    {
253    case BSP_UART_INTR_CTRL_DISABLE:
254      uwrite(uart, IER, INTERRUPT_DISABLE);
255      break;
256    case BSP_UART_INTR_CTRL_ENABLE:
257      if(uart_data[uart].hwFlow)
258        {
259          uwrite(uart, IER,
260                 (RECEIVE_ENABLE  |
261                  TRANSMIT_ENABLE |
262                  RECEIVER_LINE_ST_ENABLE |
263                  MODEM_ENABLE
264                 )
265                );
266        }
267      else
268        {
269          uwrite(uart, IER,
270                 (RECEIVE_ENABLE  |
271                  TRANSMIT_ENABLE |
272                  RECEIVER_LINE_ST_ENABLE
273                 )
274                );
275        }
276      break;
277    case BSP_UART_INTR_CTRL_TERMIOS:
278      if(uart_data[uart].hwFlow)
279        {
280          uwrite(uart, IER,
281                 (RECEIVE_ENABLE  |
282                  RECEIVER_LINE_ST_ENABLE |
283                  MODEM_ENABLE
284                 )
285                );
286        }
287      else
288        {
289          uwrite(uart, IER,
290                 (RECEIVE_ENABLE  |
291                  RECEIVER_LINE_ST_ENABLE
292                 )
293                );
294        }
295      break;
296    case BSP_UART_INTR_CTRL_GDB:
297      uwrite(uart, IER, RECEIVE_ENABLE);
298      break;
299    default:
300      assert(0);
301      break;
302    }
303
304  return;
305}
306
307void
308BSP_uart_throttle(int uart)
309{
310  unsigned int mcr;
311
312  SANITY_CHECK(uart);
313
314  if(!uart_data[uart].hwFlow)
315    {
316      /* Should not happen */
317      assert(0);
318      return;
319    }
320  mcr = uread (uart, MCR);
321  /* RTS down */
322  mcr &= ~RTS;
323  uwrite(uart, MCR, mcr);
324
325  return;
326}
327
328void
329BSP_uart_unthrottle(int uart)
330{
331  unsigned int mcr;
332
333  SANITY_CHECK(uart);
334
335  if(!uart_data[uart].hwFlow)
336    {
337      /* Should not happen */
338      assert(0);
339      return;
340    }
341  mcr = uread (uart, MCR);
342  /* RTS up */
343  mcr |= RTS;
344  uwrite(uart, MCR, mcr);
345
346  return;
347}
348
349/*
350 * Status function, -1 if error
351 * detected, 0 if no received chars available,
352 * 1 if received char available, 2 if break
353 * is detected, it will eat break and error
354 * chars. It ignores overruns - we cannot do
355 * anything about - it execpt count statistics
356 * and we are not counting it.
357 */
358int
359BSP_uart_polled_status(int uart)
360{
361  unsigned char val;
362
363  SANITY_CHECK(uart);
364
365  val = uread(uart, LSR);
366
367  if(val & BI)
368    {
369      /* BREAK found, eat character */
370      uread(uart, RBR);
371      return BSP_UART_STATUS_BREAK;
372    }
373
374  if((val & (DR | OE | FE)) ==  1)
375    {
376      /* No error, character present */
377      return BSP_UART_STATUS_CHAR;
378    }
379
380  if((val & (DR | OE | FE)) == 0)
381    {
382      /* Nothing */
383      return BSP_UART_STATUS_NOCHAR;
384    }
385
386  /*
387   * Framing or parity error
388   * eat character
389   */
390  uread(uart, RBR);
391
392  return BSP_UART_STATUS_ERROR;
393}
394
395/*
396 * Polled mode write function
397 */
398void
399BSP_uart_polled_write(int uart, int val)
400{
401  unsigned char val1;
402
403  /* Sanity check */
404  SANITY_CHECK(uart);
405
406  for(;;)
407    {
408      if((val1=uread(uart, LSR)) & THRE)
409        {
410          break;
411        }
412    }
413
414  if(uart_data[uart].hwFlow)
415    {
416      for(;;)
417        {
418          if(uread(uart, MSR) & CTS)
419            {
420              break;
421            }
422        }
423    }
424
425  uwrite(uart, THR, val & 0xff);
426
427  return;
428}
429
430void
431BSP_output_char_via_serial(const char val)
432{
433  BSP_uart_polled_write(BSPConsolePort, val);
434  if (val == '\n') BSP_uart_polled_write(BSPConsolePort,'\r');
435}
436
437/*
438 * Polled mode read function
439 */
440int
441BSP_uart_polled_read(int uart)
442{
443  unsigned char val;
444
445  SANITY_CHECK(uart);
446
447  for(;;)
448    {
449      if(uread(uart, LSR) & DR)
450        {
451          break;
452        }
453    }
454
455  val = uread(uart, RBR);
456
457  return (int)(val & 0xff);
458}
459
460unsigned
461BSP_poll_char_via_serial()
462{
463        return BSP_uart_polled_read(BSPConsolePort);
464}
465
466static void
467uart_noop(const rtems_irq_connect_data *unused)
468{
469  return;
470}
471
472/* note that the IRQ names contain _ISA_ for legacy
473 * reasons. They can be any interrupt, depending
474 * on the particular BSP...
475 */
476
477static int
478uart_isr_is_on(const rtems_irq_connect_data *irq)
479{
480  int uart;
481
482  uart = (irq->name == BSP_UART_COM1_IRQ) ?
483                        BSP_UART_COM1 : BSP_UART_COM2;
484
485  return uread(uart,IER);
486}
487
488static int
489doit(int uart, rtems_irq_hdl handler, int (*p)(const rtems_irq_connect_data*))
490{
491        rtems_irq_connect_data d={0};
492        d.name = uart_data[uart].irq;
493        d.off  = d.on = uart_noop;
494        d.isOn = uart_isr_is_on;
495        d.hdl  = handler;
496        return p(&d);
497}
498
499int
500BSP_uart_install_isr(int uart, rtems_irq_hdl handler)
501{
502/* Using shared interrupts by default might break things.. the
503 * shared IRQ installer uses malloc() and if a BSP had called this
504 * during early init it might not work...
505 */
506#ifdef BSP_UART_USE_SHARED_IRQS
507        return doit(uart, handler, BSP_install_rtems_shared_irq_handler);
508#else
509        return doit(uart, handler, BSP_install_rtems_irq_handler);
510#endif
511}
512
513int
514BSP_uart_remove_isr(int uart, rtems_irq_hdl handler)
515{
516        return doit(uart, handler, BSP_remove_rtems_irq_handler);
517}
518
519/* ================ Termios support  =================*/
520
521static volatile int  termios_stopped_com[2]        = {0,0};
522static volatile int  termios_tx_active_com[2]      = {0,0};
523static void*         termios_ttyp_com[2]           = {NULL,NULL};
524static char          termios_tx_hold_com[2]        = {0,0};
525static volatile char termios_tx_hold_valid_com[2]  = {0,0};
526
527/*
528 * Set channel parameters
529 */
530void
531BSP_uart_termios_set(int uart, void *p)
532{
533  struct rtems_termios_tty *ttyp = p;
534  unsigned char val;
535  SANITY_CHECK(uart);
536
537  if(uart_data[uart].hwFlow)
538    {
539      val = uread(uart, MSR);
540
541      termios_stopped_com[uart]    = (val & CTS) ? 0 : 1;
542    }
543  else
544  {
545      termios_stopped_com[uart] = 0;
546  }
547  termios_tx_active_com[uart]      = 0;
548  termios_ttyp_com[uart]           = ttyp;
549  termios_tx_hold_com[uart]        = 0;
550  termios_tx_hold_valid_com[uart]  = 0;
551
552  uart_data[uart].ioMode           = ttyp->device.outputUsesInterrupts;
553
554  return;
555}
556
557int
558BSP_uart_termios_write_polled(int minor, const char *buf, int len)
559{
560  int uart=minor;       /* could differ, theoretically */
561  int nwrite;
562  const char *b = buf;
563
564  assert(buf != NULL);
565
566  for (nwrite=0 ; nwrite < len ; nwrite++) {
567    BSP_uart_polled_write(uart, *b++);
568  }
569  return nwrite;
570}
571
572int
573BSP_uart_termios_write_com(int minor, const char *buf, int len)
574{
575  int uart=minor;       /* could differ, theoretically */
576  assert(buf != NULL);
577
578  if(len <= 0)
579    {
580      return 0;
581    }
582
583  /* If the TX buffer is busy - something is royally screwed up */
584  /*   assert((uread(BSP_UART_COM1, LSR) & THRE) != 0); */
585
586  if(termios_stopped_com[uart])
587    {
588      /* CTS low */
589      termios_tx_hold_com[uart]       = *buf;
590      termios_tx_hold_valid_com[uart] = 1;
591      return 0;
592    }
593
594  /* Write character */
595  uwrite(uart, THR, *buf & 0xff);
596
597  /* Enable interrupts if necessary */
598  if(!termios_tx_active_com[uart] && uart_data[uart].hwFlow)
599    {
600      termios_tx_active_com[uart] = 1;
601      uwrite(uart, IER,
602             (RECEIVE_ENABLE  |
603              TRANSMIT_ENABLE |
604              RECEIVER_LINE_ST_ENABLE |
605              MODEM_ENABLE
606             )
607            );
608    }
609  else if(!termios_tx_active_com[uart])
610    {
611      termios_tx_active_com[uart] = 1;
612      uwrite(uart, IER,
613             (RECEIVE_ENABLE  |
614              TRANSMIT_ENABLE |
615              RECEIVER_LINE_ST_ENABLE
616             )
617            );
618    }
619
620  return 0;
621}
622
623int
624BSP_uart_termios_read_com(int uart)
625{
626  int     off = (int)0;
627  char    buf[40];
628  rtems_interrupt_level l;
629
630  /* read bytes */
631  while (( off < sizeof(buf) ) && ( uread(uart, LSR) & DR )) {
632    buf[off++] = uread(uart, RBR);
633  }
634
635  /* write out data */
636  if ( off > 0 ) {
637    rtems_termios_enqueue_raw_characters(termios_ttyp_com[uart], buf, off);
638  }
639
640  /* enable receive interrupts */
641  rtems_interrupt_disable(l);
642  uwrite(uart, IER, uread(uart, IER) | (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE));
643  rtems_interrupt_enable(l);
644
645  return ( EOF );
646}
647
648static void
649BSP_uart_termios_isr_com(int uart)
650{
651  unsigned char buf[40];
652  unsigned char val, ier;
653  int      off, ret, vect;
654
655  off = 0;
656
657  for(;;)
658    {
659      vect = uread(uart, IIR) & 0xf;
660
661      switch(vect)
662        {
663        case MODEM_STATUS :
664          val = uread(uart, MSR);
665          if(uart_data[uart].hwFlow)
666            {
667              if(val & CTS)
668                {
669                  /* CTS high */
670                  termios_stopped_com[uart] = 0;
671                  if(termios_tx_hold_valid_com[uart])
672                    {
673                      termios_tx_hold_valid_com[uart] = 0;
674                      BSP_uart_termios_write_com(uart, &termios_tx_hold_com[uart],
675                                                    1);
676                    }
677                }
678              else
679                {
680                  /* CTS low */
681                  termios_stopped_com[uart] = 1;
682                }
683            }
684          break;
685        case NO_MORE_INTR :
686          /* No more interrupts */
687          if(off != 0)
688            {
689              /* Update rx buffer */
690              rtems_termios_enqueue_raw_characters(termios_ttyp_com[uart],
691                                                   (char *)buf,
692                                                   off);
693            }
694          return;
695        case TRANSMITTER_HODING_REGISTER_EMPTY :
696          /*
697           * TX holding empty: we have to disable these interrupts
698           * if there is nothing more to send.
699           */
700
701          ret = rtems_termios_dequeue_characters(termios_ttyp_com[uart], 1);
702
703          /* If nothing else to send disable interrupts */
704          if(ret == 0 && uart_data[uart].hwFlow)
705            {
706              uwrite(uart, IER,
707                     (RECEIVE_ENABLE  |
708                      RECEIVER_LINE_ST_ENABLE |
709                      MODEM_ENABLE
710                     )
711                    );
712              termios_tx_active_com[uart] = 0;
713            }
714          else if(ret == 0)
715            {
716              uwrite(uart, IER,
717                     (RECEIVE_ENABLE  |
718                      RECEIVER_LINE_ST_ENABLE
719                     )
720                    );
721              termios_tx_active_com[uart] = 0;
722            }
723          break;
724        case RECEIVER_DATA_AVAIL :
725        case CHARACTER_TIMEOUT_INDICATION:
726          if ( uart_data[uart].ioMode == TERMIOS_TASK_DRIVEN )
727            {
728              /* ensure interrupts are enabled */
729              if ( (ier = uread(uart,IER)) & RECEIVE_ENABLE )
730                {
731                   /* disable interrupts and notify termios */
732                   ier &= ~(RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE);
733                   uwrite(uart, IER, ier);
734                   rtems_termios_rxirq_occured(termios_ttyp_com[uart]);
735                }
736            }
737          else
738            {
739              /* RX data ready */
740              assert(off < sizeof(buf));
741              while ( off < sizeof(buf) && ( DR & uread(uart, LSR) ) )
742                buf[off++] = uread(uart, RBR);
743            }
744          break;
745        case RECEIVER_ERROR:
746          /* RX error: eat character */
747           uartError(uart, termios_ttyp_com[uart]);
748          break;
749        default:
750          /* Should not happen */
751          assert(0);
752          return;
753        }
754    }
755}
756
757/*
758 * XXX - Note that this can now be one isr with the uart
759 *       passed as the parameter.
760 */
761void
762BSP_uart_termios_isr_com1(void *unused)
763{
764        BSP_uart_termios_isr_com(BSP_UART_COM1);
765}
766
767void
768BSP_uart_termios_isr_com2(void *unused)
769{
770        BSP_uart_termios_isr_com(BSP_UART_COM2);
771}
772
773/* retrieve 'break' handler info */
774int
775BSP_uart_get_break_cb(int uart, rtems_libio_ioctl_args_t *arg)
776{
777BSP_UartBreakCb cb=arg->buffer;
778unsigned long flags;
779        SANITY_CHECK(uart);
780        rtems_interrupt_disable(flags);
781                *cb = uart_data[uart].breakCallback;
782        rtems_interrupt_enable(flags);
783        arg->ioctl_return=0;
784        return RTEMS_SUCCESSFUL;
785}
786
787/* install 'break' handler */
788int
789BSP_uart_set_break_cb(int uart, rtems_libio_ioctl_args_t *arg)
790{
791BSP_UartBreakCb cb=arg->buffer;
792unsigned long flags;
793        SANITY_CHECK(uart);
794        rtems_interrupt_disable(flags);
795                uart_data[uart].breakCallback = *cb;
796        rtems_interrupt_enable(flags);
797        arg->ioctl_return=0;
798        return RTEMS_SUCCESSFUL;
799}
Note: See TracBrowser for help on using the repository browser.