From patchwork Fri Jun 24 22:47:33 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Herrenschmidt X-Patchwork-Id: 640464 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rbtnS30DHz9s0M for ; Sat, 25 Jun 2016 08:49:48 +1000 (AEST) Received: from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3rbtnS1vzZzDqlb for ; Sat, 25 Jun 2016 08:49:48 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from gate.crashing.org (gate.crashing.org [63.228.1.57]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3rbtm02RrhzDqlv for ; Sat, 25 Jun 2016 08:48:32 +1000 (AEST) Received: from pasglop.au.ibm.com (localhost.localdomain [127.0.0.1]) by gate.crashing.org (8.14.1/8.13.8) with ESMTP id u5OMm2Mj022384; Fri, 24 Jun 2016 17:48:27 -0500 From: Benjamin Herrenschmidt To: skiboot@lists.ozlabs.org Date: Sat, 25 Jun 2016 08:47:33 +1000 Message-Id: <1466808476-32690-10-git-send-email-benh@kernel.crashing.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1466808476-32690-1-git-send-email-benh@kernel.crashing.org> References: <1466808476-32690-1-git-send-email-benh@kernel.crashing.org> Subject: [Skiboot] [PATCH 10/33] uart: Cleanup initialization and remove simulator hack X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Add more generic support for MMIO based UARTs, simplify code, use common initialization, and clean up the device-tree representation as well. Signed-off-by: Benjamin Herrenschmidt Acked-by: Michael Neuling --- core/init.c | 7 ++- core/platform.c | 8 ++- hw/lpc-uart.c | 152 ++++++++++++++++++++-------------------------- include/console.h | 1 - include/skiboot.h | 3 +- platforms/astbmc/common.c | 4 +- platforms/qemu/qemu.c | 8 +-- platforms/rhesus/rhesus.c | 8 +-- 8 files changed, 85 insertions(+), 106 deletions(-) diff --git a/core/init.c b/core/init.c index 67b539b..48f5322 100644 --- a/core/init.c +++ b/core/init.c @@ -657,10 +657,13 @@ void __noreturn main_cpu_entry(const void *fdt, u32 master_cpu) * to access chips via that path early on. */ init_chips(); + + /* If we detect the mambo simulator, we can enable its special console + * early on. Do that now. + */ if (chip_quirk(QUIRK_MAMBO_CALLOUTS)) enable_mambo_console(); - if (chip_quirk(QUIRK_SIMICS)) - enable_simics_console(); + xscom_init(); mfsi_init(); diff --git a/core/platform.c b/core/platform.c index 371cf42..de6e406 100644 --- a/core/platform.c +++ b/core/platform.c @@ -98,7 +98,13 @@ opal_call(OPAL_CEC_REBOOT2, opal_cec_reboot2, 2); static void generic_platform_init(void) { - force_dummy_console(); + /* Enable a UART if we find one in the device-tree */ + uart_init(); + + if (uart_enabled()) + uart_setup_opal_console(); + else + force_dummy_console(); fake_rtc_init(); } diff --git a/hw/lpc-uart.c b/hw/lpc-uart.c index 433cdff..6693265 100644 --- a/hw/lpc-uart.c +++ b/hw/lpc-uart.c @@ -64,11 +64,10 @@ DEFINE_LOG_ENTRY(OPAL_RC_UART_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_UART, static struct lock uart_lock = LOCK_UNLOCKED; static struct dt_node *uart_node; static uint32_t uart_base; -static bool has_irq, irq_ok, rx_full, tx_full; +static bool has_irq = false, irq_ok, rx_full, tx_full; static uint8_t tx_room; static uint8_t cached_ier; -static bool simics_uart; -static void *simics_uart_base; +static void *mmio_uart_base; static void uart_trace(u8 ctx, u8 cnt, u8 irq_state, u8 in_count) { @@ -83,16 +82,16 @@ static void uart_trace(u8 ctx, u8 cnt, u8 irq_state, u8 in_count) static inline uint8_t uart_read(unsigned int reg) { - if (simics_uart) - return in_8(simics_uart_base + 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 (simics_uart) - out_8(simics_uart_base + reg, val); + if (mmio_uart_base) + out_8(mmio_uart_base + reg, val); else lpc_outb(val, uart_base + reg); } @@ -121,6 +120,7 @@ static void uart_update_ier(void) 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 @@ -138,6 +138,11 @@ static void uart_update_ier(void) } } +bool uart_enabled(void) +{ + return mmio_uart_base || uart_base; +} + /* * Internal console driver (output only) */ @@ -146,7 +151,7 @@ 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() && !simics_uart) + if (!lpc_ok() && !mmio_uart_base) return written; lock(&uart_lock); @@ -362,7 +367,7 @@ static int64_t uart_opal_read(int64_t term_number, int64_t *length, uart_trace(TRACE_UART_CTX_READ, read_cnt, tx_full, in_count); unlock(&uart_lock); - + /* Adjust the OPAL event */ uart_adjust_opal_event(); @@ -492,15 +497,13 @@ static struct lpc_client uart_lpc_client = { .interrupt = uart_irq, }; -void uart_init(bool use_interrupt) +void uart_init(void) { const struct dt_property *prop; struct dt_node *n; char *path __unused; - uint32_t chip_id, irq; - - if (!lpc_present()) - return; + uint32_t chip_id; + const uint32_t *irqp; /* UART lock is in the console path and thus must block * printf re-entrancy @@ -512,19 +515,55 @@ void uart_init(bool use_interrupt) if (!n) 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; + /* 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) { + uint32_t irq = be32_to_cpu(*irqp); + + chip_id = dt_get_chip_id(uart_node); + uart_lpc_client.interrupts = LPC_IRQ(irq); + lpc_register_client(chip_id, &uart_lpc_client); + prlog(PR_DEBUG, "UART: Using LPC IRQ %d\n", irq); + has_irq = true; + } } - uart_base = dt_property_get_cell(prop, 1); + if (!uart_init_hw(dt_prop_get_u32(n, "current-speed"), dt_prop_get_u32(n, "clock-frequency"))) { @@ -532,7 +571,6 @@ void uart_init(bool use_interrupt) dt_add_property_strings(n, "status", "bad"); return; } - chip_id = dt_get_chip_id(uart_node); /* * Mark LPC used by the console (will mark the relevant @@ -542,65 +580,5 @@ void uart_init(bool use_interrupt) /* Install console backend for printf() */ set_console(&uart_con_driver); - - /* On Naples, use the SerIRQ, which Linux will have to share with - * OPAL as we don't really play the cascaded interrupt game at this - * point... - */ - if (use_interrupt) { - irq = dt_prop_get_u32(n, "interrupts"); - uart_lpc_client.interrupts = LPC_IRQ(irq); - lpc_register_client(chip_id, &uart_lpc_client); - has_irq = true; - prlog(PR_DEBUG, "UART: Using LPC IRQ %d\n", irq); - } else - has_irq = false; -} - -static bool simics_con_poll_read(void) { - uint8_t lsr = uart_read(REG_LSR); - return ((lsr & LSR_DR) != 0); } -static size_t simics_con_read(char *buf, size_t len) -{ - size_t count = 0; - while (count < len) { - if (!simics_con_poll_read()) - break; - *(buf++) = uart_read(REG_RBR); - count++; - } - return count; -} - -static struct con_ops simics_con_driver = { - .poll_read = simics_con_poll_read, - .read = simics_con_read, - .write = uart_con_write, -}; - -void enable_simics_console() { - struct dt_node *n; - - printf("Enabling Simics console\n"); - - n = dt_find_compatible_node(dt_root, NULL, "ns16550"); - if (!n) { - prerror("UART: cannot find ns16550\n"); - return; - } - - simics_uart_base = (void *)dt_prop_get_u64(n, "console-bar"); - simics_uart = 1; - has_irq = false; - - 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; - } - - set_console(&simics_con_driver); -} diff --git a/include/console.h b/include/console.h index ecb18c4..b6fc8bf 100644 --- a/include/console.h +++ b/include/console.h @@ -67,7 +67,6 @@ extern void console_complete_flush(void); extern int mambo_read(void); extern void mambo_write(const char *buf, size_t count); extern void enable_mambo_console(void); -extern void enable_simics_console(void); ssize_t console_write(bool flush_to_drivers, const void *buf, size_t count); diff --git a/include/skiboot.h b/include/skiboot.h index ded6bb8..1d33389 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -203,7 +203,7 @@ extern void probe_phb3(void); extern int phb3_preload_capp_ucode(void); extern void phb3_preload_vpd(void); extern void probe_npu(void); -extern void uart_init(bool enable_interrupt); +extern void uart_init(void); extern void homer_init(void); extern void occ_pstates_init(void); extern void slw_init(void); @@ -228,6 +228,7 @@ extern void nvram_read_complete(bool success); /* UART stuff */ extern void uart_setup_linux_passthrough(void); extern void uart_setup_opal_console(void); +extern bool uart_enabled(void); /* OCC interrupt */ extern void occ_interrupt(uint32_t chip_id); diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c index 1ed7d42..0699a44 100644 --- a/platforms/astbmc/common.c +++ b/platforms/astbmc/common.c @@ -347,8 +347,8 @@ void astbmc_early_init(void) /* Similarly, some BMCs don't configure the BT interrupt properly */ ast_setup_ibt(BT_IO_BASE, BT_LPC_IRQ); - /* Setup UART and use it as console with interrupts */ - uart_init(true); + /* Setup UART and use it as console */ + uart_init(); prd_init(); } diff --git a/platforms/qemu/qemu.c b/platforms/qemu/qemu.c index 66a6aa3..a7d2889 100644 --- a/platforms/qemu/qemu.c +++ b/platforms/qemu/qemu.c @@ -130,12 +130,8 @@ static bool qemu_probe(void) psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT); - /* - * Setup UART and use it as console. For now, we - * don't expose the interrupt as we know it's not - * working properly yet - */ - uart_init(true); + /* Setup UART and use it as console */ + uart_init(); return true; } diff --git a/platforms/rhesus/rhesus.c b/platforms/rhesus/rhesus.c index 3e2c41b..a3af777 100644 --- a/platforms/rhesus/rhesus.c +++ b/platforms/rhesus/rhesus.c @@ -270,12 +270,8 @@ static bool rhesus_probe(void) /* Add missing bits of device-tree such as the UART */ rhesus_dt_fixup(has_uart_irq); - /* - * Setup UART and use it as console. For now, we - * don't expose the interrupt as we know it's not - * working properly yet - */ - uart_init(has_uart_irq); + /* Setup UART and use it as console */ + uart_init(); return true; }