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  return mmio_region_get_bit32(uart->params.base_addr, UART_STATUS_REG_OFFSET,
20  UART_STATUS_TXFULL);
21 }
22 
23 static bool uart_tx_idle(const dif_uart_t *uart) {
24  return mmio_region_get_bit32(uart->params.base_addr, UART_STATUS_REG_OFFSET,
25  UART_STATUS_TXIDLE);
26 }
27 
28 static bool uart_rx_empty(const dif_uart_t *uart) {
29  return mmio_region_get_bit32(uart->params.base_addr, UART_STATUS_REG_OFFSET,
30  UART_STATUS_RXEMPTY);
31 }
32 
33 static uint8_t uart_rx_fifo_read(const dif_uart_t *uart) {
34  uint32_t reg =
35  mmio_region_read32(uart->params.base_addr, UART_RDATA_REG_OFFSET);
36 
37  return reg & UART_RDATA_RDATA_MASK;
38 }
39 
40 static void uart_tx_fifo_write(const dif_uart_t *uart, uint8_t byte) {
41  uint32_t reg = (byte & UART_WDATA_WDATA_MASK) << UART_WDATA_WDATA_OFFSET;
42  mmio_region_write32(uart->params.base_addr, UART_WDATA_REG_OFFSET, reg);
43 }
44 
45 /**
46  * Get the corresponding interrupt register bit offset. INTR_STATE, INTR_ENABLE
47  * and INTR_TEST registers have the same bit offsets, so this routine can be
48  * reused.
49  */
50 static bool uart_irq_offset_get(dif_uart_irq_t irq_type,
51  ptrdiff_t *offset_out) {
52  ptrdiff_t offset;
53  switch (irq_type) {
55  offset = UART_INTR_STATE_TX_WATERMARK;
56  break;
58  offset = UART_INTR_STATE_RX_WATERMARK;
59  break;
60  case kDifUartIrqTxEmpty:
61  offset = UART_INTR_STATE_TX_EMPTY;
62  break;
64  offset = UART_INTR_STATE_RX_OVERFLOW;
65  break;
67  offset = UART_INTR_STATE_RX_FRAME_ERR;
68  break;
70  offset = UART_INTR_STATE_RX_BREAK_ERR;
71  break;
73  offset = UART_INTR_STATE_RX_TIMEOUT;
74  break;
76  offset = UART_INTR_STATE_RX_PARITY_ERR;
77  break;
78  default:
79  return false;
80  }
81 
82  *offset_out = offset;
83 
84  return true;
85 }
86 
87 static void uart_reset(const dif_uart_t *uart) {
88  mmio_region_write32(uart->params.base_addr, UART_CTRL_REG_OFFSET, 0u);
89  // Write to the relevant bits clears the FIFOs.
91  uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET,
92  (1u << UART_FIFO_CTRL_RXRST) | (1u << UART_FIFO_CTRL_TXRST));
93  mmio_region_write32(uart->params.base_addr, UART_OVRD_REG_OFFSET, 0u);
94  mmio_region_write32(uart->params.base_addr, UART_TIMEOUT_CTRL_REG_OFFSET, 0u);
95  mmio_region_write32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
96  mmio_region_write32(uart->params.base_addr, UART_INTR_STATE_REG_OFFSET,
97  UART_INTR_STATE_MASK);
98 }
99 
100 /**
101  * Write up to `bytes_requested` number of bytes to the TX FIFO.
102  */
103 static size_t uart_bytes_send(const dif_uart_t *uart, const uint8_t *data,
104  size_t bytes_requested) {
105  size_t bytes_written = 0;
106  while ((bytes_written < bytes_requested) && !uart_tx_full(uart)) {
107  uart_tx_fifo_write(uart, data[bytes_written]);
108  ++bytes_written;
109  }
110 
111  return bytes_written;
112 }
113 
114 /**
115  * Read up to `bytes_requested` number of bytes from the RX FIFO.
116  */
117 static size_t uart_bytes_receive(const dif_uart_t *uart, size_t bytes_requested,
118  uint8_t *data) {
119  size_t bytes_read = 0;
120  while ((bytes_read < bytes_requested) && !uart_rx_empty(uart)) {
121  data[bytes_read] = uart_rx_fifo_read(uart);
122  ++bytes_read;
123  }
124 
125  return bytes_read;
126 }
127 
129  if (uart == NULL) {
130  return kDifUartBadArg;
131  }
132 
133  uart->params = params;
134  return kDifUartOk;
135 }
136 
138  dif_uart_config_t config) {
139  if (uart == NULL) {
140  return kDifUartConfigBadArg;
141  }
142 
143  if (config.baudrate == 0 || config.clk_freq_hz == 0) {
145  }
146 
147  // Calculation formula: NCO = 16 * 2^nco_width * baud / fclk.
148 
149  // Compute NCO register bit width
150  uint32_t nco_width = 0;
151 
152  for (int i = 0; i < 32; i++) {
153  nco_width += (UART_CTRL_NCO_MASK >> i) & 1;
154  }
155 
156  _Static_assert((UART_CTRL_NCO_MASK >> 28) == 0,
157  "NCO bit width exceeds 28 bits.");
158 
159  // NCO creates 16x of baudrate. So, in addition to the nco_width,
160  // 2^4 should be multiplied.
161  uint64_t nco =
162  ((uint64_t)config.baudrate << (nco_width + 4)) / config.clk_freq_hz;
163  uint32_t nco_masked = nco & UART_CTRL_NCO_MASK;
164 
165  // Requested baudrate is too high for the given clock frequency.
166  if (nco != nco_masked) {
167  return kDifUartConfigBadNco;
168  }
169 
170  // Must be called before the first write to any of the UART registers.
171  uart_reset(uart);
172 
173  // Set baudrate, enable RX and TX, configure parity.
174  uint32_t reg = (nco_masked << UART_CTRL_NCO_OFFSET);
175  reg |= (1u << UART_CTRL_TX);
176  reg |= (1u << UART_CTRL_RX);
177  if (config.parity_enable == kDifUartToggleEnabled) {
178  reg |= (1u << UART_CTRL_PARITY_EN);
179  }
180  if (config.parity == kDifUartParityOdd) {
181  reg |= (1u << UART_CTRL_PARITY_ODD);
182  }
183  mmio_region_write32(uart->params.base_addr, UART_CTRL_REG_OFFSET, reg);
184 
185  // Reset RX/TX FIFOs.
186  reg = (1u << UART_FIFO_CTRL_RXRST);
187  reg |= (1u << UART_FIFO_CTRL_TXRST);
188  mmio_region_write32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
189 
190  // Disable interrupts.
191  mmio_region_write32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
192 
193  return kDifUartConfigOk;
194 }
195 
197  dif_uart_irq_t irq,
198  bool *is_pending) {
199  if (uart == NULL || is_pending == NULL) {
200  return kDifUartBadArg;
201  }
202 
203  ptrdiff_t offset;
204  if (!uart_irq_offset_get(irq, &offset)) {
205  return kDifUartError;
206  }
207 
208  *is_pending = mmio_region_get_bit32(uart->params.base_addr,
209  UART_INTR_STATE_REG_OFFSET, offset);
210  return kDifUartOk;
211 }
212 
214  dif_uart_irq_t irq) {
215  if (uart == NULL) {
216  return kDifUartBadArg;
217  }
218 
219  ptrdiff_t offset;
220  if (!uart_irq_offset_get(irq, &offset)) {
221  return kDifUartError;
222  }
223 
224  // Writing to the register clears the corresponding bits.
226  UART_INTR_STATE_REG_OFFSET, offset);
227 
228  return kDifUartOk;
229 }
230 
232  dif_uart_irq_snapshot_t *snapshot) {
233  if (uart == NULL) {
234  return kDifUartBadArg;
235  }
236 
237  // Pass the current interrupt state to the caller.
238  if (snapshot != NULL) {
239  *snapshot =
240  mmio_region_read32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET);
241  }
242 
243  // Disable all UART interrupts.
244  mmio_region_write32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET, 0u);
245 
246  return kDifUartOk;
247 }
248 
250  const dif_uart_t *uart, const dif_uart_irq_snapshot_t *snapshot) {
251  if (uart == NULL || snapshot == NULL) {
252  return kDifUartBadArg;
253  }
254 
255  mmio_region_write32(uart->params.base_addr, UART_INTR_ENABLE_REG_OFFSET,
256  *snapshot);
257 
258  return kDifUartOk;
259 }
260 
262  dif_uart_irq_t irq,
263  dif_uart_toggle_t *state) {
264  if (uart == NULL || state == NULL) {
265  return kDifUartBadArg;
266  }
267 
268  ptrdiff_t offset;
269  if (!uart_irq_offset_get(irq, &offset)) {
270  return kDifUartError;
271  }
272 
273  bool is_enabled = mmio_region_get_bit32(uart->params.base_addr,
274  UART_INTR_ENABLE_REG_OFFSET, offset);
275  *state = is_enabled ? kDifUartToggleEnabled : kDifUartToggleDisabled;
276 
277  return kDifUartOk;
278 }
279 
281  dif_uart_irq_t irq,
282  dif_uart_toggle_t state) {
283  if (uart == NULL) {
284  return kDifUartBadArg;
285  }
286 
287  ptrdiff_t offset;
288  if (!uart_irq_offset_get(irq, &offset)) {
289  return kDifUartError;
290  }
291 
292  if (state == kDifUartToggleEnabled) {
294  UART_INTR_ENABLE_REG_OFFSET, offset);
295  } else {
297  UART_INTR_ENABLE_REG_OFFSET, offset);
298  }
299 
300  return kDifUartOk;
301 }
302 
304  dif_uart_irq_t irq) {
305  if (uart == NULL) {
306  return kDifUartBadArg;
307  }
308 
309  ptrdiff_t offset;
310  if (!uart_irq_offset_get(irq, &offset)) {
311  return kDifUartError;
312  }
313 
314  // Force the requested interrupt.
316  UART_INTR_TEST_REG_OFFSET, offset);
317 
318  return kDifUartOk;
319 }
320 
322  dif_uart_watermark_t watermark) {
323  if (uart == NULL) {
324  return kDifUartBadArg;
325  }
326 
327  // Check if the requested watermark is valid, and get a corresponding
328  // register definition to be written.
329  bitfield_field32_t field = {
330  .mask = UART_FIFO_CTRL_RXILVL_MASK, .index = UART_FIFO_CTRL_RXILVL_OFFSET,
331  };
332  uint32_t value;
333  switch (watermark) {
335  value = UART_FIFO_CTRL_RXILVL_RXLVL1;
336  break;
338  value = UART_FIFO_CTRL_RXILVL_RXLVL4;
339  break;
341  value = UART_FIFO_CTRL_RXILVL_RXLVL8;
342  break;
344  value = UART_FIFO_CTRL_RXILVL_RXLVL16;
345  break;
347  value = UART_FIFO_CTRL_RXILVL_RXLVL30;
348  break;
349  default:
350  return kDifUartError;
351  }
352 
353  // Set watermark level.
355  UART_FIFO_CTRL_REG_OFFSET, field, value);
356 
357  return kDifUartOk;
358 }
359 
361  dif_uart_watermark_t watermark) {
362  if (uart == NULL) {
363  return kDifUartBadArg;
364  }
365 
366  // Check if the requested watermark is valid, and get a corresponding
367  // register definition to be written.
368  bitfield_field32_t field = {
369  .mask = UART_FIFO_CTRL_TXILVL_MASK, .index = UART_FIFO_CTRL_TXILVL_OFFSET,
370  };
371  uint32_t value;
372  switch (watermark) {
374  value = UART_FIFO_CTRL_TXILVL_TXLVL1;
375  break;
377  value = UART_FIFO_CTRL_TXILVL_TXLVL4;
378  break;
380  value = UART_FIFO_CTRL_TXILVL_TXLVL8;
381  break;
383  value = UART_FIFO_CTRL_TXILVL_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.
392  UART_FIFO_CTRL_REG_OFFSET, field, value);
393 
394  return kDifUartOk;
395 }
396 
398  const uint8_t *data,
399  size_t bytes_requested,
400  size_t *bytes_written) {
401  if (uart == NULL || data == NULL) {
402  return kDifUartBadArg;
403  }
404 
405  // `bytes_written` is an optional parameter.
406  size_t res = uart_bytes_send(uart, data, bytes_requested);
407  if (bytes_written != NULL) {
408  *bytes_written = res;
409  }
410 
411  return kDifUartOk;
412 }
413 
415  size_t bytes_requested, uint8_t *data,
416  size_t *bytes_read) {
417  if (uart == NULL || data == NULL) {
418  return kDifUartBadArg;
419  }
420 
421  // `bytes_read` is an optional parameter.
422  size_t res = uart_bytes_receive(uart, bytes_requested, data);
423  if (bytes_read != NULL) {
424  *bytes_read = res;
425  }
426 
427  return kDifUartOk;
428 }
429 
431  uint8_t byte) {
432  if (uart == NULL) {
433  return kDifUartBadArg;
434  }
435 
436  // Busy wait for the TX FIFO to free up.
437  while (uart_tx_full(uart)) {
438  }
439 
440  (void)uart_bytes_send(uart, &byte, 1);
441 
442  // Busy wait for the TX FIFO to be drained and for HW to finish processing
443  // the last byte.
444  while (!uart_tx_idle(uart)) {
445  }
446 
447  return kDifUartOk;
448 }
449 
451  uint8_t *byte) {
452  if (uart == NULL || byte == NULL) {
453  return kDifUartBadArg;
454  }
455 
456  // Busy wait for the RX message in the FIFO.
457  while (uart_rx_empty(uart)) {
458  }
459 
460  (void)uart_bytes_receive(uart, 1, byte);
461 
462  return kDifUartOk;
463 }
464 
466  size_t *num_bytes) {
467  if (uart == NULL || num_bytes == NULL) {
468  return kDifUartBadArg;
469  }
470 
471  // RX FIFO fill level (in bytes).
472  *num_bytes = (size_t)mmio_region_read_mask32(
473  uart->params.base_addr, UART_FIFO_STATUS_REG_OFFSET,
474  UART_FIFO_STATUS_RXLVL_MASK, UART_FIFO_STATUS_RXLVL_OFFSET);
475 
476  return kDifUartOk;
477 }
478 
480  size_t *num_bytes) {
481  if (uart == NULL || num_bytes == NULL) {
482  return kDifUartBadArg;
483  }
484 
485  // TX FIFO fill level (in bytes).
486  uint32_t fill_bytes = mmio_region_read_mask32(
487  uart->params.base_addr, UART_FIFO_STATUS_REG_OFFSET,
488  UART_FIFO_STATUS_TXLVL_MASK, UART_FIFO_STATUS_TXLVL_OFFSET);
489 
490  *num_bytes = kDifUartFifoSizeBytes - fill_bytes;
491 
492  return kDifUartOk;
493 }
494 
496  dif_uart_fifo_reset_t reset) {
497  if (uart == NULL) {
498  return kDifUartBadArg;
499  }
500 
501  uint32_t reg =
502  mmio_region_read32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET);
503 
504  if (reset == kDifUartFifoResetRx || reset == kDifUartFifoResetAll) {
505  reg = bitfield_field32_write(reg,
507  .mask = 0x1, .index = UART_FIFO_CTRL_RXRST,
508  },
509  1);
510  }
511 
512  if (reset == kDifUartFifoResetTx || reset == kDifUartFifoResetAll) {
513  reg = bitfield_field32_write(reg,
515  .mask = 0x1, .index = UART_FIFO_CTRL_TXRST,
516  },
517  1);
518  }
519 
520  mmio_region_write32(uart->params.base_addr, UART_FIFO_CTRL_REG_OFFSET, reg);
521 
522  return kDifUartOk;
523 }
524 
526  dif_uart_loopback_t loopback,
527  dif_uart_toggle_t enable) {
528  if (uart == NULL) {
529  return kDifUartBadArg;
530  }
531 
532  bitfield_field32_t field = {
533  .mask = 0x1, .index = loopback ? UART_CTRL_LLPBK : UART_CTRL_SLPBK,
534  };
535 
536  uint32_t reg =
537  mmio_region_read32(uart->params.base_addr, UART_CTRL_REG_OFFSET);
538  reg = bitfield_field32_write(reg, field, enable == kDifUartToggleEnabled);
539  mmio_region_write32(uart->params.base_addr, UART_CTRL_REG_OFFSET, reg);
540 
541  return kDifUartOk;
542 }