source: rtems/c/src/lib/libbsp/arm/xilinx-zynq/console/zynq-uart.c @ 8fbe2e6

4.115
Last change on this file since 8fbe2e6 was 18bd35bc, checked in by Chris Johns <chrisj@…>, on 05/22/14 at 06:15:34

bsps/zynq: Add BSP_ARM_A9MPCORE_UARTCLK to set the UART clock rate.

This value can be found the xparameters.h file generated by the
Xilinx tools.

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/*
2 * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <info@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <bsp/zynq-uart.h>
16#include <bsp/zynq-uart-regs.h>
17
18#include <bspopts.h>
19
20#include <libchip/sersupp.h>
21
22static volatile zynq_uart *zynq_uart_get_regs(int minor)
23{
24  const console_tbl *ct = Console_Port_Tbl != NULL ?
25    Console_Port_Tbl[minor] : &Console_Configuration_Ports[minor];
26
27  return (volatile zynq_uart *) ct->ulCtrlPort1;
28}
29
30/*
31 * Make weak and let the user override.
32 */
33uint32_t zynq_uart_input_clock(void) __attribute__ ((weak));
34
35uint32_t zynq_uart_input_clock(void)
36{
37  return BSP_ARM_A9MPCORE_UARTCLK;
38}
39
40static int zynq_cal_baud_rate(uint32_t  baudrate,
41                              uint32_t* brgr,
42                              uint32_t* bauddiv,
43                              uint32_t  modereg)
44{
45  uint32_t brgr_value;    /* Calculated value for baud rate generator */
46  uint32_t calcbaudrate;  /* Calculated baud rate */
47  uint32_t bauderror;     /* Diff between calculated and requested baud rate */
48  uint32_t best_error = 0xFFFFFFFF;
49  uint32_t percenterror;
50  uint32_t bdiv;
51  uint32_t inputclk = zynq_uart_input_clock();
52
53  /*
54   * Make sure the baud rate is not impossilby large.
55   * Fastest possible baud rate is Input Clock / 2.
56   */
57  if ((baudrate * 2) > inputclk) {
58    return -1;
59  }
60  /*
61   * Check whether the input clock is divided by 8
62   */
63  if(modereg & ZYNQ_UART_MODE_CLKS) {
64    inputclk = inputclk / 8;
65  }
66
67  /*
68   * Determine the Baud divider. It can be 4to 254.
69   * Loop through all possible combinations
70   */
71  for (bdiv = 4; bdiv < 255; bdiv++) {
72
73    /*
74     * Calculate the value for BRGR register
75     */
76    brgr_value = inputclk / (baudrate * (bdiv + 1));
77
78    /*
79     * Calculate the baud rate from the BRGR value
80     */
81    calcbaudrate = inputclk/ (brgr_value * (bdiv + 1));
82
83    /*
84     * Avoid unsigned integer underflow
85     */
86    if (baudrate > calcbaudrate) {
87      bauderror = baudrate - calcbaudrate;
88    }
89    else {
90      bauderror = calcbaudrate - baudrate;
91    }
92
93    /*
94     * Find the calculated baud rate closest to requested baud rate.
95     */
96    if (best_error > bauderror) {
97      *brgr = brgr_value;
98      *bauddiv = bdiv;
99      best_error = bauderror;
100    }
101  }
102
103  /*
104   * Make sure the best error is not too large.
105   */
106  percenterror = (best_error * 100) / baudrate;
107#define XUARTPS_MAX_BAUD_ERROR_RATE              3      /* max % error allowed */
108  if (XUARTPS_MAX_BAUD_ERROR_RATE < percenterror) {
109    return -1;
110  }
111
112  return 0;
113}
114
115static void zynq_uart_initialize(int minor)
116{
117  volatile zynq_uart *regs = zynq_uart_get_regs(minor);
118  uint32_t brgr = 0x3e;
119  uint32_t bauddiv = 0x6;
120
121  zynq_cal_baud_rate(115200, &brgr, &bauddiv, regs->mode);
122
123  regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
124  regs->control = ZYNQ_UART_CONTROL_RXDIS
125    | ZYNQ_UART_CONTROL_TXDIS
126    | ZYNQ_UART_CONTROL_RXRES
127    | ZYNQ_UART_CONTROL_TXRES;
128  regs->mode = ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL)
129    | ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_NONE)
130    | ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8);
131  regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
132  regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
133  regs->rx_fifo_trg_lvl = ZYNQ_UART_RX_FIFO_TRG_LVL_RTRIG(0);
134  regs->rx_timeout = ZYNQ_UART_RX_TIMEOUT_RTO(0);
135  regs->control = ZYNQ_UART_CONTROL_RXEN
136    | ZYNQ_UART_CONTROL_TXEN
137    | ZYNQ_UART_CONTROL_RSTTO;
138}
139
140static int zynq_uart_first_open(int major, int minor, void *arg)
141{
142  rtems_libio_open_close_args_t *oc = (rtems_libio_open_close_args_t *) arg;
143  struct rtems_termios_tty *tty = (struct rtems_termios_tty *) oc->iop->data1;
144  console_data *cd = &Console_Port_Data[minor];
145  const console_tbl *ct = Console_Port_Tbl[minor];
146
147  cd->termios_data = tty;
148  rtems_termios_set_initial_baud(tty, (rtems_termios_baud_t) ct->pDeviceParams);
149
150  return 0;
151}
152
153static int zynq_uart_last_close(int major, int minor, void *arg)
154{
155  return 0;
156}
157
158static int zynq_uart_read_polled(int minor)
159{
160  volatile zynq_uart *regs = zynq_uart_get_regs(minor);
161
162  if ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_REMPTY) != 0) {
163    return -1;
164  } else {
165    return ZYNQ_UART_TX_RX_FIFO_FIFO_GET(regs->tx_rx_fifo);
166  }
167}
168
169static void zynq_uart_write_polled(int minor, char c)
170{
171  volatile zynq_uart *regs = zynq_uart_get_regs(minor);
172
173  while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TFUL) != 0) {
174    /* Wait */
175  }
176
177  regs->tx_rx_fifo = ZYNQ_UART_TX_RX_FIFO_FIFO(c);
178}
179
180static ssize_t zynq_uart_write_support_polled(
181  int minor,
182  const char *s,
183  size_t n
184)
185{
186  ssize_t i = 0;
187
188  for (i = 0; i < n; ++i) {
189    zynq_uart_write_polled(minor, s[i]);
190  }
191
192  return n;
193}
194
195static int zynq_uart_set_attribues(int minor, const struct termios *term)
196{
197#if 0
198  volatile zynq_uart *regs = zynq_uart_get_regs(minor);
199  uint32_t brgr = 0;
200  uint32_t bauddiv = 0;
201  int rc;
202
203  rc = zynq_cal_baud_rate(115200, &brgr, &bauddiv, regs->mode);
204  if (rc != 0)
205    return rc;
206
207  regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
208  regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
209  regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
210  regs->control |= ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
211
212  return 0;
213#else
214  return -1;
215#endif
216}
217
218const console_fns zynq_uart_fns = {
219  .deviceProbe = libchip_serial_default_probe,
220  .deviceFirstOpen = zynq_uart_first_open,
221  .deviceLastClose = zynq_uart_last_close,
222  .deviceRead = zynq_uart_read_polled,
223  .deviceWrite = zynq_uart_write_support_polled,
224  .deviceInitialize = zynq_uart_initialize,
225  .deviceWritePolled = zynq_uart_write_polled,
226  .deviceSetAttributes = zynq_uart_set_attribues,
227  .deviceOutputUsesInterrupts = false
228};
Note: See TracBrowser for help on using the repository browser.