#include <linux/serial_8250.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
+#include <linux/tty_flip.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
u8 wer;
u8 xon;
u8 xoff;
+ u8 delayed_restore;
u16 quot;
bool is_suspending;
static void omap8250_restore_regs(struct uart_8250_port *up)
{
struct omap8250_priv *priv = up->port.private_data;
+ struct uart_8250_dma *dma = up->dma;
+
+ if (dma && dma->tx_running) {
+ /*
+ * TCSANOW requests the change to occur immediately however if
+ * we have a TX-DMA operation in progress then it has been
+ * observed that it might stall and never complete. Therefore we
+ * delay DMA completes to prevent this hang from happen.
+ */
+ priv->delayed_restore = 1;
+ return;
+ }
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, UART_EFR_ECB);
priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY |
OMAP_UART_SCR_TX_TRIG_GRANU1_MASK;
+ if (up->dma)
+ priv->scr |= OMAP_UART_SCR_DMAMODE_1 |
+ OMAP_UART_SCR_DMAMODE_CTL;
+
priv->xon = termios->c_cc[VSTART];
priv->xoff = termios->c_cc[VSTOP];
priv->wer |= OMAP_UART_TX_WAKEUP_EN;
serial_out(up, UART_OMAP_WER, priv->wer);
+ if (up->dma)
+ up->dma->rx_dma(up, 0);
+
pm_runtime_mark_last_busy(port->dev);
pm_runtime_put_autosuspend(port->dev);
return 0;
struct omap8250_priv *priv = port->private_data;
flush_work(&priv->qos_work);
+ if (up->dma)
+ up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT);
pm_runtime_get_sync(port->dev);
struct circ_buf *xmit = &p->port.state->xmit;
unsigned long flags;
bool en_thri = false;
+ struct omap8250_priv *priv = p->port.private_data;
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
xmit->tail &= UART_XMIT_SIZE - 1;
p->port.icount.tx += dma->tx_size;
+ if (priv->delayed_restore) {
+ priv->delayed_restore = 0;
+ omap8250_restore_regs(p);
+ }
+
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&p->port);
return ret;
}
+/*
+ * This is mostly serial8250_handle_irq(). We have a slightly different DMA
+ * hoook for RX/TX and need different logic for them in the ISR. Therefore we
+ * use the default routine in the non-DMA case and this one for with DMA.
+ */
+static int omap_8250_dma_handle_irq(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned char status;
+ unsigned long flags;
+ u8 iir;
+ int dma_err = 0;
+
+ serial8250_rpm_get(up);
+
+ iir = serial_port_in(port, UART_IIR);
+ if (iir & UART_IIR_NO_INT) {
+ serial8250_rpm_put(up);
+ return 0;
+ }
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ status = serial_port_in(port, UART_LSR);
+
+ if (status & (UART_LSR_DR | UART_LSR_BI)) {
+
+ dma_err = omap_8250_rx_dma(up, iir);
+ if (dma_err) {
+ status = serial8250_rx_chars(up, status);
+ omap_8250_rx_dma(up, 0);
+ }
+ }
+ serial8250_modem_status(up);
+ if (status & UART_LSR_THRE && up->dma->tx_err) {
+ if (uart_tx_stopped(&up->port) ||
+ uart_circ_empty(&up->port.state->xmit)) {
+ up->dma->tx_err = 0;
+ serial8250_tx_chars(up);
+ } else {
+ /*
+ * try again due to an earlier failer which
+ * might have been resolved by now.
+ */
+ dma_err = omap_8250_tx_dma(up);
+ if (dma_err)
+ serial8250_tx_chars(up);
+ }
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
+ return 1;
+}
+
+static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
+{
+ return false;
+}
+
+#else
+
+static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
+{
+ return -EINVAL;
+}
#endif
static int omap8250_probe(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
omap_serial_fill_features_erratas(&up, priv);
+#ifdef CONFIG_SERIAL_8250_DMA
+ if (pdev->dev.of_node) {
+ /*
+ * Oh DMA support. If there are no DMA properties in the DT then
+ * we will fall back to a generic DMA channel which does not
+ * really work here. To ensure that we do not get a generic DMA
+ * channel assigned, we have the the_no_dma_filter_fn() here.
+ * To avoid "failed to request DMA" messages we check for DMA
+ * properties in DT.
+ */
+ ret = of_property_count_strings(pdev->dev.of_node, "dma-names");
+ if (ret == 2) {
+ up.dma = &priv->omap8250_dma;
+ up.port.handle_irq = omap_8250_dma_handle_irq;
+ priv->omap8250_dma.fn = the_no_dma_filter_fn;
+ priv->omap8250_dma.tx_dma = omap_8250_tx_dma;
+ priv->omap8250_dma.rx_dma = omap_8250_rx_dma;
+ priv->omap8250_dma.rx_size = RX_TRIGGER;
+ priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER;
+ priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER;
+
+ if (of_machine_is_compatible("ti,am33xx"))
+ priv->habit |= OMAP_DMA_TX_KICK;
+ }
+ }
+#endif
ret = serial8250_register_8250_port(&up);
if (ret < 0) {
dev_err(&pdev->dev, "unable to register 8250 port\n");
}
omap8250_enable_wakeup(priv, true);
+ if (up->dma)
+ omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT);
priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
schedule_work(&priv->qos_work);
if (loss_cntx)
omap8250_restore_regs(up);
+ if (up->dma)
+ omap_8250_rx_dma(up, 0);
+
priv->latency = priv->calc_latency;
schedule_work(&priv->qos_work);
return 0;