From cddd4591404fb4c53dc0b3c0b15b942cdbed4356 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Fri, 10 Apr 2020 10:47:05 +0800 Subject: 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 --- ...al-lpuart-enable-wakeup-source-for-lpuart.patch | 392 +++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch (limited to 'target/linux/layerscape/patches-5.4/819-uart-0010-tty-serial-lpuart-enable-wakeup-source-for-lpuart.patch') 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 +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 +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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) -- cgit v1.2.3