From: George Moussalem Date: Sun, 19 Jan 2025 11:25:27 +0400 Subject: [PATCH] net: phy: qcom: ipq5018 enable configuration of DAC settings Allow setting amplitude and bias current as needed on the IPQ5018 Internal GE PHY. When the "qcom,dac" property is set in the DTS, the driver expects a pair of u32 values: (from QCA8337 datasheet) 11: follow DSP setting 10: bypass half amplitude and follow DSP half bias current 01: half amplitude follow DSP and bypass half bias current 00: full amplitude and full bias current Signed-off-by: George Moussalem --- --- a/drivers/net/phy/qcom/ipq5018.c +++ b/drivers/net/phy/qcom/ipq5018.c @@ -13,6 +13,10 @@ #define IPQ5018_PHY_FIFO_CONTROL 0x19 #define IPQ5018_PHY_FIFO_RESET GENMASK(1, 0) +#define IPQ5018_PHY_DEBUG_EDAC 0x4380 +#define IPQ5018_PHY_MMD1_MDAC 0x8100 +#define IPQ5018_PHY_DAC_MASK GENMASK(15,8) + struct ipq5018_phy { int num_clks; struct clk_bulk_data *clks; @@ -20,20 +24,35 @@ struct ipq5018_phy { struct clk_hw *clk_rx, *clk_tx; struct clk_hw_onecell_data *clk_data; + + u32 mdac; + u32 edac; }; static int ipq5018_probe(struct phy_device *phydev) { - struct ipq5018_phy *priv; struct device *dev = &phydev->mdio.dev; + struct ipq5018_phy *priv; + u32 mdac, edac = 0; char name[64]; - int ret; + int ret, cnt; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return dev_err_probe(dev, -ENOMEM, "failed to allocate priv\n"); + cnt = of_property_count_u32_elems(dev->of_node, "qcom,dac"); + if (cnt == 2) { + ret = of_property_read_u32_index(dev->of_node, "qcom,dac", 0, &mdac); + if (!ret) + priv->mdac = mdac; + + ret = of_property_read_u32_index(dev->of_node, "qcom,dac", 1, &edac); + if (!ret) + priv->edac = edac; + } + priv->num_clks = devm_clk_bulk_get_all(dev, &priv->clks); if (priv->num_clks < 0) return dev_err_probe(dev, priv->num_clks, @@ -84,6 +103,8 @@ static int ipq5018_probe(struct phy_devi return dev_err_probe(dev, ret, "fail to register clock provider\n"); + phydev->priv = priv; + return 0; } @@ -112,12 +133,34 @@ static int ipq5018_cable_test_start(stru return 0; } +static int ipq5018_config_init(struct phy_device *phydev) +{ + struct ipq5018_phy *priv = phydev->priv; + int ret; + + /* setting mdac in MMD1 */ + if (priv->mdac) { + ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MDAC, + IPQ5018_PHY_DAC_MASK, priv->mdac); + if (ret) + return ret; + } + + /* setting edac in debug register */ + if (priv->edac) + return at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_EDAC, + IPQ5018_PHY_DAC_MASK, priv->edac); + + return 0; +} + static struct phy_driver ipq5018_internal_phy_driver[] = { { PHY_ID_MATCH_EXACT(IPQ5018_PHY_ID), .name = "Qualcomm IPQ5018 internal PHY", .flags = PHY_IS_INTERNAL | PHY_POLL_CABLE_TEST, .probe = ipq5018_probe, + .config_init = ipq5018_config_init, .soft_reset = ipq5018_soft_reset, .read_status = at803x_read_status, .config_intr = at803x_config_intr,