Software APIs
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 
5 #include "sw/device/silicon_creator/lib/drivers/uart.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include "dt/dt_uart.h"
14 #include "sw/device/silicon_creator/lib/drivers/ibex.h"
15 #include "sw/device/silicon_creator/lib/error.h"
16 
17 #include "uart_regs.h" // Generated.
18 
19 static const dt_uart_t kUartDt = kDtUart0;
20 
21 /**
22  * Base address of the uart registers.
23  */
24 static inline uint32_t uart_reg_base(void) {
25  return dt_uart_reg_block(kUartDt, kDtUartRegBlockCore);
26 }
27 
28 static void uart_reset(void) {
29  abs_mmio_write32(uart_reg_base() + UART_CTRL_REG_OFFSET, 0u);
30 
31  // Write to the relevant bits clears the FIFOs.
32  uint32_t reg = 0;
33  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_RXRST_BIT, true);
34  reg = bitfield_bit32_write(reg, UART_FIFO_CTRL_TXRST_BIT, true);
35  abs_mmio_write32(uart_reg_base() + UART_FIFO_CTRL_REG_OFFSET, reg);
36 
37  abs_mmio_write32(uart_reg_base() + UART_OVRD_REG_OFFSET, 0u);
38  abs_mmio_write32(uart_reg_base() + UART_TIMEOUT_CTRL_REG_OFFSET, 0u);
39  abs_mmio_write32(uart_reg_base() + UART_INTR_ENABLE_REG_OFFSET, 0u);
40  abs_mmio_write32(uart_reg_base() + UART_INTR_STATE_REG_OFFSET, UINT32_MAX);
41 }
42 
43 void uart_init(uint32_t precalculated_nco) {
44  // Must be called before the first write to any of the UART registers.
45  uart_reset();
46 
47  // Set baudrate, TX, no parity bits.
48  uint32_t reg = 0;
49  reg = bitfield_field32_write(reg, UART_CTRL_NCO_FIELD, precalculated_nco);
50  reg = bitfield_bit32_write(reg, UART_CTRL_TX_BIT, true);
51  reg = bitfield_bit32_write(reg, UART_CTRL_PARITY_EN_BIT, false);
52  abs_mmio_write32(uart_reg_base() + UART_CTRL_REG_OFFSET, reg);
53 
54  // Disable interrupts.
55  abs_mmio_write32(uart_reg_base() + UART_INTR_ENABLE_REG_OFFSET, 0u);
56 }
57 
58 void uart_enable_receiver(void) {
59  uint32_t reg = abs_mmio_read32(uart_reg_base() + UART_CTRL_REG_OFFSET);
60  reg = bitfield_bit32_write(reg, UART_CTRL_RX_BIT, true);
61  abs_mmio_write32(uart_reg_base() + UART_CTRL_REG_OFFSET, reg);
62 }
63 
65 static bool uart_tx_full(void) {
66  uint32_t reg = abs_mmio_read32(uart_reg_base() + UART_STATUS_REG_OFFSET);
67  return bitfield_bit32_read(reg, UART_STATUS_TXFULL_BIT);
68 }
69 
71 static bool uart_rx_empty(void) {
72  uint32_t reg = abs_mmio_read32(uart_reg_base() + UART_STATUS_REG_OFFSET);
73  return bitfield_bit32_read(reg, UART_STATUS_RXEMPTY_BIT);
74 }
75 
76 bool uart_tx_idle(void) {
77  uint32_t reg = abs_mmio_read32(uart_reg_base() + UART_STATUS_REG_OFFSET);
78  return bitfield_bit32_read(reg, UART_STATUS_TXIDLE_BIT);
79 }
80 
81 static void putchar_nonblocking(uint8_t byte) {
82  // If the transmit FIFO is full, wait.
83  while (uart_tx_full()) {
84  }
85  uint32_t reg = bitfield_field32_write(0, UART_WDATA_WDATA_FIELD, byte);
86  abs_mmio_write32(uart_reg_base() + UART_WDATA_REG_OFFSET, reg);
87 }
88 
89 void uart_putchar(uint8_t byte) {
90  putchar_nonblocking(byte);
91  // If the transmitter is active, wait.
92  while (!uart_tx_idle()) {
93  }
94 }
95 
96 int uart_getchar(uint32_t timeout_ms) {
97  uint8_t ch;
98  size_t n = uart_read(&ch, 1, timeout_ms);
99  return n ? (int)ch : -1;
100 }
101 
102 void uart_write(const void *data, size_t len) {
103  const uint8_t *d = (const uint8_t *)data;
104  while (len) {
105  uart_putchar(*d++);
106  len--;
107  }
108 }
109 
110 void uart_write_hex(uint32_t val, size_t len, uint32_t after) {
111  HARDENED_CHECK_LE(len, sizeof(uint32_t));
112  static const uint8_t kHexTable[16] = "0123456789abcdef";
113  size_t i = len * 8;
114  do {
115  i -= 4;
116  putchar_nonblocking(kHexTable[(val >> i) & 0xF]);
117  } while (i > 0);
118  uart_write_imm(after);
119 }
120 
121 void uart_write_imm(uint64_t imm) {
122  while (imm) {
123  putchar_nonblocking(imm & 0xFF);
124  imm >>= 8;
125  }
126 }
127 
128 size_t uart_read(uint8_t *data, size_t len, uint32_t timeout_ms) {
129  uint64_t time = ibex_mcycle();
130  uint64_t deadline = timeout_ms == UINT32_MAX
131  ? UINT64_MAX
132  : time + ibex_time_to_cycles(timeout_ms * 1000);
133 
134  size_t n = 0;
135  for (n = 0; n < len; ++n) {
136  // If the receive FIFO is empty, wait.
137  while (uart_rx_empty()) {
138  time = ibex_mcycle();
139  if (time > deadline)
140  return n;
141  }
142  uint32_t reg = abs_mmio_read32(uart_reg_base() + UART_RDATA_REG_OFFSET);
143  *data++ = (uint8_t)reg;
144  }
145  return n;
146 }
147 
148 hardened_bool_t uart_break_detect(uint32_t timeout_us) {
149  uint64_t time = ibex_mcycle();
150  uint64_t deadline = time + ibex_time_to_cycles(timeout_us);
151  while (time < deadline) {
152  uint32_t val = abs_mmio_read32(uart_reg_base() + UART_VAL_REG_OFFSET);
153  if (val)
154  return kHardenedBoolFalse;
155  time = ibex_mcycle();
156  }
157  return kHardenedBoolTrue;
158 }
159 
160 size_t uart_sink(void *uart, const char *data, size_t len) {
161  (void)uart;
162  uart_write((const uint8_t *)data, len);
163  return len;
164 }