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
19static const dt_uart_t kUartDt = kDtUart0;
20
21/**
22 * Base address of the uart registers.
23 */
24static inline uint32_t uart_reg_base(void) {
25 return dt_uart_reg_block(kUartDt, kDtUartRegBlockCore);
26}
27
28static 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
43void 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
58void 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
65static 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
71static 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
76bool 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
81static 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
89void uart_putchar(uint8_t byte) {
90 putchar_nonblocking(byte);
91 // If the transmitter is active, wait.
92 while (!uart_tx_idle()) {
93 }
94}
95
96int 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
102void 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
110void 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
121void uart_write_imm(uint64_t imm) {
122 while (imm) {
123 putchar_nonblocking(imm & 0xFF);
124 imm >>= 8;
125 }
126}
127
128size_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
148hardened_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
160size_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}