wlan-ap-Telecominfraproject/feeds/qca-wifi-7/ipq53xx/patches-6.1/0200-net-mdio-ipq4019-Support-PHY-address-program.patch
John Crispin 68cf54d9f7 qca-wifi-7: update to ath12.5.5
Signed-off-by: John Crispin <john@phrozen.org>
2025-02-27 12:45:52 +01:00

175 lines
4.7 KiB
Diff

From 8329ee73e00c6788759f430d275b7cd7f4542091 Mon Sep 17 00:00:00 2001
From: Luo Jie <quic_luoj@quicinc.com>
Date: Wed, 22 Mar 2023 18:28:55 +0800
Subject: [PATCH 200/281] net: mdio-ipq4019: Support PHY address program
The qca8386 embedded PHY address supports to be edited,
the PHY address configuration register can be specified
according to DTS property below.
phyaddr_fixup = <0xC90F018>;
uniphyaddr_fixup = <0xC90F014>;
Change-Id: Iad5eaac8b667bb0f09d6a90b569df19813be7219
Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
---
drivers/net/mdio/mdio-ipq4019.c | 126 +++++++++++++++++++++++++++++++-
1 file changed, 125 insertions(+), 1 deletion(-)
diff --git a/drivers/net/mdio/mdio-ipq4019.c b/drivers/net/mdio/mdio-ipq4019.c
index 7e78b002c87b..2a9869151cb9 100644
--- a/drivers/net/mdio/mdio-ipq4019.c
+++ b/drivers/net/mdio/mdio-ipq4019.c
@@ -40,6 +40,10 @@
#define IPQ_HIGH_ADDR_PREFIX 0x18
#define IPQ_LOW_ADDR_PREFIX 0x10
+#define PHY_ADDR_LENGTH 5
+#define PHY_ADDR_NUM 4
+#define UNIPHY_ADDR_NUM 3
+
struct ipq4019_mdio_data {
void __iomem *membase;
void __iomem *eth_ldo_rdy;
@@ -235,6 +239,122 @@ int ipq_mii_write(struct mii_bus *bus, unsigned int reg, unsigned int val)
return 0;
};
+static void ipq_phy_addr_fixup(struct mii_bus *bus, struct device_node *np)
+{
+ void __iomem *ephy_cfg_base;
+ struct device_node *child;
+ int phy_index, addr, len;
+ const __be32 *phy_cfg, *uniphy_cfg;
+ u32 val;
+ bool mdio_access = false;
+ unsigned long phyaddr_mask = 0;
+
+ phy_cfg = of_get_property(np, "phyaddr_fixup", &len);
+ uniphy_cfg = of_get_property(np, "uniphyaddr_fixup", NULL);
+
+ /*
+ * For MDIO access, phyaddr_fixup only provides the register address,
+ * as for local bus, the register length also needs to be provided
+ */
+ if(!phy_cfg || (len != (2 * sizeof(__be32)) && len != sizeof(__be32)))
+ return;
+
+ if (len == sizeof(__be32))
+ mdio_access = true;
+
+ if (!mdio_access) {
+ ephy_cfg_base = ioremap(be32_to_cpup(phy_cfg), be32_to_cpup(phy_cfg + 1));
+ if (!ephy_cfg_base)
+ return;
+ val = readl(ephy_cfg_base);
+ } else
+ val = ipq_mii_read(bus, be32_to_cpup(phy_cfg));
+
+ phy_index = 0;
+ addr = 0;
+ for_each_available_child_of_node(np, child) {
+ if (phy_index >= PHY_ADDR_NUM)
+ break;
+
+ addr = of_mdio_parse_addr(&bus->dev, child);
+ if (addr < 0) {
+ continue;
+ }
+ phyaddr_mask |= BIT(addr);
+
+ if (!of_find_property(child, "fixup", NULL))
+ continue;
+
+ addr &= GENMASK(4, 0);
+ val &= ~(GENMASK(4, 0) << (phy_index * PHY_ADDR_LENGTH));
+ val |= addr << (phy_index * PHY_ADDR_LENGTH);
+ phy_index++;
+ }
+
+ /* Programe the PHY address */
+ dev_info(bus->parent, "Program EPHY reg 0x%x with 0x%x\n",
+ be32_to_cpup(phy_cfg), val);
+
+ if (!mdio_access) {
+ writel(val, ephy_cfg_base);
+ iounmap(ephy_cfg_base);
+ } else {
+ ipq_mii_write(bus, be32_to_cpup(phy_cfg), val);
+
+ /* Programe the UNIPHY address if uniphyaddr_fixup specified.
+ * the UNIPHY address will select three MDIO address from
+ * unoccupied MDIO address space. */
+ if (uniphy_cfg) {
+ val = ipq_mii_read(bus, be32_to_cpup(uniphy_cfg));
+
+ /* For qca8386, the switch occupies the other 16 MDIO address,
+ * for example, if the phy address is in the range of 0 to 15,
+ * the switch will occupy the MDIO address from 16 to 31. */
+ if (addr > 15)
+ phyaddr_mask |= GENMASK(15, 0);
+ else
+ phyaddr_mask |= GENMASK(31, 16);
+
+ phy_index = 0;
+ for_each_clear_bit_from(addr, &phyaddr_mask, PHY_MAX_ADDR) {
+ if (phy_index >= UNIPHY_ADDR_NUM)
+ break;
+
+ val &= ~(GENMASK(4, 0) << (phy_index * PHY_ADDR_LENGTH));
+ val |= addr << (phy_index * PHY_ADDR_LENGTH);
+ phy_index++;
+ }
+
+ if (phy_index < UNIPHY_ADDR_NUM) {
+ for_each_clear_bit(addr, &phyaddr_mask, PHY_MAX_ADDR) {
+ if (phy_index >= UNIPHY_ADDR_NUM)
+ break;
+
+ val &= ~(GENMASK(4, 0) << (phy_index * PHY_ADDR_LENGTH));
+ val |= addr << (phy_index * PHY_ADDR_LENGTH);
+ phy_index++;
+ }
+ }
+
+ dev_info(bus->parent, "Program UNIPHY reg 0x%x with 0x%x\n",
+ be32_to_cpup(uniphy_cfg), val);
+
+ ipq_mii_write(bus, be32_to_cpup(uniphy_cfg), val);
+ }
+ }
+}
+
+void ipq_mii_preinit(struct mii_bus *bus)
+{
+ struct device_node *np = bus->parent->of_node;
+ if (!np)
+ return;
+
+ ipq_phy_addr_fixup(bus, np);
+ return;
+}
+EXPORT_SYMBOL_GPL(ipq_mii_preinit);
+
static int ipq_mdio_reset(struct mii_bus *bus)
{
struct ipq4019_mdio_data *priv = bus->priv;
@@ -257,9 +377,13 @@ static int ipq_mdio_reset(struct mii_bus *bus)
return ret;
ret = clk_prepare_enable(priv->mdio_clk);
- if (ret == 0)
+ if (ret == 0) {
mdelay(10);
+ /* Configure the fixup PHY address and clocks for qca8386 chip if specified */
+ ipq_mii_preinit(bus);
+ }
+
return ret;
}
--
2.17.1