source: rtems/bsps/shared/dev/serial/zynq-uart-polled.c @ f085957

Last change on this file since f085957 was f085957, checked in by Kinsey Moore <kinsey.moore@…>, on Oct 26, 2020 at 3:26:49 PM

bsps: Move zynq-uart to bsps/shared

This moves the zynq-uart driver from bsps/arm/shared to bsps/shared to
accomodate use by AArch64 BSPs.

  • Property mode set to 100644
File size: 5.4 KB
Line 
1/*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2013, 2017 embedded brains GmbH
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
31#include <bspopts.h>
32
33/*
34 * Make weak and let the user override.
35 */
36uint32_t zynq_uart_input_clock(void) __attribute__ ((weak));
37
38uint32_t zynq_uart_input_clock(void)
39{
40  return ZYNQ_CLOCK_UART;
41}
42
43static int zynq_cal_baud_rate(uint32_t  baudrate,
44                              uint32_t* brgr,
45                              uint32_t* bauddiv,
46                              uint32_t  modereg)
47{
48  uint32_t brgr_value;    /* Calculated value for baud rate generator */
49  uint32_t calcbaudrate;  /* Calculated baud rate */
50  uint32_t bauderror;     /* Diff between calculated and requested baud rate */
51  uint32_t best_error = 0xFFFFFFFF;
52  uint32_t percenterror;
53  uint32_t bdiv;
54  uint32_t inputclk = zynq_uart_input_clock();
55
56  /*
57   * Make sure the baud rate is not impossilby large.
58   * Fastest possible baud rate is Input Clock / 2.
59   */
60  if ((baudrate * 2) > inputclk) {
61    return -1;
62  }
63  /*
64   * Check whether the input clock is divided by 8
65   */
66  if(modereg & ZYNQ_UART_MODE_CLKS) {
67    inputclk = inputclk / 8;
68  }
69
70  /*
71   * Determine the Baud divider. It can be 4to 254.
72   * Loop through all possible combinations
73   */
74  for (bdiv = 4; bdiv < 255; bdiv++) {
75
76    /*
77     * Calculate the value for BRGR register
78     */
79    brgr_value = inputclk / (baudrate * (bdiv + 1));
80
81    /*
82     * Calculate the baud rate from the BRGR value
83     */
84    calcbaudrate = inputclk/ (brgr_value * (bdiv + 1));
85
86    /*
87     * Avoid unsigned integer underflow
88     */
89    if (baudrate > calcbaudrate) {
90      bauderror = baudrate - calcbaudrate;
91    }
92    else {
93      bauderror = calcbaudrate - baudrate;
94    }
95
96    /*
97     * Find the calculated baud rate closest to requested baud rate.
98     */
99    if (best_error > bauderror) {
100      *brgr = brgr_value;
101      *bauddiv = bdiv;
102      best_error = bauderror;
103    }
104  }
105
106  /*
107   * Make sure the best error is not too large.
108   */
109  percenterror = (best_error * 100) / baudrate;
110#define XUARTPS_MAX_BAUD_ERROR_RATE              3      /* max % error allowed */
111  if (XUARTPS_MAX_BAUD_ERROR_RATE < percenterror) {
112    return -1;
113  }
114
115  return 0;
116}
117
118void zynq_uart_initialize(rtems_termios_device_context *base)
119{
120  zynq_uart_context *ctx = (zynq_uart_context *) base;
121  volatile zynq_uart *regs = ctx->regs;
122  uint32_t brgr = 0x3e;
123  uint32_t bauddiv = 0x6;
124
125  zynq_uart_reset_tx_flush(ctx);
126
127  zynq_cal_baud_rate(ZYNQ_UART_DEFAULT_BAUD, &brgr, &bauddiv, regs->mode);
128
129  regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
130  regs->control = ZYNQ_UART_CONTROL_RXDIS
131    | ZYNQ_UART_CONTROL_TXDIS
132    | ZYNQ_UART_CONTROL_RXRES
133    | ZYNQ_UART_CONTROL_TXRES;
134  regs->mode = ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL)
135    | ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_NONE)
136    | ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8);
137  regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
138  regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
139  regs->rx_fifo_trg_lvl = ZYNQ_UART_RX_FIFO_TRG_LVL_RTRIG(0);
140  regs->rx_timeout = ZYNQ_UART_RX_TIMEOUT_RTO(0);
141  regs->control = ZYNQ_UART_CONTROL_RXEN
142    | ZYNQ_UART_CONTROL_TXEN
143    | ZYNQ_UART_CONTROL_RSTTO;
144}
145
146int zynq_uart_read_polled(rtems_termios_device_context *base)
147{
148  zynq_uart_context *ctx = (zynq_uart_context *) base;
149  volatile zynq_uart *regs = ctx->regs;
150
151  if ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_REMPTY) != 0) {
152    return -1;
153  } else {
154    return ZYNQ_UART_TX_RX_FIFO_FIFO_GET(regs->tx_rx_fifo);
155  }
156}
157
158void zynq_uart_write_polled(
159  rtems_termios_device_context *base,
160  char c
161)
162{
163  zynq_uart_context *ctx = (zynq_uart_context *) base;
164  volatile zynq_uart *regs = ctx->regs;
165
166  while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TFUL) != 0) {
167    /* Wait */
168  }
169
170  regs->tx_rx_fifo = ZYNQ_UART_TX_RX_FIFO_FIFO(c);
171}
172
173void zynq_uart_reset_tx_flush(zynq_uart_context *ctx)
174{
175  volatile zynq_uart *regs = ctx->regs;
176  int                 c = 4;
177
178  while (c-- > 0)
179    zynq_uart_write_polled(&ctx->base, '\r');
180
181  while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) == 0) {
182    /* Wait */
183  }
184}
Note: See TracBrowser for help on using the repository browser.