diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-09-01 09:38:00 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-09-01 09:38:00 -0700 |
commit | 8e1e49550dc85694abd04d86a8ee36bc98bd8b9e (patch) | |
tree | 03133476605e455accd14770365ea05a3bce7007 /drivers/tty/serial/fsl_lpuart.c | |
parent | e925992671907314b7db6793a28eb39b36bc21a4 (diff) | |
parent | ebf05c7dc92c11b0355aaa0e94064beadaa4b05c (diff) |
Merge tag 'tty-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver updates from Greg KH:
"Here is the big set of tty and serial driver changes for 6.6-rc1.
Lots of cleanups in here this cycle, and some driver updates. Short
summary is:
- Jiri's continued work to make the tty code and apis be a bit more
sane with regards to modern kernel coding style and types
- cpm_uart driver updates
- n_gsm updates and fixes
- meson driver updates
- sc16is7xx driver updates
- 8250 driver updates for different hardware types
- qcom-geni driver fixes
- tegra serial driver change
- stm32 driver updates
- synclink_gt driver cleanups
- tty structure size reduction
All of these have been in linux-next this week with no reported
issues. The last bit of cleanups from Jiri and the tty structure size
reduction came in last week, a bit late but as they were just style
changes and size reductions, I figured they should get into this merge
cycle so that others can work on top of them with no merge conflicts"
* tag 'tty-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (199 commits)
tty: shrink the size of struct tty_struct by 40 bytes
tty: n_tty: deduplicate copy code in n_tty_receive_buf_real_raw()
tty: n_tty: extract ECHO_OP processing to a separate function
tty: n_tty: unify counts to size_t
tty: n_tty: use u8 for chars and flags
tty: n_tty: simplify chars_in_buffer()
tty: n_tty: remove unsigned char casts from character constants
tty: n_tty: move newline handling to a separate function
tty: n_tty: move canon handling to a separate function
tty: n_tty: use MASK() for masking out size bits
tty: n_tty: make n_tty_data::num_overrun unsigned
tty: n_tty: use time_is_before_jiffies() in n_tty_receive_overrun()
tty: n_tty: use 'num' for writes' counts
tty: n_tty: use output character directly
tty: n_tty: make flow of n_tty_receive_buf_common() a bool
Revert "tty: serial: meson: Add a earlycon for the T7 SoC"
Documentation: devices.txt: Fix minors for ttyCPM*
Documentation: devices.txt: Remove ttySIOC*
Documentation: devices.txt: Remove ttyIOC*
serial: 8250_bcm7271: improve bcm7271 8250 port
...
Diffstat (limited to 'drivers/tty/serial/fsl_lpuart.c')
-rw-r--r-- | drivers/tty/serial/fsl_lpuart.c | 88 |
1 files changed, 63 insertions, 25 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index c569a08b5b19..f72e1340b47d 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -18,9 +18,9 @@ #include <linux/irq.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/of_dma.h> #include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/serial_core.h> #include <linux/slab.h> @@ -288,6 +288,7 @@ struct lpuart_port { wait_queue_head_t dma_wait; bool is_cs7; /* Set to true when character size is 7 */ /* and the parity is enabled */ + bool dma_idle_int; }; struct lpuart_soc_data { @@ -1064,26 +1065,6 @@ static irqreturn_t lpuart_int(int irq, void *dev_id) return IRQ_HANDLED; } -static irqreturn_t lpuart32_int(int irq, void *dev_id) -{ - struct lpuart_port *sport = dev_id; - unsigned long sts, rxcount; - - sts = lpuart32_read(&sport->port, UARTSTAT); - rxcount = lpuart32_read(&sport->port, UARTWATER); - rxcount = rxcount >> UARTWATER_RXCNT_OFF; - - if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use) - lpuart32_rxint(sport); - - if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use) - lpuart32_txint(sport); - - lpuart32_write(&sport->port, sts, UARTSTAT); - return IRQ_HANDLED; -} - - static inline void lpuart_handle_sysrq_chars(struct uart_port *port, unsigned char *p, int count) { @@ -1266,7 +1247,8 @@ exit: spin_unlock_irqrestore(&sport->port.lock, flags); tty_flip_buffer_push(port); - mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout); + if (!sport->dma_idle_int) + mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout); } static void lpuart_dma_rx_complete(void *arg) @@ -1276,6 +1258,50 @@ static void lpuart_dma_rx_complete(void *arg) lpuart_copy_rx_to_tty(sport); } +static void lpuart32_dma_idleint(struct lpuart_port *sport) +{ + enum dma_status dmastat; + struct dma_chan *chan = sport->dma_rx_chan; + struct circ_buf *ring = &sport->rx_ring; + struct dma_tx_state state; + int count = 0; + + dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state); + if (dmastat == DMA_ERROR) { + dev_err(sport->port.dev, "Rx DMA transfer failed!\n"); + return; + } + + ring->head = sport->rx_sgl.length - state.residue; + count = CIRC_CNT(ring->head, ring->tail, sport->rx_sgl.length); + + /* Check if new data received before copying */ + if (count) + lpuart_copy_rx_to_tty(sport); +} + +static irqreturn_t lpuart32_int(int irq, void *dev_id) +{ + struct lpuart_port *sport = dev_id; + unsigned long sts, rxcount; + + sts = lpuart32_read(&sport->port, UARTSTAT); + rxcount = lpuart32_read(&sport->port, UARTWATER); + rxcount = rxcount >> UARTWATER_RXCNT_OFF; + + if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use) + lpuart32_rxint(sport); + + if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use) + lpuart32_txint(sport); + + if ((sts & UARTSTAT_IDLE) && sport->lpuart_dma_rx_use && sport->dma_idle_int) + lpuart32_dma_idleint(sport); + + lpuart32_write(&sport->port, sts, UARTSTAT); + return IRQ_HANDLED; +} + /* * Timer function to simulate the hardware EOP (End Of Package) event. * The timer callback is to check for new RX data and copy to TTY buffer. @@ -1392,6 +1418,12 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) unsigned long temp = lpuart32_read(&sport->port, UARTBAUD); lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD); + + if (sport->dma_idle_int) { + unsigned long ctrl = lpuart32_read(&sport->port, UARTCTRL); + + lpuart32_write(&sport->port, ctrl | UARTCTRL_ILIE, UARTCTRL); + } } else { writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS, sport->port.membase + UARTCR5); @@ -1407,7 +1439,9 @@ static void lpuart_dma_rx_free(struct uart_port *port) struct dma_chan *chan = sport->dma_rx_chan; dmaengine_terminate_sync(chan); - del_timer_sync(&sport->lpuart_timer); + if (!sport->dma_idle_int) + del_timer_sync(&sport->lpuart_timer); + dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); kfree(sport->rx_ring.buf); sport->rx_ring.tail = 0; @@ -1669,6 +1703,9 @@ static void lpuart32_setup_watermark_enable(struct lpuart_port *sport) static void rx_dma_timer_init(struct lpuart_port *sport) { + if (sport->dma_idle_int) + return; + timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0); sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; add_timer(&sport->lpuart_timer); @@ -2811,8 +2848,7 @@ static int lpuart_probe(struct platform_device *pdev) if (!sport) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - sport->port.membase = devm_ioremap_resource(&pdev->dev, res); + sport->port.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(sport->port.membase)) return PTR_ERR(sport->port.membase); @@ -2822,6 +2858,8 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.type = PORT_LPUART; sport->devtype = sdata->devtype; sport->rx_watermark = sdata->rx_watermark; + sport->dma_idle_int = is_imx7ulp_lpuart(sport) || is_imx8ulp_lpuart(sport) || + is_imx8qxp_lpuart(sport); ret = platform_get_irq(pdev, 0); if (ret < 0) return ret; |