From 9999e48639b3cecb08ffb37358bcba3b48161b29 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 08:50:17 +0000 Subject: [PATCH] add ax88772_rst --- kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 167 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 136 insertions(+), 31 deletions(-) diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index 7e2e79d..6623f5a 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * dwmac-stm32.c - DWMAC Specific Glue layer for STM32 MCU * * Copyright (C) STMicroelectronics SA 2017 * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - * */ #include <linux/clk.h> @@ -25,9 +24,29 @@ #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 +#define ETH_CK_F_50M 50000000 +#define ETH_CK_F_125M 125000000 + +/* Ethernet PHY interface selection in register SYSCFG Configuration + *------------------------------------------ + * src |BIT(23)| BIT(22)| BIT(21)|BIT(20)| + *------------------------------------------ + * MII | 0 | 0 | 0 | 1 | + *------------------------------------------ + * GMII | 0 | 0 | 0 | 0 | + *------------------------------------------ + * RGMII | 0 | 0 | 1 | n/a | + *------------------------------------------ + * 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) @@ -35,14 +54,43 @@ #define SYSCFG_MCU_ETH_SEL_MII 0 #define SYSCFG_MCU_ETH_SEL_RMII 1 +/* STM32MP1 register definitions + * + * Below table summarizes the clock requirement and clock sources for + * supported phy interface modes. + * __________________________________________________________________________ + *|PHY_MODE | Normal | PHY wo crystal| PHY wo crystal |No 125Mhz from PHY| + *| | | 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,ext-phyclk | + * --------------------------------------------------------------------------- + *| RMII | - | eth-ck | eth-ck | n/a | + *| | | st,ext-phyclk | st,eth-ref-clk-sel | | + *| | | | or st,ext-phyclk | | + * --------------------------------------------------------------------------- + * + */ + struct stm32_dwmac { struct clk *clk_tx; struct clk *clk_rx; struct clk *clk_eth_ck; struct clk *clk_ethstp; struct clk *syscfg_clk; - bool int_phyclk; /* Clock from RCC to drive PHY */ - u32 mode_reg; /* MAC glue-logic mode register */ + int ext_phyclk; + 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 */ struct regmap *regmap; u32 speed; const struct stm32_ops *ops; @@ -57,6 +105,7 @@ int (*parse_data)(struct stm32_dwmac *dwmac, struct device *dev); u32 syscfg_eth_mask; + bool clk_rx_enable_in_suspend; }; static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat) @@ -74,7 +123,8 @@ if (ret) return ret; - if (!dwmac->dev->power.is_suspended) { + if (!dwmac->ops->clk_rx_enable_in_suspend || + !dwmac->dev->power.is_suspended) { ret = clk_prepare_enable(dwmac->clk_rx); if (ret) { clk_disable_unprepare(dwmac->clk_tx); @@ -101,8 +151,7 @@ ret = clk_prepare_enable(dwmac->syscfg_clk); if (ret) return ret; - - if (dwmac->int_phyclk) { + if (dwmac->enable_eth_ck) { ret = clk_prepare_enable(dwmac->clk_eth_ck); if (ret) { clk_disable_unprepare(dwmac->syscfg_clk); @@ -111,7 +160,7 @@ } } else { clk_disable_unprepare(dwmac->syscfg_clk); - if (dwmac->int_phyclk) + if (dwmac->enable_eth_ck) clk_disable_unprepare(dwmac->clk_eth_ck); } return ret; @@ -120,30 +169,46 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; - u32 reg = dwmac->mode_reg; + u32 reg = dwmac->mode_reg, clk_rate; int val; + clk_rate = clk_get_rate(dwmac->clk_eth_ck); + dwmac->enable_eth_ck = false; switch (plat_dat->interface) { case PHY_INTERFACE_MODE_MII: + if (clk_rate == ETH_CK_F_25M && dwmac->ext_phyclk) + dwmac->enable_eth_ck = true; val = SYSCFG_PMCR_ETH_SEL_MII; pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n"); break; case PHY_INTERFACE_MODE_GMII: val = SYSCFG_PMCR_ETH_SEL_GMII; - if (dwmac->int_phyclk) + if (clk_rate == ETH_CK_F_25M && + (dwmac->eth_clk_sel_reg || dwmac->ext_phyclk)) { + 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 (dwmac->int_phyclk) + if ((clk_rate == ETH_CK_F_25M || 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; + } pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n"); break; case PHY_INTERFACE_MODE_RGMII: + 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->int_phyclk) + if ((clk_rate == ETH_CK_F_25M || 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; + } pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RGMII\n"); break; default: @@ -153,6 +218,11 @@ return -EINVAL; } + /* Need to update PMCCLRR (clear register) */ + regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, + dwmac->ops->syscfg_eth_mask); + + /* Update PMCSETR (set register) */ return regmap_update_bits(dwmac->regmap, reg, dwmac->ops->syscfg_eth_mask, val); } @@ -180,7 +250,7 @@ } return regmap_update_bits(dwmac->regmap, reg, - dwmac->ops->syscfg_eth_mask, val); + dwmac->ops->syscfg_eth_mask, val << 23); } static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac) @@ -232,35 +302,63 @@ 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; - dwmac->int_phyclk = of_property_read_bool(np, "st,int-phyclk"); + /* Ethernet PHY have no crystal */ + dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk"); - /* Check if internal clk from RCC selected */ - if (dwmac->int_phyclk) { - /* Get ETH_CLK clocks */ - dwmac->clk_eth_ck = devm_clk_get(dev, "eth-ck"); - if (IS_ERR(dwmac->clk_eth_ck)) { - dev_err(dev, "No ETH CK clock provided...\n"); - return PTR_ERR(dwmac->clk_eth_ck); - } + /* Gigabit Ethernet 125MHz clock selection. */ + dwmac->eth_clk_sel_reg = of_property_read_bool(np, "st,eth-clk-sel"); + + /* Ethernet 50Mhz RMII clock selection */ + dwmac->eth_ref_clk_sel_reg = + of_property_read_bool(np, "st,eth-ref-clk-sel"); + + /* 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"); + dwmac->clk_eth_ck = NULL; } /* Clock used for low power mode */ dwmac->clk_ethstp = devm_clk_get(dev, "ethstp"); if (IS_ERR(dwmac->clk_ethstp)) { - dev_err(dev, "No ETH peripheral clock provided for CStop mode ...\n"); + dev_err(dev, + "No ETH peripheral clock provided for CStop mode ...\n"); return PTR_ERR(dwmac->clk_ethstp); } - /* Clock for sysconfig */ + /* Optional Clock for sysconfig */ dwmac->syscfg_clk = devm_clk_get(dev, "syscfg-clk"); - if (IS_ERR(dwmac->syscfg_clk)) { - dev_err(dev, "No syscfg clock provided...\n"); - return PTR_ERR(dwmac->syscfg_clk); - } + if (IS_ERR(dwmac->syscfg_clk)) + dwmac->syscfg_clk = NULL; - return 0; + /* 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 err; } static int stm32_dwmac_probe(struct platform_device *pdev) @@ -326,8 +424,14 @@ 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; 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); + } return ret; } @@ -342,7 +446,7 @@ clk_disable_unprepare(dwmac->clk_tx); clk_disable_unprepare(dwmac->syscfg_clk); - if (dwmac->int_phyclk) + if (dwmac->enable_eth_ck) clk_disable_unprepare(dwmac->clk_eth_ck); return ret; @@ -413,7 +517,8 @@ .suspend = stm32mp1_suspend, .resume = stm32mp1_resume, .parse_data = stm32mp1_parse_data, - .syscfg_eth_mask = SYSCFG_MP1_ETH_MASK + .syscfg_eth_mask = SYSCFG_MP1_ETH_MASK, + .clk_rx_enable_in_suspend = true }; static const struct of_device_id stm32_dwmac_match[] = { -- Gitblit v1.6.2