From b0da3bdb5b6b417ad6cab0084359d4eae1cb4469 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Wed, 26 Feb 2014 11:53:39 -0600 Subject: [PATCH] baytrail: workaround kernel using serial console on resume The UART hardware loses power while the system is suspended. However, the kernel currently doesn't handle the notion of the serial port losing its settings through a suspend. Because of this using a serial console in the kernel can cause hangs. Work around this by always initializing the serial port (if enabled) to 115200 8n1. Though the configuration may differ it should at least keep hangs and crashes from occuring with uninitialized serial port. BUG=chrome-os-partner:25353 BRANCH=baytrail TEST=Suspend/resume cycles successfully completed with and without 'echo N > /sys/module/printk/parameters/console_suspend'. With a serial console enabled in the kernel. Also confirmed that there are not any hiccups when coreboot has its console enabled. Change-Id: I6fd8a0ae261318769d8f677ef04320a0d6ff1b6d Signed-off-by: Aaron Durbin Reviewed-on: https://chromium-review.googlesource.com/188011 Reviewed-by: Duncan Laurie --- src/soc/intel/baytrail/southcluster.c | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/soc/intel/baytrail/southcluster.c b/src/soc/intel/baytrail/southcluster.c index 3f46f6a3be..2a1a5afd34 100644 --- a/src/soc/intel/baytrail/southcluster.c +++ b/src/soc/intel/baytrail/southcluster.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #include #include @@ -144,6 +146,42 @@ static void sc_rtc_init(void) rtc_init(rtc_fail); } +/* + * The UART hardware loses power while in suspend. Because of this the kernel + * can hang because it doesn't re-initialize serial ports it is using for + * consoles at resume time. The following function configures the UART + * if the hardware is enabled though it may not be the correct baud rate + * or configuration. This is definitely a hack, but it helps the kernel + * along. + */ +static void com1_configure_resume(device_t dev) +{ + const uint16_t port = 0x3f8; + + /* Is the UART I/O port eanbled? */ + if (!(pci_read_config32(dev, UART_CONT) & 1)) + return; + + /* Disable interrupts */ + outb(0x0, port + UART8250_IER); + + /* Enable FIFOs */ + outb(UART8250_FCR_FIFO_EN, port + UART8250_FCR); + + /* assert DTR and RTS so the other end is happy */ + outb(UART8250_MCR_DTR | UART8250_MCR_RTS, port + UART8250_MCR); + + /* DLAB on */ + outb(UART8250_LCR_DLAB | 3, port + UART8250_LCR); + + /* Set Baud Rate Divisor. 1 ==> 115200 Baud */ + outb(1, port + UART8250_DLL); + outb(0, port + UART8250_DLM); + + /* Set to 3 for 8N1 */ + outb(3, port + UART8250_LCR); +} + static void sc_init(device_t dev) { int i; @@ -176,6 +214,9 @@ static void sc_init(device_t dev) write32(gen_pmcon1, read32(gen_pmcon1) & ~DIS_SLP_X_STRCH_SUS_UP); } + + if (acpi_slp_type == 3) + com1_configure_resume(dev); } /*