From: Deepak K <deepa...@ti.com>

Original patch:
http://git.omapzoom.org/?p=kernel/omap.git;a=commitdiff;h=42d4a342c009bd9727c100abc8a4bc3063c22f0c

Errata i202 (OMAP3430 - 1.12, OMAP3630 - 1.6):
UART module MDR1 register access can cause a dummy underrun
condition which could result in a freeze in the case of IrDA
communication or if used as UART, corrupted data.

Workaround is as follows for everytime MDR1 register is changed:
* setup all required UART registers
* setup MDR1.MODE_SELECT bit field
* Wait 5 L4 clk cycles + 5 UART functional clock cycles
* Clear the Tx and RX fifo using FCR register

Note: The following step is not done as I am assuming it is not
needed due to reconfiguration being done and there is no halted
operation perse.
* Read if required, the RESUME register to resume halted operation

Cc: Govindraj R <govindraj.r...@ti.com>
Cc: Kevin Hilman <khil...@deeprootsystems.com>
Cc: Tero Kristo <tero.kri...@nokia.com>

Signed-off-by: Deepak K <deepa...@ti.com>
Signed-off-by: Nishanth Menon <n...@ti.com>
---
Changes from V2:
  * Use macros instead of hardcoded values

Ref:
V2: http://marc.info/?t=127084514600010&r=1&w=2&n=2
v1: http://marc.info/?t=127074933100005&r=1&w=2

 arch/arm/mach-omap2/serial.c |   41 ++++++++++++++++++++++++++++++++++++++---
 1 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index a7c45b5..6d13183 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -185,6 +185,42 @@ static inline void __init omap_uart_reset(struct 
omap_uart_state *uart)
 
 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
 
+/*
+ * Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6)
+ * The access to uart register after MDR1 Access
+ * causes UART to corrupt data.
+ *
+ * Need a delay =
+ * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS)
+ * give 10 times as much
+ */
+static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
+               u8 fcr_val)
+{
+       struct plat_serial8250_port *p = uart->p;
+       u8 timeout = 255;
+
+       serial_write_reg(p, UART_OMAP_MDR1, mdr1_val);
+       udelay(2);
+       serial_write_reg(p, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
+                       UART_FCR_CLEAR_RCVR);
+       /*
+        * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
+        * TX_FIFO_E bit is 1.
+        */
+       while (UART_LSR_THRE != (serial_read_reg(p, UART_LSR) &
+                               (UART_LSR_THRE | UART_LSR_DR))) {
+               timeout--;
+               if (!timeout) {
+                       /* Should *never* happen. we warn and carry on */
+                       dev_crit(&uart->pdev.dev, "Errata i202: timedout %x\n",
+                               serial_read_reg(p, UART_LSR));
+                       break;
+               }
+               udelay(1);
+       }
+}
+
 static void omap_uart_save_context(struct omap_uart_state *uart)
 {
        u16 lcr = 0;
@@ -222,7 +258,7 @@ static void omap_uart_restore_context(struct 
omap_uart_state *uart)
 
        uart->context_valid = 0;
 
-       serial_write_reg(p, UART_OMAP_MDR1, 0x7);
+       omap_uart_mdr1_errataset(uart, 0x07, 0xA0);
        serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
        efr = serial_read_reg(p, UART_EFR);
        serial_write_reg(p, UART_EFR, UART_EFR_ECB);
@@ -235,14 +271,13 @@ static void omap_uart_restore_context(struct 
omap_uart_state *uart)
        serial_write_reg(p, UART_IER, uart->ier);
        serial_write_reg(p, UART_LCR, 0x80);
        serial_write_reg(p, UART_MCR, uart->mcr);
-       serial_write_reg(p, UART_FCR, 0xA1);
        serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
        serial_write_reg(p, UART_EFR, efr);
        serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
        serial_write_reg(p, UART_OMAP_SCR, uart->scr);
        serial_write_reg(p, UART_OMAP_WER, uart->wer);
        serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
-       serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+       omap_uart_mdr1_errataset(uart, 0x00, 0xA1);
 }
 #else
 static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to