From patchwork Tue Oct 5 06:14:07 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Walmsley X-Patchwork-Id: 231161 X-Patchwork-Delegate: paul@pwsan.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o956EBmc015739 for ; Tue, 5 Oct 2010 06:14:11 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757497Ab0JEGOK (ORCPT ); Tue, 5 Oct 2010 02:14:10 -0400 Received: from utopia.booyaka.com ([72.9.107.138]:32781 "EHLO utopia.booyaka.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754548Ab0JEGOJ (ORCPT ); Tue, 5 Oct 2010 02:14:09 -0400 Received: (qmail 23070 invoked by uid 1019); 5 Oct 2010 06:14:07 -0000 Date: Tue, 5 Oct 2010 00:14:07 -0600 (MDT) From: Paul Walmsley To: Ming Lei cc: Kevin Hilman , Govindraj , Pramod , "Premi, Sanjeev" , "linux-omap@vger.kernel.org" Subject: Re: beagle hangs in uart3 disabling clocks In-Reply-To: Message-ID: References: <4CA9C5F6.7060902@ti.com> <87wrpy0xp3.fsf@deeprootsystems.com> <87iq1hzt3u.fsf@deeprootsystems.com> User-Agent: Alpine 2.00 (DEB 1167 2008-08-23) MIME-Version: 1.0 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 05 Oct 2010 06:14:11 +0000 (UTC) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 338e46a..577f8f9 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -28,10 +28,13 @@ #include #include +#include + #ifdef CONFIG_SERIAL_OMAP #include #endif +#include #include #include #include @@ -39,6 +42,8 @@ #include #include +#include + #include "prm.h" #include "pm.h" #include "cm.h" @@ -51,6 +56,8 @@ #define UART_ERRATA_FIFO_FULL_ABORT (0x1 << 0) #define UART_ERRATA_i202_MDR1_ACCESS (0x1 << 1) +#define uart_id_to_ttys_id(u) (u - 1) + /* * NOTE: By default the serial timeout is disabled as it causes lost characters * over the serial ports. This means that the UART clocks will stay on until @@ -106,6 +113,83 @@ static LIST_HEAD(uart_list); static u8 num_uarts; /* + * early_console_uart: if earlyconsole is enabled and active, the UART + * ID (e.g., 1, 2, 3, 4) will be stored here. '0' means earlyconsole + * is disabled or some problem occurred during earlyconsole handling. + */ +static int early_console_uart; + +#define for_each_console(con) \ + for (con = console_drivers; con != NULL; con = con->next) + +/* XXX belongs in kernel/printk.c or some earlyconsole file */ +/* XXX The "earlycon" string is an ugly hack */ +int _is_early_console_enabled(void) +{ + int ret = 0; + struct console *c; + + acquire_console_sem(); + for_each_console(c) + if (!strcmp("earlycon", c->name)) + ret = 1; + release_console_sem(); + + return ret; +} + +/* XXX document */ +static int _get_early_console_uart(void) +{ + u32 v; + int u = -EINVAL; + + v = __raw_readl(phys_to_virt(OMAP_UART_INFO)); + /* XXX see the OMAP debug-macro.S for this table */ + switch (v) { + case 0: + case OMAP2UART1: + u = 1; + break; + case OMAP2UART2: + u = 2; + break; + case OMAP2UART3: + case OMAP3UART3: + case OMAP4UART3: + u = 3; + break; + case OMAP3UART4: + case OMAP4UART4: + u = 4; + break; + case ZOOM_UART: + WARN(1, "omap serial: ZOOM UART in use - does that go through " + "the OMAP serial code?\n"); + break; + default: + WARN(1, "omap serial: unknown serial port in use!\n"); + } + + return u; +} + +/* XXX document */ +static void _store_early_console_uart_id(void) +{ + int uart_id; + + if (_is_early_console_enabled()) { + uart_id = _get_early_console_uart(); + if (uart_id > 0) { + early_console_uart = uart_id; + pr_info("omap serial: early console active on UART%d (ttyS%d)\n", + uart_id, uart_id_to_ttys_id(uart_id)); + } + } +} + +/* * Since these idle/enable hooks are used in the idle path itself * which has interrupts disabled, use the non-locking versions of * the hwmod enable/disable functions. @@ -801,6 +885,17 @@ void __init omap_serial_init_port(int port) oh->dev_attr = uart; /* + * XXX How do we know whether the console is on this UART or not? + * We should only call acquire_console_sem() if the console is on + * this UART. + * + * Of course, the console is not the only thing that could be using + * this UART. + */ + if (uart->num == uart_id_to_ttys_id(early_console_uart)) + acquire_console_sem(); + + /* * Because of early UART probing, UART did not get idled * on init. Now that omap_device is ready, ensure full idle * before doing omap_device_enable(). @@ -824,6 +919,9 @@ void __init omap_serial_init_port(int port) omap_uart_block_sleep(uart); uart->timeout = DEFAULT_TIMEOUT; + if (uart->num == uart_id_to_ttys_id(early_console_uart)) + release_console_sem(); + if ((cpu_is_omap34xx() && uart->padconf) || (uart->wk_en && uart->wk_mask)) { device_init_wakeup(&od->pdev.dev, true); @@ -846,6 +944,8 @@ void __init omap_serial_init(void) { struct omap_uart_state *uart; + _store_early_console_uart_id(); + list_for_each_entry(uart, &uart_list, node) omap_serial_init_port(uart->num); }