mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-14 19:30:27 +00:00
The current hierarchy : CONSOLE --> SERIAL -->UART DRIVER This patch remove SERIAL layer, that is console will call UART driver directly, change it to: CONSOLE --> UART DRIVER Remove some related data structures and registration and callback. Cleanup vuart.c Signed-off-by: Mingqiang Chi <mingqiang.chi@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
168 lines
4.2 KiB
C
168 lines
4.2 KiB
C
/*
|
|
* Copyright (C) 2018 Intel Corporation. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <hypervisor.h>
|
|
#include "uart16550.h"
|
|
|
|
#if defined(CONFIG_SERIAL_PIO_BASE)
|
|
static int serial_port_mapped = 1;
|
|
static int uart_enabled = 1;
|
|
#define UART_BASE_ADDRESS CONFIG_SERIAL_PIO_BASE
|
|
#elif defined(CONFIG_SERIAL_MMIO_BASE)
|
|
static int serial_port_mapped;
|
|
static int uart_enabled = 1;
|
|
#define UART_BASE_ADDRESS CONFIG_SERIAL_MMIO_BASE
|
|
#else
|
|
#warning "no uart base configure, please check!"
|
|
static int serial_port_mapped;
|
|
static int uart_enabled;
|
|
#define UART_BASE_ADDRESS 0
|
|
#endif
|
|
|
|
typedef uint32_t uart_reg_t;
|
|
|
|
static uint64_t uart_base_address;
|
|
|
|
static spinlock_t uart_rx_lock;
|
|
static spinlock_t uart_tx_lock;
|
|
|
|
static inline uint32_t uart16550_read_reg(uint64_t base, uint32_t reg_idx)
|
|
{
|
|
if (serial_port_mapped != 0) {
|
|
return io_read_byte((uint16_t)base + reg_idx);
|
|
} else {
|
|
return mmio_read_long((void*)((uint32_t*)HPA2HVA(base) + reg_idx));
|
|
}
|
|
}
|
|
|
|
static inline void uart16550_write_reg(uint64_t base,
|
|
uint32_t val, uint32_t reg_idx)
|
|
{
|
|
if (serial_port_mapped != 0) {
|
|
io_write_byte(val, (uint16_t)base + reg_idx);
|
|
} else {
|
|
mmio_write_long(val, (void*)((uint32_t*)HPA2HVA(base) + reg_idx));
|
|
}
|
|
}
|
|
|
|
static void uart16550_calc_baud_div(uint32_t ref_freq,
|
|
uint32_t *baud_div_ptr, uint32_t baud_rate_arg)
|
|
{
|
|
uint32_t baud_rate = baud_rate_arg;
|
|
uint32_t baud_multiplier = baud_rate < BAUD_460800 ? 16 : 13;
|
|
|
|
if (baud_rate == 0) {
|
|
baud_rate = BAUD_115200;
|
|
}
|
|
*baud_div_ptr = ref_freq / (baud_multiplier * baud_rate);
|
|
}
|
|
|
|
static void uart16550_set_baud_rate(uint32_t baud_rate)
|
|
{
|
|
uint32_t baud_div, duart_clock = UART_CLOCK_RATE;
|
|
uart_reg_t temp_reg;
|
|
|
|
/* Calculate baud divisor */
|
|
uart16550_calc_baud_div(duart_clock, &baud_div, baud_rate);
|
|
|
|
/* Enable DLL and DLM registers for setting the Divisor */
|
|
temp_reg = uart16550_read_reg(uart_base_address, UART16550_LCR);
|
|
temp_reg |= LCR_DLAB;
|
|
uart16550_write_reg(uart_base_address, temp_reg, UART16550_LCR);
|
|
|
|
/* Write the appropriate divisor value */
|
|
uart16550_write_reg(uart_base_address,
|
|
((baud_div >> 8) & 0xFFU), UART16550_DLM);
|
|
uart16550_write_reg(uart_base_address,
|
|
(baud_div & 0xFFU), UART16550_DLL);
|
|
|
|
/* Disable DLL and DLM registers */
|
|
temp_reg &= ~LCR_DLAB;
|
|
uart16550_write_reg(uart_base_address, temp_reg, UART16550_LCR);
|
|
}
|
|
|
|
void uart16550_init(void)
|
|
{
|
|
if (uart_base_address == 0) {
|
|
uart_base_address = UART_BASE_ADDRESS;
|
|
}
|
|
spinlock_init(&uart_rx_lock);
|
|
spinlock_init(&uart_tx_lock);
|
|
/* Enable TX and RX FIFOs */
|
|
uart16550_write_reg(uart_base_address,
|
|
FCR_FIFOE | FCR_RFR | FCR_TFR, UART16550_FCR);
|
|
|
|
/* Set-up data bits / parity / stop bits. */
|
|
uart16550_write_reg(uart_base_address,
|
|
(LCR_WL8 | LCR_NB_STOP_BITS_1 | LCR_PARITY_NONE),
|
|
UART16550_LCR);
|
|
|
|
/* Disable interrupts (we use polling) */
|
|
uart16550_write_reg(uart_base_address,
|
|
UART_IER_DISABLE_ALL, UART16550_IER);
|
|
|
|
/* Set baud rate */
|
|
uart16550_set_baud_rate(BAUD_115200);
|
|
|
|
/* Data terminal ready + Request to send */
|
|
uart16550_write_reg(uart_base_address,
|
|
MCR_RTS | MCR_DTR, UART16550_MCR);
|
|
}
|
|
|
|
char uart16550_getc(void)
|
|
{
|
|
char ret = -1;
|
|
|
|
spinlock_obtain(&uart_rx_lock);
|
|
|
|
/* If a character has been received, read it */
|
|
if ((uart16550_read_reg(uart_base_address, UART16550_LSR) & LSR_DR)
|
|
== LSR_DR) {
|
|
/* Read a character */
|
|
ret = uart16550_read_reg(uart_base_address, UART16550_RBR);
|
|
|
|
}
|
|
spinlock_release(&uart_rx_lock);
|
|
return ret;
|
|
}
|
|
|
|
static void uart16550_putc(const char *buf)
|
|
{
|
|
uint32_t reg;
|
|
/* Ensure there are no further Transmit buffer write requests */
|
|
do {
|
|
reg = uart16550_read_reg(uart_base_address, UART16550_LSR);
|
|
} while ((reg & LSR_THRE) == 0U || (reg & LSR_TEMT) == 0U);
|
|
|
|
/* Transmit the character. */
|
|
uart16550_write_reg(uart_base_address, *buf, UART16550_THR);
|
|
}
|
|
|
|
int uart16550_puts(const char *buf, uint32_t len)
|
|
{
|
|
uint32_t i;
|
|
|
|
spinlock_obtain(&uart_tx_lock);
|
|
for (i = 0U; i < len; i++) {
|
|
/* Transmit character */
|
|
uart16550_putc(buf);
|
|
if (*buf == '\n') {
|
|
/* Append '\r', no need change the len */
|
|
uart16550_putc("\r");
|
|
}
|
|
buf++;
|
|
}
|
|
spinlock_release(&uart_tx_lock);
|
|
return (int)len;
|
|
}
|
|
|
|
void uart16550_set_property(int enabled, int port_mapped, uint64_t base_addr)
|
|
{
|
|
uart_enabled = enabled;
|
|
serial_port_mapped = port_mapped;
|
|
uart_base_address = base_addr;
|
|
}
|