mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-17 17:31:27 +00:00
237 lines
7.2 KiB
Diff
237 lines
7.2 KiB
Diff
From f48fab0efed0fe088248815f138d529781c3a104 Mon Sep 17 00:00:00 2001
|
|
From: Luo Jie <quic_luoj@quicinc.com>
|
|
Date: Wed, 22 Mar 2023 18:55:42 +0800
|
|
Subject: [PATCH 201/281] net: mdio-ipq4019: Add the qca8386 initialization.
|
|
|
|
The clock fixup of qca8386 is necessary before the MDIO
|
|
bus registered, which makes the embedded PHY probed correctly.
|
|
|
|
Change-Id: I8e3f66c39c8362eb0333d96a4df17439dd713404
|
|
Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
|
|
---
|
|
drivers/net/mdio/mdio-ipq4019.c | 187 ++++++++++++++++++++++++++++++++
|
|
1 file changed, 187 insertions(+)
|
|
|
|
diff --git a/drivers/net/mdio/mdio-ipq4019.c b/drivers/net/mdio/mdio-ipq4019.c
|
|
index 2a9869151cb9..c555ee6d0fcd 100644
|
|
--- a/drivers/net/mdio/mdio-ipq4019.c
|
|
+++ b/drivers/net/mdio/mdio-ipq4019.c
|
|
@@ -44,6 +44,27 @@
|
|
#define PHY_ADDR_NUM 4
|
|
#define UNIPHY_ADDR_NUM 3
|
|
|
|
+#define EPHY_CFG 0xC90F018
|
|
+#define GEPHY0_TX_CBCR 0xC800058
|
|
+#define SRDS0_SYS_CBCR 0xC8001A8
|
|
+#define SRDS1_SYS_CBCR 0xC8001AC
|
|
+#define EPHY0_SYS_CBCR 0xC8001B0
|
|
+#define EPHY1_SYS_CBCR 0xC8001B4
|
|
+#define EPHY2_SYS_CBCR 0xC8001B8
|
|
+#define EPHY3_SYS_CBCR 0xC8001BC
|
|
+#define GCC_GEPHY_MISC 0xC800304
|
|
+#define QFPROM_RAW_PTE_ROW2_MSB 0xC900014
|
|
+#define QFPROM_RAW_CALIBRATION_ROW4_LSB 0xC900048
|
|
+#define QFPROM_RAW_CALIBRATION_ROW7_LSB 0xC900060
|
|
+#define QFPROM_RAW_CALIBRATION_ROW8_LSB 0xC900068
|
|
+#define QFPROM_RAW_CALIBRATION_ROW6_MSB 0xC90005C
|
|
+#define PHY_DEBUG_PORT_ADDR 0x1d
|
|
+#define PHY_DEBUG_PORT_DATA 0x1e
|
|
+#define PHY_LDO_EFUSE_REG 0x180
|
|
+#define PHY_ICC_EFUSE_REG 0x280
|
|
+#define PHY_10BT_SG_THRESH_REG 0x3380
|
|
+#define PHY_MMD1_CTRL2ANA_OPTION2_REG 0x40018102
|
|
+
|
|
struct ipq4019_mdio_data {
|
|
void __iomem *membase;
|
|
void __iomem *eth_ldo_rdy;
|
|
@@ -239,6 +260,54 @@ int ipq_mii_write(struct mii_bus *bus, unsigned int reg, unsigned int val)
|
|
return 0;
|
|
};
|
|
|
|
+static inline void ipq_qca8386_clk_enable(struct mii_bus *mii_bus, u32 reg)
|
|
+{
|
|
+ u32 val;
|
|
+
|
|
+ val = ipq_mii_read(mii_bus, reg);
|
|
+ val |= BIT(0);
|
|
+ ipq_mii_write(mii_bus, reg, val);
|
|
+}
|
|
+
|
|
+static inline void ipq_qca8386_clk_disable(struct mii_bus *mii_bus, u32 reg)
|
|
+{
|
|
+ u32 val;
|
|
+
|
|
+ val = ipq_mii_read(mii_bus, reg);
|
|
+ val &= ~BIT(0);
|
|
+ ipq_mii_write(mii_bus, reg, val);
|
|
+}
|
|
+
|
|
+static inline void ipq_qca8386_clk_reset(struct mii_bus *mii_bus, u32 reg)
|
|
+{
|
|
+ u32 val;
|
|
+
|
|
+ val = ipq_mii_read(mii_bus, reg);
|
|
+ val |= BIT(2);
|
|
+ ipq_mii_write(mii_bus, reg, val);
|
|
+
|
|
+ usleep_range(20000, 21000);
|
|
+
|
|
+ val &= ~BIT(2);
|
|
+ ipq_mii_write(mii_bus, reg, val);
|
|
+}
|
|
+
|
|
+static u16 ipq_phy_debug_read(struct mii_bus *mii_bus, u32 phy_addr, u32 reg_id)
|
|
+{
|
|
+ mii_bus->write(mii_bus, phy_addr, PHY_DEBUG_PORT_ADDR, reg_id);
|
|
+
|
|
+ return mii_bus->read(mii_bus, phy_addr, PHY_DEBUG_PORT_DATA);
|
|
+}
|
|
+
|
|
+static void ipq_phy_debug_write(struct mii_bus *mii_bus, u32 phy_addr, u32 reg_id, u16 reg_val)
|
|
+{
|
|
+
|
|
+ mii_bus->write(mii_bus, phy_addr, PHY_DEBUG_PORT_ADDR, reg_id);
|
|
+
|
|
+ mii_bus->write(mii_bus, phy_addr, PHY_DEBUG_PORT_DATA, reg_val);
|
|
+}
|
|
+
|
|
+
|
|
static void ipq_phy_addr_fixup(struct mii_bus *bus, struct device_node *np)
|
|
{
|
|
void __iomem *ephy_cfg_base;
|
|
@@ -344,6 +413,121 @@ static void ipq_phy_addr_fixup(struct mii_bus *bus, struct device_node *np)
|
|
}
|
|
}
|
|
|
|
+static void ipq_qca8386_efuse_loading(struct mii_bus *mii_bus, u8 ethphy)
|
|
+{
|
|
+ u32 val = 0, ldo_efuse = 0, icc_efuse = 0, phy_addr = 0;
|
|
+ u16 reg_val = 0;
|
|
+
|
|
+ phy_addr = ipq_mii_read(mii_bus, EPHY_CFG);
|
|
+ phy_addr = (phy_addr >> (ethphy * PHY_ADDR_LENGTH)) & GENMASK(4, 0);
|
|
+
|
|
+ switch(ethphy) {
|
|
+ case 0:
|
|
+ val = ipq_mii_read(mii_bus, QFPROM_RAW_CALIBRATION_ROW4_LSB);
|
|
+ ldo_efuse = FIELD_GET(GENMASK(21, 18), val);
|
|
+ icc_efuse = FIELD_GET(GENMASK(26, 22), val);
|
|
+ break;
|
|
+ case 1:
|
|
+ val = ipq_mii_read(mii_bus, QFPROM_RAW_CALIBRATION_ROW7_LSB);
|
|
+ ldo_efuse = FIELD_GET(GENMASK(26, 23), val);
|
|
+ icc_efuse = FIELD_GET(GENMASK(31, 27), val);
|
|
+ break;
|
|
+ case 2:
|
|
+ val = ipq_mii_read(mii_bus, QFPROM_RAW_CALIBRATION_ROW8_LSB);
|
|
+ ldo_efuse = FIELD_GET(GENMASK(26, 23), val);
|
|
+ icc_efuse = FIELD_GET(GENMASK(31, 27), val);
|
|
+ break;
|
|
+ case 3:
|
|
+ val = ipq_mii_read(mii_bus, QFPROM_RAW_CALIBRATION_ROW6_MSB);
|
|
+ ldo_efuse = FIELD_GET(GENMASK(17, 14), val);
|
|
+ icc_efuse = FIELD_GET(GENMASK(22, 18), val);
|
|
+ break;
|
|
+ }
|
|
+ reg_val = ipq_phy_debug_read(mii_bus, phy_addr, PHY_LDO_EFUSE_REG);
|
|
+ reg_val &= ~GENMASK(7, 4);
|
|
+ reg_val |= FIELD_PREP(GENMASK(7, 4), ldo_efuse);
|
|
+ ipq_phy_debug_write(mii_bus, phy_addr, PHY_LDO_EFUSE_REG, reg_val);
|
|
+
|
|
+ reg_val = ipq_phy_debug_read(mii_bus, phy_addr, PHY_ICC_EFUSE_REG);
|
|
+ reg_val &= ~GENMASK(4, 0);
|
|
+ reg_val |= FIELD_PREP(GENMASK(4, 0), icc_efuse);
|
|
+ ipq_phy_debug_write(mii_bus, phy_addr, PHY_ICC_EFUSE_REG, reg_val);
|
|
+}
|
|
+
|
|
+static void ipq_qca8386_ethphy_ana_fixup(struct mii_bus *mii_bus, u8 ethphy)
|
|
+{
|
|
+ u32 phy_addr = 0;
|
|
+ u16 reg_val = 0;
|
|
+
|
|
+ phy_addr = ipq_mii_read(mii_bus, EPHY_CFG);
|
|
+ phy_addr = (phy_addr >> (ethphy * PHY_ADDR_LENGTH)) & GENMASK(4, 0);
|
|
+
|
|
+ /*increase 100BT tx amplitude*/
|
|
+ reg_val = mii_bus->read(mii_bus, phy_addr, PHY_MMD1_CTRL2ANA_OPTION2_REG);
|
|
+ mii_bus->write(mii_bus, phy_addr, PHY_MMD1_CTRL2ANA_OPTION2_REG, reg_val | 0x7f);
|
|
+
|
|
+ /*increase 10BT signal detect threshold*/
|
|
+ reg_val = ipq_phy_debug_read(mii_bus, phy_addr, PHY_10BT_SG_THRESH_REG);
|
|
+ ipq_phy_debug_write(mii_bus, phy_addr, PHY_10BT_SG_THRESH_REG, reg_val | 0x1);
|
|
+}
|
|
+
|
|
+static void ipq_qca8386_clock_init(struct mii_bus *mii_bus)
|
|
+{
|
|
+ u32 val = 0;
|
|
+ int i;
|
|
+
|
|
+ /* Enable serdes */
|
|
+ ipq_qca8386_clk_enable(mii_bus, SRDS0_SYS_CBCR);
|
|
+ ipq_qca8386_clk_enable(mii_bus, SRDS1_SYS_CBCR);
|
|
+
|
|
+ /* Reset serdes */
|
|
+ ipq_qca8386_clk_reset(mii_bus, SRDS0_SYS_CBCR);
|
|
+ ipq_qca8386_clk_reset(mii_bus, SRDS1_SYS_CBCR);
|
|
+
|
|
+ /* Disable EPHY GMII clock */
|
|
+ i = 0;
|
|
+ while (i < 2 * PHY_ADDR_NUM) {
|
|
+ ipq_qca8386_clk_disable(mii_bus, GEPHY0_TX_CBCR + i*0x20);
|
|
+ i++;
|
|
+ }
|
|
+
|
|
+ /* Enable ephy */
|
|
+ ipq_qca8386_clk_enable(mii_bus, EPHY0_SYS_CBCR);
|
|
+ ipq_qca8386_clk_enable(mii_bus, EPHY1_SYS_CBCR);
|
|
+ ipq_qca8386_clk_enable(mii_bus, EPHY2_SYS_CBCR);
|
|
+ ipq_qca8386_clk_enable(mii_bus, EPHY3_SYS_CBCR);
|
|
+
|
|
+ /* Reset ephy */
|
|
+ ipq_qca8386_clk_reset(mii_bus, EPHY0_SYS_CBCR);
|
|
+ ipq_qca8386_clk_reset(mii_bus, EPHY1_SYS_CBCR);
|
|
+ ipq_qca8386_clk_reset(mii_bus, EPHY2_SYS_CBCR);
|
|
+ ipq_qca8386_clk_reset(mii_bus, EPHY3_SYS_CBCR);
|
|
+
|
|
+ /* Deassert EPHY DSP */
|
|
+ val = ipq_mii_read(mii_bus, GCC_GEPHY_MISC);
|
|
+ val &= ~GENMASK(4, 0);
|
|
+ ipq_mii_write(mii_bus, GCC_GEPHY_MISC, val);
|
|
+ /*for ES chips, need to load efuse manually*/
|
|
+ val = ipq_mii_read(mii_bus, QFPROM_RAW_PTE_ROW2_MSB);
|
|
+ val = FIELD_GET(GENMASK(23, 16), val);
|
|
+ if(val == 1 || val == 2) {
|
|
+ for(i = 0; i < 4; i++)
|
|
+ ipq_qca8386_efuse_loading(mii_bus, i);
|
|
+ }
|
|
+ /*fix 100BT template issue and 10BT threshold issue*/
|
|
+ for(i = 0; i < 4; i++)
|
|
+ ipq_qca8386_ethphy_ana_fixup(mii_bus, i);
|
|
+ /* Enable efuse loading into analog circuit */
|
|
+ val = ipq_mii_read(mii_bus, EPHY_CFG);
|
|
+ /* BIT20 for PHY0 and PHY1, BIT21 for PHY2 and PHY3 */
|
|
+ val &= ~GENMASK(21, 20);
|
|
+ ipq_mii_write(mii_bus, EPHY_CFG, val);
|
|
+
|
|
+ /* Sleep 10ms */
|
|
+ usleep_range(10000, 11000);
|
|
+}
|
|
+
|
|
+
|
|
void ipq_mii_preinit(struct mii_bus *bus)
|
|
{
|
|
struct device_node *np = bus->parent->of_node;
|
|
@@ -351,6 +535,9 @@ void ipq_mii_preinit(struct mii_bus *bus)
|
|
return;
|
|
|
|
ipq_phy_addr_fixup(bus, np);
|
|
+ if (of_property_read_bool(np, "mdio_clk_fixup"))
|
|
+ ipq_qca8386_clock_init(bus);
|
|
+
|
|
return;
|
|
}
|
|
EXPORT_SYMBOL_GPL(ipq_mii_preinit);
|
|
--
|
|
2.17.1
|
|
|