Re: [PATCH 5/5 v4] omap2/3/4: serial: errata i202: fix for MDR1 access

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On 06/23/2010 07:17 AM, ext Nishanth Menon wrote:
From: Deepak K<deepak.k@xxxxxx>

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.raja@xxxxxx>
Cc: Kevin Hilman<khilman@xxxxxxxxxxxxxxxxxxx>
Cc: Tero Kristo<tero.kristo@xxxxxxxxx>
Cc: Tony Lindgren<tony@xxxxxxxxxxx>

Signed-off-by: Deepak K<deepak.k@xxxxxx>
Signed-off-by: Nishanth Menon<nm@xxxxxx>
---
  arch/arm/mach-omap2/serial.c |   52 +++++++++++++++++++++++++++++++++++++++--
  1 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 009b63f..566e991 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -38,6 +38,7 @@
  #define UART_OMAP_WER		0x17	/* Wake-up enable register */

  #define UART_ERRATA_FIFO_FULL_ABORT	(0x1<<  0)
+#define UART_ERRATA_i202_MDR1_ACCESS	(0x1<<  1)

  /*
   * NOTE: By default the serial timeout is disabled as it causes lost characters
@@ -184,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;
@@ -221,7 +258,10 @@ static void omap_uart_restore_context(struct omap_uart_state *uart)

  	uart->context_valid = 0;

-	serial_write_reg(p, UART_OMAP_MDR1, 0x7);
+	if (uart->errata&  UART_ERRATA_i202_MDR1_ACCESS)
+		omap_uart_mdr1_errataset(uart, 0x07, 0xA0);

If errata you set both MDR1 and FCR
+	else
+		serial_write_reg(p, UART_OMAP_MDR1, 0x7);

If not errata you set only MDR1

  	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);
@@ -234,14 +274,16 @@ 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);

If not errata, FCR is never set.

  	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 */
+	if (uart->errata&  UART_ERRATA_i202_MDR1_ACCESS)
+		omap_uart_mdr1_errataset(uart, 0x00, 0xA1);
+	else
+		serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
same here

FCR is never touched if no errata condition?
Is this going to be a problem for non erroneous devices?

  }
  #else
  static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
@@ -769,6 +811,10 @@ void __init omap_serial_init_port(int port)
  		uart->p->serial_in = serial_in_override;
  		uart->p->serial_out = serial_out_override;
  	}
+
+	/* Enable the MDR1 errata for OMAP3 */
+	if (cpu_is_omap34xx())
+		uart->errata |= UART_ERRATA_i202_MDR1_ACCESS;
  }

  /**

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


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux