#define UART_ERRATA_i202_MDR1_ACCESS (1 << 0)
#define OMAP_UART_WER_HAS_TX_WAKEUP (1 << 1)
#define OMAP_DMA_TX_KICK (1 << 2)
+/*
+ * See Advisory 21 in AM437x errata SPRZ408B, updated April 2015.
+ * The same errata is applicable to AM335x and DRA7x processors too.
+ */
+#define UART_ERRATA_CLOCK_DISABLE (1 << 3)
#define OMAP_UART_FCR_RX_TRIG 6
#define OMAP_UART_FCR_TX_TRIG 4
#define OMAP_UART_MVR_MAJ_SHIFT 8
#define OMAP_UART_MVR_MIN_MASK 0x3f
+/* SYSC register bitmasks */
+#define OMAP_UART_SYSC_SOFTRESET (1 << 1)
+
+/* SYSS register bitmasks */
+#define OMAP_UART_SYSS_RESETDONE (1 << 0)
+
#define UART_TI752_TLR_TX 0
#define UART_TI752_TLR_RX 4
return 0;
}
-static const u8 am3352_habit = OMAP_DMA_TX_KICK;
+static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE;
+static const u8 am4372_habit = UART_ERRATA_CLOCK_DISABLE;
static const struct of_device_id omap8250_dt_ids[] = {
{ .compatible = "ti,omap2-uart" },
{ .compatible = "ti,omap3-uart" },
{ .compatible = "ti,omap4-uart" },
{ .compatible = "ti,am3352-uart", .data = &am3352_habit, },
+ { .compatible = "ti,am4372-uart", .data = &am4372_habit, },
{},
};
MODULE_DEVICE_TABLE(of, omap8250_dt_ids);
{
u32 val;
- val = serial_in(up, UART_OMAP_MDR1);
+ val = serial_in(up, UART_OMAP_SCR);
/*
- * If we lose context, then MDR1 is set to its reset value which is
- * UART_OMAP_MDR1_DISABLE. After set_termios() we set it either to 13x
- * or 16x but never to disable again.
+ * If we lose context, then SCR is set to its reset value of zero.
+ * After set_termios() we set bit 3 of SCR (TX_EMPTY_CTL_IT) to 1,
+ * among other bits, to never set the register back to zero again.
*/
- if (val == UART_OMAP_MDR1_DISABLE)
+ if (!val)
return 1;
return 0;
}
+/* TODO: in future, this should happen via API in drivers/reset/ */
+static int omap8250_soft_reset(struct device *dev)
+{
+ struct omap8250_priv *priv = dev_get_drvdata(dev);
+ struct uart_8250_port *up = serial8250_get_port(priv->line);
+ int timeout = 100;
+ int sysc;
+ int syss;
+
+ sysc = serial_in(up, UART_OMAP_SYSC);
+
+ /* softreset the UART */
+ sysc |= OMAP_UART_SYSC_SOFTRESET;
+ serial_out(up, UART_OMAP_SYSC, sysc);
+
+ /* By experiments, 1us enough for reset complete on AM335x */
+ do {
+ udelay(1);
+ syss = serial_in(up, UART_OMAP_SYSS);
+ } while (--timeout && !(syss & OMAP_UART_SYSS_RESETDONE));
+
+ if (!timeout) {
+ dev_err(dev, "timed out waiting for reset done\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
static int omap8250_runtime_suspend(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
return -EBUSY;
}
+ if (priv->habit & UART_ERRATA_CLOCK_DISABLE) {
+ int ret;
+
+ ret = omap8250_soft_reset(dev);
+ if (ret)
+ return ret;
+
+ /* Restore to UART mode after reset (for wakeup) */
+ omap8250_update_mdr1(up, priv);
+ }
+
if (up->dma && up->dma->rxchan)
omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT);