Software APIs
dif_uart.c
1 // Copyright lowRISC contributors.
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
6 
7 #include <assert.h>
8 #include <stddef.h>
9 
12 
13 #include "uart_regs.h" // Generated.
14 
15 #define UART_INTR_STATE_MASK 0xffffffffu
16 
17 const uint32_t kDifUartFifoSizeBytes = 32u;
18 
19 static bool uart_tx_full(const dif_uart_t *uart) {
20  uint32_t reg = mmio_region_read32(uart->base_addr, UART_STATUS_REG_OFFSET);
21  return bitfield_bit32_read(reg, UART_STATUS_TXFULL_BIT);
22 }
23 
24 static bool uart_tx_idle(const dif_uart_t *uart) {
25  uint32_t reg = mmio_region_read32(uart->base_addr, UART_STATUS_REG_OFFSET);
26  return bitfield_bit32_read(reg, UART_STATUS_TXIDLE_BIT);
27 }
28 
29 static bool uart_rx_empty(const dif_uart_t *uart) {
30  uint32_t reg = mmio_region_read32(uart->base_addr, UART_STATUS_REG_OFFSET);
31  return bitfield_bit32_read(reg, UART_STATUS_RXEMPTY_BIT);
32 }
33 
34 static uint8_t uart_rx_fifo_read(const dif_uart_t *uart) {
35  uint32_t reg = mmio_region_read32(uart->base_addr, UART_RDATA_REG_OFFSET);
36 
37  return bitfield_field32_read(reg, UART_RDATA_RDATA_FIELD);
38 }
39 
40 static void uart_tx_fifo_write(const dif_uart_t *uart, uint8_t byte) {
41  uint32_t reg = bitfield_field32_write(0, UART_WDATA_WDATA_FIELD, byte);
42  mmio_region_write32(uart->base_addr, UART_WDATA_REG_OFFSET, reg);
43 }
44 
45 static void uart_reset(const dif_uart_t *uart) {
46  mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, 0u);
47 
48  // Write to the relevant bits clears the FIFOs.
49  uint32_t reg = 0;
50  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_RXRST_BIT, true);
51  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_TXRST_BIT, true);
52  mmio_region_write32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
53 
54  mmio_region_write32(uart->base_addr, UART_OVRD_REG_OFFSET, 0u);
55  mmio_region_write32(uart->base_addr, UART_TIMEOUT_CTRL_REG_OFFSET, 0u);
56  mmio_region_write32(uart->base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
57  mmio_region_write32(uart->base_addr, UART_INTR_STATE_REG_OFFSET,
58  UART_INTR_STATE_MASK);
59 }
60 
61 /**
62  * Write up to `bytes_requested` number of bytes to the TX FIFO.
63  */
64 static size_t uart_bytes_send(const dif_uart_t *uart, const uint8_t *data,
65  size_t bytes_requested) {
66  size_t bytes_written = 0;
67  while ((bytes_written < bytes_requested) && !uart_tx_full(uart)) {
68  uart_tx_fifo_write(uart, data[bytes_written]);
69  ++bytes_written;
70  }
71 
72  return bytes_written;
73 }
74 
75 /**
76  * Read up to `bytes_requested` number of bytes from the RX FIFO.
77  */
78 static size_t uart_bytes_receive(const dif_uart_t *uart, size_t bytes_requested,
79  uint8_t *data) {
80  size_t bytes_read = 0;
81  while ((bytes_read < bytes_requested) && !uart_rx_empty(uart)) {
82  data[bytes_read] = uart_rx_fifo_read(uart);
83  ++bytes_read;
84  }
85 
86  return bytes_read;
87 }
88 
90  dif_uart_config_t config) {
91  if (uart == NULL) {
92  return kDifBadArg;
93  }
94 
95  if (config.baudrate == 0 || config.clk_freq_hz == 0) {
96  return kDifBadArg;
97  }
98 
99  // Calculation formula: NCO = 16 * 2^nco_width * baud / fclk.
100 
101  // Compute NCO register bit width
102  uint32_t nco_width = 0;
103 
104  for (int i = 0; i < 32; i++) {
105  nco_width += (UART_CTRL_NCO_MASK >> i) & 1;
106  }
107 
108  static_assert((UART_CTRL_NCO_MASK >> 28) == 0,
109  "NCO bit width exceeds 28 bits.");
110 
111  // NCO creates 16x of baudrate. So, in addition to the nco_width,
112  // 2^4 should be multiplied.
113  // If uart baud rate is 1.5Mbps and IO is 24Mhz, NCO is 0x10000, which is over
114  // the NCO width, use NCO = 0xffff for this case since the error is tolerable.
115  // Refer to #4263
116  uint64_t nco =
117  ((uint64_t)config.baudrate == 1500000 && config.clk_freq_hz == 24000000)
118  ? 0xffff
119  : ((uint64_t)config.baudrate << (nco_width + 4)) / config.clk_freq_hz;
120  uint32_t nco_masked = nco & UART_CTRL_NCO_MASK;
121 
122  // Requested baudrate is too high for the given clock frequency.
123  if (nco != nco_masked) {
124  return kDifBadArg;
125  }
126 
127  // Must be called before the first write to any of the UART registers.
128  uart_reset(uart);
129 
130  // Set baudrate, enable RX and TX, configure parity.
131  uint32_t reg = 0;
132  reg = bitfield_field32_write(reg, UART_CTRL_NCO_FIELD, nco_masked);
133  reg = bitfield_bit32_write(reg, UART_CTRL_TX_BIT, true);
134  reg = bitfield_bit32_write(reg, UART_CTRL_RX_BIT, true);
135  if (config.parity_enable == kDifToggleEnabled) {
136  reg = bitfield_bit32_write(reg, UART_CTRL_PARITY_EN_BIT, true);
137  }
138  if (config.parity == kDifUartParityOdd) {
139  reg = bitfield_bit32_write(reg, UART_CTRL_PARITY_ODD_BIT, true);
140  }
141  mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, reg);
142 
143  // Disable interrupts.
144  mmio_region_write32(uart->base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
145 
146  return kDifOk;
147 }
148 
150  dif_uart_watermark_t watermark) {
151  if (uart == NULL) {
152  return kDifBadArg;
153  }
154 
155  // Check if the requested watermark is valid, and get a corresponding
156  // register definition to be written.
157  uint32_t value;
158  switch (watermark) {
160  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL1;
161  break;
163  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL4;
164  break;
166  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL8;
167  break;
169  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL16;
170  break;
172  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL30;
173  break;
174  default:
175  return kDifError;
176  }
177 
178  // Set watermark level.
179  uint32_t reg = mmio_region_read32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET);
180  reg = bitfield_field32_write(reg, UART_FIFO_CTRL_RXILVL_FIELD, value);
181  mmio_region_write32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
182 
183  return kDifOk;
184 }
185 
187  dif_uart_watermark_t watermark) {
188  if (uart == NULL) {
189  return kDifBadArg;
190  }
191 
192  // Check if the requested watermark is valid, and get a corresponding
193  // register definition to be written.
194  uint32_t value;
195  switch (watermark) {
197  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL1;
198  break;
200  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL4;
201  break;
203  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL8;
204  break;
206  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL16;
207  break;
208  default:
209  // The minimal TX watermark is 1 byte, maximal 16 bytes.
210  return kDifError;
211  }
212 
213  // Set watermark level.
214  uint32_t reg = mmio_region_read32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET);
215  reg = bitfield_field32_write(reg, UART_FIFO_CTRL_TXILVL_FIELD, value);
216  mmio_region_write32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
217 
218  return kDifOk;
219 }
220 
221 dif_result_t dif_uart_bytes_send(const dif_uart_t *uart, const uint8_t *data,
222  size_t bytes_requested,
223  size_t *bytes_written) {
224  if (uart == NULL || data == NULL) {
225  return kDifBadArg;
226  }
227 
228  // `bytes_written` is an optional parameter.
229  size_t res = uart_bytes_send(uart, data, bytes_requested);
230  if (bytes_written != NULL) {
231  *bytes_written = res;
232  }
233 
234  return kDifOk;
235 }
236 
238  size_t bytes_requested, uint8_t *data,
239  size_t *bytes_read) {
240  if (uart == NULL || data == NULL) {
241  return kDifBadArg;
242  }
243 
244  // `bytes_read` is an optional parameter.
245  size_t res = uart_bytes_receive(uart, bytes_requested, data);
246  if (bytes_read != NULL) {
247  *bytes_read = res;
248  }
249 
250  return kDifOk;
251 }
252 
254  if (uart == NULL) {
255  return kDifBadArg;
256  }
257 
258  // Busy wait for the TX FIFO to free up.
259  while (uart_tx_full(uart)) {
260  }
261 
262  (void)uart_bytes_send(uart, &byte, 1);
263 
264  // Busy wait for the TX FIFO to be drained and for HW to finish processing
265  // the last byte.
266  while (!uart_tx_idle(uart)) {
267  }
268 
269  return kDifOk;
270 }
271 
273  uint8_t *byte) {
274  if (uart == NULL || byte == NULL) {
275  return kDifBadArg;
276  }
277 
278  // Busy wait for the RX message in the FIFO.
279  while (uart_rx_empty(uart)) {
280  }
281 
282  (void)uart_bytes_receive(uart, 1, byte);
283 
284  return kDifOk;
285 }
286 
288  size_t *num_bytes) {
289  if (uart == NULL || num_bytes == NULL) {
290  return kDifBadArg;
291  }
292 
293  // RX FIFO fill level (in bytes).
294  uint32_t reg =
295  mmio_region_read32(uart->base_addr, UART_FIFO_STATUS_REG_OFFSET);
296  *num_bytes = (size_t)bitfield_field32_read(reg, UART_FIFO_STATUS_RXLVL_FIELD);
297 
298  return kDifOk;
299 }
300 
302  size_t *num_bytes) {
303  if (uart == NULL || num_bytes == NULL) {
304  return kDifBadArg;
305  }
306 
307  // TX FIFO fill level (in bytes).
308  uint32_t reg =
309  mmio_region_read32(uart->base_addr, UART_FIFO_STATUS_REG_OFFSET);
310  uint32_t fill_bytes =
311  bitfield_field32_read(reg, UART_FIFO_STATUS_TXLVL_FIELD);
312  *num_bytes = kDifUartFifoSizeBytes - fill_bytes;
313 
314  return kDifOk;
315 }
316 
318  dif_uart_fifo_reset_t reset) {
319  if (uart == NULL) {
320  return kDifBadArg;
321  }
322 
323  uint32_t reg = mmio_region_read32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET);
324 
325  if (reset == kDifUartFifoResetRx || reset == kDifUartFifoResetAll) {
326  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_RXRST_BIT, true);
327  }
328 
329  if (reset == kDifUartFifoResetTx || reset == kDifUartFifoResetAll) {
330  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_TXRST_BIT, true);
331  }
332 
333  mmio_region_write32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
334 
335  return kDifOk;
336 }
337 
339  dif_uart_loopback_t loopback,
340  dif_toggle_t enable) {
341  if (uart == NULL) {
342  return kDifBadArg;
343  }
344 
345  uint32_t index = loopback ? UART_CTRL_LLPBK_BIT : UART_CTRL_SLPBK_BIT;
346  uint32_t reg = mmio_region_read32(uart->base_addr, UART_CTRL_REG_OFFSET);
347  reg = bitfield_bit32_write(reg, index, enable == kDifToggleEnabled);
348  mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, reg);
349 
350  return kDifOk;
351 }
352 
354  uint32_t duration_ticks) {
355  if (uart == NULL || (duration_ticks & ~UART_TIMEOUT_CTRL_VAL_MASK) != 0) {
356  return kDifBadArg;
357  }
358 
359  uint32_t reg = bitfield_bit32_write(0, UART_TIMEOUT_CTRL_EN_BIT, true);
360  reg =
361  bitfield_field32_write(reg, UART_TIMEOUT_CTRL_VAL_FIELD, duration_ticks);
362  mmio_region_write32(uart->base_addr, UART_TIMEOUT_CTRL_REG_OFFSET, reg);
363 
364  return kDifOk;
365 }
366 
368  if (uart == NULL) {
369  return kDifBadArg;
370  }
371 
372  uint32_t reg = bitfield_bit32_write(0, UART_TIMEOUT_CTRL_EN_BIT, false);
373  reg = bitfield_field32_write(reg, UART_TIMEOUT_CTRL_VAL_FIELD, 0);
374  mmio_region_write32(uart->base_addr, UART_TIMEOUT_CTRL_REG_OFFSET, reg);
375 
376  return kDifOk;
377 }
378 
380  dif_toggle_t *status,
381  uint32_t *duration_ticks) {
382  if (uart == NULL || status == NULL) {
383  return kDifBadArg;
384  }
385 
386  uint32_t reg =
387  mmio_region_read32(uart->base_addr, UART_TIMEOUT_CTRL_REG_OFFSET);
388  *status = bitfield_bit32_read(reg, UART_TIMEOUT_CTRL_EN_BIT)
391 
392  if (duration_ticks != NULL) {
393  *duration_ticks = bitfield_field32_read(reg, UART_TIMEOUT_CTRL_VAL_FIELD);
394  }
395 
396  return kDifOk;
397 }