mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-17 09:21:35 +00:00
175 lines
4.7 KiB
Diff
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
|
|
|