From 324c5b908a5294390ed9659a6439758cb20ecd61 Mon Sep 17 00:00:00 2001 From: Luo Jie Date: Tue, 9 Apr 2024 16:30:55 +0800 Subject: [PATCH 07/50] net: phy: qca808x: Add package clocks and resets for QCA8084 Parse the PHY package clocks from the PHY package DTS node. These package level clocks will be enabled in the PHY package init function. Deassert PHY package reset, which is necessary for accessing the PHY registers. Change-Id: I254d0aa0a1155d3618c6f1fc7d7a5b6ecadccbaa Signed-off-by: Luo Jie --- drivers/net/phy/qcom/qca808x.c | 67 ++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index 85bb299fe0a3..632cad1ad190 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "qcom.h" @@ -148,10 +149,35 @@ MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver"); MODULE_AUTHOR("Matus Ujhelyi, Luo Jie"); MODULE_LICENSE("GPL"); +enum { + APB_BRIDGE_CLK, + AHB_CLK, + SEC_CTRL_AHB_CLK, + TLMM_CLK, + TLMM_AHB_CLK, + CNOC_AHB_CLK, + MDIO_AHB_CLK, + PACKAGE_CLK_MAX +}; + struct qca808x_priv { int led_polarity_mode; }; +struct qca808x_shared_priv { + struct clk *clk[PACKAGE_CLK_MAX]; +}; + +static const char *const qca8084_package_clk_name[PACKAGE_CLK_MAX] = { + [APB_BRIDGE_CLK] = "apb_bridge", + [AHB_CLK] = "ahb", + [SEC_CTRL_AHB_CLK] = "sec_ctrl_ahb", + [TLMM_CLK] = "tlmm", + [TLMM_AHB_CLK] = "tlmm_ahb", + [CNOC_AHB_CLK] = "cnoc_ahb", + [MDIO_AHB_CLK] = "mdio_ahb", +}; + static int __qca8084_set_page(struct mii_bus *bus, u16 sw_addr, u16 page) { return __mdiobus_write(bus, QCA8084_HIGH_ADDR_PREFIX | (sw_addr >> 5), @@ -853,11 +879,24 @@ static void qca8084_link_change_notify(struct phy_device *phydev) QCA8084_IPG_10_TO_11_EN : 0); } +/* QCA8084 is a four-port PHY, which integrates the clock controller, + * 4 PHY devices and 2 PCS interfaces (PCS0 and PCS1). PCS1 includes + * XPCS and PCS to support 10G-QXGMII and SGMII. PCS0 includes one PCS + * to support SGMII. + * + * The clocks and resets are sourced from the integrated clock controller + * of the PHY package. This integrated clock controller is driven by a + * QCA8K clock provider that supplies the clocks and resets to the four + * PHYs, PCS and PHY package. + */ static int qca8084_phy_package_probe_once(struct phy_device *phydev) { int addr[QCA8084_MDIO_DEVICE_NUM] = {0, 1, 2, 3, 4, 5, 6}; struct phy_package_shared *shared = phydev->shared; - int ret, clear, set; + struct qca808x_shared_priv *shared_priv; + struct reset_control *rstc; + int i, ret, clear, set; + struct clk *clk; /* Program the MDIO address of PHY and PCS optionally, the MDIO * address 0-6 is used for PHY and PCS MDIO devices by default. @@ -889,17 +928,39 @@ static int qca8084_phy_package_probe_once(struct phy_device *phydev) set |= FIELD_PREP(QCA8084_PCS_ADDR1_MASK, addr[5]); set |= FIELD_PREP(QCA8084_PCS_ADDR2_MASK, addr[6]); - return qca8084_mii_modify(phydev, QCA8084_PCS_CFG, clear, set); + ret = qca8084_mii_modify(phydev, QCA8084_PCS_CFG, clear, set); + if (ret) + return ret; + + shared_priv = shared->priv; + for (i = 0; i < ARRAY_SIZE(qca8084_package_clk_name); i++) { + clk = of_clk_get_by_name(shared->np, + qca8084_package_clk_name[i]); + if (IS_ERR(clk)) + return dev_err_probe(&phydev->mdio.dev, PTR_ERR(clk), + "package clock %s not ready\n", + qca8084_package_clk_name[i]); + shared_priv->clk[i] = clk; + } + + rstc = of_reset_control_get_exclusive(shared->np, NULL); + if (IS_ERR(rstc)) + return dev_err_probe(&phydev->mdio.dev, PTR_ERR(rstc), + "package reset not ready\n"); + + /* Deassert PHY package. */ + return reset_control_deassert(rstc); } static int qca8084_probe(struct phy_device *phydev) { + struct qca808x_shared_priv *shared_priv; struct device *dev = &phydev->mdio.dev; struct reset_control *rstc; struct clk *clk; int ret; - ret = devm_of_phy_package_join(dev, phydev, 0); + ret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv)); if (ret) return ret; -- 2.45.2