|
@@ -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);
|
|
|
+ else
|
|
|
+ serial_write_reg(p, UART_OMAP_MDR1, 0x7);
|
|
|
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);
|
|
|
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 */
|
|
|
}
|
|
|
#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;
|
|
|
}
|
|
|
|
|
|
/**
|