aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch
diff options
context:
space:
mode:
authorYangbo Lu <yangbo.lu@nxp.com>2020-04-10 10:47:05 +0800
committerPetr Štetiar <ynezz@true.cz>2020-05-07 12:53:06 +0200
commitcddd4591404fb4c53dc0b3c0b15b942cdbed4356 (patch)
tree392c1179de46b0f804e3789edca19069b64e6b44 /target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch
parentd1d2c0b5579ea4f69a42246c9318539d61ba1999 (diff)
downloadupstream-cddd4591404fb4c53dc0b3c0b15b942cdbed4356.tar.gz
upstream-cddd4591404fb4c53dc0b3c0b15b942cdbed4356.tar.bz2
upstream-cddd4591404fb4c53dc0b3c0b15b942cdbed4356.zip
layerscape: add patches-5.4
Add patches for linux-5.4. The patches are from NXP LSDK-20.04 release which was tagged LSDK-20.04-V5.4. https://source.codeaurora.org/external/qoriq/qoriq-components/linux/ For boards LS1021A-IOT, and Traverse-LS1043 which are not involved in LSDK, port the dts patches from 4.14. The patches are sorted into the following categories: 301-arch-xxxx 302-dts-xxxx 303-core-xxxx 701-net-xxxx 801-audio-xxxx 802-can-xxxx 803-clock-xxxx 804-crypto-xxxx 805-display-xxxx 806-dma-xxxx 807-gpio-xxxx 808-i2c-xxxx 809-jailhouse-xxxx 810-keys-xxxx 811-kvm-xxxx 812-pcie-xxxx 813-pm-xxxx 814-qe-xxxx 815-sata-xxxx 816-sdhc-xxxx 817-spi-xxxx 818-thermal-xxxx 819-uart-xxxx 820-usb-xxxx 821-vfio-xxxx Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
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.patch392
1 files changed, 392 insertions, 0 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
new file mode 100644
index 0000000000..b3c03bc245
--- /dev/null
+++ b/target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch
@@ -0,0 +1,392 @@
+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>
+@@ -1709,10 +1710,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 */
+@@ -1725,14 +1739,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;
+ }
+@@ -1759,11 +1766,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;
+
+@@ -1784,17 +1807,8 @@ static int lpuart32_startup(struct uart_
+ sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) &
+ UARTFIFO_FIFOSIZE_MASK);
+
+- 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;
+ }
+
+@@ -2852,108 +2866,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)