diff options
author | Deepak K <deepak.k@ti.com> | 2010-08-02 06:18:12 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-08-02 06:18:12 -0400 |
commit | 0003450964357ec85eeeeda2e4bb8b06a6f82ad3 (patch) | |
tree | 69e8e5fab5bba66712681c0022fda2b6594c0ce3 /arch/arm/mach-omap2/serial.c | |
parent | 5a927b36f56c2a937e67f0947f233f723660f690 (diff) |
omap2/3/4: serial: errata i202: fix for MDR1 access
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
Based on an earlier patch at:
http://git.omapzoom.org/?p=kernel/omap.git;a=commitdiff;h=42d4a342c009bd9727c100abc8a4bc3063c22f0c
Signed-off-by: Deepak K <deepak.k@ti.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/serial.c')
-rw-r--r-- | 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 009b63fc79f0..566e991ede81 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #define UART_OMAP_WER 0x17 /* Wake-up enable register */ | 38 | #define UART_OMAP_WER 0x17 /* Wake-up enable register */ |
39 | 39 | ||
40 | #define UART_ERRATA_FIFO_FULL_ABORT (0x1 << 0) | 40 | #define UART_ERRATA_FIFO_FULL_ABORT (0x1 << 0) |
41 | #define UART_ERRATA_i202_MDR1_ACCESS (0x1 << 1) | ||
41 | 42 | ||
42 | /* | 43 | /* |
43 | * NOTE: By default the serial timeout is disabled as it causes lost characters | 44 | * 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) | |||
184 | 185 | ||
185 | #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) | 186 | #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) |
186 | 187 | ||
188 | /* | ||
189 | * Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6) | ||
190 | * The access to uart register after MDR1 Access | ||
191 | * causes UART to corrupt data. | ||
192 | * | ||
193 | * Need a delay = | ||
194 | * 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) | ||
195 | * give 10 times as much | ||
196 | */ | ||
197 | static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val, | ||
198 | u8 fcr_val) | ||
199 | { | ||
200 | struct plat_serial8250_port *p = uart->p; | ||
201 | u8 timeout = 255; | ||
202 | |||
203 | serial_write_reg(p, UART_OMAP_MDR1, mdr1_val); | ||
204 | udelay(2); | ||
205 | serial_write_reg(p, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT | | ||
206 | UART_FCR_CLEAR_RCVR); | ||
207 | /* | ||
208 | * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and | ||
209 | * TX_FIFO_E bit is 1. | ||
210 | */ | ||
211 | while (UART_LSR_THRE != (serial_read_reg(p, UART_LSR) & | ||
212 | (UART_LSR_THRE | UART_LSR_DR))) { | ||
213 | timeout--; | ||
214 | if (!timeout) { | ||
215 | /* Should *never* happen. we warn and carry on */ | ||
216 | dev_crit(&uart->pdev.dev, "Errata i202: timedout %x\n", | ||
217 | serial_read_reg(p, UART_LSR)); | ||
218 | break; | ||
219 | } | ||
220 | udelay(1); | ||
221 | } | ||
222 | } | ||
223 | |||
187 | static void omap_uart_save_context(struct omap_uart_state *uart) | 224 | static void omap_uart_save_context(struct omap_uart_state *uart) |
188 | { | 225 | { |
189 | u16 lcr = 0; | 226 | u16 lcr = 0; |
@@ -221,7 +258,10 @@ static void omap_uart_restore_context(struct omap_uart_state *uart) | |||
221 | 258 | ||
222 | uart->context_valid = 0; | 259 | uart->context_valid = 0; |
223 | 260 | ||
224 | serial_write_reg(p, UART_OMAP_MDR1, 0x7); | 261 | if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS) |
262 | omap_uart_mdr1_errataset(uart, 0x07, 0xA0); | ||
263 | else | ||
264 | serial_write_reg(p, UART_OMAP_MDR1, 0x7); | ||
225 | serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ | 265 | serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ |
226 | efr = serial_read_reg(p, UART_EFR); | 266 | efr = serial_read_reg(p, UART_EFR); |
227 | serial_write_reg(p, UART_EFR, UART_EFR_ECB); | 267 | serial_write_reg(p, UART_EFR, UART_EFR_ECB); |
@@ -234,14 +274,16 @@ static void omap_uart_restore_context(struct omap_uart_state *uart) | |||
234 | serial_write_reg(p, UART_IER, uart->ier); | 274 | serial_write_reg(p, UART_IER, uart->ier); |
235 | serial_write_reg(p, UART_LCR, 0x80); | 275 | serial_write_reg(p, UART_LCR, 0x80); |
236 | serial_write_reg(p, UART_MCR, uart->mcr); | 276 | serial_write_reg(p, UART_MCR, uart->mcr); |
237 | serial_write_reg(p, UART_FCR, 0xA1); | ||
238 | serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ | 277 | serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ |
239 | serial_write_reg(p, UART_EFR, efr); | 278 | serial_write_reg(p, UART_EFR, efr); |
240 | serial_write_reg(p, UART_LCR, UART_LCR_WLEN8); | 279 | serial_write_reg(p, UART_LCR, UART_LCR_WLEN8); |
241 | serial_write_reg(p, UART_OMAP_SCR, uart->scr); | 280 | serial_write_reg(p, UART_OMAP_SCR, uart->scr); |
242 | serial_write_reg(p, UART_OMAP_WER, uart->wer); | 281 | serial_write_reg(p, UART_OMAP_WER, uart->wer); |
243 | serial_write_reg(p, UART_OMAP_SYSC, uart->sysc); | 282 | serial_write_reg(p, UART_OMAP_SYSC, uart->sysc); |
244 | serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */ | 283 | if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS) |
284 | omap_uart_mdr1_errataset(uart, 0x00, 0xA1); | ||
285 | else | ||
286 | serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */ | ||
245 | } | 287 | } |
246 | #else | 288 | #else |
247 | static inline void omap_uart_save_context(struct omap_uart_state *uart) {} | 289 | static inline void omap_uart_save_context(struct omap_uart_state *uart) {} |
@@ -769,6 +811,10 @@ void __init omap_serial_init_port(int port) | |||
769 | uart->p->serial_in = serial_in_override; | 811 | uart->p->serial_in = serial_in_override; |
770 | uart->p->serial_out = serial_out_override; | 812 | uart->p->serial_out = serial_out_override; |
771 | } | 813 | } |
814 | |||
815 | /* Enable the MDR1 errata for OMAP3 */ | ||
816 | if (cpu_is_omap34xx()) | ||
817 | uart->errata |= UART_ERRATA_i202_MDR1_ACCESS; | ||
772 | } | 818 | } |
773 | 819 | ||
774 | /** | 820 | /** |