[7/9] net: mdio: ipq4019: program phy address when "fixup" defined

Message ID 20231115032515.4249-8-quic_luoj@quicinc.com
State New
Headers
Series add MDIO changes on ipq5332 platform |

Commit Message

Jie Luo Nov. 15, 2023, 3:25 a.m. UTC
  The PHY/PCS MDIO address can be programed when the property
"fixup" of phy node is defined.

The qca8084 PHY/PCS address configuration register is accessed
by MDIO bus with the special MDIO sequence.

The PHY address configuration register of IPQ5018 is accessed
by local bus.

Add the function ipq_mdio_preinit, which should be called before
the PHY device scanned and registered.

Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
---
 drivers/net/mdio/mdio-ipq4019.c | 107 +++++++++++++++++++++++++++++++-
 1 file changed, 106 insertions(+), 1 deletion(-)
  

Comments

Andrew Lunn Nov. 15, 2023, 4:17 p.m. UTC | #1
On Wed, Nov 15, 2023 at 11:25:13AM +0800, Luo Jie wrote:
> The PHY/PCS MDIO address can be programed when the property
> "fixup" of phy node is defined.
> 
> The qca8084 PHY/PCS address configuration register is accessed
> by MDIO bus with the special MDIO sequence.
> 
> The PHY address configuration register of IPQ5018 is accessed
> by local bus.
> 
> Add the function ipq_mdio_preinit, which should be called before
> the PHY device scanned and registered.

I'm not convinced this belongs in the MDIO bus driver. Its really a
PHY property, so i think all this should be in the PHY driver. If you
specify the PHY ID in the compatible string, you can get the driver
loaded and the probe function called. You can then set the PHY
address.

	Andrew
  
Jie Luo Nov. 16, 2023, 11:17 a.m. UTC | #2
On 11/16/2023 12:17 AM, Andrew Lunn wrote:
> On Wed, Nov 15, 2023 at 11:25:13AM +0800, Luo Jie wrote:
>> The PHY/PCS MDIO address can be programed when the property
>> "fixup" of phy node is defined.
>>
>> The qca8084 PHY/PCS address configuration register is accessed
>> by MDIO bus with the special MDIO sequence.
>>
>> The PHY address configuration register of IPQ5018 is accessed
>> by local bus.
>>
>> Add the function ipq_mdio_preinit, which should be called before
>> the PHY device scanned and registered.
> 
> I'm not convinced this belongs in the MDIO bus driver. Its really a
> PHY property, so i think all this should be in the PHY driver. If you
> specify the PHY ID in the compatible string, you can get the driver
> loaded and the probe function called. You can then set the PHY
> address.
> 
> 	Andrew

I will try to do the initialization configs in the PHY probe function,
Thanks Andrew for the suggestions.
  

Patch

diff --git a/drivers/net/mdio/mdio-ipq4019.c b/drivers/net/mdio/mdio-ipq4019.c
index 8dc611666c34..1c461c243ae0 100644
--- a/drivers/net/mdio/mdio-ipq4019.c
+++ b/drivers/net/mdio/mdio-ipq4019.c
@@ -61,6 +61,15 @@ 
 #define IPQ_HIGH_ADDR_PREFIX			0x18
 #define IPQ_LOW_ADDR_PREFIX			0x10
 
+/* QCA8084 PHY & PCS address can be customized, 4 PHYs and 3 PCSs are
+ * available.
+ */
+#define QCA8084_PHY_ADDR_LENGTH			5
+#define QCA8084_PHY_ADDR_NUM			4
+#define QCA8084_PCS_ADDR_NUM			3
+#define QCA8084_PHY_ADDR_MASK			GENMASK(19, 0)
+#define QCA8084_PCS_ADDR_MASK			GENMASK(14, 0)
+
 enum mdio_clk_id {
 	MDIO_CLK_MDIO_AHB,
 	MDIO_CLK_UNIPHY0_AHB,
@@ -317,6 +326,102 @@  static int qca8084_modify(struct mii_bus *bus, u32 regaddr, u32 clear, u32 set)
 	return qca8084_mii_write(bus, IPQ_LOW_ADDR_PREFIX | addr, reg, val);
 };
 
+/* The PHY/PCS MDIO address can be programed when the device tree property
+ * "fixup" of PHY node is specified.
+ */
+static int ipq_phy_addr_fixup(struct mii_bus *bus, struct device_node *mdio_node)
+{
+	const __be32 *phy_cfg;
+	u32 phy_addr_val, pcs_addr_val;
+	int ret, phy_index, pcs_index;
+	struct device_node *child;
+
+	phy_index = 0;
+	pcs_index = 0;
+	phy_addr_val = 0;
+	pcs_addr_val = 0;
+	for_each_available_child_of_node(mdio_node, child) {
+		ret = of_mdio_parse_addr(&bus->dev, child);
+		if (ret < 0)
+			continue;
+
+		if (!of_property_present(child, "fixup"))
+			continue;
+
+		if (of_property_present(child, "compatible")) {
+			pcs_addr_val |= ret << (QCA8084_PHY_ADDR_LENGTH * pcs_index);
+			pcs_index++;
+		} else {
+			phy_addr_val |= ret << (QCA8084_PHY_ADDR_LENGTH * phy_index);
+			phy_index++;
+		}
+	}
+
+	if (!phy_addr_val && !pcs_addr_val)
+		return 0;
+
+	if (phy_index > QCA8084_PHY_ADDR_NUM || pcs_index > QCA8084_PCS_ADDR_NUM) {
+		dev_err(&bus->dev,
+			"Too many MDIO address(phy number %d, pcs number %d) to be programed\n",
+			phy_index, pcs_index);
+		return -1;
+	}
+
+	phy_cfg = of_get_property(mdio_node, "phyaddr-fixup", &ret);
+
+	/* For MDIO access, phyaddr-fixup only provides the register address,
+	 * such as qca8084 PHY.
+	 *
+	 * As for local bus, the register length also needs to be provided,
+	 * such as the internal PHY of IPQ5018, only PHY address can be programed.
+	 */
+	if (!phy_cfg || (ret != (2 * sizeof(__be32)) && ret != sizeof(__be32)))
+		return 0;
+
+	if (ret == sizeof(__be32)) {
+		const __be32 *pcs_cfg;
+
+		/* MDIO access for customizing PHY address of qca8084 */
+		if (phy_addr_val != 0) {
+			ret = qca8084_modify(bus, be32_to_cpup(phy_cfg),
+					     QCA8084_PHY_ADDR_MASK, phy_addr_val);
+			if (ret)
+				return ret;
+		}
+
+		pcs_cfg = of_get_property(mdio_node, "pcsaddr-fixup", NULL);
+		/* Programe the PCS address if pcsaddr-fixup specified */
+		if (pcs_cfg && pcs_addr_val != 0) {
+			ret = qca8084_modify(bus, be32_to_cpup(pcs_cfg),
+					     QCA8084_PCS_ADDR_MASK, pcs_addr_val);
+			if (ret)
+				return ret;
+		}
+	} else {
+		void __iomem *ephy_cfg_base;
+
+		/* Local bus access for customizing internal PHY address of IPQ5018 */
+		ephy_cfg_base = ioremap(be32_to_cpup(phy_cfg), be32_to_cpup(phy_cfg + 1));
+		if (!ephy_cfg_base)
+			return -ENOMEM;
+
+		if (phy_addr_val != 0)
+			writel(phy_addr_val, ephy_cfg_base);
+	}
+
+	return 0;
+}
+
+static int ipq_mdio_preinit(struct mii_bus *bus)
+{
+	struct device_node *mdio_node = dev_of_node(&bus->dev);
+
+	if (!mdio_node)
+		return 0;
+
+	return ipq_phy_addr_fixup(bus, mdio_node);
+}
+
 /* For the CMN PLL block, the reference clock can be configured according to
  * the device tree property "cmn_ref_clk", the internal 48MHZ is used by default
  * on the ipq533 platform.
@@ -455,7 +560,7 @@  static int ipq_mdio_reset(struct mii_bus *bus)
 	if (ret == 0)
 		mdelay(10);
 
-	return ret;
+	return ipq_mdio_preinit(bus);
 }
 
 static int ipq4019_mdio_probe(struct platform_device *pdev)