2019-03-28 14:37:03 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 - 2019 Antmicro <www.antmicro.com>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2024-08-01 10:14:09 +02:00
|
|
|
#define DT_DRV_COMPAT litex_uart
|
2020-03-24 15:58:31 -05:00
|
|
|
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/kernel.h>
|
|
|
|
#include <zephyr/arch/cpu.h>
|
|
|
|
#include <zephyr/init.h>
|
|
|
|
#include <zephyr/irq.h>
|
|
|
|
#include <zephyr/device.h>
|
|
|
|
#include <zephyr/drivers/uart.h>
|
2019-03-28 14:37:03 +01:00
|
|
|
#include <zephyr/types.h>
|
|
|
|
|
2024-01-18 14:47:45 +01:00
|
|
|
#include <soc.h>
|
|
|
|
|
2024-07-09 16:54:05 +02:00
|
|
|
#define UART_EV_TX BIT(0)
|
|
|
|
#define UART_EV_RX BIT(1)
|
2019-03-28 14:37:03 +01:00
|
|
|
|
2024-06-19 08:17:52 +02:00
|
|
|
struct uart_litex_device_config {
|
2024-07-09 16:54:05 +02:00
|
|
|
uint32_t rxtx_addr;
|
|
|
|
uint32_t txfull_addr;
|
|
|
|
uint32_t rxempty_addr;
|
|
|
|
uint32_t ev_status_addr;
|
|
|
|
uint32_t ev_pending_addr;
|
|
|
|
uint32_t ev_enable_addr;
|
|
|
|
uint32_t txempty_addr;
|
|
|
|
uint32_t rxfull_addr;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t baud_rate;
|
2019-03-28 14:37:03 +01:00
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
2024-07-09 16:54:05 +02:00
|
|
|
void (*config_func)(const struct device *dev);
|
2019-03-28 14:37:03 +01:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2024-06-19 08:17:52 +02:00
|
|
|
struct uart_litex_data {
|
2019-03-28 14:37:03 +01:00
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
2024-07-09 16:54:05 +02:00
|
|
|
struct k_timer timer;
|
2019-03-28 14:37:03 +01:00
|
|
|
uart_irq_callback_user_data_t callback;
|
|
|
|
void *cb_data;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Output a character in polled mode.
|
|
|
|
*
|
|
|
|
* Writes data to tx register. Waits for space if transmitter is full.
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
* @param c Character to send
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static void uart_litex_poll_out(const struct device *dev, unsigned char c)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
2019-03-28 14:37:03 +01:00
|
|
|
/* wait for space */
|
2024-07-09 16:54:05 +02:00
|
|
|
while (litex_read8(config->txfull_addr)) {
|
2019-06-04 10:52:23 -04:00
|
|
|
}
|
2019-03-28 14:37:03 +01:00
|
|
|
|
2024-07-09 16:54:05 +02:00
|
|
|
litex_write8(c, config->rxtx_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Poll the device for input.
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
* @param c Pointer to character
|
|
|
|
*
|
|
|
|
* @return 0 if a character arrived, -1 if the input buffer if empty.
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static int uart_litex_poll_in(const struct device *dev, unsigned char *c)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
|
|
|
|
|
|
|
if (!litex_read8(config->rxempty_addr)) {
|
|
|
|
*c = litex_read8(config->rxtx_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
|
|
|
|
/* refresh UART_RXEMPTY by writing UART_EV_RX
|
|
|
|
* to UART_EV_PENDING
|
|
|
|
*/
|
2024-07-09 16:54:05 +02:00
|
|
|
litex_write8(UART_EV_RX, config->ev_pending_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
|
|
|
/**
|
|
|
|
* @brief Enable TX interrupt in event register
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static void uart_litex_irq_tx_enable(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
|
|
|
struct uart_litex_data *data = dev->data;
|
2019-03-28 14:37:03 +01:00
|
|
|
|
2024-07-09 16:54:05 +02:00
|
|
|
uint8_t enable = litex_read8(config->ev_enable_addr);
|
|
|
|
|
|
|
|
litex_write8(enable | UART_EV_TX, config->ev_enable_addr);
|
|
|
|
|
|
|
|
if (!litex_read8(config->txfull_addr)) {
|
|
|
|
/*
|
|
|
|
* TX done event already generated an edge interrupt. Generate a
|
|
|
|
* soft interrupt and have it call the callback function in
|
|
|
|
* timer isr context.
|
|
|
|
*/
|
|
|
|
k_timer_start(&data->timer, K_NO_WAIT, K_NO_WAIT);
|
|
|
|
}
|
2019-03-28 14:37:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Disable TX interrupt in event register
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static void uart_litex_irq_tx_disable(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
2019-03-28 14:37:03 +01:00
|
|
|
|
2024-07-09 16:54:05 +02:00
|
|
|
uint8_t enable = litex_read8(config->ev_enable_addr);
|
|
|
|
|
|
|
|
litex_write8(enable & ~(UART_EV_TX), config->ev_enable_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Enable RX interrupt in event register
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static void uart_litex_irq_rx_enable(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
|
|
|
|
|
|
|
uint8_t enable = litex_read8(config->ev_enable_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
|
2024-07-09 16:54:05 +02:00
|
|
|
litex_write8(enable | UART_EV_RX, config->ev_enable_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Disable RX interrupt in event register
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static void uart_litex_irq_rx_disable(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
|
|
|
|
|
|
|
uint8_t enable = litex_read8(config->ev_enable_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
|
2024-07-09 16:54:05 +02:00
|
|
|
litex_write8(enable & ~(UART_EV_RX), config->ev_enable_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Check if Tx IRQ has been raised and UART is ready to accept new data
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
*
|
|
|
|
* @return 1 if an IRQ has been raised, 0 otherwise
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static int uart_litex_irq_tx_ready(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
|
|
|
|
|
|
|
uint8_t val = litex_read8(config->txfull_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
|
|
|
|
return !val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Check if Rx IRQ has been raised and there's data to be read from UART
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
*
|
|
|
|
* @return 1 if an IRQ has been raised, 0 otherwise
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static int uart_litex_irq_rx_ready(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t pending;
|
2019-03-28 14:37:03 +01:00
|
|
|
|
2024-07-09 16:54:05 +02:00
|
|
|
pending = litex_read8(config->ev_pending_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
|
|
|
|
if (pending & UART_EV_RX) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Fill FIFO with data
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
* @param tx_data Data to transmit
|
|
|
|
* @param size Number of bytes to send
|
|
|
|
*
|
|
|
|
* @return Number of bytes sent
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static int uart_litex_fifo_fill(const struct device *dev,
|
|
|
|
const uint8_t *tx_data, int size)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
2019-03-28 14:37:03 +01:00
|
|
|
int i;
|
|
|
|
|
2025-05-01 21:59:00 +02:00
|
|
|
litex_write8(UART_EV_RX, config->ev_pending_addr);
|
2024-07-09 16:54:05 +02:00
|
|
|
for (i = 0; i < size && !litex_read8(config->txfull_addr); i++) {
|
|
|
|
litex_write8(tx_data[i], config->rxtx_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
}
|
2025-05-01 21:59:00 +02:00
|
|
|
while (!litex_read8(config->txfull_addr)) {
|
|
|
|
litex_write8(0, config->rxtx_addr);
|
|
|
|
}
|
2019-03-28 14:37:03 +01:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Read data from FIFO
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
* @param rxData Data container
|
|
|
|
* @param size Container size
|
|
|
|
*
|
|
|
|
* @return Number of bytes read
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static int uart_litex_fifo_read(const struct device *dev,
|
|
|
|
uint8_t *rx_data, const int size)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
2019-03-28 14:37:03 +01:00
|
|
|
int i;
|
|
|
|
|
2024-07-09 16:54:05 +02:00
|
|
|
for (i = 0; i < size && !litex_read8(config->rxempty_addr); i++) {
|
|
|
|
rx_data[i] = litex_read8(config->rxtx_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
|
|
|
|
/* refresh UART_RXEMPTY by writing UART_EV_RX
|
|
|
|
* to UART_EV_PENDING
|
|
|
|
*/
|
2024-07-09 16:54:05 +02:00
|
|
|
litex_write8(UART_EV_RX, config->ev_pending_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2024-06-19 08:17:52 +02:00
|
|
|
static void uart_litex_irq_err(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Check if any IRQ is pending
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
*
|
|
|
|
* @return 1 if an IRQ is pending, 0 otherwise
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static int uart_litex_irq_is_pending(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
return (uart_litex_irq_tx_ready(dev) || uart_litex_irq_rx_ready(dev));
|
2019-03-28 14:37:03 +01:00
|
|
|
}
|
|
|
|
|
2024-06-19 08:17:52 +02:00
|
|
|
static int uart_litex_irq_update(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the callback function pointer for IRQ.
|
|
|
|
*
|
|
|
|
* @param dev UART device struct
|
|
|
|
* @param cb Callback function pointer.
|
|
|
|
*/
|
2024-06-19 08:17:52 +02:00
|
|
|
static void uart_litex_irq_callback_set(const struct device *dev,
|
|
|
|
uart_irq_callback_user_data_t cb,
|
|
|
|
void *cb_data)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-06-19 08:17:52 +02:00
|
|
|
struct uart_litex_data *data;
|
2019-03-28 14:37:03 +01:00
|
|
|
|
2022-01-19 12:14:50 +01:00
|
|
|
data = dev->data;
|
2019-03-28 14:37:03 +01:00
|
|
|
data->callback = cb;
|
|
|
|
data->cb_data = cb_data;
|
|
|
|
}
|
|
|
|
|
2024-06-19 08:17:52 +02:00
|
|
|
static void uart_litex_irq_handler(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
2024-06-19 08:17:52 +02:00
|
|
|
struct uart_litex_data *data = dev->data;
|
2022-07-13 16:50:25 +02:00
|
|
|
unsigned int key = irq_lock();
|
2019-03-28 14:37:03 +01:00
|
|
|
|
|
|
|
if (data->callback) {
|
2020-06-24 15:47:15 +02:00
|
|
|
data->callback(dev, data->cb_data);
|
2019-03-28 14:37:03 +01:00
|
|
|
}
|
|
|
|
|
drivers: serial: uart_liteuart: fix interrupt-driven mode
Interrupt-driven mode was not working, and disabled by default.
When it was forced on, the behavior was to only have a few bytes:
as many as min(CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE, 9).
After the hardware FIFO was filled by software and emptied by hardware,
no interrupt occured, and enqueuing more data did never happen.
By letting the events enabled for TX (only), then interrupts are still
generated after the first transfer, and the software can then add the
subsequent transfers until all data is print: the UART works.
It does not generate endless interrupts either, which was tested by
adding litex_write8('%', UART_RXTX_ADDR) in liteuart_uart_irq_handler()
to log all interrupts events, and when there is nothing to print, no
interrupt is fired.
It was tested with the Zephyr shell.
Fixes #63794
Signed-off-by: Josuah Demangeon <me@josuah.net>
2023-10-12 12:58:40 +02:00
|
|
|
/* Clear RX events, TX events still needed to enqueue the next transfer */
|
2025-05-01 21:59:00 +02:00
|
|
|
if (litex_read8(config->rxempty_addr)) {
|
|
|
|
litex_write8(UART_EV_RX, config->ev_pending_addr);
|
|
|
|
}
|
2019-03-28 14:37:03 +01:00
|
|
|
|
|
|
|
irq_unlock(key);
|
|
|
|
}
|
2024-07-09 16:54:05 +02:00
|
|
|
|
|
|
|
static void uart_litex_tx_soft_isr(struct k_timer *timer)
|
|
|
|
{
|
|
|
|
const struct device *dev = k_timer_user_data_get(timer);
|
|
|
|
|
|
|
|
uart_litex_irq_handler(dev);
|
|
|
|
}
|
2019-03-28 14:37:03 +01:00
|
|
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
|
|
|
|
2024-11-28 21:21:48 +01:00
|
|
|
static DEVICE_API(uart, uart_litex_driver_api) = {
|
2024-06-19 08:17:52 +02:00
|
|
|
.poll_in = uart_litex_poll_in,
|
|
|
|
.poll_out = uart_litex_poll_out,
|
2019-03-28 14:37:03 +01:00
|
|
|
.err_check = NULL,
|
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
2024-06-19 08:17:52 +02:00
|
|
|
.fifo_fill = uart_litex_fifo_fill,
|
|
|
|
.fifo_read = uart_litex_fifo_read,
|
|
|
|
.irq_tx_enable = uart_litex_irq_tx_enable,
|
|
|
|
.irq_tx_disable = uart_litex_irq_tx_disable,
|
|
|
|
.irq_tx_ready = uart_litex_irq_tx_ready,
|
|
|
|
.irq_rx_enable = uart_litex_irq_rx_enable,
|
|
|
|
.irq_rx_disable = uart_litex_irq_rx_disable,
|
|
|
|
.irq_rx_ready = uart_litex_irq_rx_ready,
|
|
|
|
.irq_err_enable = uart_litex_irq_err,
|
|
|
|
.irq_err_disable = uart_litex_irq_err,
|
|
|
|
.irq_is_pending = uart_litex_irq_is_pending,
|
|
|
|
.irq_update = uart_litex_irq_update,
|
|
|
|
.irq_callback_set = uart_litex_irq_callback_set
|
2019-03-28 14:37:03 +01:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2024-06-19 08:17:52 +02:00
|
|
|
static int uart_litex_init(const struct device *dev)
|
2019-03-28 14:37:03 +01:00
|
|
|
{
|
2024-07-09 16:54:05 +02:00
|
|
|
const struct uart_litex_device_config *config = dev->config;
|
|
|
|
|
|
|
|
litex_write8(UART_EV_TX | UART_EV_RX, config->ev_pending_addr);
|
2019-03-28 14:37:03 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
2024-07-09 16:54:05 +02:00
|
|
|
struct uart_litex_data *data = dev->data;
|
|
|
|
|
|
|
|
k_timer_init(&data->timer, &uart_litex_tx_soft_isr, NULL);
|
|
|
|
k_timer_user_data_set(&data->timer, (void *)dev);
|
|
|
|
|
|
|
|
config->config_func(dev);
|
2019-03-28 14:37:03 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2024-07-09 16:54:05 +02:00
|
|
|
|
|
|
|
#define LITEX_UART_IRQ_INIT(n) \
|
|
|
|
static void uart_irq_config##n(const struct device *dev) \
|
|
|
|
{ \
|
|
|
|
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_litex_irq_handler, \
|
|
|
|
DEVICE_DT_INST_GET(n), 0); \
|
|
|
|
\
|
|
|
|
irq_enable(DT_INST_IRQN(n)); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define LITEX_UART_INIT(n) \
|
|
|
|
IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, (LITEX_UART_IRQ_INIT(n))) \
|
|
|
|
\
|
|
|
|
static struct uart_litex_data uart_litex_data_##n; \
|
|
|
|
\
|
|
|
|
static const struct uart_litex_device_config uart_litex_dev_cfg_##n = { \
|
|
|
|
.rxtx_addr = DT_INST_REG_ADDR_BY_NAME(n, rxtx), \
|
|
|
|
.txfull_addr = DT_INST_REG_ADDR_BY_NAME(n, txfull), \
|
|
|
|
.rxempty_addr = DT_INST_REG_ADDR_BY_NAME(n, rxempty), \
|
|
|
|
.ev_status_addr = DT_INST_REG_ADDR_BY_NAME(n, ev_status), \
|
|
|
|
.ev_pending_addr = DT_INST_REG_ADDR_BY_NAME(n, ev_pending), \
|
|
|
|
.ev_enable_addr = DT_INST_REG_ADDR_BY_NAME(n, ev_enable), \
|
|
|
|
.txempty_addr = DT_INST_REG_ADDR_BY_NAME(n, txempty), \
|
|
|
|
.rxfull_addr = DT_INST_REG_ADDR_BY_NAME(n, rxfull), \
|
|
|
|
.baud_rate = DT_INST_PROP(n, current_speed), \
|
|
|
|
IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, (.config_func = uart_irq_config##n,))}; \
|
|
|
|
\
|
|
|
|
DEVICE_DT_INST_DEFINE(n, uart_litex_init, NULL, &uart_litex_data_##n, \
|
|
|
|
&uart_litex_dev_cfg_##n, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
|
|
|
|
(void *)&uart_litex_driver_api);
|
|
|
|
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(LITEX_UART_INIT)
|