diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c')
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 203 |
1 files changed, 99 insertions, 104 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index c1732955a697..e1b260ed4790 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -47,23 +47,18 @@ *------------------------------------------ */ #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_PMCR_PHY_INTF_SEL_MASK GENMASK(23, 21) #define SYSCFG_MCU_ETH_SEL_MII 0 #define SYSCFG_MCU_ETH_SEL_RMII 1 /* STM32MP2 register definitions */ #define SYSCFG_MP2_ETH_MASK GENMASK(31, 0) +#define SYSCFG_ETHCR_ETH_SEL_MASK GENMASK(6, 4) #define SYSCFG_ETHCR_ETH_PTP_CLK_SEL BIT(2) #define SYSCFG_ETHCR_ETH_CLK_SEL BIT(1) #define SYSCFG_ETHCR_ETH_REF_CLK_SEL BIT(0) -#define SYSCFG_ETHCR_ETH_SEL_MII 0 -#define SYSCFG_ETHCR_ETH_SEL_RGMII BIT(4) -#define SYSCFG_ETHCR_ETH_SEL_RMII BIT(6) - /* STM32MPx register definitions * * Below table summarizes the clock requirement and clock sources for @@ -119,7 +114,7 @@ struct stm32_ops { u32 syscfg_clr_off; }; -static int stm32_dwmac_clk_enable(struct stm32_dwmac *dwmac, bool resume) +static int stm32_dwmac_clk_enable(struct stm32_dwmac *dwmac) { int ret; @@ -127,11 +122,9 @@ static int stm32_dwmac_clk_enable(struct stm32_dwmac *dwmac, bool resume) if (ret) goto err_clk_tx; - if (!dwmac->ops->clk_rx_enable_in_suspend || !resume) { - ret = clk_prepare_enable(dwmac->clk_rx); - if (ret) - goto err_clk_rx; - } + ret = clk_prepare_enable(dwmac->clk_rx); + if (ret) + goto err_clk_rx; ret = clk_prepare_enable(dwmac->syscfg_clk); if (ret) @@ -148,15 +141,14 @@ static int stm32_dwmac_clk_enable(struct stm32_dwmac *dwmac, bool resume) err_clk_eth_ck: clk_disable_unprepare(dwmac->syscfg_clk); err_syscfg_clk: - if (!dwmac->ops->clk_rx_enable_in_suspend || !resume) - clk_disable_unprepare(dwmac->clk_rx); + clk_disable_unprepare(dwmac->clk_rx); err_clk_rx: clk_disable_unprepare(dwmac->clk_tx); err_clk_tx: return ret; } -static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat, bool resume) +static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; int ret; @@ -167,14 +159,14 @@ static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat, bool resume) return ret; } - return stm32_dwmac_clk_enable(dwmac, resume); + return stm32_dwmac_clk_enable(dwmac); } static int stm32mp1_select_ethck_external(struct plat_stmmacenet_data *plat_dat) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; - switch (plat_dat->mac_interface) { + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: dwmac->enable_eth_ck = dwmac->ext_phyclk; return 0; @@ -196,7 +188,7 @@ static int stm32mp1_select_ethck_external(struct plat_stmmacenet_data *plat_dat) default: dwmac->enable_eth_ck = false; dev_err(dwmac->dev, "Mode %s not supported", - phy_modes(plat_dat->mac_interface)); + phy_modes(plat_dat->phy_interface)); return -EINVAL; } } @@ -209,7 +201,7 @@ static int stm32mp1_validate_ethck_rate(struct plat_stmmacenet_data *plat_dat) if (!dwmac->enable_eth_ck) return 0; - switch (plat_dat->mac_interface) { + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_GMII: if (clk_rate == ETH_CK_F_25M) @@ -231,17 +223,20 @@ static int stm32mp1_validate_ethck_rate(struct plat_stmmacenet_data *plat_dat) } dev_err(dwmac->dev, "Mode %s does not match eth-ck frequency %d Hz", - phy_modes(plat_dat->mac_interface), clk_rate); + phy_modes(plat_dat->phy_interface), clk_rate); return -EINVAL; } -static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat) +static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat, + u8 phy_intf_sel) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; u32 reg = dwmac->mode_reg; - int val = 0; + int val; - switch (plat_dat->mac_interface) { + val = FIELD_PREP(SYSCFG_PMCR_PHY_INTF_SEL_MASK, phy_intf_sel); + + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: /* * STM32MP15xx supports both MII and GMII, STM32MP13xx MII only. @@ -253,12 +248,10 @@ static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat) val |= SYSCFG_PMCR_ETH_SEL_MII; break; case PHY_INTERFACE_MODE_GMII: - val = SYSCFG_PMCR_ETH_SEL_GMII; if (dwmac->enable_eth_ck) val |= SYSCFG_PMCR_ETH_CLK_SEL; break; case PHY_INTERFACE_MODE_RMII: - val = SYSCFG_PMCR_ETH_SEL_RMII; if (dwmac->enable_eth_ck) val |= SYSCFG_PMCR_ETH_REF_CLK_SEL; break; @@ -266,18 +259,17 @@ static int stm32mp1_configure_pmcr(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 (dwmac->enable_eth_ck) val |= SYSCFG_PMCR_ETH_CLK_SEL; break; default: dev_err(dwmac->dev, "Mode %s not supported", - phy_modes(plat_dat->mac_interface)); + phy_modes(plat_dat->phy_interface)); /* Do not manage others interfaces */ return -EINVAL; } - dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->mac_interface)); + dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->phy_interface)); /* Shift value at correct ethernet MAC offset in SYSCFG_PMCSETR */ val <<= ffs(dwmac->mode_mask) - ffs(SYSCFG_MP1_ETH_MASK); @@ -291,18 +283,20 @@ static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat) dwmac->mode_mask, val); } -static int stm32mp2_configure_syscfg(struct plat_stmmacenet_data *plat_dat) +static int stm32mp2_configure_syscfg(struct plat_stmmacenet_data *plat_dat, + u8 phy_intf_sel) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; u32 reg = dwmac->mode_reg; - int val = 0; + int val; - switch (plat_dat->mac_interface) { + val = FIELD_PREP(SYSCFG_ETHCR_ETH_SEL_MASK, phy_intf_sel); + + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: /* ETH_REF_CLK_SEL bit in SYSCFG register is not applicable in MII mode */ break; case PHY_INTERFACE_MODE_RMII: - val = SYSCFG_ETHCR_ETH_SEL_RMII; if (dwmac->enable_eth_ck) { /* Internal clock ETH_CLK of 50MHz from RCC is used */ val |= SYSCFG_ETHCR_ETH_REF_CLK_SEL; @@ -312,8 +306,6 @@ static int stm32mp2_configure_syscfg(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_ETHCR_ETH_SEL_RGMII; - fallthrough; case PHY_INTERFACE_MODE_GMII: if (dwmac->enable_eth_ck) { /* Internal clock ETH_CLK of 125MHz from RCC is used */ @@ -322,12 +314,12 @@ static int stm32mp2_configure_syscfg(struct plat_stmmacenet_data *plat_dat) break; default: dev_err(dwmac->dev, "Mode %s not supported", - phy_modes(plat_dat->mac_interface)); + phy_modes(plat_dat->phy_interface)); /* Do not manage others interfaces */ return -EINVAL; } - dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->mac_interface)); + dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->phy_interface)); /* Select PTP (IEEE1588) clock selection from RCC (ck_ker_ethxptp) */ val |= SYSCFG_ETHCR_ETH_PTP_CLK_SEL; @@ -340,7 +332,7 @@ static int stm32mp2_configure_syscfg(struct plat_stmmacenet_data *plat_dat) static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; - int ret; + int phy_intf_sel, ret; ret = stm32mp1_select_ethck_external(plat_dat); if (ret) @@ -350,10 +342,19 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) if (ret) return ret; + phy_intf_sel = stmmac_get_phy_intf_sel(plat_dat->phy_interface); + if (phy_intf_sel != PHY_INTF_SEL_GMII_MII && + phy_intf_sel != PHY_INTF_SEL_RGMII && + phy_intf_sel != PHY_INTF_SEL_RMII) { + dev_err(dwmac->dev, "Mode %s not supported\n", + phy_modes(plat_dat->phy_interface)); + return phy_intf_sel < 0 ? phy_intf_sel : -EINVAL; + } + if (!dwmac->ops->is_mp2) - return stm32mp1_configure_pmcr(plat_dat); + return stm32mp1_configure_pmcr(plat_dat, phy_intf_sel); else - return stm32mp2_configure_syscfg(plat_dat); + return stm32mp2_configure_syscfg(plat_dat, phy_intf_sel); } static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat) @@ -362,7 +363,7 @@ static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat) u32 reg = dwmac->mode_reg; int val; - switch (plat_dat->mac_interface) { + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: val = SYSCFG_MCU_ETH_SEL_MII; break; @@ -371,23 +372,21 @@ static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat) break; default: dev_err(dwmac->dev, "Mode %s not supported", - phy_modes(plat_dat->mac_interface)); + phy_modes(plat_dat->phy_interface)); /* Do not manage others interfaces */ return -EINVAL; } - dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->mac_interface)); + dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->phy_interface)); return regmap_update_bits(dwmac->regmap, reg, SYSCFG_MCU_ETH_MASK, val << 23); } -static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac, bool suspend) +static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac) { clk_disable_unprepare(dwmac->clk_tx); - if (!dwmac->ops->clk_rx_enable_in_suspend || !suspend) - clk_disable_unprepare(dwmac->clk_rx); - + clk_disable_unprepare(dwmac->clk_rx); clk_disable_unprepare(dwmac->syscfg_clk); if (dwmac->enable_eth_ck) clk_disable_unprepare(dwmac->clk_eth_ck); @@ -419,16 +418,11 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac, } /* Get mode register */ - dwmac->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon"); + dwmac->regmap = syscon_regmap_lookup_by_phandle_args(np, "st,syscon", + 1, &dwmac->mode_reg); if (IS_ERR(dwmac->regmap)) 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 mode offset (%d)\n", err); - return err; - } - if (dwmac->ops->is_mp2) return 0; @@ -508,6 +502,26 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, return err; } +static int stm32_dwmac_suspend(struct device *dev, void *bsp_priv) +{ + struct stm32_dwmac *dwmac = bsp_priv; + + stm32_dwmac_clk_disable(dwmac); + + return dwmac->ops->suspend ? dwmac->ops->suspend(dwmac) : 0; +} + +static int stm32_dwmac_resume(struct device *dev, void *bsp_priv) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dev)); + struct stm32_dwmac *dwmac = bsp_priv; + + if (dwmac->ops->resume) + dwmac->ops->resume(dwmac); + + return stm32_dwmac_init(priv->plat); +} + static int stm32_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -543,20 +557,37 @@ static int stm32_dwmac_probe(struct platform_device *pdev) return ret; } + plat_dat->flags |= STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP; plat_dat->bsp_priv = dwmac; + plat_dat->suspend = stm32_dwmac_suspend; + plat_dat->resume = stm32_dwmac_resume; - ret = stm32_dwmac_init(plat_dat, false); + ret = stm32_dwmac_init(plat_dat); if (ret) return ret; + /* If this platform requires the clock to be running in suspend, + * prepare and enable the receive clock an additional time to keep + * it running. + */ + if (dwmac->ops->clk_rx_enable_in_suspend) { + ret = clk_prepare_enable(dwmac->clk_rx); + if (ret) + goto err_clk_disable; + } + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) - goto err_clk_disable; + goto err_clk_disable_suspend; return 0; +err_clk_disable_suspend: + if (dwmac->ops->clk_rx_enable_in_suspend) + clk_disable_unprepare(dwmac->clk_rx); + err_clk_disable: - stm32_dwmac_clk_disable(dwmac, false); + stm32_dwmac_clk_disable(dwmac); return ret; } @@ -569,7 +600,15 @@ static void stm32_dwmac_remove(struct platform_device *pdev) stmmac_dvr_remove(&pdev->dev); - stm32_dwmac_clk_disable(dwmac, false); + /* If this platform requires the clock to be running in suspend, + * we need to disable and unprepare the receive clock an additional + * time to balance the extra clk_prepare_enable() in the probe + * function. + */ + if (dwmac->ops->clk_rx_enable_in_suspend) + clk_disable_unprepare(dwmac->clk_rx); + + stm32_dwmac_clk_disable(dwmac); if (dwmac->irq_pwr_wakeup >= 0) { dev_pm_clear_wake_irq(&pdev->dev); @@ -587,50 +626,6 @@ static void stm32mp1_resume(struct stm32_dwmac *dwmac) clk_disable_unprepare(dwmac->clk_ethstp); } -#ifdef CONFIG_PM_SLEEP -static int stm32_dwmac_suspend(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct stm32_dwmac *dwmac = priv->plat->bsp_priv; - - int ret; - - ret = stmmac_suspend(dev); - if (ret) - return ret; - - stm32_dwmac_clk_disable(dwmac, true); - - if (dwmac->ops->suspend) - ret = dwmac->ops->suspend(dwmac); - - return ret; -} - -static int stm32_dwmac_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct stm32_dwmac *dwmac = priv->plat->bsp_priv; - int ret; - - if (dwmac->ops->resume) - dwmac->ops->resume(dwmac); - - ret = stm32_dwmac_init(priv->plat, true); - if (ret) - return ret; - - ret = stmmac_resume(dev); - - return ret; -} -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops, - stm32_dwmac_suspend, stm32_dwmac_resume); - static struct stm32_ops stm32mcu_dwmac_data = { .set_mode = stm32mcu_set_mode }; @@ -675,10 +670,10 @@ MODULE_DEVICE_TABLE(of, stm32_dwmac_match); static struct platform_driver stm32_dwmac_driver = { .probe = stm32_dwmac_probe, - .remove_new = stm32_dwmac_remove, + .remove = stm32_dwmac_remove, .driver = { .name = "stm32-dwmac", - .pm = &stm32_dwmac_pm_ops, + .pm = &stmmac_simple_pm_ops, .of_match_table = stm32_dwmac_match, }, }; |
