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 <stddef.h>
8 
11 
12 #include "uart_regs.h" // Generated.
13 
14 #define UART_INTR_STATE_MASK 0xffffffffu
15 
16 const uint32_t kDifUartFifoSizeBytes = 32u;
17 
18 static bool uart_tx_full(const dif_uart_t *uart) {
19  uint32_t reg =
20  mmio_region_read32(uart->params.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 =
26  mmio_region_read32(uart->params.base_addr, UART_STATUS_REG_OFFSET);
27  return bitfield_bit32_read(reg, UART_STATUS_TXIDLE_BIT);
28 }
29 
30 static bool uart_rx_empty(const dif_uart_t *uart) {
31  uint32_t reg =
32  mmio_region_read32(uart->params.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 =
38  mmio_region_read32(uart->params.base_addr, UART_RDATA_REG_OFFSET);
39 
40  return bitfield_field32_read(reg, UART_RDATA_RDATA_FIELD);
41 }
42 
43 static void uart_tx_fifo_write(const dif_uart_t *uart, uint8_t byte) {
44  uint32_t reg = bitfield_field32_write(0, UART_WDATA_WDATA_FIELD, byte);
45  mmio_region_write32(uart->params.base_addr, UART_WDATA_REG_OFFSET, reg);
46 }
47 
48 /**
49  * Get the corresponding interrupt register bit offset. INTR_STATE, INTR_ENABLE
50  * and INTR_TEST registers have the same bit offsets, so this routine can be
51  * reused.
52  */
53 static bool uart_irq_offset_get(dif_uart_irq_t irq_type,
54  ptrdiff_t *offset_out) {
55  ptrdiff_t offset;
56  switch (irq_type) {
58  offset = UART_INTR_STATE_TX_WATERMARK_BIT;
59  break;
61  offset = UART_INTR_STATE_RX_WATERMARK_BIT;
62  break;
63  case kDifUartIrqTxEmpty:
64  offset = UART_INTR_STATE_TX_EMPTY_BIT;
65  break;
67  offset = UART_INTR_STATE_RX_OVERFLOW_BIT;
68  break;
70  offset = UART_INTR_STATE_RX_FRAME_ERR_BIT;
71  break;
73  offset = UART_INTR_STATE_RX_BREAK_ERR_BIT;
74  break;
76  offset = UART_INTR_STATE_RX_TIMEOUT_BIT;
77  break;
79  offset = UART_INTR_STATE_RX_PARITY_ERR_BIT;
80  break;
81  default:
82  return false;
83  }
84 
85  *offset_out = offset;
86 
87  return true;
88 }
89 
90 static void uart_reset(const dif_uart_t *uart) {
91  mmio_region_write32(uart->params.base_addr, UART_CTRL_REG_OFFSET, 0u);
92 
93  // Write to the relevant bits clears the FIFOs.
94  uint32_t reg = 0;
95  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_RXRST_BIT, true);
96  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_TXRST_BIT, true);
97  mmio_region_write32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
98 
99  mmio_region_write32(uart->params.base_addr, UART_OVRD_REG_OFFSET, 0u);
100  mmio_region_write32(uart->params.base_addr, UART_TIMEOUT_CTRL_REG_OFFSET, 0u);
101  mmio_region_write32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
102  mmio_region_write32(uart->params.base_addr, UART_INTR_STATE_REG_OFFSET,
103  UART_INTR_STATE_MASK);
104 }
105 
106 /**
107  * Write up to `bytes_requested` number of bytes to the TX FIFO.
108  */
109 static size_t uart_bytes_send(const dif_uart_t *uart, const uint8_t *data,
110  size_t bytes_requested) {
111  size_t bytes_written = 0;
112  while ((bytes_written < bytes_requested) && !uart_tx_full(uart)) {
113  uart_tx_fifo_write(uart, data[bytes_written]);
114  ++bytes_written;
115  }
116 
117  return bytes_written;
118 }
119 
120 /**
121  * Read up to `bytes_requested` number of bytes from the RX FIFO.
122  */
123 static size_t uart_bytes_receive(const dif_uart_t *uart, size_t bytes_requested,
124  uint8_t *data) {
125  size_t bytes_read = 0;
126  while ((bytes_read < bytes_requested) && !uart_rx_empty(uart)) {
127  data[bytes_read] = uart_rx_fifo_read(uart);
128  ++bytes_read;
129  }
130 
131  return bytes_read;
132 }
133 
135  if (uart == NULL) {
136  return kDifUartBadArg;
137  }
138 
139  uart->params = params;
140  return kDifUartOk;
141 }
142 
144  dif_uart_config_t config) {
145  if (uart == NULL) {
146  return kDifUartConfigBadArg;
147  }
148 
149  if (config.baudrate == 0 || config.clk_freq_hz == 0) {
151  }
152 
153  // Calculation formula: NCO = 16 * 2^nco_width * baud / fclk.
154 
155  // Compute NCO register bit width
156  uint32_t nco_width = 0;
157 
158  for (int i = 0; i < 32; i++) {
159  nco_width += (UART_CTRL_NCO_MASK >> i) & 1;
160  }
161 
162  _Static_assert((UART_CTRL_NCO_MASK >> 28) == 0,
163  "NCO bit width exceeds 28 bits.");
164 
165  // NCO creates 16x of baudrate. So, in addition to the nco_width,
166  // 2^4 should be multiplied.
167  uint64_t nco =
168  ((uint64_t)config.baudrate << (nco_width + 4)) / config.clk_freq_hz;
169  uint32_t nco_masked = nco & UART_CTRL_NCO_MASK;
170 
171  // Requested baudrate is too high for the given clock frequency.
172  if (nco != nco_masked) {
173  return kDifUartConfigBadNco;
174  }
175 
176  // Must be called before the first write to any of the UART registers.
177  uart_reset(uart);
178 
179  // Set baudrate, enable RX and TX, configure parity.
180  uint32_t reg = 0;
181  reg = bitfield_field32_write(reg, UART_CTRL_NCO_FIELD, nco_masked);
182  reg = bitfield_bit32_write(reg, UART_CTRL_TX_BIT, true);
183  reg = bitfield_bit32_write(reg, UART_CTRL_RX_BIT, true);
184  if (config.parity_enable == kDifUartToggleEnabled) {
185  reg = bitfield_bit32_write(reg, UART_CTRL_PARITY_EN_BIT, true);
186  }
187  if (config.parity == kDifUartParityOdd) {
188  reg = bitfield_bit32_write(reg, UART_CTRL_PARITY_ODD_BIT, true);
189  }
190  mmio_region_write32(uart->params.base_addr, UART_CTRL_REG_OFFSET, reg);
191 
192  // Disable interrupts.
193  mmio_region_write32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
194 
195  return kDifUartConfigOk;
196 }
197 
199  dif_uart_irq_t irq,
200  bool *is_pending) {
201  if (uart == NULL || is_pending == NULL) {
202  return kDifUartBadArg;
203  }
204 
205  ptrdiff_t offset;
206  if (!uart_irq_offset_get(irq, &offset)) {
207  return kDifUartError;
208  }
209 
210  uint32_t reg =
211  mmio_region_read32(uart->params.base_addr, UART_INTR_STATE_REG_OFFSET);
212  *is_pending = bitfield_bit32_read(reg, offset);
213 
214  return kDifUartOk;
215 }
216 
218  dif_uart_irq_t irq) {
219  if (uart == NULL) {
220  return kDifUartBadArg;
221  }
222 
223  ptrdiff_t offset;
224  if (!uart_irq_offset_get(irq, &offset)) {
225  return kDifUartError;
226  }
227 
228  // Writing to the register clears the corresponding bits (Write-one clear).
229  uint32_t reg = bitfield_bit32_write(0, offset, true);
230  mmio_region_write32(uart->params.base_addr, UART_INTR_STATE_REG_OFFSET, reg);
231 
232  return kDifUartOk;
233 }
234 
236  dif_uart_irq_snapshot_t *snapshot) {
237  if (uart == NULL) {
238  return kDifUartBadArg;
239  }
240 
241  // Pass the current interrupt state to the caller.
242  if (snapshot != NULL) {
243  *snapshot =
244  mmio_region_read32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET);
245  }
246 
247  // Disable all UART interrupts.
248  mmio_region_write32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
249 
250  return kDifUartOk;
251 }
252 
254  const dif_uart_t *uart, const dif_uart_irq_snapshot_t *snapshot) {
255  if (uart == NULL || snapshot == NULL) {
256  return kDifUartBadArg;
257  }
258 
259  mmio_region_write32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET,
260  *snapshot);
261 
262  return kDifUartOk;
263 }
264 
266  dif_uart_irq_t irq,
267  dif_uart_toggle_t *state) {
268  if (uart == NULL || state == NULL) {
269  return kDifUartBadArg;
270  }
271 
272  ptrdiff_t offset;
273  if (!uart_irq_offset_get(irq, &offset)) {
274  return kDifUartError;
275  }
276 
277  uint32_t reg =
278  mmio_region_read32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET);
279 
280  bool is_enabled = bitfield_bit32_read(reg, offset);
281  *state = is_enabled ? kDifUartToggleEnabled : kDifUartToggleDisabled;
282 
283  return kDifUartOk;
284 }
285 
287  dif_uart_irq_t irq,
288  dif_uart_toggle_t state) {
289  if (uart == NULL) {
290  return kDifUartBadArg;
291  }
292 
293  ptrdiff_t offset;
294  if (!uart_irq_offset_get(irq, &offset)) {
295  return kDifUartError;
296  }
297 
298  uint32_t reg =
299  mmio_region_read32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET);
300  bool bit = (state == kDifUartToggleEnabled) ? true : false;
301  reg = bitfield_bit32_write(reg, offset, bit);
302  mmio_region_write32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET, reg);
303 
304  return kDifUartOk;
305 }
306 
308  dif_uart_irq_t irq) {
309  if (uart == NULL) {
310  return kDifUartBadArg;
311  }
312 
313  ptrdiff_t offset;
314  if (!uart_irq_offset_get(irq, &offset)) {
315  return kDifUartError;
316  }
317 
318  // Force the requested interrupt (write-only).
319  uint32_t reg = bitfield_bit32_write(0, offset, true);
320  mmio_region_write32(uart->params.base_addr, UART_INTR_TEST_REG_OFFSET, reg);
321 
322  return kDifUartOk;
323 }
324 
326  dif_uart_watermark_t watermark) {
327  if (uart == NULL) {
328  return kDifUartBadArg;
329  }
330 
331  // Check if the requested watermark is valid, and get a corresponding
332  // register definition to be written.
333  uint32_t value;
334  switch (watermark) {
336  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL1;
337  break;
339  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL4;
340  break;
342  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL8;
343  break;
345  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL16;
346  break;
348  value = UART_FIFO_CTRL_RXILVL_VALUE_RXLVL30;
349  break;
350  default:
351  return kDifUartError;
352  }
353 
354  // Set watermark level.
355  uint32_t reg =
356  mmio_region_read32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET);
357  reg = bitfield_field32_write(reg, UART_FIFO_CTRL_RXILVL_FIELD, value);
358  mmio_region_write32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
359 
360  return kDifUartOk;
361 }
362 
364  dif_uart_watermark_t watermark) {
365  if (uart == NULL) {
366  return kDifUartBadArg;
367  }
368 
369  // Check if the requested watermark is valid, and get a corresponding
370  // register definition to be written.
371  uint32_t value;
372  switch (watermark) {
374  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL1;
375  break;
377  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL4;
378  break;
380  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL8;
381  break;
383  value = UART_FIFO_CTRL_TXILVL_VALUE_TXLVL16;
384  break;
385  default:
386  // The minimal TX watermark is 1 byte, maximal 16 bytes.
387  return kDifUartError;
388  }
389 
390  // Set watermark level.
391  uint32_t reg =
392  mmio_region_read32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET);
393  reg = bitfield_field32_write(reg, UART_FIFO_CTRL_TXILVL_FIELD, value);
394  mmio_region_write32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
395 
396  return kDifUartOk;
397 }
398 
400  const uint8_t *data,
401  size_t bytes_requested,
402  size_t *bytes_written) {
403  if (uart == NULL || data == NULL) {
404  return kDifUartBadArg;
405  }
406 
407  // `bytes_written` is an optional parameter.
408  size_t res = uart_bytes_send(uart, data, bytes_requested);
409  if (bytes_written != NULL) {
410  *bytes_written = res;
411  }
412 
413  return kDifUartOk;
414 }
415 
417  size_t bytes_requested, uint8_t *data,
418  size_t *bytes_read) {
419  if (uart == NULL || data == NULL) {
420  return kDifUartBadArg;
421  }
422 
423  // `bytes_read` is an optional parameter.
424  size_t res = uart_bytes_receive(uart, bytes_requested, data);
425  if (bytes_read != NULL) {
426  *bytes_read = res;
427  }
428 
429  return kDifUartOk;
430 }
431 
433  uint8_t byte) {
434  if (uart == NULL) {
435  return kDifUartBadArg;
436  }
437 
438  // Busy wait for the TX FIFO to free up.
439  while (uart_tx_full(uart)) {
440  }
441 
442  (void)uart_bytes_send(uart, &byte, 1);
443 
444  // Busy wait for the TX FIFO to be drained and for HW to finish processing
445  // the last byte.
446  while (!uart_tx_idle(uart)) {
447  }
448 
449  return kDifUartOk;
450 }
451 
453  uint8_t *byte) {
454  if (uart == NULL || byte == NULL) {
455  return kDifUartBadArg;
456  }
457 
458  // Busy wait for the RX message in the FIFO.
459  while (uart_rx_empty(uart)) {
460  }
461 
462  (void)uart_bytes_receive(uart, 1, byte);
463 
464  return kDifUartOk;
465 }
466 
468  size_t *num_bytes) {
469  if (uart == NULL || num_bytes == NULL) {
470  return kDifUartBadArg;
471  }
472 
473  // RX FIFO fill level (in bytes).
474  uint32_t reg =
475  mmio_region_read32(uart->params.base_addr, UART_FIFO_STATUS_REG_OFFSET);
476  *num_bytes = (size_t)bitfield_field32_read(reg, UART_FIFO_STATUS_RXLVL_FIELD);
477 
478  return kDifUartOk;
479 }
480 
482  size_t *num_bytes) {
483  if (uart == NULL || num_bytes == NULL) {
484  return kDifUartBadArg;
485  }
486 
487  // TX FIFO fill level (in bytes).
488  uint32_t reg =
489  mmio_region_read32(uart->params.base_addr, UART_FIFO_STATUS_REG_OFFSET);
490  uint32_t fill_bytes =
491  bitfield_field32_read(reg, UART_FIFO_STATUS_TXLVL_FIELD);
492  *num_bytes = kDifUartFifoSizeBytes - fill_bytes;
493 
494  return kDifUartOk;
495 }
496 
498  dif_uart_fifo_reset_t reset) {
499  if (uart == NULL) {
500  return kDifUartBadArg;
501  }
502 
503  uint32_t reg =
504  mmio_region_read32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET);
505 
506  if (reset == kDifUartFifoResetRx || reset == kDifUartFifoResetAll) {
507  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_RXRST_BIT, true);
508  }
509 
510  if (reset == kDifUartFifoResetTx || reset == kDifUartFifoResetAll) {
511  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_TXRST_BIT, true);
512  }
513 
514  mmio_region_write32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
515 
516  return kDifUartOk;
517 }
518 
520  dif_uart_loopback_t loopback,
521  dif_uart_toggle_t enable) {
522  if (uart == NULL) {
523  return kDifUartBadArg;
524  }
525 
526  uint32_t index = loopback ? UART_CTRL_LLPBK_BIT : UART_CTRL_SLPBK_BIT;
527  uint32_t reg =
528  mmio_region_read32(uart->params.base_addr, UART_CTRL_REG_OFFSET);
529  reg = bitfield_bit32_write(reg, index, enable == kDifUartToggleEnabled);
530  mmio_region_write32(uart->params.base_addr, UART_CTRL_REG_OFFSET, reg);
531 
532  return kDifUartOk;
533 }
534 
536  uint32_t duration_ticks) {
537  if (uart == NULL || (duration_ticks & ~UART_TIMEOUT_CTRL_VAL_MASK) != 0) {
538  return kDifUartBadArg;
539  }
540 
541  uint32_t reg = bitfield_bit32_write(0, UART_TIMEOUT_CTRL_EN_BIT, true);
542  reg =
543  bitfield_field32_write(reg, UART_TIMEOUT_CTRL_VAL_FIELD, duration_ticks);
544  mmio_region_write32(uart->params.base_addr, UART_TIMEOUT_CTRL_REG_OFFSET,
545  reg);
546 
547  return kDifUartOk;
548 }
549 
551  if (uart == NULL) {
552  return kDifUartBadArg;
553  }
554 
555  uint32_t reg = bitfield_bit32_write(0, UART_TIMEOUT_CTRL_EN_BIT, false);
556  reg = bitfield_field32_write(reg, UART_TIMEOUT_CTRL_VAL_FIELD, 0);
557  mmio_region_write32(uart->params.base_addr, UART_TIMEOUT_CTRL_REG_OFFSET,
558  reg);
559 
560  return kDifUartOk;
561 }
562 
564  dif_uart_toggle_t *status,
565  uint32_t *duration_ticks) {
566  if (uart == NULL || status == NULL) {
567  return kDifUartBadArg;
568  }
569 
570  uint32_t reg =
571  mmio_region_read32(uart->params.base_addr, UART_TIMEOUT_CTRL_REG_OFFSET);
572  *status = bitfield_bit32_read(reg, UART_TIMEOUT_CTRL_EN_BIT)
575 
576  if (duration_ticks != NULL) {
577  *duration_ticks = bitfield_field32_read(reg, UART_TIMEOUT_CTRL_VAL_FIELD);
578  }
579 
580  return kDifUartOk;
581 }