blob: 834011b371f79a45f550d0d3cb5f516edb2f85f7 [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/*
* Serial port hanging off LPC
*
* Copyright 2013-2019 IBM Corp.
*/
#include <skiboot.h>
#include <lpc.h>
#include <console.h>
#include <opal.h>
#include <device.h>
#include <interrupts.h>
#include <processor.h>
#include <errorlog.h>
#include <trace.h>
#include <timebase.h>
#include <cpu.h>
#include <chip.h>
#include <io.h>
#include <nvram.h>
DEFINE_LOG_ENTRY(OPAL_RC_UART_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_UART,
OPAL_CEC_HARDWARE, OPAL_PREDICTIVE_ERR_GENERAL,
OPAL_NA);
/* UART reg defs */
#define REG_RBR 0
#define REG_THR 0
#define REG_DLL 0
#define REG_IER 1
#define REG_DLM 1
#define REG_FCR 2
#define REG_IIR 2
#define REG_LCR 3
#define REG_MCR 4
#define REG_LSR 5
#define REG_MSR 6
#define REG_SCR 7
#define LSR_DR 0x01 /* Data ready */
#define LSR_OE 0x02 /* Overrun */
#define LSR_PE 0x04 /* Parity error */
#define LSR_FE 0x08 /* Framing error */
#define LSR_BI 0x10 /* Break */
#define LSR_THRE 0x20 /* Xmit holding register empty */
#define LSR_TEMT 0x40 /* Xmitter empty */
#define LSR_ERR 0x80 /* Error */
#define LCR_DLAB 0x80 /* DLL access */
#define IER_RX 0x01
#define IER_THRE 0x02
#define IER_ALL 0x0f
static struct lock uart_lock = LOCK_UNLOCKED;
static struct dt_node *uart_node;
static uint32_t uart_base;
static uint64_t uart_tx_full_time;
static bool has_irq = false, irq_ok, rx_full, tx_full;
static uint8_t tx_room;
static uint8_t cached_ier;
static void *mmio_uart_base;
static int uart_console_policy = UART_CONSOLE_OPAL;
static int lpc_irq = -1;
void uart_set_console_policy(int policy)
{
uart_console_policy = policy;
}
static void uart_trace(u8 ctx, u8 cnt, u8 irq_state, u8 in_count)
{
union trace t;
t.uart.ctx = ctx;
t.uart.cnt = cnt;
t.uart.irq_state = irq_state;
t.uart.in_count = cpu_to_be16(in_count);
trace_add(&t, TRACE_UART, sizeof(struct trace_uart));
}
static inline uint8_t uart_read(unsigned int reg)
{
if (mmio_uart_base)
return in_8(mmio_uart_base + reg);
else
return lpc_inb(uart_base + reg);
}
static inline void uart_write(unsigned int reg, uint8_t val)
{
if (mmio_uart_base)
out_8(mmio_uart_base + reg, val);
else
lpc_outb(val, uart_base + reg);
}
static bool uart_check_tx_room(void)
{
if (tx_room)
return true;
if (uart_read(REG_LSR) & LSR_THRE) {
/* FIFO is 16 entries */
tx_room = 16;
tx_full = false;
return true;
}
return false;
}
/* Must be called with UART lock held */
static void uart_write_thr(uint8_t val)
{
uart_write(REG_THR, val);
tx_room--;
if (tx_room == 0) {
if (!uart_check_tx_room())
uart_tx_full_time = mftb();
}
}
static bool uart_timed_out(unsigned long msecs)
{
if (uart_check_tx_room())
return false;
if (chip_quirk(QUIRK_SLOW_SIM))
msecs *= 5;
if (tb_compare(mftb(), uart_tx_full_time + msecs_to_tb(msecs)) == TB_AAFTERB)
return true;
return false;
}
static bool uart_wait_tx_room(void)
{
if (uart_check_tx_room())
return true;
smt_lowest();
while (!uart_check_tx_room()) {
if (uart_timed_out(100)) {
smt_medium();
return false;
}
}
smt_medium();
return true;
}
static void uart_update_ier(void)
{
uint8_t ier = 0;
if (!has_irq)
return;
/* If we have never got an interrupt, enable them all,
* the first interrupt received will tell us if interrupts
* are functional (some boards are missing an EC or FPGA
* programming causing LPC interrupts not to work).
*/
if (!irq_ok)
ier = IER_ALL;
if (!rx_full)
ier |= IER_RX;
if (tx_full)
ier |= IER_THRE;
if (ier != cached_ier) {
uart_write(REG_IER, ier);
cached_ier = ier;
}
}
bool uart_enabled(void)
{
return mmio_uart_base || uart_base;
}
/*
* Internal console driver (output only)
*/
static size_t uart_con_write(const char *buf, size_t len)
{
size_t written = 0;
/* If LPC bus is bad, we just swallow data */
if (!lpc_ok() && !mmio_uart_base)
return len;
lock(&uart_lock);
while (written < len) {
if (!uart_wait_tx_room())
break;
uart_write_thr(buf[written++]);
}
if (!written && uart_timed_out(1000)) {
unlock(&uart_lock);
return len; /* swallow data */
}
unlock(&uart_lock);
return written;
}
static struct con_ops uart_con_driver = {
.write = uart_con_write,
};
/*
* OPAL console driver
*/
/*
* We implement a simple buffer to buffer input data as some bugs in
* Linux make it fail to read fast enough after we get an interrupt.
*
* We use it on non-interrupt operations as well while at it because
* it doesn't cost us much and might help in a few cases where Linux
* is calling opal_poll_events() but not actually reading.
*
* Most of the time I expect we'll flush it completely to Linux into
* it's tty flip buffers so I don't bother with a ring buffer.
*/
#define IN_BUF_SIZE 0x1000
static uint8_t *in_buf;
static uint32_t in_count;
/*
* We implement a ring buffer for output data as well to speed things
* up a bit. This allows us to have interrupt driven sends. This is only
* for the output data coming from the OPAL API, not the internal one
* which is already bufferred.
*/
#define OUT_BUF_SIZE 0x1000
static uint8_t *out_buf;
static uint32_t out_buf_prod;
static uint32_t out_buf_cons;
/* Asynchronous flush, uart_lock must be held */
static int64_t uart_con_flush(void)
{
bool tx_was_full = tx_full;
uint32_t out_buf_cons_initial = out_buf_cons;
while(out_buf_prod != out_buf_cons) {
if (tx_room == 0) {
/*
* If the interrupt is not functional,
* we force a full synchronous flush,
* otherwise the Linux console isn't
* usable (too slow).
*/
if (irq_ok)
uart_check_tx_room();
else
uart_wait_tx_room();
}
if (tx_room == 0) {
tx_full = true;
break;
}
uart_write_thr(out_buf[out_buf_cons++]);
out_buf_cons %= OUT_BUF_SIZE;
}
if (tx_full != tx_was_full)
uart_update_ier();
if (out_buf_prod != out_buf_cons) {
/* Return busy if nothing was flushed this call */
if (out_buf_cons == out_buf_cons_initial) {
if (uart_timed_out(1000))
return OPAL_TIMEOUT;
return OPAL_BUSY;
}
/* Return partial if there's more to flush */
return OPAL_PARTIAL;
}
return OPAL_SUCCESS;
}
static uint32_t uart_tx_buf_space(void)
{
return OUT_BUF_SIZE - 1 -
(out_buf_prod + OUT_BUF_SIZE - out_buf_cons) % OUT_BUF_SIZE;
}
static int64_t uart_opal_write(int64_t term_number, __be64 *__length,
const uint8_t *buffer)
{
size_t written = 0, len = be64_to_cpu(*__length);
int64_t ret = OPAL_SUCCESS;
if (term_number != 0)
return OPAL_PARAMETER;
lock(&uart_lock);
/* Copy data to out buffer */
while (uart_tx_buf_space() && len--) {
out_buf[out_buf_prod++] = *(buffer++);
out_buf_prod %= OUT_BUF_SIZE;
written++;
}
/* Flush out buffer again */
uart_con_flush();
if (!written && uart_timed_out(1000))
ret = OPAL_TIMEOUT;
unlock(&uart_lock);
*__length = cpu_to_be64(written);
return ret;
}
static int64_t uart_opal_write_buffer_space(int64_t term_number,
__be64 *__length)
{
int64_t ret = OPAL_SUCCESS;
int64_t tx_buf_len;
if (term_number != 0)
return OPAL_PARAMETER;
lock(&uart_lock);
tx_buf_len = uart_tx_buf_space();
if ((tx_buf_len < be64_to_cpu(*__length)) && uart_timed_out(1000))
ret = OPAL_TIMEOUT;
*__length = cpu_to_be64(tx_buf_len);
unlock(&uart_lock);
return ret;
}
/* Must be called with UART lock held */
static void uart_read_to_buffer(void)
{
/* As long as there is room in the buffer */
while(in_count < IN_BUF_SIZE) {
/* Read status register */
uint8_t lsr = uart_read(REG_LSR);
/* Nothing to read ... */
if ((lsr & LSR_DR) == 0)
break;
/* Read and add to buffer */
in_buf[in_count++] = uart_read(REG_RBR);
}
/* If the buffer is full disable the interrupt */
rx_full = (in_count == IN_BUF_SIZE);
uart_update_ier();
}
static void uart_adjust_opal_event(void)
{
if (in_count)
opal_update_pending_evt(OPAL_EVENT_CONSOLE_INPUT,
OPAL_EVENT_CONSOLE_INPUT);
else
opal_update_pending_evt(OPAL_EVENT_CONSOLE_INPUT, 0);
}
/* This is called with the console lock held */
static int64_t uart_opal_read(int64_t term_number, __be64 *__length,
uint8_t *buffer)
{
size_t req_count = be64_to_cpu(*__length), read_cnt = 0;
uint8_t lsr = 0;
if (term_number != 0)
return OPAL_PARAMETER;
if (!in_buf)
return OPAL_INTERNAL_ERROR;
lock(&uart_lock);
/* Read from buffer first */
if (in_count) {
read_cnt = in_count;
if (req_count < read_cnt)
read_cnt = req_count;
memcpy(buffer, in_buf, read_cnt);
req_count -= read_cnt;
if (in_count != read_cnt)
memmove(in_buf, in_buf + read_cnt, in_count - read_cnt);
in_count -= read_cnt;
}
/*
* If there's still room in the user buffer, read from the UART
* directly
*/
while(req_count) {
lsr = uart_read(REG_LSR);
if ((lsr & LSR_DR) == 0)
break;
buffer[read_cnt++] = uart_read(REG_RBR);
req_count--;
}
/* Finally, flush whatever's left in the UART into our buffer */
uart_read_to_buffer();
uart_trace(TRACE_UART_CTX_READ, read_cnt, tx_full, in_count);
unlock(&uart_lock);
/* Adjust the OPAL event */
uart_adjust_opal_event();
*__length = cpu_to_be64(read_cnt);
return OPAL_SUCCESS;
}
static int64_t uart_opal_flush(int64_t term_number)
{
int64_t rc;
if (term_number != 0)
return OPAL_PARAMETER;
lock(&uart_lock);
rc = uart_con_flush();
unlock(&uart_lock);
return rc;
}
static void __uart_do_poll(u8 trace_ctx)
{
if (!in_buf)
return;
lock(&uart_lock);
uart_read_to_buffer();
uart_con_flush();
uart_trace(trace_ctx, 0, tx_full, in_count);
unlock(&uart_lock);
uart_adjust_opal_event();
}
static void uart_console_poll(void *data __unused)
{
__uart_do_poll(TRACE_UART_CTX_POLL);
}
static void uart_irq(uint32_t chip_id __unused, uint32_t irq_mask __unused)
{
if (!irq_ok) {
prlog(PR_DEBUG, "UART: IRQ functional !\n");
irq_ok = true;
}
__uart_do_poll(TRACE_UART_CTX_IRQ);
}
/*
* Common setup/inits
*/
static void uart_setup_os_passthrough(void)
{
char *path;
static struct lpc_client uart_lpc_os_client = {
.reset = NULL,
.interrupt = NULL,
.interrupts = 0
};
dt_add_property_strings(uart_node, "status", "ok");
path = dt_get_path(uart_node);
dt_add_property_string(dt_chosen, "linux,stdout-path", path);
free(path);
/* Setup LPC client for OS interrupts */
if (lpc_irq >= 0) {
uint32_t chip_id = dt_get_chip_id(uart_node);
uart_lpc_os_client.interrupts = LPC_IRQ(lpc_irq);
lpc_register_client(chip_id, &uart_lpc_os_client,
IRQ_ATTR_TARGET_LINUX);
}
prlog(PR_DEBUG, "UART: Enabled as OS pass-through\n");
}
static void uart_setup_opal_console(void)
{
static struct lpc_client uart_lpc_opal_client = {
.interrupt = uart_irq,
};
/* Add the opal console node */
add_opal_console_node(0, "raw", OUT_BUF_SIZE);
dt_add_property_string(dt_chosen, "linux,stdout-path",
"/ibm,opal/consoles/serial@0");
/*
* We mark the UART as reserved since we don't want the
* kernel to start using it with its own 8250 driver
*/
dt_add_property_strings(uart_node, "status", "reserved");
/* Allocate an input buffer */
in_buf = zalloc(IN_BUF_SIZE);
out_buf = zalloc(OUT_BUF_SIZE);
/* Setup LPC client for OPAL interrupts */
if (lpc_irq >= 0) {
uint32_t chip_id = dt_get_chip_id(uart_node);
uart_lpc_opal_client.interrupts = LPC_IRQ(lpc_irq);
lpc_register_client(chip_id, &uart_lpc_opal_client,
IRQ_ATTR_TARGET_OPAL);
has_irq = true;
}
/*
* If the interrupt is enabled, turn on RX interrupts (and
* only these for now
*/
tx_full = rx_full = false;
uart_update_ier();
/* Start console poller */
opal_add_poller(uart_console_poll, NULL);
}
static void uart_init_opal_console(void)
{
const char *nv_policy;
/* Update the policy if the corresponding nvram variable
* is present
*/
nv_policy = nvram_query_dangerous("uart-con-policy");
if (nv_policy) {
if (!strcmp(nv_policy, "opal"))
uart_console_policy = UART_CONSOLE_OPAL;
else if (!strcmp(nv_policy, "os"))
uart_console_policy = UART_CONSOLE_OS;
else
prlog(PR_WARNING,
"UART: Unknown console policy in NVRAM: %s\n",
nv_policy);
}
if (uart_console_policy == UART_CONSOLE_OPAL)
uart_setup_opal_console();
else
uart_setup_os_passthrough();
}
struct opal_con_ops uart_opal_con = {
.name = "OPAL UART console",
.init = uart_init_opal_console,
.read = uart_opal_read,
.write = uart_opal_write,
.space = uart_opal_write_buffer_space,
.flush = uart_opal_flush,
};
static bool uart_init_hw(unsigned int speed, unsigned int clock)
{
unsigned int dll = (clock / 16) / speed;
/* Clear line control */
uart_write(REG_LCR, 0x00);
/* Check if the UART responds */
uart_write(REG_IER, 0x01);
if (uart_read(REG_IER) != 0x01)
goto detect_fail;
uart_write(REG_IER, 0x00);
if (uart_read(REG_IER) != 0x00)
goto detect_fail;
uart_write(REG_LCR, LCR_DLAB);
uart_write(REG_DLL, dll & 0xff);
uart_write(REG_DLM, dll >> 8);
uart_write(REG_LCR, 0x03); /* 8N1 */
uart_write(REG_MCR, 0x03); /* RTS/DTR */
uart_write(REG_FCR, 0x07); /* clear & en. fifos */
/*
* On some UART implementations[1], we have observed that characters
* written to the UART during early boot (where no RX path is used,
* so we don't read from RBR) can cause a character timeout interrupt
* once we eventually enable interrupts through the IER. This
* interrupt can only be cleared by reading from RBR (even though we've
* cleared the RX FIFO!).
*
* Unfortunately though, the LCR[DR] bit does *not* indicate that there
* are characters to be read from RBR, so we may never read it, so the
* interrupt continuously fires.
*
* So, manually clear the timeout interrupt by reading the RBR here.
* We discard the read data, but that shouldn't matter as we've just
* reset the FIFO anyway.
*
* 1: seen on the AST2500 SUART. I assume this applies to 2400 too.
*/
uart_read(REG_RBR);
return true;
detect_fail:
prerror("UART: Presence detect failed !\n");
return false;
}
/*
* early_uart_init() is similar to uart_init() in that it configures skiboot
* console log to output via a UART. The main differences are that the early
* version only works with MMIO UARTs and will not setup interrupts or locks.
*/
void early_uart_init(void)
{
struct dt_node *uart_node;
u32 clk, baud;
uart_node = dt_find_compatible_node(dt_root, NULL, "ns16550");
if (!uart_node)
return;
/* Try translate the address, if this fails then it's not a MMIO UART */
mmio_uart_base = (void *) dt_translate_address(uart_node, 0, NULL);
if (!mmio_uart_base)
return;
clk = dt_prop_get_u32(uart_node, "clock-frequency");
baud = dt_prop_get_u32(uart_node, "current-speed");
if (uart_init_hw(baud, clk)) {
set_console(&uart_con_driver);
prlog(PR_DEBUG, "UART: Using UART at %p\n", mmio_uart_base);
} else {
prerror("UART: Early init failed!");
mmio_uart_base = NULL;
}
}
void uart_init(void)
{
const struct dt_property *prop;
struct dt_node *n;
char *path __unused;
const be32 *irqp;
/* Clean up after early_uart_init() */
mmio_uart_base = NULL;
/* UART lock is in the console path and thus must block
* printf re-entrancy
*/
uart_lock.in_con_path = true;
/* We support only one */
uart_node = n = dt_find_compatible_node(dt_root, NULL, "ns16550");
if (!n)
return;
/* Read the interrupts property if any */
irqp = dt_prop_get_def(n, "interrupts", NULL);
/* Now check if the UART is on the root bus. This is the case of
* directly mapped UARTs in simulation environments
*/
if (n->parent == dt_root) {
printf("UART: Found at root !\n");
mmio_uart_base = (void *)dt_translate_address(n, 0, NULL);
if (!mmio_uart_base) {
printf("UART: Failed to translate address !\n");
return;
}
/* If it has an interrupt properly, we consider this to be
* a direct XICS/XIVE interrupt
*/
if (irqp)
has_irq = true;
} else {
if (!lpc_present())
return;
/* Get IO base */
prop = dt_find_property(n, "reg");
if (!prop) {
log_simple_error(&e_info(OPAL_RC_UART_INIT),
"UART: Can't find reg property\n");
return;
}
if (dt_property_get_cell(prop, 0) != OPAL_LPC_IO) {
log_simple_error(&e_info(OPAL_RC_UART_INIT),
"UART: Only supports IO addresses\n");
return;
}
uart_base = dt_property_get_cell(prop, 1);
if (irqp) {
lpc_irq = be32_to_cpu(*irqp);
prlog(PR_DEBUG, "UART: Using LPC IRQ %d\n", lpc_irq);
}
}
if (!uart_init_hw(dt_prop_get_u32(n, "current-speed"),
dt_prop_get_u32(n, "clock-frequency"))) {
prerror("UART: Initialization failed\n");
dt_add_property_strings(n, "status", "bad");
return;
}
/*
* Mark LPC used by the console (will mark the relevant
* locks to avoid deadlocks when flushing the console)
*/
lpc_used_by_console();
/* Install console backend for printf() */
set_console(&uart_con_driver);
}