diff mbox

beagle hangs in uart3 disabling clocks

Message ID alpine.DEB.2.00.1010050013210.13816@utopia.booyaka.com (mailing list archive)
State New, archived
Delegated to: Paul Walmsley
Headers show

Commit Message

Paul Walmsley Oct. 5, 2010, 6:14 a.m. UTC
None
diff mbox

Patch

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 <linux/serial_8250.h>
 #include <linux/pm_runtime.h>
 
+#include <linux/console.h>
+
 #ifdef CONFIG_SERIAL_OMAP
 #include <plat/omap-serial.h>
 #endif
 
+#include <plat/serial.h>
 #include <plat/common.h>
 #include <plat/board.h>
 #include <plat/clock.h>
@@ -39,6 +42,8 @@ 
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
 
+#include <asm/memory.h>
+
 #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);
 }