From edb75d8544f2a81271e24ce887c07fda229bd30b Mon Sep 17 00:00:00 2001 From: Christophe Priouzeau Date: Tue, 31 May 2022 12:00:39 +0200 Subject: [PATCH 13/22] ARM-5.15.24-stm32mp1-r1-NET-TTY Signed-off-by: Christophe Priouzeau --- .../net/ethernet/stmicro/stmmac/dwmac-stm32.c | 231 ++++-- drivers/net/phy/realtek.c | 12 +- drivers/net/phy/smsc.c | 27 + drivers/tty/Kconfig | 12 + drivers/tty/Makefile | 1 + drivers/tty/serial/serial_core.c | 10 + drivers/tty/serial/serial_mctrl_gpio.c | 38 + drivers/tty/serial/serial_mctrl_gpio.h | 18 + drivers/tty/serial/stm32-usart.c | 758 ++++++++++++++---- drivers/tty/serial/stm32-usart.h | 18 +- include/uapi/linux/serial.h | 4 +- 11 files changed, 892 insertions(+), 237 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index 2b38a499a..f0849cf42 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -24,10 +25,6 @@ #define SYSCFG_MCU_ETH_MASK BIT(23) #define SYSCFG_MP1_ETH_MASK GENMASK(23, 16) -#define SYSCFG_PMCCLRR_OFFSET 0x40 - -#define SYSCFG_PMCR_ETH_CLK_SEL BIT(16) -#define SYSCFG_PMCR_ETH_REF_CLK_SEL BIT(17) /* CLOCK feed to PHY*/ #define ETH_CK_F_25M 25000000 @@ -47,9 +44,6 @@ * RMII | 1 | 0 | 0 | n/a | *------------------------------------------ */ -#define SYSCFG_PMCR_ETH_SEL_MII BIT(20) -#define SYSCFG_PMCR_ETH_SEL_RGMII BIT(21) -#define SYSCFG_PMCR_ETH_SEL_RMII BIT(23) #define SYSCFG_PMCR_ETH_SEL_GMII 0 #define SYSCFG_MCU_ETH_SEL_MII 0 #define SYSCFG_MCU_ETH_SEL_RMII 1 @@ -63,17 +57,17 @@ *| | | 25MHz | 50MHz | | * --------------------------------------------------------------------------- *| MII | - | eth-ck | n/a | n/a | - *| | | st,ext-phyclk | | | + *| | | | | | * --------------------------------------------------------------------------- *| GMII | - | eth-ck | n/a | n/a | - *| | | st,ext-phyclk | | | + *| | | | | | * --------------------------------------------------------------------------- *| RGMII | - | eth-ck | n/a | eth-ck | - *| | | st,ext-phyclk | | st,eth-clk-sel or| + *| | | | | st,eth-clk-sel or| *| | | | | st,ext-phyclk | * --------------------------------------------------------------------------- *| RMII | - | eth-ck | eth-ck | n/a | - *| | | st,ext-phyclk | st,eth-ref-clk-sel | | + *| | | | st,eth-ref-clk-sel | | *| | | | or st,ext-phyclk | | * --------------------------------------------------------------------------- * @@ -89,14 +83,27 @@ struct stm32_dwmac { int enable_eth_ck; int eth_clk_sel_reg; int eth_ref_clk_sel_reg; - int irq_pwr_wakeup; u32 mode_reg; /* MAC glue-logic mode register */ + u32 mode_mask; struct regmap *regmap; + struct regulator *regulator; u32 speed; const struct stm32_ops *ops; struct device *dev; }; +struct stm32_syscfg_pmcsetr { + u32 eth1_clk_sel; + u32 eth1_ref_clk_sel; + u32 eth1_selmii; + u32 eth1_sel_rgmii; + u32 eth1_sel_rmii; + u32 eth2_clk_sel; + u32 eth2_ref_clk_sel; + u32 eth2_sel_rgmii; + u32 eth2_sel_rmii; +}; + struct stm32_ops { int (*set_mode)(struct plat_stmmacenet_data *plat_dat); int (*clk_prepare)(struct stm32_dwmac *dwmac, bool prepare); @@ -104,7 +111,8 @@ struct stm32_ops { void (*resume)(struct stm32_dwmac *dwmac); int (*parse_data)(struct stm32_dwmac *dwmac, struct device *dev); - u32 syscfg_eth_mask; + u32 syscfg_clr_off; + struct stm32_syscfg_pmcsetr pmcsetr; }; static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat) @@ -174,26 +182,26 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) dwmac->enable_eth_ck = false; switch (plat_dat->interface) { case PHY_INTERFACE_MODE_MII: - if (clk_rate == ETH_CK_F_25M && dwmac->ext_phyclk) + if (clk_rate == ETH_CK_F_25M) dwmac->enable_eth_ck = true; - val = SYSCFG_PMCR_ETH_SEL_MII; + val = dwmac->ops->pmcsetr.eth1_selmii; pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n"); break; case PHY_INTERFACE_MODE_GMII: val = SYSCFG_PMCR_ETH_SEL_GMII; - if (clk_rate == ETH_CK_F_25M && - (dwmac->eth_clk_sel_reg || dwmac->ext_phyclk)) { + if (clk_rate == ETH_CK_F_25M) dwmac->enable_eth_ck = true; - val |= SYSCFG_PMCR_ETH_CLK_SEL; - } pr_debug("SYSCFG init : PHY_INTERFACE_MODE_GMII\n"); break; case PHY_INTERFACE_MODE_RMII: - val = SYSCFG_PMCR_ETH_SEL_RMII; - if ((clk_rate == ETH_CK_F_25M || clk_rate == ETH_CK_F_50M) && + val = dwmac->ops->pmcsetr.eth1_sel_rmii | dwmac->ops->pmcsetr.eth2_sel_rmii; + if (clk_rate == ETH_CK_F_25M) + dwmac->enable_eth_ck = true; + if ((clk_rate == ETH_CK_F_50M) && (dwmac->eth_ref_clk_sel_reg || dwmac->ext_phyclk)) { dwmac->enable_eth_ck = true; - val |= SYSCFG_PMCR_ETH_REF_CLK_SEL; + val |= dwmac->ops->pmcsetr.eth1_ref_clk_sel; + val |= dwmac->ops->pmcsetr.eth2_ref_clk_sel; } pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n"); break; @@ -201,11 +209,14 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: - val = SYSCFG_PMCR_ETH_SEL_RGMII; - if ((clk_rate == ETH_CK_F_25M || clk_rate == ETH_CK_F_125M) && + val = dwmac->ops->pmcsetr.eth1_sel_rgmii | dwmac->ops->pmcsetr.eth2_sel_rgmii; + if (clk_rate == ETH_CK_F_25M) + dwmac->enable_eth_ck = true; + if ((clk_rate == ETH_CK_F_125M) && (dwmac->eth_clk_sel_reg || dwmac->ext_phyclk)) { dwmac->enable_eth_ck = true; - val |= SYSCFG_PMCR_ETH_CLK_SEL; + val |= dwmac->ops->pmcsetr.eth1_clk_sel; + val |= dwmac->ops->pmcsetr.eth2_clk_sel; } pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RGMII\n"); break; @@ -217,12 +228,12 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) } /* Need to update PMCCLRR (clear register) */ - regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, - dwmac->ops->syscfg_eth_mask); + regmap_write(dwmac->regmap, dwmac->ops->syscfg_clr_off, + dwmac->mode_mask); /* Update PMCSETR (set register) */ return regmap_update_bits(dwmac->regmap, reg, - dwmac->ops->syscfg_eth_mask, val); + dwmac->mode_mask, val); } static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat) @@ -248,7 +259,7 @@ static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat) } return regmap_update_bits(dwmac->regmap, reg, - dwmac->ops->syscfg_eth_mask, val << 23); + SYSCFG_MCU_ETH_MASK, val << 23); } static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac) @@ -291,18 +302,33 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac, return PTR_ERR(dwmac->regmap); err = of_property_read_u32_index(np, "st,syscon", 1, &dwmac->mode_reg); + if (err) { + dev_err(dev, "Can't get sysconfig register offset (%d)\n", err); + return err; + } + + dwmac->mode_mask = SYSCFG_MP1_ETH_MASK; + err = of_property_read_u32_index(np, "st,syscon", 2, &dwmac->mode_mask); if (err) - dev_err(dev, "Can't get sysconfig mode offset (%d)\n", err); + pr_debug("Warning sysconfig register mask not set\n"); - return err; + dwmac->regulator = devm_regulator_get_optional(dev, "phy"); + if (IS_ERR(dwmac->regulator)) { + if (PTR_ERR(dwmac->regulator) == -EPROBE_DEFER) { + dev_dbg(dev, "phy regulator is not available yet, deferred probing\n"); + return -EPROBE_DEFER; + } + dev_dbg(dev, "no regulator found\n"); + dwmac->regulator = NULL; + } + + return 0; } static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); struct device_node *np = dev->of_node; - int err = 0; /* Ethernet PHY have no crystal */ dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk"); @@ -317,7 +343,7 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, /* Get ETH_CLK clocks */ dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck"); if (IS_ERR(dwmac->clk_eth_ck)) { - dev_info(dev, "No phy clock provided...\n"); + dev_dbg(dev, "No phy clock provided...\n"); dwmac->clk_eth_ck = NULL; } @@ -334,29 +360,45 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, if (IS_ERR(dwmac->syscfg_clk)) dwmac->syscfg_clk = NULL; - /* Get IRQ information early to have an ability to ask for deferred - * probe if needed before we went too far with resource allocation. - */ - dwmac->irq_pwr_wakeup = platform_get_irq_byname_optional(pdev, - "stm32_pwr_wakeup"); - if (dwmac->irq_pwr_wakeup == -EPROBE_DEFER) - return -EPROBE_DEFER; - - if (!dwmac->clk_eth_ck && dwmac->irq_pwr_wakeup >= 0) { - err = device_init_wakeup(&pdev->dev, true); - if (err) { - dev_err(&pdev->dev, "Failed to init wake up irq\n"); - return err; - } - err = dev_pm_set_dedicated_wake_irq(&pdev->dev, - dwmac->irq_pwr_wakeup); - if (err) { - dev_err(&pdev->dev, "Failed to set wake up irq\n"); - device_init_wakeup(&pdev->dev, false); - } - device_set_wakeup_enable(&pdev->dev, false); + return 0; +} + +static int stm32_dwmac_wake_init(struct device *dev, + struct stmmac_resources *stmmac_res) +{ + int err; + + device_set_wakeup_capable(dev, true); + + err = dev_pm_set_wake_irq(dev, stmmac_res->wol_irq); + if (err) { + dev_err(dev, "Failed to set wake up irq\n"); + device_set_wakeup_capable(dev, false); + return err; + } + + return 0; +} + +static int phy_power_on(struct stm32_dwmac *bsp_priv, bool enable) +{ + int ret; + struct device *dev = bsp_priv->dev; + + if (!bsp_priv->regulator) + return 0; + + if (enable) { + ret = regulator_enable(bsp_priv->regulator); + if (ret) + dev_err(dev, "fail to enable phy-supply\n"); + } else { + ret = regulator_disable(bsp_priv->regulator); + if (ret) + dev_err(dev, "fail to disable phy-supply\n"); } - return err; + + return 0; } static int stm32_dwmac_probe(struct platform_device *pdev) @@ -397,23 +439,39 @@ static int stm32_dwmac_probe(struct platform_device *pdev) goto err_remove_config_dt; } + if (stmmac_res.wol_irq && !dwmac->clk_eth_ck) { + ret = stm32_dwmac_wake_init(&pdev->dev, &stmmac_res); + if (ret) + goto err_wake_init_disable; + } + plat_dat->bsp_priv = dwmac; ret = stm32_dwmac_init(plat_dat); if (ret) - goto err_remove_config_dt; + goto err_wake_init_disable; - ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + ret = phy_power_on(plat_dat->bsp_priv, true); if (ret) goto err_clk_disable; + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) + goto err_gmac_powerdown; + return 0; +err_gmac_powerdown: + phy_power_on(plat_dat->bsp_priv, false); err_clk_disable: stm32_dwmac_clk_disable(dwmac); +err_wake_init_disable: + if (stmmac_res.wol_irq && !dwmac->clk_eth_ck) { + dev_pm_clear_wake_irq(&pdev->dev); + device_set_wakeup_capable(&pdev->dev, false); + } err_remove_config_dt: stmmac_remove_config_dt(pdev, plat_dat); - return ret; } @@ -422,14 +480,16 @@ static int stm32_dwmac_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct stmmac_priv *priv = netdev_priv(ndev); int ret = stmmac_dvr_remove(&pdev->dev); - struct stm32_dwmac *dwmac = priv->plat->bsp_priv; + + if (ret) + return ret; stm32_dwmac_clk_disable(priv->plat->bsp_priv); - if (dwmac->irq_pwr_wakeup >= 0) { - dev_pm_clear_wake_irq(&pdev->dev); - device_init_wakeup(&pdev->dev, false); - } + dev_pm_clear_wake_irq(&pdev->dev); + ret = device_init_wakeup(&pdev->dev, false); + + phy_power_on(priv->plat->bsp_priv, false); return ret; } @@ -447,12 +507,20 @@ static int stm32mp1_suspend(struct stm32_dwmac *dwmac) if (dwmac->enable_eth_ck) clk_disable_unprepare(dwmac->clk_eth_ck); + /* Keep the PHY up if we use Wake-on-Lan. */ + if (!device_may_wakeup(dwmac->dev)) + phy_power_on(dwmac, false); + return ret; } static void stm32mp1_resume(struct stm32_dwmac *dwmac) { clk_disable_unprepare(dwmac->clk_ethstp); + + /* The PHY was up for Wake-on-Lan. */ + if (!device_may_wakeup(dwmac->dev)) + phy_power_on(dwmac, true); } static int stm32mcu_suspend(struct stm32_dwmac *dwmac) @@ -506,7 +574,6 @@ static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops, static struct stm32_ops stm32mcu_dwmac_data = { .set_mode = stm32mcu_set_mode, .suspend = stm32mcu_suspend, - .syscfg_eth_mask = SYSCFG_MCU_ETH_MASK }; static struct stm32_ops stm32mp1_dwmac_data = { @@ -515,12 +582,44 @@ static struct stm32_ops stm32mp1_dwmac_data = { .suspend = stm32mp1_suspend, .resume = stm32mp1_resume, .parse_data = stm32mp1_parse_data, - .syscfg_eth_mask = SYSCFG_MP1_ETH_MASK + .syscfg_clr_off = 0x44, + .pmcsetr = { + .eth1_clk_sel = BIT(16), + .eth1_ref_clk_sel = BIT(17), + .eth1_selmii = BIT(20), + .eth1_sel_rgmii = BIT(21), + .eth1_sel_rmii = BIT(23), + .eth2_clk_sel = 0, + .eth2_ref_clk_sel = 0, + .eth2_sel_rgmii = 0, + .eth2_sel_rmii = 0 + } +}; + +static struct stm32_ops stm32mp13_dwmac_data = { + .set_mode = stm32mp1_set_mode, + .clk_prepare = stm32mp1_clk_prepare, + .suspend = stm32mp1_suspend, + .resume = stm32mp1_resume, + .parse_data = stm32mp1_parse_data, + .syscfg_clr_off = 0x08, + .pmcsetr = { + .eth1_clk_sel = BIT(16), + .eth1_ref_clk_sel = BIT(17), + .eth1_selmii = 0, + .eth1_sel_rgmii = BIT(21), + .eth1_sel_rmii = BIT(23), + .eth2_clk_sel = BIT(24), + .eth2_ref_clk_sel = BIT(25), + .eth2_sel_rgmii = BIT(29), + .eth2_sel_rmii = BIT(31) + } }; static const struct of_device_id stm32_dwmac_match[] = { { .compatible = "st,stm32-dwmac", .data = &stm32mcu_dwmac_data}, { .compatible = "st,stm32mp1-dwmac", .data = &stm32mp1_dwmac_data}, + { .compatible = "st,stm32mp13-dwmac", .data = &stm32mp13_dwmac_data}, { } }; MODULE_DEVICE_TABLE(of, stm32_dwmac_match); diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 11be60333..c61c37294 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -336,14 +336,10 @@ static int rtl8211f_config_init(struct phy_device *phydev) u16 val_txdly, val_rxdly; int ret; - ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, - RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, - priv->phycr1); - if (ret < 0) { - dev_err(dev, "aldps mode configuration failed: %pe\n", - ERR_PTR(ret)); - return ret; - } + /* Set green LED for Link, yellow LED for Active */ + phy_write(phydev, RTL821x_PAGE_SELECT, 0xd04); + phy_write(phydev, 0x10, 0x617f); + phy_write(phydev, RTL821x_PAGE_SELECT, 0x0); switch (phydev->interface) { case PHY_INTERFACE_MODE_RGMII: diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index d8cac02a7..b7d65470b 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -481,6 +481,32 @@ static struct phy_driver smsc_phy_driver[] = { .get_strings = smsc_get_strings, .get_stats = smsc_get_stats, + .suspend = genphy_suspend, + .resume = genphy_resume, +}, { + .phy_id = 0x0007c130, + .phy_id_mask = 0xfffffff0, + .name = "SMSC LAN8742A", + + /* PHY_BASIC_FEATURES */ + .flags = PHY_RST_AFTER_CLK_EN, + + .probe = smsc_phy_probe, + + /* basic functions */ + .read_status = lan87xx_read_status, + .config_init = smsc_phy_config_init, + .soft_reset = smsc_phy_reset, + + /* IRQ related */ + .config_intr = smsc_phy_config_intr, + .handle_interrupt = smsc_phy_handle_interrupt, + + /* Statistics */ + .get_sset_count = smsc_get_sset_count, + .get_strings = smsc_get_strings, + .get_stats = smsc_get_stats, + .suspend = genphy_suspend, .resume = genphy_resume, } }; @@ -498,6 +524,7 @@ static struct mdio_device_id __maybe_unused smsc_tbl[] = { { 0x0007c0d0, 0xfffffff0 }, { 0x0007c0f0, 0xfffffff0 }, { 0x0007c110, 0xfffffff0 }, + { 0x0007c130, 0xfffffff0 }, { } }; diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 23cc988c6..cc30ff93e 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -368,6 +368,18 @@ config VCC source "drivers/tty/hvc/Kconfig" +config RPMSG_TTY + tristate "RPMSG tty driver" + depends on RPMSG + help + Say y here to export rpmsg endpoints as tty devices, usually found + in /dev/ttyRPMSGx. + This makes it possible for user-space programs to send and receive + rpmsg messages as a standard tty protocol. + + To compile this driver as a module, choose M here: the module will be + called rpmsg_tty. + endif # TTY source "drivers/tty/serdev/Kconfig" diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index a2bd75fba..07aca5184 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -26,5 +26,6 @@ obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o obj-$(CONFIG_VCC) += vcc.o +obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o obj-y += ipwireless/ diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index dc6129dde..bde6c62e6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3238,6 +3238,16 @@ int uart_get_rs485_mode(struct uart_port *port) u32 rs485_delay[2]; int ret; + ret = device_property_read_u32_array(dev, "rs485-rts-delay-ns", + rs485_delay, 2); + if (!ret) { + rs485conf->delay_rts_before_send_ns = rs485_delay[0]; + rs485conf->delay_rts_after_send_ns = rs485_delay[1]; + } else { + rs485conf->delay_rts_before_send_ns = 0; + rs485conf->delay_rts_after_send_ns = 0; + } + ret = device_property_read_u32_array(dev, "rs485-rts-delay", rs485_delay, 2); if (!ret) { diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index c41d8911c..1663b3afc 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -299,4 +299,42 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) } EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms); +void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) +{ + enum mctrl_gpio_idx i; + + if (!gpios) + return; + + if (!gpios->mctrl_on) + return; + + for (i = 0; i < UART_GPIO_MAX; ++i) { + if (!gpios->irq[i]) + continue; + + enable_irq_wake(gpios->irq[i]); + } +} +EXPORT_SYMBOL_GPL(mctrl_gpio_enable_irq_wake); + +void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) +{ + enum mctrl_gpio_idx i; + + if (!gpios) + return; + + if (!gpios->mctrl_on) + return; + + for (i = 0; i < UART_GPIO_MAX; ++i) { + if (!gpios->irq[i]) + continue; + + disable_irq_wake(gpios->irq[i]); + } +} +EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake); + MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index b134a0ffc..fc76910fb 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -91,6 +91,16 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); */ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios); +/* + * Enable gpio wakeup interrupts to enable wake up source. + */ +void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios); + +/* + * Disable gpio wakeup interrupts to enable wake up source. + */ +void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios); + #else /* GPIOLIB */ static inline @@ -142,6 +152,14 @@ static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) { } +static inline void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) +{ +} + +static inline void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) +{ +} + #endif /* GPIOLIB */ #endif diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 200cd293d..f8c048443 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -61,38 +61,65 @@ static void stm32_usart_clr_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } -static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, - u32 delay_DDE, u32 baud) +static u32 stm32_usart_config_delay_rs485(u32 *cr1, u32 delay, u32 baud, + bool over8, u32 rs485_deat_dedt_max, + struct serial_rs485 *rs485conf) { - u32 rs485_deat_dedt; + u64 tmp; + + /* + * Compute (de)assertion time by using the delay (in ns), the baud rate + * (in bits/s) and the oversampling (in 1/8 or 1/16 bit) + */ + tmp = (u64)delay * (u64)baud * 8ULL; + + /* Handle oversampling 16 */ + if (!over8) + tmp = tmp * 2ULL; + + tmp = DIV_ROUND_CLOSEST_ULL(tmp, NSEC_PER_SEC); + + /* Set delay to max value if result is higher than max value */ + tmp = tmp > rs485_deat_dedt_max ? rs485_deat_dedt_max : tmp; + + return tmp; +} + +static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 baud, + struct serial_rs485 *rs485conf) +{ + u32 delay_ADE, delay_DDE, rs485_deat_dedt; u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT); bool over8; + u32 tmp; + + /* + * Assertion and deassertion delays (in ns) are computed by the + * selection of rs485-rts-delay-ns (in ns) or rs485-rts-delay (in ms) + * provided by device tree + */ + if (rs485conf->delay_rts_before_send_ns != 0 || + rs485conf->delay_rts_after_send_ns != 0) { + delay_ADE = rs485conf->delay_rts_before_send_ns; + delay_DDE = rs485conf->delay_rts_after_send_ns; + } else { + delay_ADE = rs485conf->delay_rts_before_send * NSEC_PER_MSEC; + delay_DDE = rs485conf->delay_rts_after_send * NSEC_PER_MSEC; + } *cr3 |= USART_CR3_DEM; over8 = *cr1 & USART_CR1_OVER8; - if (over8) - rs485_deat_dedt = delay_ADE * baud * 8; - else - rs485_deat_dedt = delay_ADE * baud * 16; - - rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); - rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? - rs485_deat_dedt_max : rs485_deat_dedt; - rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEAT_SHIFT) & - USART_CR1_DEAT_MASK; + /* Assertion time */ + tmp = stm32_usart_config_delay_rs485(cr1, delay_ADE, baud, over8, + rs485_deat_dedt_max, rs485conf); + rs485_deat_dedt = (tmp << USART_CR1_DEAT_SHIFT) & USART_CR1_DEAT_MASK; *cr1 |= rs485_deat_dedt; - if (over8) - rs485_deat_dedt = delay_DDE * baud * 8; - else - rs485_deat_dedt = delay_DDE * baud * 16; - - rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); - rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? - rs485_deat_dedt_max : rs485_deat_dedt; - rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEDT_SHIFT) & - USART_CR1_DEDT_MASK; + /* Deassertion time */ + tmp = stm32_usart_config_delay_rs485(cr1, delay_DDE, baud, over8, + rs485_deat_dedt_max, rs485conf); + rs485_deat_dedt = (tmp << USART_CR1_DEDT_SHIFT) & USART_CR1_DEDT_MASK; *cr1 |= rs485_deat_dedt; } @@ -123,10 +150,7 @@ static int stm32_usart_config_rs485(struct uart_port *port, << USART_BRR_04_R_SHIFT; baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv); - stm32_usart_config_reg_rs485(&cr1, &cr3, - rs485conf->delay_rts_before_send, - rs485conf->delay_rts_after_send, - baud); + stm32_usart_config_reg_rs485(&cr1, &cr3, baud, rs485conf); if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { cr3 &= ~USART_CR3_DEP; @@ -165,63 +189,103 @@ static int stm32_usart_init_rs485(struct uart_port *port, return uart_get_rs485_mode(port); } -static int stm32_usart_pending_rx(struct uart_port *port, u32 *sr, - int *last_res, bool threaded) +static bool stm32_usart_rx_dma_started(struct stm32_port *stm32_port) +{ + return stm32_port->rx_ch ? stm32_port->rx_dma_busy : false; +} + +static void stm32_usart_rx_dma_terminate(struct stm32_port *stm32_port) +{ + dmaengine_terminate_async(stm32_port->rx_ch); + stm32_port->rx_dma_busy = false; +} + +static int stm32_usart_dma_pause_resume(struct stm32_port *stm32_port, + struct dma_chan *chan, + enum dma_status expected_status, + int (*dma_action)(struct dma_chan *chan), + bool (*dma_started)(struct stm32_port *stm32_port), + void (*dma_terminate)(struct stm32_port *stm32_port)) +{ + struct uart_port *port = &stm32_port->port; + enum dma_status dma_status; + int ret; + + if (!(*dma_started)(stm32_port)) + return -EPERM; + + dma_status = dmaengine_tx_status(chan, chan->cookie, NULL); + if (dma_status != expected_status) + return -EAGAIN; + + ret = (*dma_action)(chan); + if (ret) { + dev_err(port->dev, "DMA failed with error code: %d\n", ret); + (*dma_terminate)(stm32_port); + } + return ret; +} + +static int stm32_usart_rx_dma_pause(struct stm32_port *stm32_port) +{ + return stm32_usart_dma_pause_resume(stm32_port, stm32_port->rx_ch, + DMA_IN_PROGRESS, dmaengine_pause, + stm32_usart_rx_dma_started, + stm32_usart_rx_dma_terminate); +} + +static int stm32_usart_rx_dma_resume(struct stm32_port *stm32_port) +{ + return stm32_usart_dma_pause_resume(stm32_port, stm32_port->rx_ch, + DMA_PAUSED, dmaengine_resume, + stm32_usart_rx_dma_started, + stm32_usart_rx_dma_terminate); +} + +/* Return true when data is pending (in pio mode), and false when no data is pending. */ +static bool stm32_usart_pending_rx_pio(struct uart_port *port, u32 *sr) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - enum dma_status status; - struct dma_tx_state state; *sr = readl_relaxed(port->membase + ofs->isr); - - if (threaded && stm32_port->rx_ch) { - status = dmaengine_tx_status(stm32_port->rx_ch, - stm32_port->rx_ch->cookie, - &state); - if (status == DMA_IN_PROGRESS && (*last_res != state.residue)) - return 1; - else - return 0; - } else if (*sr & USART_SR_RXNE) { - return 1; + /* Get pending characters in RDR or FIFO */ + if (*sr & USART_SR_RXNE) { + /* Get all pending characters from the RDR or the FIFO when using interrupts */ + if (!stm32_usart_rx_dma_started(stm32_port)) + return true; + + /* Handle only RX data errors when using DMA */ + if (*sr & USART_SR_ERR_MASK) + return true; } - return 0; + + return false; } -static unsigned long stm32_usart_get_char(struct uart_port *port, u32 *sr, - int *last_res) +static unsigned long stm32_usart_get_char_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; - if (stm32_port->rx_ch) { - c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; - if ((*last_res) == 0) - *last_res = RX_BUF_L; - } else { - c = readl_relaxed(port->membase + ofs->rdr); - /* apply RDR data mask */ - c &= stm32_port->rdr_mask; - } + c = readl_relaxed(port->membase + ofs->rdr); + /* Apply RDR data mask */ + c &= stm32_port->rdr_mask; return c; } -static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) +static unsigned int stm32_usart_receive_chars_pio(struct uart_port *port) { - struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; + unsigned int size = 0; u32 sr; char flag; - spin_lock(&port->lock); - - while (stm32_usart_pending_rx(port, &sr, &stm32_port->last_res, - threaded)) { + while (stm32_usart_pending_rx_pio(port, &sr)) { sr |= USART_SR_DUMMY_RX; flag = TTY_NORMAL; @@ -240,8 +304,9 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) writel_relaxed(sr & USART_SR_ERR_MASK, port->membase + ofs->icr); - c = stm32_usart_get_char(port, &sr, &stm32_port->last_res); + c = stm32_usart_get_char_pio(port); port->icount.rx++; + size++; if (sr & USART_SR_ERR_MASK) { if (sr & USART_SR_ORE) { port->icount.overrun++; @@ -275,21 +340,208 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) uart_insert_char(port, sr, USART_SR_ORE, c, flag); } - uart_unlock_and_check_sysrq(port); + return size; +} + +static void stm32_usart_push_buffer_dma(struct uart_port *port, unsigned int dma_size) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct tty_port *ttyport = &stm32_port->port.state->port; + unsigned char *dma_start; + int dma_count, i; + + dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res); - tty_flip_buffer_push(tport); + /* + * Apply rdr_mask on buffer in order to mask parity bit. + * This loop is useless in cs8 mode because DMA copies only + * 8 bits and already ignores parity bit. + */ + if (!(stm32_port->rdr_mask == (BIT(8) - 1))) + for (i = 0; i < dma_size; i++) + *(dma_start + i) &= stm32_port->rdr_mask; + + dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size); + port->icount.rx += dma_count; + if (dma_count != dma_size) + port->icount.buf_overrun++; + stm32_port->last_res -= dma_count; + if (stm32_port->last_res == 0) + stm32_port->last_res = RX_BUF_L; +} + +static unsigned int stm32_usart_receive_chars_dma(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int dma_size, size = 0; + + /* DMA buffer is configured in cyclic mode and handles the rollback of the buffer. */ + if (stm32_port->rx_dma_state.residue > stm32_port->last_res) { + /* Conditional first part: from last_res to end of DMA buffer */ + dma_size = stm32_port->last_res; + stm32_usart_push_buffer_dma(port, dma_size); + size = dma_size; + } + + dma_size = stm32_port->last_res - stm32_port->rx_dma_state.residue; + stm32_usart_push_buffer_dma(port, dma_size); + size += dma_size; + + return size; +} + +static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force_dma_flush) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + enum dma_status rx_dma_status; + u32 sr; + unsigned int size = 0; + + if (stm32_usart_rx_dma_started(stm32_port) || force_dma_flush) { + rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + &stm32_port->rx_dma_state); + if (rx_dma_status == DMA_IN_PROGRESS || + rx_dma_status == DMA_PAUSED) { + /* Empty DMA buffer */ + size = stm32_usart_receive_chars_dma(port); + sr = readl_relaxed(port->membase + ofs->isr); + if (sr & USART_SR_ERR_MASK) { + /* Disable DMA request line */ + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + + /* Switch to PIO mode to handle the errors */ + size += stm32_usart_receive_chars_pio(port); + + /* Switch back to DMA mode */ + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + } + } else { + /* Disable RX DMA */ + stm32_usart_rx_dma_terminate(stm32_port); + /* Fall back to interrupt mode */ + dev_dbg(port->dev, "DMA error, fallback to irq mode\n"); + size = stm32_usart_receive_chars_pio(port); + } + } else { + size = stm32_usart_receive_chars_pio(port); + } + + return size; +} + +static void stm32_usart_rx_dma_complete(void *arg) +{ + struct uart_port *port = arg; + struct tty_port *tport = &port->state->port; + unsigned int size; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); +} + +static int stm32_usart_rx_dma_start_or_resume(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct dma_async_tx_descriptor *desc; + enum dma_status rx_dma_status; + int ret; + + if (stm32_port->throttled) + return 0; + + if (stm32_port->rx_dma_busy) { + rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + NULL); + if (rx_dma_status == DMA_IN_PROGRESS) + return 0; + + if (rx_dma_status == DMA_PAUSED && !stm32_usart_rx_dma_resume(stm32_port)) + return 0; + + dev_err(port->dev, "DMA failed : status error.\n"); + stm32_usart_rx_dma_terminate(stm32_port); + } + + stm32_port->rx_dma_busy = true; + + stm32_port->last_res = RX_BUF_L; + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, + stm32_port->rx_dma_buf, + RX_BUF_L, RX_BUF_P, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(port->dev, "rx dma prep cyclic failed\n"); + stm32_port->rx_dma_busy = false; + return -ENODEV; + } + + desc->callback = stm32_usart_rx_dma_complete; + desc->callback_param = port; + + /* Push current DMA transaction in the pending queue */ + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dmaengine_terminate_sync(stm32_port->rx_ch); + stm32_port->rx_dma_busy = false; + return ret; + } + + /* Issue pending DMA requests */ + dma_async_issue_pending(stm32_port->rx_ch); + + return 0; +} + +static void stm32_usart_tx_dma_terminate(struct stm32_port *stm32_port) +{ + dmaengine_terminate_async(stm32_port->tx_ch); + stm32_port->tx_dma_busy = false; +} + +static bool stm32_usart_tx_dma_started(struct stm32_port *stm32_port) +{ + /* + * We cannot use the function "dmaengine_tx_status" to know the + * status of DMA. This function does not show if the "dma complete" + * callback of the DMA transaction have been called. So we prefer + * to use "tx_dma_busy" flag to prevent dual dma transaction at the + * same time. + */ + return stm32_port->tx_dma_busy; +} + +static int stm32_usart_tx_dma_pause(struct stm32_port *stm32_port) +{ + return stm32_usart_dma_pause_resume(stm32_port, stm32_port->tx_ch, + DMA_IN_PROGRESS, dmaengine_pause, + stm32_usart_tx_dma_started, + stm32_usart_tx_dma_terminate); +} + +static int stm32_usart_tx_dma_resume(struct stm32_port *stm32_port) +{ + return stm32_usart_dma_pause_resume(stm32_port, stm32_port->tx_ch, + DMA_PAUSED, dmaengine_resume, + stm32_usart_tx_dma_started, + stm32_usart_tx_dma_terminate); } static void stm32_usart_tx_dma_complete(void *arg) { struct uart_port *port = arg; struct stm32_port *stm32port = to_stm32_port(port); - const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; unsigned long flags; - dmaengine_terminate_async(stm32port->tx_ch); - stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32port->tx_dma_busy = false; + stm32_usart_tx_dma_terminate(stm32port); /* Let's see if we have pending data to send */ spin_lock_irqsave(&port->lock, flags); @@ -329,11 +581,6 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port) const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct circ_buf *xmit = &port->state->xmit; - if (stm32_port->tx_dma_busy) { - stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32_port->tx_dma_busy = false; - } - while (!uart_circ_empty(xmit)) { /* Check that TDR is empty before filling FIFO */ if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) @@ -353,15 +600,17 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port) static void stm32_usart_transmit_chars_dma(struct uart_port *port) { struct stm32_port *stm32port = to_stm32_port(port); - const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; struct circ_buf *xmit = &port->state->xmit; struct dma_async_tx_descriptor *desc = NULL; - unsigned int count, i; + unsigned int count; + int ret; - if (stm32port->tx_dma_busy) + if (stm32_usart_tx_dma_started(stm32port)) { + ret = stm32_usart_tx_dma_resume(stm32port); + if (ret < 0 && ret != -EAGAIN) + goto fallback_err; return; - - stm32port->tx_dma_busy = true; + } count = uart_circ_chars_pending(xmit); @@ -392,28 +641,35 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port) if (!desc) goto fallback_err; + /* + * Set "tx_dma_busy" flag. This flag will be release when + * dmaengine_terminate_async will be called. This flag helps + * transmit_chars_dma not to start another dma transaction + * if the callback of the previous is not yet called. + */ + stm32port->tx_dma_busy = true; + desc->callback = stm32_usart_tx_dma_complete; desc->callback_param = port; /* Push current DMA TX transaction in the pending queue */ - if (dma_submit_error(dmaengine_submit(desc))) { - /* dma no yet started, safe to free resources */ - dmaengine_terminate_async(stm32port->tx_ch); + /* DMA no yet started, safe to free resources */ + ret = dma_submit_error(dmaengine_submit(desc)); + if (ret) { + dev_err(port->dev, "DMA failed with error code: %d\n", ret); + stm32_usart_tx_dma_terminate(stm32port); goto fallback_err; } /* Issue pending DMA TX requests */ dma_async_issue_pending(stm32port->tx_ch); - stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); port->icount.tx += count; return; fallback_err: - for (i = count; i > 0; i--) - stm32_usart_transmit_chars_pio(port); + stm32_usart_transmit_chars_pio(port); } static void stm32_usart_transmit_chars(struct uart_port *port) @@ -421,15 +677,28 @@ static void stm32_usart_transmit_chars(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct circ_buf *xmit = &port->state->xmit; + u32 isr; + int ret; if (port->x_char) { - if (stm32_port->tx_dma_busy) - stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + /* dma terminate may have been called in case of dma pause failure */ + stm32_usart_tx_dma_pause(stm32_port); + + /* Check that TDR is empty before filling FIFO */ + ret = + readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, + isr, + (isr & USART_SR_TXE), + 10, 1000); + if (ret) + dev_warn(port->dev, "1 character may be erased\n"); + writel_relaxed(port->x_char, port->membase + ofs->tdr); port->x_char = 0; port->icount.tx++; - if (stm32_port->tx_dma_busy) - stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); + + /* dma terminate may have been called in case of dma resume failure */ + stm32_usart_tx_dma_resume(stm32_port); return; } @@ -462,6 +731,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; u32 sr; + unsigned int size; sr = readl_relaxed(port->membase + ofs->isr); @@ -478,8 +748,20 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) pm_wakeup_event(tport->tty->dev, 0); } - if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) - stm32_usart_receive_chars(port, false); + /* + * rx errors in dma mode has to be handled ASAP to avoid overrun as the DMA request + * line has been masked by HW and rx data are stacking in FIFO. + */ + if (!stm32_port->throttled) { + if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_started(stm32_port)) || + ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_started(stm32_port))) { + spin_lock(&port->lock); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq(port); + if (size) + tty_flip_buffer_push(tport); + } + } if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { spin_lock(&port->lock); @@ -487,7 +769,8 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) spin_unlock(&port->lock); } - if (stm32_port->rx_ch) + if ((sr & USART_SR_RTOF) && !(stm32_port->throttled) && + stm32_usart_rx_dma_started(stm32_port)) return IRQ_WAKE_THREAD; else return IRQ_HANDLED; @@ -496,10 +779,16 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; - struct stm32_port *stm32_port = to_stm32_port(port); + struct tty_port *tport = &port->state->port; + unsigned int size; + unsigned long flags; - if (stm32_port->rx_ch) - stm32_usart_receive_chars(port, true); + /* Receiver timeout irq for DMA RX */ + spin_lock_irqsave(&port->lock, flags); + size = stm32_usart_receive_chars(port, false); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); return IRQ_HANDLED; } @@ -557,6 +846,9 @@ static void stm32_usart_stop_tx(struct uart_port *port) stm32_usart_tx_interrupt_disable(port); + /* dma terminate may have been called in case of dma pause failure */ + stm32_usart_tx_dma_pause(stm32_port); + if (rs485conf->flags & SER_RS485_ENABLED) { if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { mctrl_gpio_set(stm32_port->gpios, @@ -595,13 +887,9 @@ static void stm32_usart_start_tx(struct uart_port *port) static void stm32_usart_flush_buffer(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - if (stm32_port->tx_ch) { - dmaengine_terminate_async(stm32_port->tx_ch); - stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32_port->tx_dma_busy = false; - } + if (stm32_port->tx_ch) + stm32_usart_tx_dma_terminate(stm32_port); } /* Throttle the remote when input buffer is about to overflow. */ @@ -612,10 +900,18 @@ static void stm32_usart_throttle(struct uart_port *port) unsigned long flags; spin_lock_irqsave(&port->lock, flags); + + /* + * Pause DMA transfer, so the RX data gets queued into the FIFO. + * Hardware flow control is triggered when RX FIFO is full. + */ + stm32_usart_rx_dma_pause(stm32_port); + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_port->throttled = true; spin_unlock_irqrestore(&port->lock, flags); } @@ -631,6 +927,15 @@ static void stm32_usart_unthrottle(struct uart_port *port) if (stm32_port->cr3_irq) stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_port->throttled = false; + + /* + * Switch back to DMA mode (resume DMA). + * Hardware flow control is stopped when FIFO is not full any more. + */ + if (stm32_port->rx_ch) + stm32_usart_rx_dma_start_or_resume(port); + spin_unlock_irqrestore(&port->lock, flags); } @@ -640,6 +945,9 @@ static void stm32_usart_stop_rx(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + /* Disable DMA request line. */ + stm32_usart_rx_dma_pause(stm32_port); + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); @@ -676,6 +984,14 @@ static int stm32_usart_startup(struct uart_port *port) if (ofs->rqr != UNDEF_REG) writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); + if (stm32_port->rx_ch) { + ret = stm32_usart_rx_dma_start_or_resume(port); + if (ret) { + free_irq(port->irq, port); + return ret; + } + } + /* RX enabling */ val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); stm32_usart_set_bits(port, ofs->cr1, val); @@ -691,10 +1007,11 @@ static void stm32_usart_shutdown(struct uart_port *port) u32 val, isr; int ret; - if (stm32_port->tx_dma_busy) { - dmaengine_terminate_async(stm32_port->tx_ch); + if (stm32_usart_tx_dma_started(stm32_port)) + stm32_usart_tx_dma_terminate(stm32_port); + + if (stm32_port->tx_ch) stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - } /* Disable modem control interrupts */ stm32_usart_disable_ms(port); @@ -713,6 +1030,12 @@ static void stm32_usart_shutdown(struct uart_port *port) if (ret) dev_err(port->dev, "Transmission is not complete\n"); + /* Disable RX DMA. */ + if (stm32_port->rx_ch) { + stm32_usart_rx_dma_terminate(stm32_port); + dmaengine_synchronize(stm32_port->rx_ch); + } + /* flush RX & TX FIFO */ if (ofs->rqr != UNDEF_REG) writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, @@ -815,9 +1138,11 @@ static void stm32_usart_set_termios(struct uart_port *port, stm32_port->cr1_irq = USART_CR1_RTOIE; writel_relaxed(bits, port->membase + ofs->rtor); cr2 |= USART_CR2_RTOEN; - /* Not using dma, enable fifo threshold irq */ - if (!stm32_port->rx_ch) - stm32_port->cr3_irq = USART_CR3_RXFTIE; + /* + * Enable fifo threshold irq in two cases, either when there is no DMA, or when + * wake up over usart, from low power until the DMA gets re-enabled by resume. + */ + stm32_port->cr3_irq = USART_CR3_RXFTIE; } cr1 |= stm32_port->cr1_irq; @@ -880,14 +1205,22 @@ static void stm32_usart_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= USART_SR_DUMMY_RX; - if (stm32_port->rx_ch) + if (stm32_port->rx_ch) { + /* + * Setup DMA to collect only valid data and enable error irqs. + * This also enables break reception when using DMA. + */ + cr1 |= USART_CR1_PEIE; + cr3 |= USART_CR3_EIE; cr3 |= USART_CR3_DMAR; + cr3 |= USART_CR3_DDRE; + } + + if (stm32_port->tx_ch) + cr3 |= USART_CR3_DMAT; if (rs485conf->flags & SER_RS485_ENABLED) { - stm32_usart_config_reg_rs485(&cr1, &cr3, - rs485conf->delay_rts_before_send, - rs485conf->delay_rts_after_send, - baud); + stm32_usart_config_reg_rs485(&cr1, &cr3, baud, rs485conf); if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { cr3 &= ~USART_CR3_DEP; rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; @@ -970,6 +1303,40 @@ static void stm32_usart_pm(struct uart_port *port, unsigned int state, } } +#if defined(CONFIG_CONSOLE_POLL) + + /* Callbacks for characters polling in debug context (i.e. KGDB). */ +static int stm32_usart_poll_init(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + + return clk_prepare_enable(stm32_port->clk); +} + +static int stm32_usart_poll_get_char(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned int ret; + + if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_RXNE)) + return NO_POLL_CHAR; + + ret = readl_relaxed(port->membase + ofs->rdr); + /* Apply RDR data mask */ + ret &= stm32_port->rdr_mask; + + return ret; +} + +static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, int ch); + +static void stm32_usart_poll_put_char(struct uart_port *port, unsigned char ch) +{ + stm32_usart_console_putchar(port, (int)ch); +} +#endif + static const struct uart_ops stm32_uart_ops = { .tx_empty = stm32_usart_tx_empty, .set_mctrl = stm32_usart_set_mctrl, @@ -991,6 +1358,12 @@ static const struct uart_ops stm32_uart_ops = { .request_port = stm32_usart_request_port, .config_port = stm32_usart_config_port, .verify_port = stm32_usart_verify_port, +#if defined(CONFIG_CONSOLE_POLL) + .poll_init = stm32_usart_poll_init, + .poll_get_char = stm32_usart_poll_get_char, + .poll_put_char = stm32_usart_poll_put_char, +#endif /* CONFIG_CONSOLE_POLL */ + }; /* @@ -1171,7 +1544,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, struct uart_port *port = &stm32port->port; struct device *dev = &pdev->dev; struct dma_slave_config config; - struct dma_async_tx_descriptor *desc = NULL; int ret; /* @@ -1199,32 +1571,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, return ret; } - /* Prepare a DMA cyclic transaction */ - desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch, - stm32port->rx_dma_buf, - RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); - if (!desc) { - dev_err(dev, "rx dma prep cyclic failed\n"); - stm32_usart_of_dma_rx_remove(stm32port, pdev); - return -ENODEV; - } - - /* No callback as dma buffer is drained on usart interrupt */ - desc->callback = NULL; - desc->callback_param = NULL; - - /* Push current DMA transaction in the pending queue */ - ret = dma_submit_error(dmaengine_submit(desc)); - if (ret) { - dmaengine_terminate_sync(stm32port->rx_ch); - stm32_usart_of_dma_rx_remove(stm32port, pdev); - return ret; - } - - /* Issue pending DMA requests */ - dma_async_issue_pending(stm32port->rx_ch); - return 0; } @@ -1245,8 +1591,6 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, struct dma_slave_config config; int ret; - stm32port->tx_dma_busy = false; - stm32port->tx_buf = dma_alloc_coherent(dev, TX_BUF_L, &stm32port->tx_dma_buf, GFP_KERNEL); @@ -1377,6 +1721,7 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; int err; + u32 cr3; pm_runtime_get_sync(&pdev->dev); err = uart_remove_one_port(&stm32_usart_driver, port); @@ -1387,7 +1732,7 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_PEIE); if (stm32_port->tx_ch) { stm32_usart_of_dma_tx_remove(stm32_port, pdev); @@ -1395,12 +1740,16 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) } if (stm32_port->rx_ch) { - dmaengine_terminate_async(stm32_port->rx_ch); stm32_usart_of_dma_rx_remove(stm32_port, pdev); dma_release_channel(stm32_port->rx_ch); } - stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + cr3 = readl_relaxed(port->membase + ofs->cr3); + cr3 &= ~USART_CR3_EIE; + cr3 &= ~USART_CR3_DMAR; + cr3 &= ~USART_CR3_DMAT; + cr3 &= ~USART_CR3_DDRE; + writel_relaxed(cr3, port->membase + ofs->cr3); if (stm32_port->wakeup_src) { dev_pm_clear_wake_irq(&pdev->dev); @@ -1412,18 +1761,24 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_SERIAL_STM32_CONSOLE -static void stm32_usart_console_putchar(struct uart_port *port, int ch) +static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, int ch) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + u32 isr; + int ret; - while (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) - cpu_relax(); - + ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, isr, + (isr & USART_SR_TXE), 100, + STM32_USART_TIMEOUT_USEC); + if (ret != 0) { + dev_err(port->dev, "Error while sending data in UART TX : %d\n", ret); + return; + } writel_relaxed(ch, port->membase + ofs->tdr); } +#ifdef CONFIG_SERIAL_STM32_CONSOLE static void stm32_usart_console_write(struct console *co, const char *s, unsigned int cnt) { @@ -1499,6 +1854,57 @@ static struct console stm32_console = { #define STM32_SERIAL_CONSOLE NULL #endif /* CONFIG_SERIAL_STM32_CONSOLE */ +#ifdef CONFIG_SERIAL_EARLYCON +static void early_stm32_usart_console_putchar(struct uart_port *port, int ch) +{ + struct stm32_usart_info *info = port->private_data; + + while (!(readl_relaxed(port->membase + info->ofs.isr) & USART_SR_TXE)) + cpu_relax(); + + writel_relaxed(ch, port->membase + info->ofs.tdr); +} + +static void early_stm32_serial_write(struct console *console, const char *s, unsigned int count) +{ + struct earlycon_device *device = console->data; + struct uart_port *port = &device->port; + + uart_console_write(port, s, count, early_stm32_usart_console_putchar); +} + +static int __init early_stm32_h7_serial_setup(struct earlycon_device *device, const char *options) +{ + if (!(device->port.membase || device->port.iobase)) + return -ENODEV; + device->port.private_data = &stm32h7_info; + device->con->write = early_stm32_serial_write; + return 0; +} + +static int __init early_stm32_f7_serial_setup(struct earlycon_device *device, const char *options) +{ + if (!(device->port.membase || device->port.iobase)) + return -ENODEV; + device->port.private_data = &stm32f7_info; + device->con->write = early_stm32_serial_write; + return 0; +} + +static int __init early_stm32_f4_serial_setup(struct earlycon_device *device, const char *options) +{ + if (!(device->port.membase || device->port.iobase)) + return -ENODEV; + device->port.private_data = &stm32f4_info; + device->con->write = early_stm32_serial_write; + return 0; +} + +OF_EARLYCON_DECLARE(stm32h7serial, "st,stm32h7-uart", early_stm32_h7_serial_setup); +OF_EARLYCON_DECLARE(stm32f7serial, "st,stm32f7-uart", early_stm32_f7_serial_setup); +OF_EARLYCON_DECLARE(stm32f4serial, "st,stm32-uart", early_stm32_f4_serial_setup); +#endif /* CONFIG_SERIAL_EARLYCON */ + static struct uart_driver stm32_usart_driver = { .driver_name = DRIVER_NAME, .dev_name = STM32_SERIAL_NAME, @@ -1508,14 +1914,18 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; -static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, - bool enable) +static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, + bool enable) { struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct tty_port *tport = &port->state->port; + int ret; + unsigned int size = 0; + unsigned long flags; - if (!stm32_port->wakeup_src) - return; + if (!stm32_port->wakeup_src || !tty_port_initialized(tport)) + return 0; /* * Enable low-power wake-up and wake-up irq if argument is set to @@ -1524,20 +1934,52 @@ static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, if (enable) { stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); + mctrl_gpio_enable_irq_wake(stm32_port->gpios); + + /* + * When DMA is used for reception, it must be disabled before + * entering low-power mode and re-enabled when exiting from + * low-power mode. + */ + if (stm32_port->rx_ch) { + spin_lock_irqsave(&port->lock, flags); + /* Poll data from DMA RX buffer if any */ + if (!stm32_usart_rx_dma_pause(stm32_port)) + size += stm32_usart_receive_chars(port, true); + stm32_usart_rx_dma_terminate(stm32_port); + uart_unlock_and_check_sysrq_irqrestore(port, flags); + if (size) + tty_flip_buffer_push(tport); + } + + /* Poll data from RX FIFO if any */ + stm32_usart_receive_chars(port, false); } else { + if (stm32_port->rx_ch) { + ret = stm32_usart_rx_dma_start_or_resume(port); + if (ret) + return ret; + } + mctrl_gpio_disable_irq_wake(stm32_port->gpios); stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); } + + return 0; } static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; uart_suspend_port(&stm32_usart_driver, port); - if (device_may_wakeup(dev) || device_wakeup_path(dev)) - stm32_usart_serial_en_wakeup(port, true); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, true); + if (ret) + return ret; + } /* * When "no_console_suspend" is enabled, keep the pinctrl default state @@ -1558,11 +2000,15 @@ static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) static int __maybe_unused stm32_usart_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; pinctrl_pm_select_default_state(dev); - if (device_may_wakeup(dev) || device_wakeup_path(dev)) - stm32_usart_serial_en_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, false); + if (ret) + return ret; + } return uart_resume_port(&stm32_usart_driver, port); } diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 07ac29132..9c7ddb906 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -109,7 +109,7 @@ struct stm32_usart_info stm32h7_info = { /* USART_SR (F4) / USART_ISR (F7) */ #define USART_SR_PE BIT(0) #define USART_SR_FE BIT(1) -#define USART_SR_NF BIT(2) +#define USART_SR_NE BIT(2) /* F7 (NF for F4) */ #define USART_SR_ORE BIT(3) #define USART_SR_IDLE BIT(4) #define USART_SR_RXNE BIT(5) @@ -126,7 +126,8 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_SBKF BIT(18) /* F7 */ #define USART_SR_WUF BIT(20) /* H7 */ #define USART_SR_TEACK BIT(21) /* F7 */ -#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE) +#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_NE | USART_SR_FE |\ + USART_SR_PE) /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) @@ -246,9 +247,11 @@ struct stm32_usart_info stm32h7_info = { #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8 -#define RX_BUF_L 200 /* dma rx buffer length */ -#define RX_BUF_P RX_BUF_L /* dma rx buffer period */ -#define TX_BUF_L 200 /* dma tx buffer length */ +#define RX_BUF_L 4096 /* dma rx buffer length */ +#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ +#define TX_BUF_L RX_BUF_L /* dma tx buffer length */ + +#define STM32_USART_TIMEOUT_USEC USEC_PER_SEC /* 1s timeout in µs */ struct stm32_port { struct uart_port port; @@ -263,7 +266,9 @@ struct stm32_port { u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */ u32 cr3_irq; /* USART_CR3_RXFTIE */ int last_res; - bool tx_dma_busy; /* dma tx busy */ + bool tx_dma_busy; /* dma tx transaction in progress */ + bool rx_dma_busy; /* dma rx transaction in progress */ + bool throttled; /* port throttled */ bool hw_flow_control; bool swap; /* swap RX & TX pins */ bool fifoen; @@ -272,6 +277,7 @@ struct stm32_port { bool wakeup_src; int rdr_mask; /* receive data register mask */ struct mctrl_gpios *gpios; /* modem control gpios */ + struct dma_tx_state rx_dma_state; }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h index fa6b16e5f..e79080578 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -128,7 +128,9 @@ struct serial_rs485 { (if supported) */ __u32 delay_rts_before_send; /* Delay before send (milliseconds) */ __u32 delay_rts_after_send; /* Delay after send (milliseconds) */ - __u32 padding[5]; /* Memory is cheap, new structs + __u32 delay_rts_before_send_ns; /* Delay (nanoseconds) */ + __u32 delay_rts_after_send_ns; /* Delay (nanoseconds) */ + __u32 padding[3]; /* Memory is cheap, new structs are a royal PITA .. */ }; -- 2.25.1