net: stmmac: dwmac-qcom-ethqos: add support for the optional serdes phy
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Mon, 19 Jun 2023 09:23:56 +0000 (11:23 +0200)
committerJakub Kicinski <kuba@kernel.org>
Wed, 21 Jun 2023 03:44:38 +0000 (20:44 -0700)
On sa8775p platforms, there's a SGMII SerDes PHY between the MAC and
external PHY that we need to enable and configure.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c

index ec3bbd19950138dce75478b66e57d222e62b78cf..042733b5e80b9da6c5cbdae584c90d183aa93306 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/phy.h>
+#include <linux/phy/phy.h>
 #include <linux/property.h>
 
 #include "stmmac.h"
@@ -93,6 +94,7 @@ struct qcom_ethqos {
 
        unsigned int rgmii_clk_rate;
        struct clk *rgmii_clk;
+       struct phy *serdes_phy;
        unsigned int speed;
 
        const struct ethqos_emac_por *por;
@@ -565,6 +567,30 @@ static void ethqos_fix_mac_speed(void *priv, unsigned int speed)
        ethqos_configure(ethqos);
 }
 
+static int qcom_ethqos_serdes_powerup(struct net_device *ndev, void *priv)
+{
+       struct qcom_ethqos *ethqos = priv;
+       int ret;
+
+       ret = phy_init(ethqos->serdes_phy);
+       if (ret)
+               return ret;
+
+       ret = phy_power_on(ethqos->serdes_phy);
+       if (ret)
+               return ret;
+
+       return phy_set_speed(ethqos->serdes_phy, ethqos->speed);
+}
+
+static void qcom_ethqos_serdes_powerdown(struct net_device *ndev, void *priv)
+{
+       struct qcom_ethqos *ethqos = priv;
+
+       phy_power_off(ethqos->serdes_phy);
+       phy_exit(ethqos->serdes_phy);
+}
+
 static int ethqos_clks_config(void *priv, bool enabled)
 {
        struct qcom_ethqos *ethqos = priv;
@@ -650,6 +676,12 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
        if (ret)
                goto out_config_dt;
 
+       ethqos->serdes_phy = devm_phy_optional_get(dev, "serdes");
+       if (IS_ERR(ethqos->serdes_phy)) {
+               ret = PTR_ERR(ethqos->serdes_phy);
+               goto out_config_dt;
+       }
+
        ethqos->speed = SPEED_1000;
        ethqos_update_rgmii_clk(ethqos, SPEED_1000);
        ethqos_set_func_clk_en(ethqos);
@@ -665,6 +697,11 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
        if (of_device_is_compatible(np, "qcom,qcs404-ethqos"))
                plat_dat->rx_clk_runs_in_lpi = 1;
 
+       if (ethqos->serdes_phy) {
+               plat_dat->serdes_powerup = qcom_ethqos_serdes_powerup;
+               plat_dat->serdes_powerdown  = qcom_ethqos_serdes_powerdown;
+       }
+
        ret = stmmac_dvr_probe(dev, plat_dat, &stmmac_res);
        if (ret)
                goto out_config_dt;