diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch | 392 |
1 files changed, 0 insertions, 392 deletions
diff --git a/target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch b/target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch deleted file mode 100644 index 1f42e5cb5d..0000000000 --- a/target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch +++ /dev/null @@ -1,392 +0,0 @@ -From 4db59ee0d7224e0c8008534c9247480a83889034 Mon Sep 17 00:00:00 2001 -From: Fugang Duan <fugang.duan@nxp.com> -Date: Wed, 11 Sep 2019 17:01:45 +0800 -Subject: [PATCH] tty: serial: lpuart: enable wakeup source for lpuart - -When use lpuart with DMA mode as wake up source, it still switch to -cpu mode in .suspend() that enable cpu interrupts RIE and ILIE as -wakeup source. Enable the wakeup irq bits in .suspend_noirq() and -disable the wakeup irq bits in .resume_noirq(). - -For DMA mode, after system resume back, it needs to setup DMA again, -if DMA setup is failed, it switchs to CPU mode. .resume() will share -the HW setup code with .startup(), so abstract the same code to the -api like lpuartx_hw_setup(). - -Signed-off-by: Fugang Duan <fugang.duan@nxp.com> ---- - drivers/tty/serial/fsl_lpuart.c | 285 ++++++++++++++++++++++++++++------------ - 1 file changed, 198 insertions(+), 87 deletions(-) - ---- a/drivers/tty/serial/fsl_lpuart.c -+++ b/drivers/tty/serial/fsl_lpuart.c -@@ -21,6 +21,7 @@ - #include <linux/of.h> - #include <linux/of_device.h> - #include <linux/of_dma.h> -+#include <linux/pinctrl/consumer.h> - #include <linux/pm_domain.h> - #include <linux/pm_runtime.h> - #include <linux/reset.h> -@@ -1722,10 +1723,23 @@ static void lpuart_rx_dma_startup(struct - } - } - -+static void lpuart_hw_setup(struct lpuart_port *sport) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sport->port.lock, flags); -+ -+ lpuart_setup_watermark_enable(sport); -+ -+ lpuart_rx_dma_startup(sport); -+ lpuart_tx_dma_startup(sport); -+ -+ spin_unlock_irqrestore(&sport->port.lock, flags); -+} -+ - static int lpuart_startup(struct uart_port *port) - { - struct lpuart_port *sport = container_of(port, struct lpuart_port, port); -- unsigned long flags; - unsigned char temp; - - /* determine FIFO size and enable FIFO mode */ -@@ -1738,14 +1752,7 @@ static int lpuart_startup(struct uart_po - sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) & - UARTPFIFO_FIFOSIZE_MASK); - -- spin_lock_irqsave(&sport->port.lock, flags); -- -- lpuart_setup_watermark_enable(sport); -- -- lpuart_rx_dma_startup(sport); -- lpuart_tx_dma_startup(sport); -- -- spin_unlock_irqrestore(&sport->port.lock, flags); -+ lpuart_hw_setup(sport); - - return 0; - } -@@ -1772,11 +1779,27 @@ static void lpuart32_configure(struct lp - lpuart32_write(&sport->port, temp, UARTCTRL); - } - -+static void lpuart32_hw_setup(struct lpuart_port *sport) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sport->port.lock, flags); -+ -+ lpuart32_hw_disable(sport); -+ -+ lpuart_rx_dma_startup(sport); -+ lpuart_tx_dma_startup(sport); -+ -+ lpuart32_setup_watermark_enable(sport); -+ lpuart32_configure(sport); -+ -+ spin_unlock_irqrestore(&sport->port.lock, flags); -+} -+ - static int lpuart32_startup(struct uart_port *port) - { - struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - struct tty_port *tty_port = &sport->port.state->port; -- unsigned long flags; - unsigned long temp; - int ret; - -@@ -1808,17 +1831,8 @@ static int lpuart32_startup(struct uart_ - sport->port.fifosize = sport->txfifo_size; - } - -- spin_lock_irqsave(&sport->port.lock, flags); -- -- lpuart32_hw_disable(sport); -- -- lpuart_rx_dma_startup(sport); -- lpuart_tx_dma_startup(sport); -- -- lpuart32_setup_watermark_enable(sport); -- lpuart32_configure(sport); -+ lpuart32_hw_setup(sport); - -- spin_unlock_irqrestore(&sport->port.lock, flags); - return 0; - } - -@@ -2879,108 +2893,205 @@ static int lpuart_runtime_resume(struct - return lpuart_enable_clks(sport); - }; - --static int lpuart_suspend(struct device *dev) -+static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on) - { -- struct lpuart_port *sport = dev_get_drvdata(dev); -- unsigned long temp; -- bool irq_wake; -- int ret; -- -- ret = clk_prepare_enable(sport->ipg_clk); -- if (ret) -- return ret; -+ unsigned int val; - - if (lpuart_is_32(sport)) { -- /* disable Rx/Tx and interrupts */ -- temp = lpuart32_read(&sport->port, UARTCTRL); -- temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE); -- lpuart32_write(&sport->port, temp, UARTCTRL); -+ val = lpuart32_read(&sport->port, UARTCTRL); -+ if (on) -+ val |= (UARTCTRL_RIE | UARTCTRL_ILIE); -+ else -+ val &= ~(UARTCTRL_RIE | UARTCTRL_ILIE); -+ lpuart32_write(&sport->port, val, UARTCTRL); - } else { -- /* disable Rx/Tx and interrupts */ -- temp = readb(sport->port.membase + UARTCR2); -- temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE); -- writeb(temp, sport->port.membase + UARTCR2); -+ val = readb(sport->port.membase + UARTCR2); -+ if (on) -+ val |= UARTCR2_RIE; -+ else -+ val &= ~UARTCR2_RIE; -+ writeb(val, sport->port.membase + UARTCR2); - } -+} - -- clk_disable_unprepare(sport->ipg_clk); -+static bool lpuart_uport_is_active(struct lpuart_port *sport) -+{ -+ struct tty_port *port = &sport->port.state->port; -+ struct tty_struct *tty; -+ struct device *tty_dev; -+ int may_wake = 0; - -- uart_suspend_port(&lpuart_reg, &sport->port); -+ tty = tty_port_tty_get(port); -+ if (tty) { -+ tty_dev = tty->dev; -+ may_wake = device_may_wakeup(tty_dev); -+ tty_kref_put(tty); -+ } - -- /* uart_suspend_port() might set wakeup flag */ -- irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); -- if (sport->port.suspended && !irq_wake) -- return 0; -+ if ((tty_port_initialized(port) && may_wake) || -+ (!console_suspend_enabled && uart_console(&sport->port))) -+ return true; - -- if (sport->lpuart_dma_rx_use) { -- /* -- * EDMA driver during suspend will forcefully release any -- * non-idle DMA channels. If port wakeup is enabled or if port -- * is console port or 'no_console_suspend' is set the Rx DMA -- * cannot resume as as expected, hence gracefully release the -- * Rx DMA path before suspend and start Rx DMA path on resume. -- */ -- if (irq_wake) { -- lpuart_del_timer_sync(sport); -- lpuart_dma_rx_free(&sport->port); -- } -+ return false; -+} - -- /* Disable Rx DMA to use UART port as wakeup source */ -+static int lpuart_suspend_noirq(struct device *dev) -+{ -+ struct lpuart_port *sport = dev_get_drvdata(dev); -+ bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); -+ -+ if (lpuart_uport_is_active(sport)) -+ serial_lpuart_enable_wakeup(sport, !!irq_wake); -+ -+ pinctrl_pm_select_sleep_state(dev); -+ -+ return 0; -+} -+ -+static int lpuart_resume_noirq(struct device *dev) -+{ -+ struct lpuart_port *sport = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ pinctrl_pm_select_default_state(dev); -+ -+ if (lpuart_uport_is_active(sport)) { -+ serial_lpuart_enable_wakeup(sport, false); -+ -+ /* clear the wakeup flags */ - if (lpuart_is_32(sport)) { -- temp = lpuart32_read(&sport->port, UARTBAUD); -- lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE, -- UARTBAUD); -- } else { -- writeb(readb(sport->port.membase + UARTCR5) & -- ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); -+ val = lpuart32_read(&sport->port, UARTSTAT); -+ lpuart32_write(&sport->port, val, UARTSTAT); - } - } - -- if (sport->lpuart_dma_tx_use) { -- sport->dma_tx_in_progress = false; -- dmaengine_terminate_all(sport->dma_tx_chan); -- } -- - return 0; - } - --static int lpuart_resume(struct device *dev) -+static int lpuart_suspend(struct device *dev) - { - struct lpuart_port *sport = dev_get_drvdata(dev); -- bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); -- int ret; -+ unsigned long temp; -+ unsigned long flags; - -- ret = clk_prepare_enable(sport->ipg_clk); -- if (ret) -- return ret; -+ uart_suspend_port(&lpuart_reg, &sport->port); - -- if (lpuart_is_32(sport)) -- lpuart32_setup_watermark_enable(sport); -- else -- lpuart_setup_watermark_enable(sport); -+ if (lpuart_uport_is_active(sport)) { -+ spin_lock_irqsave(&sport->port.lock, flags); -+ if (lpuart_is_32(sport)) { -+ temp = lpuart32_read(&sport->port, UARTCTRL); -+ temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE); -+ lpuart32_write(&sport->port, temp, UARTCTRL); -+ } else { -+ temp = readb(sport->port.membase + UARTCR2); -+ temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE); -+ writeb(temp, sport->port.membase + UARTCR2); -+ } -+ spin_unlock_irqrestore(&sport->port.lock, flags); - -- if (sport->lpuart_dma_rx_use) { -- if (irq_wake) { -- if (!lpuart_start_rx_dma(sport)) -- rx_dma_timer_init(sport); -- else -- sport->lpuart_dma_rx_use = false; -+ if (sport->lpuart_dma_rx_use) { -+ /* -+ * EDMA driver during suspend will forcefully release any -+ * non-idle DMA channels. If port wakeup is enabled or if port -+ * is console port or 'no_console_suspend' is set the Rx DMA -+ * cannot resume as as expected, hence gracefully release the -+ * Rx DMA path before suspend and start Rx DMA path on resume. -+ */ -+ lpuart_del_timer_sync(sport); -+ lpuart_dma_rx_free(&sport->port); -+ -+ /* Disable Rx DMA to use UART port as wakeup source */ -+ spin_lock_irqsave(&sport->port.lock, flags); -+ if (lpuart_is_32(sport)) { -+ temp = lpuart32_read(&sport->port, UARTBAUD); -+ lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE, -+ UARTBAUD); -+ } else { -+ writeb(readb(sport->port.membase + UARTCR5) & -+ ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); -+ } -+ spin_unlock_irqrestore(&sport->port.lock, flags); -+ } -+ -+ if (sport->lpuart_dma_tx_use) { -+ spin_lock_irqsave(&sport->port.lock, flags); -+ if (lpuart_is_32(sport)) { -+ temp = lpuart32_read(&sport->port, UARTBAUD); -+ temp &= ~UARTBAUD_TDMAE; -+ lpuart32_write(&sport->port, temp, UARTBAUD); -+ } else { -+ temp = readb(sport->port.membase + UARTCR5); -+ temp &= ~UARTCR5_TDMAS; -+ writeb(temp, sport->port.membase + UARTCR5); -+ } -+ spin_unlock_irqrestore(&sport->port.lock, flags); -+ sport->dma_tx_in_progress = false; -+ dmaengine_terminate_all(sport->dma_tx_chan); - } -+ } else if (pm_runtime_active(sport->port.dev)) { -+ lpuart_disable_clks(sport); -+ pm_runtime_disable(sport->port.dev); -+ pm_runtime_set_suspended(sport->port.dev); - } - -- lpuart_tx_dma_startup(sport); -+ return 0; -+} - -- if (lpuart_is_32(sport)) -- lpuart32_configure(sport); -+static void lpuart_console_fixup(struct lpuart_port *sport) -+{ -+ struct tty_port *port = &sport->port.state->port; -+ struct uart_port *uport = &sport->port; -+ struct ktermios termios; - -- clk_disable_unprepare(sport->ipg_clk); -+ /* i.MX7ULP enter VLLS mode that lpuart module power off and registers -+ * all lost no matter the port is wakeup source. -+ * For console port, console baud rate setting lost and print messy -+ * log when enable the console port as wakeup source. To avoid the -+ * issue happen, user should not enable uart port as wakeup source -+ * in VLLS mode, or restore console setting here. -+ */ -+ if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) && -+ console_suspend_enabled && uart_console(&sport->port)) { -+ -+ mutex_lock(&port->mutex); -+ memset(&termios, 0, sizeof(struct ktermios)); -+ termios.c_cflag = uport->cons->cflag; -+ if (port->tty && termios.c_cflag == 0) -+ termios = port->tty->termios; -+ uport->ops->set_termios(uport, &termios, NULL); -+ mutex_unlock(&port->mutex); -+ } -+} -+ -+static int lpuart_resume(struct device *dev) -+{ -+ struct lpuart_port *sport = dev_get_drvdata(dev); -+ int ret; - -+ if (lpuart_uport_is_active(sport)) { -+ if (lpuart_is_32(sport)) -+ lpuart32_hw_setup(sport); -+ else -+ lpuart_hw_setup(sport); -+ } else if (pm_runtime_active(sport->port.dev)) { -+ ret = lpuart_enable_clks(sport); -+ if (ret) -+ return ret; -+ pm_runtime_set_active(sport->port.dev); -+ pm_runtime_enable(sport->port.dev); -+ } -+ -+ lpuart_console_fixup(sport); - uart_resume_port(&lpuart_reg, &sport->port); - - return 0; - } -+ - static const struct dev_pm_ops lpuart_pm_ops = { - SET_RUNTIME_PM_OPS(lpuart_runtime_suspend, - lpuart_runtime_resume, NULL) -+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(lpuart_suspend_noirq, -+ lpuart_resume_noirq) - SET_SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume) - }; - #define SERIAL_LPUART_PM_OPS (&lpuart_pm_ops) |