Skip to content

Commit cdb929e

Browse files
nsekhargregkh
authored andcommitted
serial: 8250_omap: workaround errata around idling UART after using DMA
AM335x, AM437x and DRA7x SoCs have an errata[1] due to which UART cannot be idled after it has been used with DMA. OMAP3 has a similar sounding errata which has been worked around in a2fc366 ("ARM: OMAP3: Use manual idle for UARTs because of DMA errata"). But the workaround used there does not apply to AM335x, AM437x SoCs. After using DMA, the UART module on these SoCs must be soft reset to go to idle. This patch implements that errata workaround. It is expected that UART will be used with DMA so no explicit check for DMA usage has been added for errata applicability. MDR1 register needs to be restored right after soft-reset because "UART mode" must be set in that register for module wake-up on AM335x to work. As a result, SCR register is now used to determine if context was lost during sleep. [1] See Advisory 21 in AM437x errata SPRZ408B, updated April 2015. http://www.ti.com/lit/er/sprz408b/sprz408b.pdf Signed-off-by: Sekhar Nori <nsekhar@ti.com> Acked-by: Tony Lindgren <tony@atomide.com> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 4fcdff9 commit cdb929e

File tree

1 file changed

+59
-6
lines changed

1 file changed

+59
-6
lines changed

drivers/tty/serial/8250/8250_omap.c

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
#define UART_ERRATA_i202_MDR1_ACCESS (1 << 0)
3434
#define OMAP_UART_WER_HAS_TX_WAKEUP (1 << 1)
3535
#define OMAP_DMA_TX_KICK (1 << 2)
36+
/*
37+
* See Advisory 21 in AM437x errata SPRZ408B, updated April 2015.
38+
* The same errata is applicable to AM335x and DRA7x processors too.
39+
*/
40+
#define UART_ERRATA_CLOCK_DISABLE (1 << 3)
3641

3742
#define OMAP_UART_FCR_RX_TRIG 6
3843
#define OMAP_UART_FCR_TX_TRIG 4
@@ -54,6 +59,12 @@
5459
#define OMAP_UART_MVR_MAJ_SHIFT 8
5560
#define OMAP_UART_MVR_MIN_MASK 0x3f
5661

62+
/* SYSC register bitmasks */
63+
#define OMAP_UART_SYSC_SOFTRESET (1 << 1)
64+
65+
/* SYSS register bitmasks */
66+
#define OMAP_UART_SYSS_RESETDONE (1 << 0)
67+
5768
#define UART_TI752_TLR_TX 0
5869
#define UART_TI752_TLR_RX 4
5970

@@ -1062,13 +1073,15 @@ static int omap8250_no_handle_irq(struct uart_port *port)
10621073
return 0;
10631074
}
10641075

1065-
static const u8 am3352_habit = OMAP_DMA_TX_KICK;
1076+
static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE;
1077+
static const u8 am4372_habit = UART_ERRATA_CLOCK_DISABLE;
10661078

10671079
static const struct of_device_id omap8250_dt_ids[] = {
10681080
{ .compatible = "ti,omap2-uart" },
10691081
{ .compatible = "ti,omap3-uart" },
10701082
{ .compatible = "ti,omap4-uart" },
10711083
{ .compatible = "ti,am3352-uart", .data = &am3352_habit, },
1084+
{ .compatible = "ti,am4372-uart", .data = &am4372_habit, },
10721085
{},
10731086
};
10741087
MODULE_DEVICE_TABLE(of, omap8250_dt_ids);
@@ -1282,17 +1295,46 @@ static int omap8250_lost_context(struct uart_8250_port *up)
12821295
{
12831296
u32 val;
12841297

1285-
val = serial_in(up, UART_OMAP_MDR1);
1298+
val = serial_in(up, UART_OMAP_SCR);
12861299
/*
1287-
* If we lose context, then MDR1 is set to its reset value which is
1288-
* UART_OMAP_MDR1_DISABLE. After set_termios() we set it either to 13x
1289-
* or 16x but never to disable again.
1300+
* If we lose context, then SCR is set to its reset value of zero.
1301+
* After set_termios() we set bit 3 of SCR (TX_EMPTY_CTL_IT) to 1,
1302+
* among other bits, to never set the register back to zero again.
12901303
*/
1291-
if (val == UART_OMAP_MDR1_DISABLE)
1304+
if (!val)
12921305
return 1;
12931306
return 0;
12941307
}
12951308

1309+
/* TODO: in future, this should happen via API in drivers/reset/ */
1310+
static int omap8250_soft_reset(struct device *dev)
1311+
{
1312+
struct omap8250_priv *priv = dev_get_drvdata(dev);
1313+
struct uart_8250_port *up = serial8250_get_port(priv->line);
1314+
int timeout = 100;
1315+
int sysc;
1316+
int syss;
1317+
1318+
sysc = serial_in(up, UART_OMAP_SYSC);
1319+
1320+
/* softreset the UART */
1321+
sysc |= OMAP_UART_SYSC_SOFTRESET;
1322+
serial_out(up, UART_OMAP_SYSC, sysc);
1323+
1324+
/* By experiments, 1us enough for reset complete on AM335x */
1325+
do {
1326+
udelay(1);
1327+
syss = serial_in(up, UART_OMAP_SYSS);
1328+
} while (--timeout && !(syss & OMAP_UART_SYSS_RESETDONE));
1329+
1330+
if (!timeout) {
1331+
dev_err(dev, "timed out waiting for reset done\n");
1332+
return -ETIMEDOUT;
1333+
}
1334+
1335+
return 0;
1336+
}
1337+
12961338
static int omap8250_runtime_suspend(struct device *dev)
12971339
{
12981340
struct omap8250_priv *priv = dev_get_drvdata(dev);
@@ -1310,6 +1352,17 @@ static int omap8250_runtime_suspend(struct device *dev)
13101352
return -EBUSY;
13111353
}
13121354

1355+
if (priv->habit & UART_ERRATA_CLOCK_DISABLE) {
1356+
int ret;
1357+
1358+
ret = omap8250_soft_reset(dev);
1359+
if (ret)
1360+
return ret;
1361+
1362+
/* Restore to UART mode after reset (for wakeup) */
1363+
omap8250_update_mdr1(up, priv);
1364+
}
1365+
13131366
if (up->dma && up->dma->rxchan)
13141367
omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT);
13151368

0 commit comments

Comments
 (0)