|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | #include "sw/device/lib/uart.h" | 
|  |  | 
|  | #include "sw/device/lib/arch/device.h" | 
|  | #include "sw/device/lib/dif/dif_uart.h" | 
|  | #include "sw/device/lib/runtime/ibex.h" | 
|  |  | 
|  | #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" | 
|  |  | 
|  | static dif_uart_t uart0; | 
|  |  | 
|  | void uart_init(unsigned int baud) { | 
|  | // Note that, due to a GCC bug, we cannot use the standard `(void) expr` | 
|  | // syntax to drop this value on the ground. | 
|  | // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 | 
|  | mmio_region_t base_addr = mmio_region_from_addr(TOP_EARLGREY_UART_BASE_ADDR); | 
|  | if (dif_uart_init((dif_uart_params_t){.base_addr = base_addr}, &uart0)) { | 
|  | } | 
|  | if (dif_uart_configure(&uart0, (dif_uart_config_t){ | 
|  | .baudrate = baud, | 
|  | .clk_freq_hz = kClockFreqPeripheralHz, | 
|  | .parity_enable = kDifUartToggleDisabled, | 
|  | .parity = kDifUartParityEven, | 
|  | })) { | 
|  | } | 
|  | } | 
|  |  | 
|  | void uart_send_char(char c) { | 
|  | // Note that, due to a GCC bug, we cannot use the standard `(void) expr` | 
|  | // syntax to drop this value on the ground. | 
|  | // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509 | 
|  | if (dif_uart_byte_send_polled(&uart0, (uint8_t)c)) { | 
|  | } | 
|  | } | 
|  |  | 
|  | void uart_send_str(char *str) { | 
|  | while (*str != '\0') { | 
|  | uart_send_char(*str++); | 
|  | } | 
|  | } | 
|  |  | 
|  | size_t uart_send_buf(void *data, const char *buf, size_t len) { | 
|  | for (size_t i = 0; i < len; ++i) { | 
|  | uart_send_char(buf[i]); | 
|  | } | 
|  | return len; | 
|  | } | 
|  |  | 
|  | const buffer_sink_t uart_stdout = { | 
|  | .data = NULL, .sink = &uart_send_buf, | 
|  | }; | 
|  |  | 
|  | #define hexchar(i) (((i & 0xf) > 9) ? (i & 0xf) - 10 + 'A' : (i & 0xf) + '0') | 
|  |  | 
|  | void uart_send_uint(uint32_t n, int bits) { | 
|  | for (int i = bits - 4; i >= 0; i -= 4) { | 
|  | uart_send_char(hexchar(n >> i)); | 
|  | } | 
|  | } | 
|  |  | 
|  | int uart_rcv_char(char *c) { | 
|  | size_t num_bytes = 0; | 
|  | if (dif_uart_rx_bytes_available(&uart0, &num_bytes) != kDifUartOk) { | 
|  | return -1; | 
|  | } | 
|  | if (num_bytes == 0) { | 
|  | return -1; | 
|  | } | 
|  | // The pointer cast from char* to uint8_t* is dangerous. This needs to be | 
|  | // revisited. | 
|  | if (dif_uart_bytes_receive(&uart0, 1, (uint8_t *)c, NULL) != kDifUartOk) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } |