/* Copyright 2013-2014 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 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 void uart_check_tx_room(void) { if (uart_read(REG_LSR) & LSR_THRE) { /* FIFO is 16 entries */ tx_room = 16; tx_full = false; } } static void uart_wait_tx_room(void) { while (!tx_room) { uart_check_tx_room(); if (!tx_room) { smt_lowest(); do { barrier(); uart_check_tx_room(); } while (!tx_room); smt_medium(); } } } 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 written; lock(&uart_lock); while(written < len) { if (tx_room == 0) { uart_wait_tx_room(); if (tx_room == 0) goto bail; } else { uart_write(REG_THR, buf[written++]); tx_room--; } } bail: 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(REG_THR, out_buf[out_buf_cons++]); out_buf_cons %= OUT_BUF_SIZE; tx_room--; } 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) 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, int64_t *length, const uint8_t *buffer) { size_t written = 0, len = *length; 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(); unlock(&uart_lock); *length = written; return OPAL_SUCCESS; } static int64_t uart_opal_write_buffer_space(int64_t term_number, int64_t *length) { if (term_number != 0) return OPAL_PARAMETER; lock(&uart_lock); *length = uart_tx_buf_space(); unlock(&uart_lock); return OPAL_SUCCESS; } /* 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, int64_t *length, uint8_t *buffer) { size_t req_count = *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 = 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("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 uint32_t *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); }