source: rtems/bsps/shared/dev/serial/zynq-uart.c @ 0c3d6f58

Last change on this file since 0c3d6f58 was 0c3d6f58, checked in by Sebastian Huber <sebastian.huber@…>, on 05/23/23 at 08:44:04

termios: Add <rtems/termiosdevice.h>

Add <rtems/termiosdevice.h> which does not depend on <rtems/libio.h> to
provide rtems_termios_device_context and rtems_termios_device_handler.
For polled serial device drivers, this removes a header file dependency
to the full file system support.

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2013, 2017 embedded brains GmbH & Co. KG
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <dev/serial/zynq-uart.h>
29#include <dev/serial/zynq-uart-regs.h>
30#include <bsp/irq.h>
31#include <rtems/termiostypes.h>
32
33#include <bspopts.h>
34
35#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
36static void zynq_uart_interrupt(void *arg)
37{
38  rtems_termios_tty *tty = arg;
39  zynq_uart_context *ctx = rtems_termios_get_device_context(tty);
40  volatile zynq_uart *regs = ctx->regs;
41
42  if ((regs->irq_sts & ZYNQ_UART_RTRIG) != 0) {
43    char buf[32];
44    int c = 0;
45    regs->irq_sts = ZYNQ_UART_RTRIG;
46    while (c < sizeof(buf) &&
47           (regs->channel_sts & ZYNQ_UART_CHANNEL_STS_REMPTY) == 0) {
48       buf[c++] = (char) ZYNQ_UART_TX_RX_FIFO_FIFO_GET(regs->tx_rx_fifo);
49    }
50    rtems_termios_enqueue_raw_characters(tty, buf, c);
51  }
52
53  if (ctx->transmitting) {
54    int sent = ctx->tx_queued;
55    regs->irq_dis = ZYNQ_UART_TEMPTY;
56    ctx->transmitting = false;
57    ctx->tx_queued = 0;
58    rtems_termios_dequeue_characters(tty, sent);
59  }
60}
61#endif
62
63static bool zynq_uart_first_open(
64  rtems_termios_tty *tty,
65  rtems_termios_device_context *base,
66  struct termios *term,
67  rtems_libio_open_close_args_t *args
68)
69{
70#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
71  zynq_uart_context *ctx = (zynq_uart_context *) base;
72  volatile zynq_uart *regs = ctx->regs;
73  rtems_status_code sc;
74#endif
75
76  rtems_termios_set_initial_baud(tty, ZYNQ_UART_DEFAULT_BAUD);
77  zynq_uart_initialize(base);
78
79#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
80  regs->rx_fifo_trg_lvl = 1;
81  regs->irq_dis = 0xffffffff;
82  regs->irq_sts = 0xffffffff;
83  regs->irq_en = ZYNQ_UART_RTRIG;
84  sc = rtems_interrupt_handler_install(
85    ctx->irq,
86    "UART",
87    RTEMS_INTERRUPT_SHARED,
88    zynq_uart_interrupt,
89    tty
90  );
91  if (sc != RTEMS_SUCCESSFUL) {
92    return false;
93  }
94#endif
95
96  return true;
97}
98
99#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
100static void zynq_uart_last_close(
101  rtems_termios_tty *tty,
102  rtems_termios_device_context *base,
103  rtems_libio_open_close_args_t *args
104)
105{
106  zynq_uart_context *ctx = (zynq_uart_context *) base;
107
108  rtems_interrupt_handler_remove(ctx->irq, zynq_uart_interrupt, tty);
109}
110#endif
111
112static void zynq_uart_write_support(
113  rtems_termios_device_context *base,
114  const char *buf,
115  size_t len
116)
117{
118#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
119  zynq_uart_context *ctx = (zynq_uart_context *) base;
120  volatile zynq_uart *regs = ctx->regs;
121
122  regs->irq_dis = ZYNQ_UART_TEMPTY;
123
124  if (len > 0) {
125    const char *p = &buf[0];
126    regs->irq_sts = ZYNQ_UART_TEMPTY;
127    while (((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TNFUL) == 0) &&
128           len > 0) {
129      regs->tx_rx_fifo = ZYNQ_UART_TX_RX_FIFO_FIFO(*p);
130      ++p;
131      ++ctx->tx_queued;
132      --len;
133    }
134    ctx->transmitting = true;
135    regs->irq_en = ZYNQ_UART_TEMPTY;
136  }
137#else
138  ssize_t i;
139  for (i = 0; i < len; ++i) {
140    zynq_uart_write_polled(base, buf[i]);
141  }
142#endif
143}
144
145static bool zynq_uart_set_attributes(
146  rtems_termios_device_context *context,
147  const struct termios *term
148)
149{
150  zynq_uart_context *ctx = (zynq_uart_context *) context;
151  volatile zynq_uart *regs = ctx->regs;
152  int32_t baud;
153  uint32_t brgr = 0;
154  uint32_t bauddiv = 0;
155  uint32_t mode = 0;
156  int rc;
157
158  /*
159   * Determine the baud rate
160   */
161  baud = rtems_termios_baud_to_number(term->c_ospeed);
162
163  if (baud > 0) {
164    rc = zynq_cal_baud_rate(baud, &brgr, &bauddiv, regs->mode);
165    if (rc != 0)
166      return rc;
167  }
168
169  /*
170   * Configure the mode register
171   */
172  mode = regs->mode & ZYNQ_UART_MODE_CLKS;
173  mode |= ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL);
174
175  /*
176   * Parity
177   */
178  mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_NONE);
179  if (term->c_cflag & PARENB) {
180    if (!(term->c_cflag & PARODD)) {
181      mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_ODD);
182    } else {
183      mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_EVEN);
184    }
185  }
186
187  /*
188   * Character Size
189   */
190  switch (term->c_cflag & CSIZE)
191  {
192  case CS5:
193    return false;
194  case CS6:
195    mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_6);
196    break;
197  case CS7:
198    mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_7);
199    break;
200  case CS8:
201  default:
202    mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8);
203    break;
204  }
205
206  /*
207   * Stop Bits
208   */
209  if (term->c_cflag & CSTOPB) {
210    /* 2 stop bits */
211    mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_2);
212  } else {
213    /* 1 stop bit */
214    mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_1);
215  }
216
217  /*
218   * Wait for any data in the TXFIFO to be sent then wait while the
219   * transmiter is active.
220   */
221  while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) == 0 ||
222         (regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TACTIVE) != 0) {
223    /* Wait */
224  }
225
226  regs->control = ZYNQ_UART_CONTROL_RXDIS | ZYNQ_UART_CONTROL_TXDIS;
227  /* Ignore baud rate of B0. There are no modem control lines to de-assert */
228  if (baud > 0) {
229    regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
230    regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
231  }
232  regs->control = ZYNQ_UART_CONTROL_RXRES | ZYNQ_UART_CONTROL_TXRES;
233  regs->mode = mode;
234  regs->irq_sts = 0xffffffff;
235  regs->control = ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
236
237  return true;
238}
239
240const rtems_termios_device_handler zynq_uart_handler = {
241  .first_open = zynq_uart_first_open,
242  .set_attributes = zynq_uart_set_attributes,
243  .write = zynq_uart_write_support,
244#ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
245  .last_close = zynq_uart_last_close,
246  .mode = TERMIOS_IRQ_DRIVEN
247#else
248  .poll_read = zynq_uart_read_polled,
249  .mode = TERMIOS_POLLED
250#endif
251};
Note: See TracBrowser for help on using the repository browser.