source: rtems/c/src/lib/libbsp/sparc/leon3/console/console.c @ 5d48037

4.115
Last change on this file since 5d48037 was 5d48037, checked in by Daniel Hellstrom <daniel@…>, on 04/19/12 at 13:21:25

LEON3: added TX-wait-complete and CR on NL support for UART

Signed-off-by: Daniel Hellstrom <daniel@…>

  • Property mode set to 100644
File size: 11.2 KB
Line 
1/*
2 *  This file contains the TTY driver for the serial ports on the LEON.
3 *
4 *  This driver uses the termios pseudo driver.
5 *
6 *  COPYRIGHT (c) 1989-1998.
7 *  On-Line Applications Research Corporation (OAR).
8 *
9 *  Modified for LEON3 BSP.
10 *  COPYRIGHT (c) 2004.
11 *  Gaisler Research.
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.com/license/LICENSE.
16 */
17
18/* Define CONSOLE_USE_INTERRUPTS to enable APBUART interrupt handling instead
19 * of polling mode.
20 *
21 * Note that it is not possible to use the interrupt mode of the driver
22 * together with the "old" APBUART and -u to GRMON. However the new
23 * APBUART core (from GRLIB 1.0.17-b2710) has the GRMON debug bit and can
24 * handle interrupts.
25 *
26 * NOTE: This can be defined in the make/custom/leon3.cfg file.
27 */
28
29#include <bsp.h>
30#include <rtems/libio.h>
31#include <stdlib.h>
32#include <assert.h>
33#include <rtems/bspIo.h>
34#include <amba.h>
35
36/* Let user override which on-chip APBUART will be debug UART
37 * 0 = Default APBUART. On MP system CPU0=APBUART0, CPU1=APBUART1...
38 * 1 = APBUART[0]
39 * 2 = APBUART[1]
40 * 3 = APBUART[2]
41 * ...
42 */
43int syscon_uart_index __attribute__((weak)) = 0;
44
45/*
46 *  apbuart_outbyte_polled
47 *
48 *  This routine transmits a character using polling.
49 */
50
51extern void apbuart_outbyte_polled(
52  ambapp_apb_uart *regs,
53  unsigned char ch,
54  int do_cr_on_newline,
55  int wait_sent
56  );
57
58
59/* body is in debugputs.c */
60
61/*
62 *  apbuart_inbyte_nonblocking
63 *
64 *  This routine polls for a character.
65 */
66
67extern int apbuart_inbyte_nonblocking(ambapp_apb_uart *regs);
68
69/* body is in debugputs.c */
70
71struct apbuart_priv {
72  ambapp_apb_uart *regs;
73  unsigned int freq_hz;
74#if CONSOLE_USE_INTERRUPTS
75  int irq;
76  void *cookie;
77  volatile int sending;
78  char *buf;
79#endif
80};
81static struct apbuart_priv apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS];
82static int uarts = 0;
83
84#if CONSOLE_USE_INTERRUPTS
85
86/* Handle UART interrupts */
87void console_isr(void *arg)
88{
89  struct apbuart_priv *uart = arg;
90  unsigned int status;
91  char data;
92
93  /* Get all received characters */
94  while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) {
95    /* Data has arrived, get new data */
96    data = uart->regs->data;
97
98    /* Tell termios layer about new character */
99    rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1);
100  }
101
102  if (status & LEON_REG_UART_STATUS_THE) {
103    /* Sent the one char, we disable TX interrupts */
104    uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI;
105
106    /* Tell close that we sent everything */
107    uart->sending = 0;
108
109    /* write_interrupt will get called from this function */
110    rtems_termios_dequeue_characters(uart->cookie, 1);
111  }
112}
113
114/*
115 *  Console Termios Write-Buffer Support Entry Point
116 *
117 */
118int console_write_interrupt(int minor, const char *buf, int len)
119{
120  struct apbuart_priv *uart;
121  unsigned int oldLevel;
122
123  if (minor == 0)
124    uart = &apbuarts[syscon_uart_index];
125  else
126    uart = &apbuarts[minor - 1];
127
128  /* Remember what position in buffer */
129
130  rtems_interrupt_disable(oldLevel);
131
132  /* Enable TX interrupt */
133  uart->regs->ctrl |= LEON_REG_UART_CTRL_TI;
134
135  /* start UART TX, this will result in an interrupt when done */
136  uart->regs->data = *buf;
137
138  uart->sending = 1;
139
140  rtems_interrupt_enable(oldLevel);
141
142  return 0;
143}
144
145#else
146
147/*
148 *  Console Termios Support Entry Points
149 *
150 */
151
152ssize_t console_write_polled(int minor, const char *buf, size_t len)
153{
154  int nwrite = 0, port;
155
156  if (minor == 0)
157    port = syscon_uart_index;
158  else
159    port = minor - 1;
160
161  while (nwrite < len) {
162    apbuart_outbyte_polled(apbuarts[port].regs, *buf++, 1, 0);
163    nwrite++;
164  }
165  return nwrite;
166}
167
168int console_pollRead(int minor)
169{
170  int port;
171
172  if (minor == 0)
173    port = syscon_uart_index;
174  else
175    port = minor - 1;
176
177  return apbuart_inbyte_nonblocking(apbuarts[port].regs);
178}
179
180#endif
181
182int console_set_attributes(int minor, const struct termios *t)
183{
184  unsigned int scaler;
185  unsigned int ctrl;
186  int baud;
187  struct apbuart_priv *uart;
188
189  switch (t->c_cflag & CSIZE) {
190    default:
191    case CS5:
192    case CS6:
193    case CS7:
194      /* Hardware doesn't support other than CS8 */
195      return -1;
196    case CS8:
197      break;
198  }
199
200  if (minor == 0)
201    uart = &apbuarts[syscon_uart_index];
202  else
203    uart = &apbuarts[minor - 1];
204
205  /* Read out current value */
206  ctrl = uart->regs->ctrl;
207
208  switch (t->c_cflag & (PARENB|PARODD)) {
209    case (PARENB|PARODD):
210      /* Odd parity */
211      ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
212      break;
213
214    case PARENB:
215      /* Even parity */
216      ctrl &= ~LEON_REG_UART_CTRL_PS;
217      ctrl |= LEON_REG_UART_CTRL_PE;
218      break;
219
220    default:
221    case 0:
222    case PARODD:
223      /* No Parity */
224      ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
225  }
226
227  if (!(t->c_cflag & CLOCAL)) {
228    ctrl |= LEON_REG_UART_CTRL_FL;
229  } else {
230    ctrl &= ~LEON_REG_UART_CTRL_FL;
231  }
232
233  /* Update new settings */
234  uart->regs->ctrl = ctrl;
235
236  /* Baud rate */
237  baud = rtems_termios_baud_to_number(t->c_cflag);
238  if (baud > 0) {
239    /* Calculate Baud rate generator "scaler" number */
240    scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10;
241
242    /* Set new baud rate by setting scaler */
243    uart->regs->scaler = scaler;
244  }
245
246  return 0;
247}
248
249/* AMBA PP find routine. Extract AMBA PnP information into data structure. */
250int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg)
251{
252  struct ambapp_apb_info *apb = (struct ambapp_apb_info *)dev->devinfo;
253
254  /* Extract needed information of one APBUART */
255  apbuarts[uarts].regs = (ambapp_apb_uart *)apb->start;
256#if CONSOLE_USE_INTERRUPTS
257  apbuarts[uarts].irq = apb->irq;
258#endif
259  /* Get APBUART core frequency, it is assumed that it is the same
260   * as Bus frequency where the UART is situated
261   */
262  apbuarts[uarts].freq_hz = ambapp_freq_get(&ambapp_plb, dev);
263  uarts++;
264
265  if (uarts >= BSP_NUMBER_OF_TERMIOS_PORTS)
266    return 1; /* Satisfied number of UARTs, stop search */
267  else
268    return 0; /* Continue searching for more UARTs */
269}
270
271/* Find all UARTs */
272int console_scan_uarts(void)
273{
274  memset(apbuarts, 0, sizeof(apbuarts));
275
276  /* Find APBUART cores */
277  ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS), VENDOR_GAISLER,
278                  GAISLER_APBUART, find_matching_apbuart, NULL);
279
280  return uarts;
281}
282
283/*
284 *  Console Device Driver Entry Points
285 *
286 */
287
288rtems_device_driver console_initialize(
289  rtems_device_major_number  major,
290  rtems_device_minor_number  minor,
291  void                      *arg
292)
293{
294  rtems_status_code status;
295  int i;
296  char console_name[16];
297
298  rtems_termios_initialize();
299
300  /* Find UARTs */
301  console_scan_uarts();
302
303  /* Update syscon_uart_index to index used as /dev/console
304   * Let user select System console by setting syscon_uart_index. If the
305   * BSP is to provide the default UART (syscon_uart_index==0):
306   *   non-MP: APBUART[0] is system console
307   *   MP: LEON CPU index select UART
308   */
309  if (syscon_uart_index == 0) {
310#if defined(RTEMS_MULTIPROCESSING)
311    syscon_uart_index = LEON3_Cpu_Index;
312#else
313    syscon_uart_index = 0;
314#endif
315  } else {
316    syscon_uart_index = syscon_uart_index - 1; /* User selected sys-console */
317  }
318
319  /*  Register Device Names
320   *
321   *  0 /dev/console   - APBUART[USER-SELECTED, DEFAULT=APBUART[0]]
322   *  1 /dev/console_a - APBUART[0] (by default not present because is console)
323   *  2 /dev/console_b - APBUART[1]
324   *  ...
325   *
326   * On a MP system one should not open UARTs that other OS instances use.
327   */
328  if (syscon_uart_index < uarts) {
329    status = rtems_io_register_name("/dev/console", major, 0);
330    if (status != RTEMS_SUCCESSFUL)
331      rtems_fatal_error_occurred(status);
332  }
333  strcpy(console_name,"/dev/console_a");
334  for (i = 0; i < uarts; i++) {
335    if (i == syscon_uart_index)
336      continue; /* skip UART that is registered as /dev/console */
337    console_name[13] = 'a' + i;
338    status = rtems_io_register_name( console_name, major, i+1);
339  }
340
341  return RTEMS_SUCCESSFUL;
342}
343
344rtems_device_driver console_open(
345  rtems_device_major_number major,
346  rtems_device_minor_number minor,
347  void                    * arg
348)
349{
350  rtems_status_code sc;
351  struct apbuart_priv *uart;
352#if CONSOLE_USE_INTERRUPTS
353  rtems_libio_open_close_args_t *priv = arg;
354
355  /* Interrupt mode routines */
356  static const rtems_termios_callbacks Callbacks = {
357    NULL,                        /* firstOpen */
358    NULL,                        /* lastClose */
359    NULL,                        /* pollRead */
360    console_write_interrupt,     /* write */
361    console_set_attributes,      /* setAttributes */
362    NULL,                        /* stopRemoteTx */
363    NULL,                        /* startRemoteTx */
364    1                            /* outputUsesInterrupts */
365  };
366#else
367  /* Polling mode routines */
368  static const rtems_termios_callbacks Callbacks = {
369    NULL,                        /* firstOpen */
370    NULL,                        /* lastClose */
371    console_pollRead,            /* pollRead */
372    console_write_polled,        /* write */
373    console_set_attributes,      /* setAttributes */
374    NULL,                        /* stopRemoteTx */
375    NULL,                        /* startRemoteTx */
376    0                            /* outputUsesInterrupts */
377  };
378#endif
379
380  assert(minor <= uarts);
381  if (minor > uarts || minor == (syscon_uart_index + 1))
382    return RTEMS_INVALID_NUMBER;
383
384  sc = rtems_termios_open(major, minor, arg, &Callbacks);
385  if (sc != RTEMS_SUCCESSFUL)
386    return sc;
387
388  if (minor == 0)
389    uart = &apbuarts[syscon_uart_index];
390  else
391    uart = &apbuarts[minor - 1];
392
393#if CONSOLE_USE_INTERRUPTS
394  if (priv && priv->iop)
395    uart->cookie = priv->iop->data1;
396  else
397    uart->cookie = NULL;
398
399  /* Register Interrupt handler */
400  sc = rtems_interrupt_handler_install(uart->irq, "console",
401                                       RTEMS_INTERRUPT_SHARED, console_isr,
402                                       uart);
403  if (sc != RTEMS_SUCCESSFUL)
404    return sc;
405
406  uart->sending = 0;
407  /* Enable Receiver and transmitter and Turn on RX interrupts */
408  uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE |
409                      LEON_REG_UART_CTRL_RI;
410#else
411  /* Initialize UART on opening */
412  uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
413#endif
414  uart->regs->status = 0;
415
416  return RTEMS_SUCCESSFUL;
417}
418
419rtems_device_driver console_close(
420  rtems_device_major_number major,
421  rtems_device_minor_number minor,
422  void                    * arg
423)
424{
425#if CONSOLE_USE_INTERRUPTS
426  struct apbuart_priv *uart;
427
428  if (minor == 0)
429    uart = &apbuarts[syscon_uart_index];
430  else
431    uart = &apbuarts[minor - 1];
432
433  /* Turn off RX interrupts */
434  uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI);
435
436  /**** Flush device ****/
437  while (uart->sending) {
438    /* Wait until all data has been sent */
439  }
440
441  /* uninstall ISR */
442  rtems_interrupt_handler_remove(uart->irq, console_isr, uart);
443#endif
444  return rtems_termios_close(arg);
445}
446
447rtems_device_driver console_read(
448  rtems_device_major_number major,
449  rtems_device_minor_number minor,
450  void                    * arg
451)
452{
453  return rtems_termios_read(arg);
454}
455
456rtems_device_driver console_write(
457  rtems_device_major_number major,
458  rtems_device_minor_number minor,
459  void                    * arg
460)
461{
462  return rtems_termios_write(arg);
463}
464
465rtems_device_driver console_control(
466  rtems_device_major_number major,
467  rtems_device_minor_number minor,
468  void                    * arg
469)
470{
471  return rtems_termios_ioctl(arg);
472}
473
Note: See TracBrowser for help on using the repository browser.