|
@@ -51,6 +51,7 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
|
|
|
static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
|
|
|
static void serial_omap_rx_timeout(unsigned long uart_no);
|
|
|
static int serial_omap_start_rxdma(struct uart_omap_port *up);
|
|
|
+static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
|
|
|
|
|
|
static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
|
|
|
{
|
|
@@ -808,7 +809,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
|
|
|
/* Protocol, Baud Rate, and Interrupt Settings */
|
|
|
|
|
|
- serial_out(up, UART_OMAP_MDR1, up->mdr1);
|
|
|
+ if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
|
|
|
+ serial_omap_mdr1_errataset(up, up->mdr1);
|
|
|
+ else
|
|
|
+ serial_out(up, UART_OMAP_MDR1, up->mdr1);
|
|
|
+
|
|
|
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
|
|
|
|
|
up->efr = serial_in(up, UART_EFR);
|
|
@@ -833,7 +838,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
else
|
|
|
up->mdr1 = UART_OMAP_MDR1_16X_MODE;
|
|
|
|
|
|
- serial_out(up, UART_OMAP_MDR1, up->mdr1);
|
|
|
+ if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
|
|
|
+ serial_omap_mdr1_errataset(up, up->mdr1);
|
|
|
+ else
|
|
|
+ serial_out(up, UART_OMAP_MDR1, up->mdr1);
|
|
|
|
|
|
/* Hardware Flow Control Configuration */
|
|
|
|
|
@@ -1362,6 +1370,7 @@ static int serial_omap_probe(struct platform_device *pdev)
|
|
|
up->port.flags = omap_up_info->flags;
|
|
|
up->port.uartclk = omap_up_info->uartclk;
|
|
|
up->uart_dma.uart_base = mem->start;
|
|
|
+ up->errata = omap_up_info->errata;
|
|
|
|
|
|
if (omap_up_info->dma_enabled) {
|
|
|
up->uart_dma.uart_dma_tx = dma_tx->start;
|
|
@@ -1415,9 +1424,47 @@ static int serial_omap_remove(struct platform_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)
|
|
|
+ * 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 serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1)
|
|
|
+{
|
|
|
+ u8 timeout = 255;
|
|
|
+
|
|
|
+ serial_out(up, UART_OMAP_MDR1, mdr1);
|
|
|
+ udelay(2);
|
|
|
+ serial_out(up, UART_FCR, up->fcr | 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_in(up, UART_LSR) &
|
|
|
+ (UART_LSR_THRE | UART_LSR_DR))) {
|
|
|
+ timeout--;
|
|
|
+ if (!timeout) {
|
|
|
+ /* Should *never* happen. we warn and carry on */
|
|
|
+ dev_crit(&up->pdev->dev, "Errata i202: timedout %x\n",
|
|
|
+ serial_in(up, UART_LSR));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ udelay(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void serial_omap_restore_context(struct uart_omap_port *up)
|
|
|
{
|
|
|
- serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
|
|
|
+ if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
|
|
|
+ serial_omap_mdr1_errataset(up, UART_OMAP_MDR1_DISABLE);
|
|
|
+ else
|
|
|
+ serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
|
|
|
+
|
|
|
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */
|
|
|
serial_out(up, UART_EFR, UART_EFR_ECB);
|
|
|
serial_out(up, UART_LCR, 0x0); /* Operational mode */
|
|
@@ -1434,7 +1481,10 @@ static void serial_omap_restore_context(struct uart_omap_port *up)
|
|
|
serial_out(up, UART_OMAP_SCR, up->scr);
|
|
|
serial_out(up, UART_EFR, up->efr);
|
|
|
serial_out(up, UART_LCR, up->lcr);
|
|
|
- serial_out(up, UART_OMAP_MDR1, up->mdr1);
|
|
|
+ if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
|
|
|
+ serial_omap_mdr1_errataset(up, up->mdr1);
|
|
|
+ else
|
|
|
+ serial_out(up, UART_OMAP_MDR1, up->mdr1);
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PM_RUNTIME
|
|
@@ -1449,6 +1499,11 @@ static int serial_omap_runtime_suspend(struct device *dev)
|
|
|
if (pdata->get_context_loss_count)
|
|
|
up->context_loss_cnt = pdata->get_context_loss_count(dev);
|
|
|
|
|
|
+ /* Errata i291 */
|
|
|
+ if (up->use_dma && pdata->set_forceidle &&
|
|
|
+ (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
|
|
|
+ pdata->set_forceidle(up->pdev);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1464,6 +1519,11 @@ static int serial_omap_runtime_resume(struct device *dev)
|
|
|
if (up->context_loss_cnt != loss_cnt)
|
|
|
serial_omap_restore_context(up);
|
|
|
}
|
|
|
+
|
|
|
+ /* Errata i291 */
|
|
|
+ if (up->use_dma && pdata->set_noidle &&
|
|
|
+ (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
|
|
|
+ pdata->set_noidle(up->pdev);
|
|
|
}
|
|
|
|
|
|
return 0;
|