source: rtems/c/src/lib/libbsp/sparc/leon3/console/console.c @ 1d5d6de

4.115
Last change on this file since 1d5d6de was 1d5d6de, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 26, 2013 at 8:11:57 AM

bsp/leon3: Console driver changes

Move declaration of global variables and functions to <leon.h> header
file. Make several global variables and functions static.

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