From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
To: linux-serial@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, tony@atomide.com,
balbi@ti.com, gregkh@linuxfoundation.org,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Subject: [PATCH 13/13] tty: serial: 8250: omap: add dma support
Date: Mon, 29 Sep 2014 20:06:49 +0200 [thread overview]
Message-ID: <1412014009-13315-14-git-send-email-bigeasy@linutronix.de> (raw)
In-Reply-To: <1412014009-13315-1-git-send-email-bigeasy@linutronix.de>
This patch adds the required pieces to 8250-OMAP UART driver for DMA
support. The TX burst size is set to 1 so we can send an arbitrary
amount of bytes.
The RX burst is currently set to 48 which means we receive an DMA
interrupt every 48 bytes and have to reprogram everything. Less bytes in
the RX-FIFO mean that no DMA transfer will happen and the UART will send a
RX-timeout _or_ RDI event at which point the FIFO will be manually purged.
There is a workaround for TX-DMA on AM33xx where we put the first byte
into the FIFO to kick start the DMA process. Haven't seen this problem on
OMAP36xx (beagle board xm) or DRA7xx.
On AM375x there is "Usage Note 2.7: UART: Cannot Acknowledge Idle
Requests in Smartidle Mode When Configured for DMA Operations" in the
errata document. This problem persists even after disabling DMA in the
UART and will be addressed in the HWMOD.
v10:
- delay update_registers() from set_termios() until TX-DMA is
done. It has been reported / proved that invoking
update_registers() while TX-DMA is in progress may stall the
DMA operation and it won't finish.
- use the new omap DMA-TX-RX hooks and DMA only interrupt
routine.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
drivers/tty/serial/8250/8250_omap.c | 71 +++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 6500547f8fda..57a8b1241b85 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -88,6 +88,7 @@ struct omap8250_priv {
u8 wer;
u8 xon;
u8 xoff;
+ u8 delayed_restore;
u16 quot;
bool is_suspending;
@@ -211,6 +212,18 @@ static void omap8250_update_scr(struct uart_8250_port *up,
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);
@@ -375,6 +388,10 @@ static void omap_8250_set_termios(struct uart_port *port,
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];
@@ -554,6 +571,9 @@ static int omap_8250_startup(struct uart_port *port)
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;
@@ -572,6 +592,8 @@ static void omap_8250_shutdown(struct uart_port *port)
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);
@@ -725,6 +747,7 @@ static void omap_8250_dma_tx_complete(void *param)
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);
@@ -737,6 +760,11 @@ static void omap_8250_dma_tx_complete(void *param)
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);
@@ -909,6 +937,18 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
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)
@@ -1010,6 +1050,32 @@ 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");
@@ -1146,6 +1212,8 @@ static int omap8250_runtime_suspend(struct device *dev)
}
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);
@@ -1170,6 +1238,9 @@ static int omap8250_runtime_resume(struct device *dev)
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;
--
2.1.0
next prev parent reply other threads:[~2014-09-29 18:06 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-29 18:06 [PATCH 00/13 v10] omap 8250 based UART + DMA Sebastian Andrzej Siewior
2014-09-29 18:06 ` [PATCH 01/13] tty: serial: 8250: Fix wording in runtime-PM comments Sebastian Andrzej Siewior
2014-09-29 18:06 ` [PATCH 02/13] tty: serial: 8250: make serial8250_console_setup() non _init Sebastian Andrzej Siewior
2014-09-30 20:27 ` Peter Hurley
2014-09-29 18:06 ` [PATCH 03/13] tty: serial: Add 8250-core based omap driver Sebastian Andrzej Siewior
2014-09-29 18:06 ` [PATCH 04/13] tty: serial: 8250_dma: handle error on TX submit Sebastian Andrzej Siewior
2014-09-29 18:06 ` [PATCH 05/13] tty: serial: 8250_dma: keep own book keeping about RX transfers Sebastian Andrzej Siewior
2014-09-29 18:06 ` [PATCH 06/13] tty: serial: 8250: allow to use custom DMA implementation Sebastian Andrzej Siewior
2014-09-29 18:06 ` [PATCH 07/13] tty: serial: 8250_omap: add custom DMA-TX callback Sebastian Andrzej Siewior
2014-09-29 18:06 ` [PATCH 08/13] tty: serial: 8250_omap: add custom DMA-RX callback Sebastian Andrzej Siewior
2014-09-29 18:06 ` [PATCH 09/13] dmaengine: edma: check for echan->edesc => NULL in edma_dma_pause() Sebastian Andrzej Siewior
2014-10-01 12:00 ` Peter Ujfalusi
2014-10-15 15:27 ` Vinod Koul
2014-10-15 15:28 ` Vinod Koul
2014-09-29 18:06 ` [PATCH 10/13] arm: dts: am33xx: add DMA properties for UART Sebastian Andrzej Siewior
2014-09-29 18:06 ` [PATCH 11/13] arm: dts: dra7: " Sebastian Andrzej Siewior
2014-11-04 17:02 ` Lennart Sorensen
2014-11-04 17:06 ` Sebastian Andrzej Siewior
2014-11-04 17:21 ` Lennart Sorensen
2014-11-04 18:32 ` Javier Martinez Canillas
2014-11-04 18:48 ` Nishanth Menon
[not found] ` <CABxcv=kT+M70Xoyf_z4eQQyM0Oo9S5Y0YeX2R6PbAqxK-JTLLg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-11-04 19:00 ` Lennart Sorensen
2014-11-04 18:33 ` Lennart Sorensen
2014-11-04 21:03 ` Lennart Sorensen
[not found] ` <20141104210315.GF24112-1wCw9BSqJbv44Nm34jS7GywD8/FfD2ys@public.gmane.org>
2014-11-05 1:15 ` Lennart Sorensen
[not found] ` <20141105011506.GG24112-1wCw9BSqJbv44Nm34jS7GywD8/FfD2ys@public.gmane.org>
2014-11-05 8:11 ` Sebastian Andrzej Siewior
2014-11-05 15:33 ` Lennart Sorensen
2014-11-05 16:20 ` Lennart Sorensen
2014-11-05 16:30 ` Sebastian Andrzej Siewior
2014-11-05 19:43 ` Lennart Sorensen
[not found] ` <20141105194323.GI24112-1wCw9BSqJbv44Nm34jS7GywD8/FfD2ys@public.gmane.org>
2014-11-13 18:34 ` Sebastian Andrzej Siewior
2014-11-13 22:08 ` Lennart Sorensen
2014-09-29 18:06 ` [PATCH 12/13] tty: serial: 8250: omap: add custom irq handling Sebastian Andrzej Siewior
2014-10-09 13:19 ` Heikki Krogerus
2014-09-29 18:06 ` Sebastian Andrzej Siewior [this message]
2014-10-02 16:43 ` [PATCH 00/13 v10] omap 8250 based UART + DMA Tony Lindgren
2014-10-02 23:19 ` Sebastian Andrzej Siewior
2014-10-03 13:08 ` Peter Hurley
2014-11-06 3:14 ` Greg KH
2014-11-06 10:27 ` Sebastian Andrzej Siewior
2014-11-10 17:24 ` Tony Lindgren
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1412014009-13315-14-git-send-email-bigeasy@linutronix.de \
--to=bigeasy@linutronix.de \
--cc=balbi@ti.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
--cc=tony@atomide.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).