Software APIs
dif_uart.c
1 // Copyright lowRISC contributors (OpenTitan project).
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 
10 #include "dif_base.h"
14 
15 #include "uart_regs.h" // Generated.
16 
17 #define UART_INTR_STATE_MASK 0xffffffffu
18 
19 const uint32_t kDifUartFifoSizeBytes = 32u;
20 
21 static bool uart_tx_full(const dif_uart_t *uart) {
22  uint32_t reg = mmio_region_read32(uart->base_addr, UART_STATUS_REG_OFFSET);
23  return bitfield_bit32_read(reg, UART_STATUS_TXFULL_BIT);
24 }
25 
26 static bool uart_tx_idle(const dif_uart_t *uart) {
27  uint32_t reg = mmio_region_read32(uart->base_addr, UART_STATUS_REG_OFFSET);
28  return bitfield_bit32_read(reg, UART_STATUS_TXIDLE_BIT);
29 }
30 
31 static bool uart_rx_empty(const dif_uart_t *uart) {
32  uint32_t reg = mmio_region_read32(uart->base_addr, UART_STATUS_REG_OFFSET);
33  return bitfield_bit32_read(reg, UART_STATUS_RXEMPTY_BIT);
34 }
35 
36 static uint8_t uart_rx_fifo_read(const dif_uart_t *uart) {
37  uint32_t reg = mmio_region_read32(uart->base_addr, UART_RDATA_REG_OFFSET);
38 
39  return (uint8_t)bitfield_field32_read(reg, UART_RDATA_RDATA_FIELD);
40 }
41 
42 static void uart_tx_fifo_write(const dif_uart_t *uart, uint8_t byte) {
43  uint32_t reg = bitfield_field32_write(0, UART_WDATA_WDATA_FIELD, byte);
44  mmio_region_write32(uart->base_addr, UART_WDATA_REG_OFFSET, reg);
45 }
46 
47 static void uart_reset(const dif_uart_t *uart) {
48  mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, 0u);
49 
50  // Write to the relevant bits clears the FIFOs.
51  uint32_t reg = 0;
52  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_RXRST_BIT, true);
53  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_TXRST_BIT, true);
54  mmio_region_write32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
55 
56  mmio_region_write32(uart->base_addr, UART_OVRD_REG_OFFSET, 0u);
57  mmio_region_write32(uart->base_addr, UART_TIMEOUT_CTRL_REG_OFFSET, 0u);
58  mmio_region_write32(uart->base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
59  mmio_region_write32(uart->base_addr, UART_INTR_STATE_REG_OFFSET,
60  UART_INTR_STATE_MASK);
61 }
62 
63 /**
64  * Write up to `bytes_requested` number of bytes to the TX FIFO.
65  */
66 static size_t uart_bytes_send(const dif_uart_t *uart, const uint8_t *data,
67  size_t bytes_requested) {
68  size_t bytes_written = 0;
69  while ((bytes_written < bytes_requested) && !uart_tx_full(uart)) {
70  uart_tx_fifo_write(uart, data[bytes_written]);
71  ++bytes_written;
72  }
73 
74  return bytes_written;
75 }
76 
77 /**
78  * Read up to `bytes_requested` number of bytes from the RX FIFO.
79  */
80 static size_t uart_bytes_receive(const dif_uart_t *uart, size_t bytes_requested,
81  uint8_t *data) {
82  size_t bytes_read = 0;
83  while ((bytes_read < bytes_requested) && !uart_rx_empty(uart)) {
84  data[bytes_read] = uart_rx_fifo_read(uart);
85  ++bytes_read;
86  }
87 
88  return bytes_read;
89 }
90 
92  dif_uart_config_t config) {
93  if (uart == NULL || config.baudrate == 0 || config.clk_freq_hz == 0 ||
94  !dif_is_valid_toggle(config.tx_enable) ||
95  !dif_is_valid_toggle(config.rx_enable)) {
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  : udiv64_slow((uint64_t)config.baudrate << (nco_width + 4),
120  config.clk_freq_hz, NULL);
121  uint32_t nco_masked = nco & UART_CTRL_NCO_MASK;
122 
123  // Requested baudrate is too high for the given clock frequency.
124  if (nco != nco_masked) {
125  return kDifBadArg;
126  }
127 
128  // Check requested RXBLVL is within bounds.
129  uint32_t rxblvl = config.rx_break_level;
130  if ((rxblvl & UART_CTRL_RXBLVL_MASK) != rxblvl) {
131  return kDifBadArg;
132  }
133 
134  // Must be called before the first write to any of the UART registers.
135  uart_reset(uart);
136 
137  // Set baudrate, enable RX and TX, configure parity.
138  uint32_t reg = 0;
139  reg = bitfield_field32_write(reg, UART_CTRL_NCO_FIELD, nco_masked);
140  reg = bitfield_field32_write(reg, UART_CTRL_RXBLVL_FIELD, rxblvl);
141  if (dif_toggle_to_bool(config.tx_enable)) {
142  reg = bitfield_bit32_write(reg, UART_CTRL_TX_BIT, true);
143  }
144  if (dif_toggle_to_bool(config.rx_enable)) {
145  reg = bitfield_bit32_write(reg, UART_CTRL_RX_BIT, true);
146  }
147  if (config.parity_enable == kDifToggleEnabled) {
148  reg = bitfield_bit32_write(reg, UART_CTRL_PARITY_EN_BIT, true);
149  }
150  if (config.parity == kDifUartParityOdd) {
151  reg = bitfield_bit32_write(reg, UART_CTRL_PARITY_ODD_BIT, true);
152  }
153  mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, reg);
154 
155  // Disable interrupts.
156  mmio_region_write32(uart->base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
157 
158  return kDifOk;
159 }
160 
162  const dif_uart_t *uart, dif_uart_rx_break_level_t rx_break_level) {
163  if (uart == NULL) {
164  return kDifBadArg;
165  }
166 
167  uint32_t reg = mmio_region_read32(uart->base_addr, UART_CTRL_REG_OFFSET);
168  reg = bitfield_field32_write(reg, UART_CTRL_RXBLVL_FIELD, rx_break_level);
169  mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, reg);
170 
171  return kDifOk;
172 }
173 
175  dif_uart_watermark_t watermark) {
176  if (uart == NULL) {
177  return kDifBadArg;
178  }
179 
180  // Check if the requested watermark is valid, and get a corresponding
181  // register definition to be written.
182  uint32_t value;
183  switch (watermark) {
185  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL1;
186  break;
188  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL2;
189  break;
191  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL4;
192  break;
194  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL8;
195  break;
197  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL16;
198  break;
200  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL32;
201  break;
203  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL62;
204  break;
205  default:
206  return kDifError;
207  }
208 
209  // Set watermark level.
210  uint32_t reg = mmio_region_read32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET);
211  reg = bitfield_field32_write(reg, UART_FIFO_CTRL_RXILVL_FIELD, value);
212  mmio_region_write32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
213 
214  return kDifOk;
215 }
216 
218  dif_uart_watermark_t watermark) {
219  if (uart == NULL) {
220  return kDifBadArg;
221  }
222 
223  // Check if the requested watermark is valid, and get a corresponding
224  // register definition to be written.
225  uint32_t value;
226  switch (watermark) {
228  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL1;
229  break;
231  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL2;
232  break;
234  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL4;
235  break;
237  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL8;
238  break;
240  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL16;
241  break;
242  default:
243  // The minimal TX watermark is 1 byte, maximal 16 bytes.
244  return kDifError;
245  }
246 
247  // Set watermark level.
248  uint32_t reg = mmio_region_read32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET);
249  reg = bitfield_field32_write(reg, UART_FIFO_CTRL_TXILVL_FIELD, value);
250  mmio_region_write32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
251 
252  return kDifOk;
253 }
254 
256  dif_uart_datapath_t datapath,
257  dif_toggle_t enabled) {
258  if (uart == NULL || !dif_is_valid_toggle(enabled)) {
259  return kDifBadArg;
260  }
261 
262  uint32_t reg = mmio_region_read32(uart->base_addr, UART_CTRL_REG_OFFSET);
263 
264  switch (datapath) {
265  case kDifUartDatapathRx:
266  reg = bitfield_bit32_write(reg, UART_CTRL_RX_BIT,
267  dif_toggle_to_bool(enabled));
268  break;
269  case kDifUartDatapathTx:
270  reg = bitfield_bit32_write(reg, UART_CTRL_TX_BIT,
271  dif_toggle_to_bool(enabled));
272  break;
273  case kDifUartDatapathAll:
274  reg = bitfield_bit32_write(reg, UART_CTRL_RX_BIT,
275  dif_toggle_to_bool(enabled));
276  reg = bitfield_bit32_write(reg, UART_CTRL_TX_BIT,
277  dif_toggle_to_bool(enabled));
278  break;
279  default:
280  return kDifBadArg;
281  }
282 
283  mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, reg);
284 
285  return kDifOk;
286 }
287 
288 dif_result_t dif_uart_bytes_send(const dif_uart_t *uart, const uint8_t *data,
289  size_t bytes_requested,
290  size_t *bytes_written) {
291  if (uart == NULL || data == NULL) {
292  return kDifBadArg;
293  }
294 
295  // `bytes_written` is an optional parameter.
296  size_t res = uart_bytes_send(uart, data, bytes_requested);
297  if (bytes_written != NULL) {
298  *bytes_written = res;
299  }
300 
301  return kDifOk;
302 }
303 
305  size_t bytes_requested, uint8_t *data,
306  size_t *bytes_read) {
307  if (uart == NULL || data == NULL) {
308  return kDifBadArg;
309  }
310 
311  // `bytes_read` is an optional parameter.
312  size_t res = uart_bytes_receive(uart, bytes_requested, data);
313  if (bytes_read != NULL) {
314  *bytes_read = res;
315  }
316 
317  return kDifOk;
318 }
319 
321  if (uart == NULL) {
322  return kDifBadArg;
323  }
324 
325  // Busy wait for the TX FIFO to free up.
326  while (uart_tx_full(uart)) {
327  }
328 
329  (void)uart_bytes_send(uart, &byte, 1);
330 
331  // Busy wait for the TX FIFO to be drained and for HW to finish processing
332  // the last byte.
333  while (!uart_tx_idle(uart)) {
334  }
335 
336  return kDifOk;
337 }
338 
340  uint8_t *byte) {
341  if (uart == NULL || byte == NULL) {
342  return kDifBadArg;
343  }
344 
345  // Busy wait for the RX message in the FIFO.
346  while (uart_rx_empty(uart)) {
347  }
348 
349  (void)uart_bytes_receive(uart, 1, byte);
350 
351  return kDifOk;
352 }
353 
355  size_t *num_bytes) {
356  if (uart == NULL || num_bytes == NULL) {
357  return kDifBadArg;
358  }
359 
360  // RX FIFO fill level (in bytes).
361  uint32_t reg =
362  mmio_region_read32(uart->base_addr, UART_FIFO_STATUS_REG_OFFSET);
363  *num_bytes = (size_t)bitfield_field32_read(reg, UART_FIFO_STATUS_RXLVL_FIELD);
364 
365  return kDifOk;
366 }
367 
369  size_t *num_bytes) {
370  if (uart == NULL || num_bytes == NULL) {
371  return kDifBadArg;
372  }
373 
374  // TX FIFO fill level (in bytes).
375  uint32_t reg =
376  mmio_region_read32(uart->base_addr, UART_FIFO_STATUS_REG_OFFSET);
377  uint32_t fill_bytes =
378  bitfield_field32_read(reg, UART_FIFO_STATUS_TXLVL_FIELD);
379  *num_bytes = kDifUartFifoSizeBytes - fill_bytes;
380 
381  return kDifOk;
382 }
383 
385  dif_uart_datapath_t fifo) {
386  if (uart == NULL) {
387  return kDifBadArg;
388  }
389 
390  uint32_t reg = mmio_region_read32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET);
391 
392  switch (fifo) {
393  case kDifUartDatapathRx:
394  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_RXRST_BIT, true);
395  break;
396  case kDifUartDatapathTx:
397  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_TXRST_BIT, true);
398  break;
399  case kDifUartDatapathAll:
400  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_RXRST_BIT, true);
401  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_TXRST_BIT, true);
402  break;
403  default:
404  return kDifBadArg;
405  }
406 
407  mmio_region_write32(uart->base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
408 
409  return kDifOk;
410 }
411 
413  dif_uart_loopback_t loopback,
414  dif_toggle_t enable) {
415  if (uart == NULL) {
416  return kDifBadArg;
417  }
418 
419  uint32_t index = loopback ? UART_CTRL_LLPBK_BIT : UART_CTRL_SLPBK_BIT;
420  uint32_t reg = mmio_region_read32(uart->base_addr, UART_CTRL_REG_OFFSET);
421  reg = bitfield_bit32_write(reg, index, enable == kDifToggleEnabled);
422  mmio_region_write32(uart->base_addr, UART_CTRL_REG_OFFSET, reg);
423 
424  return kDifOk;
425 }
426 
428  uint32_t duration_ticks) {
429  if (uart == NULL ||
430  (duration_ticks & ~(uint32_t)UART_TIMEOUT_CTRL_VAL_MASK) != 0) {
431  return kDifBadArg;
432  }
433 
434  uint32_t reg = bitfield_bit32_write(0, UART_TIMEOUT_CTRL_EN_BIT, true);
435  reg =
436  bitfield_field32_write(reg, UART_TIMEOUT_CTRL_VAL_FIELD, duration_ticks);
437  mmio_region_write32(uart->base_addr, UART_TIMEOUT_CTRL_REG_OFFSET, reg);
438 
439  return kDifOk;
440 }
441 
443  if (uart == NULL) {
444  return kDifBadArg;
445  }
446 
447  uint32_t reg = bitfield_bit32_write(0, UART_TIMEOUT_CTRL_EN_BIT, false);
448  reg = bitfield_field32_write(reg, UART_TIMEOUT_CTRL_VAL_FIELD, 0);
449  mmio_region_write32(uart->base_addr, UART_TIMEOUT_CTRL_REG_OFFSET, reg);
450 
451  return kDifOk;
452 }
453 
456  uint32_t *duration_ticks) {
457  if (uart == NULL || status == NULL) {
458  return kDifBadArg;
459  }
460 
461  uint32_t reg =
462  mmio_region_read32(uart->base_addr, UART_TIMEOUT_CTRL_REG_OFFSET);
463  *status = bitfield_bit32_read(reg, UART_TIMEOUT_CTRL_EN_BIT)
466 
467  if (duration_ticks != NULL) {
468  *duration_ticks = bitfield_field32_read(reg, UART_TIMEOUT_CTRL_VAL_FIELD);
469  }
470 
471  return kDifOk;
472 }